confpub-cli 0.2.0__tar.gz
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.
- confpub_cli-0.2.0/.github/workflows/publish.yml +49 -0
- confpub_cli-0.2.0/.gitignore +31 -0
- confpub_cli-0.2.0/LICENSE +21 -0
- confpub_cli-0.2.0/PKG-INFO +425 -0
- confpub_cli-0.2.0/PRD.md +817 -0
- confpub_cli-0.2.0/README.md +387 -0
- confpub_cli-0.2.0/confpub/__init__.py +3 -0
- confpub_cli-0.2.0/confpub/applier.py +188 -0
- confpub_cli-0.2.0/confpub/assets.py +153 -0
- confpub_cli-0.2.0/confpub/cli.py +388 -0
- confpub_cli-0.2.0/confpub/config.py +188 -0
- confpub_cli-0.2.0/confpub/confluence.py +239 -0
- confpub_cli-0.2.0/confpub/converter.py +371 -0
- confpub_cli-0.2.0/confpub/envelope.py +106 -0
- confpub_cli-0.2.0/confpub/errors.py +172 -0
- confpub_cli-0.2.0/confpub/guide.py +207 -0
- confpub_cli-0.2.0/confpub/lockfile.py +91 -0
- confpub_cli-0.2.0/confpub/manifest.py +180 -0
- confpub_cli-0.2.0/confpub/output.py +80 -0
- confpub_cli-0.2.0/confpub/planner.py +164 -0
- confpub_cli-0.2.0/confpub/publish.py +152 -0
- confpub_cli-0.2.0/confpub/py.typed +0 -0
- confpub_cli-0.2.0/confpub/validator.py +85 -0
- confpub_cli-0.2.0/confpub/verifier.py +122 -0
- confpub_cli-0.2.0/confpub.lock +10 -0
- confpub_cli-0.2.0/pyproject.toml +64 -0
- confpub_cli-0.2.0/tests/__init__.py +0 -0
- confpub_cli-0.2.0/tests/conftest.py +21 -0
- confpub_cli-0.2.0/tests/test_applier.py +155 -0
- confpub_cli-0.2.0/tests/test_assets.py +108 -0
- confpub_cli-0.2.0/tests/test_config.py +111 -0
- confpub_cli-0.2.0/tests/test_confluence.py +155 -0
- confpub_cli-0.2.0/tests/test_converter.py +222 -0
- confpub_cli-0.2.0/tests/test_envelope.py +117 -0
- confpub_cli-0.2.0/tests/test_errors.py +129 -0
- confpub_cli-0.2.0/tests/test_guide.py +101 -0
- confpub_cli-0.2.0/tests/test_integration.py +95 -0
- confpub_cli-0.2.0/tests/test_lockfile.py +112 -0
- confpub_cli-0.2.0/tests/test_manifest.py +189 -0
- confpub_cli-0.2.0/tests/test_output.py +90 -0
- confpub_cli-0.2.0/tests/test_planner.py +131 -0
- confpub_cli-0.2.0/tests/test_publish.py +134 -0
- confpub_cli-0.2.0/tests/test_validator.py +101 -0
- confpub_cli-0.2.0/tests/test_verifier.py +78 -0
- confpub_cli-0.2.0/uv.lock +1247 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distribution
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v5
|
|
20
|
+
|
|
21
|
+
- name: Build package
|
|
22
|
+
run: uv build
|
|
23
|
+
|
|
24
|
+
- name: Upload distribution artifacts
|
|
25
|
+
uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: python-package-distributions
|
|
28
|
+
path: dist/
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
name: Publish to PyPI
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment:
|
|
35
|
+
name: pypi
|
|
36
|
+
url: https://pypi.org/p/confpub-cli
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write
|
|
39
|
+
steps:
|
|
40
|
+
- name: Download distribution artifacts
|
|
41
|
+
uses: actions/download-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: python-package-distributions
|
|
44
|
+
path: dist/
|
|
45
|
+
|
|
46
|
+
- name: Publish to PyPI
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
48
|
+
with:
|
|
49
|
+
skip-existing: true
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
ENV/
|
|
17
|
+
|
|
18
|
+
# Testing
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
*.swo
|
|
28
|
+
|
|
29
|
+
# OS
|
|
30
|
+
.DS_Store
|
|
31
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Klok Rohde
|
|
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.
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: confpub-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Agent-first CLI to publish Markdown to Confluence
|
|
5
|
+
Project-URL: Homepage, https://github.com/ThomasRohde/confpub-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/ThomasRohde/confpub-cli.git
|
|
7
|
+
Project-URL: Issues, https://github.com/ThomasRohde/confpub-cli/issues
|
|
8
|
+
Author-email: Thomas Klok Rohde <rohde.thomas@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: atlassian,cli,confluence,documentation,markdown,publishing
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Natural Language :: English
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Documentation
|
|
24
|
+
Classifier: Topic :: Office/Business
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: atlassian-python-api>=3.41
|
|
28
|
+
Requires-Dist: keyring>=24.0
|
|
29
|
+
Requires-Dist: markdown-it-py[linkify,plugins]>=3.0
|
|
30
|
+
Requires-Dist: orjson>=3.9
|
|
31
|
+
Requires-Dist: pydantic>=2.0
|
|
32
|
+
Requires-Dist: pyyaml>=6.0
|
|
33
|
+
Requires-Dist: typer[all]>=0.9
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# confpub
|
|
40
|
+
|
|
41
|
+
**Agent-first CLI to publish Markdown to Confluence.**
|
|
42
|
+
|
|
43
|
+
Publish one file or an entire documentation tree — from the terminal, a CI pipeline, or an LLM agent. Every command returns structured JSON. Every error has a stable code. One call to `confpub guide` gives an agent everything it needs to drive the tool zero-shot.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
pip install confpub
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### Publish a single file
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
export CONFPUB_URL=https://yourorg.atlassian.net/wiki
|
|
57
|
+
export CONFPUB_TOKEN=your-api-token
|
|
58
|
+
export CONFPUB_USER=you@example.com
|
|
59
|
+
|
|
60
|
+
confpub page publish README.md --space DEV --parent "Engineering"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Publish a documentation tree
|
|
64
|
+
|
|
65
|
+
Create a `confpub.yaml` manifest:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
schema_version: "1.0"
|
|
69
|
+
space: DEV
|
|
70
|
+
parent: "Engineering"
|
|
71
|
+
|
|
72
|
+
pages:
|
|
73
|
+
- title: "Architecture Overview"
|
|
74
|
+
file: docs/architecture.md
|
|
75
|
+
assets:
|
|
76
|
+
- docs/diagrams/*.png
|
|
77
|
+
children:
|
|
78
|
+
- title: "API Reference"
|
|
79
|
+
file: docs/api.md
|
|
80
|
+
- title: "Deployment Guide"
|
|
81
|
+
file: docs/deploy.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then run the transactional workflow:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
confpub plan create --manifest confpub.yaml # Plan (no writes)
|
|
88
|
+
confpub plan validate --plan confpub-plan.json # Check for drift
|
|
89
|
+
confpub plan apply --plan confpub-plan.json # Apply to Confluence
|
|
90
|
+
confpub plan verify --assertions verify.json # Assert post-conditions
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Or preview first with `--dry-run`:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
confpub plan apply --plan confpub-plan.json --dry-run
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Features
|
|
102
|
+
|
|
103
|
+
- **Structured JSON output** — every command returns the same envelope shape on stdout
|
|
104
|
+
- **Transactional workflow** — plan → validate → apply → verify with fingerprint-based conflict detection
|
|
105
|
+
- **Markdown → Confluence** — code blocks become code macros, `> [!NOTE]` becomes Info panels, tables stay tables
|
|
106
|
+
- **Asset handling** — images are uploaded as attachments and URLs are rewritten automatically
|
|
107
|
+
- **Idempotent** — a lockfile tracks page IDs so re-publishing updates in place
|
|
108
|
+
- **Agent-ready** — `confpub guide` returns the full CLI schema; `LLM=true` suppresses interactive behavior
|
|
109
|
+
- **Cloud + Server** — works with Confluence Cloud (*.atlassian.net) and Server/Data Center
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Commands
|
|
114
|
+
|
|
115
|
+
All commands follow a `noun verb` pattern. Verbs telegraph mutation intent.
|
|
116
|
+
|
|
117
|
+
| Command | Mutates | Description |
|
|
118
|
+
|---------|---------|-------------|
|
|
119
|
+
| `confpub guide` | No | Machine-readable CLI schema |
|
|
120
|
+
| `confpub page list` | No | List pages in a space |
|
|
121
|
+
| `confpub page inspect` | No | Detailed view of one page |
|
|
122
|
+
| `confpub page publish` | **Yes** | Publish a single Markdown file |
|
|
123
|
+
| `confpub page delete` | **Yes** | Delete a page |
|
|
124
|
+
| `confpub space list` | No | List accessible spaces |
|
|
125
|
+
| `confpub attachment list` | No | List attachments on a page |
|
|
126
|
+
| `confpub attachment upload` | **Yes** | Upload a file as an attachment |
|
|
127
|
+
| `confpub plan create` | No | Generate a plan artifact from a manifest |
|
|
128
|
+
| `confpub plan validate` | No | Check a plan against current state |
|
|
129
|
+
| `confpub plan apply` | **Yes** | Execute a plan (supports `--dry-run`) |
|
|
130
|
+
| `confpub plan verify` | No | Assert post-conditions hold |
|
|
131
|
+
| `confpub auth inspect` | No | Show credential status |
|
|
132
|
+
| `confpub config set` | **Yes** | Write a config value |
|
|
133
|
+
| `confpub config inspect` | No | Show current config |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Structured Envelope
|
|
138
|
+
|
|
139
|
+
Every command — success or failure — returns this exact shape on stdout:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"schema_version": "1.0",
|
|
144
|
+
"request_id": "req_20260228_143000_7f3a",
|
|
145
|
+
"ok": true,
|
|
146
|
+
"command": "page.publish",
|
|
147
|
+
"target": {
|
|
148
|
+
"space": "DEV",
|
|
149
|
+
"title": "Architecture Overview"
|
|
150
|
+
},
|
|
151
|
+
"result": { "..." : "..." },
|
|
152
|
+
"warnings": [],
|
|
153
|
+
"errors": [],
|
|
154
|
+
"metrics": {
|
|
155
|
+
"duration_ms": 842
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
On failure, `ok` is `false`, `result` is `null`, and `errors` contains structured error objects:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"ok": false,
|
|
165
|
+
"errors": [
|
|
166
|
+
{
|
|
167
|
+
"code": "ERR_CONFLICT_FINGERPRINT",
|
|
168
|
+
"message": "Page was modified externally since plan was created",
|
|
169
|
+
"retryable": false,
|
|
170
|
+
"suggested_action": "fix_input",
|
|
171
|
+
"details": {
|
|
172
|
+
"page_id": "123456",
|
|
173
|
+
"plan_fingerprint": "sha256:abc123",
|
|
174
|
+
"current_fingerprint": "sha256:def456"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Invariants:**
|
|
182
|
+
- `stdout` is exclusively JSON — one object, no preamble, no epilogue
|
|
183
|
+
- `errors` and `warnings` are always arrays (possibly empty)
|
|
184
|
+
- `result` is always present (`null` on failure)
|
|
185
|
+
- `stderr` gets progress events, diagnostics, and debug logs
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Exit Codes
|
|
190
|
+
|
|
191
|
+
| Code | Meaning | Action |
|
|
192
|
+
|------|---------|--------|
|
|
193
|
+
| `0` | Success | — |
|
|
194
|
+
| `10` | Validation error | Fix input, do not retry |
|
|
195
|
+
| `20` | Auth / permission | Re-authenticate or escalate |
|
|
196
|
+
| `40` | Conflict | Re-plan, do not blindly retry |
|
|
197
|
+
| `50` | I/O error | Retry with backoff |
|
|
198
|
+
| `90` | Internal error | File a bug |
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Error Codes
|
|
203
|
+
|
|
204
|
+
Stable across versions. An agent can branch on these without parsing messages.
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
ERR_VALIDATION_REQUIRED Missing required argument
|
|
208
|
+
ERR_VALIDATION_MANIFEST Manifest fails schema validation
|
|
209
|
+
ERR_VALIDATION_MARKDOWN Unparseable Markdown
|
|
210
|
+
ERR_VALIDATION_ASSET_MISSING Referenced image not found on disk
|
|
211
|
+
|
|
212
|
+
ERR_AUTH_REQUIRED No credentials configured
|
|
213
|
+
ERR_AUTH_EXPIRED Token has expired
|
|
214
|
+
ERR_AUTH_FORBIDDEN Lacks permission to write
|
|
215
|
+
|
|
216
|
+
ERR_CONFLICT_FINGERPRINT Page changed since plan was created
|
|
217
|
+
ERR_CONFLICT_LOCK Another confpub process holds the lock
|
|
218
|
+
ERR_CONFLICT_PAGE_EXISTS Title exists with unexpected ID
|
|
219
|
+
|
|
220
|
+
ERR_IO_FILE_NOT_FOUND Source file missing
|
|
221
|
+
ERR_IO_CONNECTION Confluence unreachable
|
|
222
|
+
ERR_IO_TIMEOUT Request timed out
|
|
223
|
+
|
|
224
|
+
ERR_INTERNAL_CONVERTER Conversion crashed
|
|
225
|
+
ERR_INTERNAL_SDK Unexpected API response
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Authentication
|
|
231
|
+
|
|
232
|
+
Credentials are resolved in this order (highest precedence first):
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
CLI flags → --token / --user
|
|
236
|
+
Env vars → CONFPUB_TOKEN / CONFPUB_USER / CONFPUB_URL
|
|
237
|
+
Config file → ~/.config/confpub/config.json
|
|
238
|
+
OS keychain → via keyring
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Cloud vs Server is auto-detected from the URL: `*.atlassian.net` uses token + email auth; everything else uses PAT.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Check current auth status
|
|
245
|
+
confpub auth inspect
|
|
246
|
+
|
|
247
|
+
# Set config values
|
|
248
|
+
confpub config set base_url https://yourorg.atlassian.net/wiki
|
|
249
|
+
confpub config set user you@example.com
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
When `LLM=true` or stdin is non-interactive, confpub never prompts — it returns a structured `ERR_AUTH_REQUIRED` error instead.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Markdown Conversion
|
|
257
|
+
|
|
258
|
+
confpub converts Markdown to Confluence Storage Format:
|
|
259
|
+
|
|
260
|
+
| Markdown | Confluence Output |
|
|
261
|
+
|----------|-------------------|
|
|
262
|
+
| `# Heading` | `<h1>Heading</h1>` |
|
|
263
|
+
| `**bold**` | `<strong>bold</strong>` |
|
|
264
|
+
| `` `code` `` | `<code>code</code>` |
|
|
265
|
+
| Fenced code block | `<ac:structured-macro ac:name="code">` with language param |
|
|
266
|
+
| `> [!NOTE]` | Confluence Info macro |
|
|
267
|
+
| `> [!WARNING]` | Confluence Warning macro |
|
|
268
|
+
| `> [!TIP]` | Confluence Tip macro |
|
|
269
|
+
| `` | Upload attachment + `<ac:image>` reference |
|
|
270
|
+
| Tables | Standard XHTML `<table>` |
|
|
271
|
+
| `~~strikethrough~~` | `<del>strikethrough</del>` |
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Manifest Format
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
schema_version: "1.0"
|
|
279
|
+
space: DEV
|
|
280
|
+
parent: "Architecture Notes"
|
|
281
|
+
|
|
282
|
+
confluence:
|
|
283
|
+
base_url: https://yourorg.atlassian.net/wiki
|
|
284
|
+
auth:
|
|
285
|
+
type: token # Credentials via CONFPUB_TOKEN + CONFPUB_USER
|
|
286
|
+
|
|
287
|
+
conflict_strategy: fail # fail | overwrite | skip
|
|
288
|
+
on_removal: leave # leave | delete
|
|
289
|
+
version_comment: "Published by confpub @ {timestamp}"
|
|
290
|
+
|
|
291
|
+
labels:
|
|
292
|
+
- architecture
|
|
293
|
+
- auto-published
|
|
294
|
+
|
|
295
|
+
assertions:
|
|
296
|
+
- type: page.exists
|
|
297
|
+
title: "Overview"
|
|
298
|
+
- type: page.parent
|
|
299
|
+
title: "Components"
|
|
300
|
+
expected_parent: "Overview"
|
|
301
|
+
|
|
302
|
+
pages:
|
|
303
|
+
- title: "Overview"
|
|
304
|
+
file: overview.md
|
|
305
|
+
|
|
306
|
+
- title: "Component Design"
|
|
307
|
+
file: components/design.md
|
|
308
|
+
assets:
|
|
309
|
+
- components/diagrams/*.png
|
|
310
|
+
children:
|
|
311
|
+
- title: "API Reference"
|
|
312
|
+
file: components/api.md
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Lockfile
|
|
318
|
+
|
|
319
|
+
After the first successful apply, confpub writes `confpub.lock` alongside the manifest. Commit this to version control — it maps page titles to Confluence page IDs for idempotent re-publishing.
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"schema_version": "1.0",
|
|
324
|
+
"last_updated": "2026-02-28T14:35:00Z",
|
|
325
|
+
"pages": {
|
|
326
|
+
"Overview": { "page_id": "123456", "version": 5 },
|
|
327
|
+
"Component Design": { "page_id": "123457", "version": 1 },
|
|
328
|
+
"API Reference": { "page_id": "123458", "version": 1 }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Agent Integration
|
|
336
|
+
|
|
337
|
+
An LLM agent can drive confpub entirely from one bootstrap call:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# Step 1: Learn the CLI
|
|
341
|
+
confpub guide
|
|
342
|
+
|
|
343
|
+
# Step 2: Check credentials
|
|
344
|
+
confpub auth inspect
|
|
345
|
+
|
|
346
|
+
# Step 3: Explore
|
|
347
|
+
confpub space list
|
|
348
|
+
confpub page list --space DEV
|
|
349
|
+
|
|
350
|
+
# Step 4: Publish
|
|
351
|
+
confpub page publish doc.md --space DEV --parent "Docs" --dry-run
|
|
352
|
+
confpub page publish doc.md --space DEV --parent "Docs"
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The `guide` command returns the complete schema — all commands with flags, all error codes with exit codes and retry hints, auth precedence, and concurrency rules:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
confpub guide # Full schema
|
|
359
|
+
confpub guide --section auth # Just auth info
|
|
360
|
+
confpub guide --section error_codes # Just error codes
|
|
361
|
+
confpub guide --section commands # Just commands
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Environment variables for agents
|
|
365
|
+
|
|
366
|
+
| Variable | Effect |
|
|
367
|
+
|----------|--------|
|
|
368
|
+
| `LLM=true` | Suppress interactive prompts; return structured errors instead |
|
|
369
|
+
| `CONFPUB_TOKEN` | API token |
|
|
370
|
+
| `CONFPUB_USER` | Email / username |
|
|
371
|
+
| `CONFPUB_URL` | Confluence base URL |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Development
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
# Install in editable mode with dev dependencies
|
|
379
|
+
pip install -e ".[dev]"
|
|
380
|
+
|
|
381
|
+
# Run tests
|
|
382
|
+
pytest tests/ -v
|
|
383
|
+
|
|
384
|
+
# Run with coverage
|
|
385
|
+
pytest tests/ -v --cov=confpub
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Project Structure
|
|
389
|
+
|
|
390
|
+
```
|
|
391
|
+
confpub/
|
|
392
|
+
├── cli.py # Typer app, commands, envelope wrapping
|
|
393
|
+
├── envelope.py # Pydantic envelope model
|
|
394
|
+
├── errors.py # Error codes, exit codes, ConfpubError
|
|
395
|
+
├── output.py # TOON / LLM=true / isatty logic
|
|
396
|
+
├── config.py # Credential precedence
|
|
397
|
+
├── confluence.py # atlassian-python-api wrapper
|
|
398
|
+
├── converter.py # Markdown → Confluence Storage Format
|
|
399
|
+
├── manifest.py # Manifest + plan artifact models
|
|
400
|
+
├── lockfile.py # confpub.lock persistence
|
|
401
|
+
├── assets.py # Asset discovery, upload, URL rewriting
|
|
402
|
+
├── planner.py # plan.create
|
|
403
|
+
├── validator.py # plan.validate
|
|
404
|
+
├── applier.py # plan.apply
|
|
405
|
+
├── verifier.py # plan.verify
|
|
406
|
+
├── publish.py # page.publish shortcut
|
|
407
|
+
└── guide.py # Machine-readable CLI schema
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Technology Stack
|
|
411
|
+
|
|
412
|
+
| Concern | Choice |
|
|
413
|
+
|---------|--------|
|
|
414
|
+
| CLI framework | [Typer](https://typer.tiangolo.com) |
|
|
415
|
+
| Confluence API | [atlassian-python-api](https://github.com/atlassian-api/atlassian-python-api) |
|
|
416
|
+
| Markdown parsing | [markdown-it-py](https://github.com/executablebooks/markdown-it-py) |
|
|
417
|
+
| Validation | [Pydantic v2](https://docs.pydantic.dev) |
|
|
418
|
+
| JSON serialization | [orjson](https://github.com/ijl/orjson) |
|
|
419
|
+
| Credentials | [keyring](https://github.com/jaraco/keyring) + env vars |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## License
|
|
424
|
+
|
|
425
|
+
MIT
|