kctl-outline 0.6.1__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.
Files changed (46) hide show
  1. kctl_outline-0.6.1/.gitignore +33 -0
  2. kctl_outline-0.6.1/PKG-INFO +145 -0
  3. kctl_outline-0.6.1/README.md +116 -0
  4. kctl_outline-0.6.1/pyproject.toml +62 -0
  5. kctl_outline-0.6.1/skills/outline-admin/SKILL.md +158 -0
  6. kctl_outline-0.6.1/src/kctl_outline/__init__.py +3 -0
  7. kctl_outline-0.6.1/src/kctl_outline/__main__.py +5 -0
  8. kctl_outline-0.6.1/src/kctl_outline/cli.py +120 -0
  9. kctl_outline-0.6.1/src/kctl_outline/commands/__init__.py +0 -0
  10. kctl_outline-0.6.1/src/kctl_outline/commands/attachments.py +95 -0
  11. kctl_outline-0.6.1/src/kctl_outline/commands/collections.py +195 -0
  12. kctl_outline-0.6.1/src/kctl_outline/commands/comments.py +74 -0
  13. kctl_outline-0.6.1/src/kctl_outline/commands/config_cmd.py +490 -0
  14. kctl_outline-0.6.1/src/kctl_outline/commands/dashboard.py +141 -0
  15. kctl_outline-0.6.1/src/kctl_outline/commands/doctor_cmd.py +72 -0
  16. kctl_outline-0.6.1/src/kctl_outline/commands/documents.py +279 -0
  17. kctl_outline-0.6.1/src/kctl_outline/commands/events.py +78 -0
  18. kctl_outline-0.6.1/src/kctl_outline/commands/groups.py +152 -0
  19. kctl_outline-0.6.1/src/kctl_outline/commands/health.py +155 -0
  20. kctl_outline-0.6.1/src/kctl_outline/commands/revisions.py +73 -0
  21. kctl_outline-0.6.1/src/kctl_outline/commands/search.py +43 -0
  22. kctl_outline-0.6.1/src/kctl_outline/commands/shares.py +99 -0
  23. kctl_outline-0.6.1/src/kctl_outline/commands/stars.py +62 -0
  24. kctl_outline-0.6.1/src/kctl_outline/commands/sync.py +543 -0
  25. kctl_outline-0.6.1/src/kctl_outline/commands/templates.py +107 -0
  26. kctl_outline-0.6.1/src/kctl_outline/commands/tokens.py +80 -0
  27. kctl_outline-0.6.1/src/kctl_outline/commands/users.py +152 -0
  28. kctl_outline-0.6.1/src/kctl_outline/core/__init__.py +0 -0
  29. kctl_outline-0.6.1/src/kctl_outline/core/callbacks.py +42 -0
  30. kctl_outline-0.6.1/src/kctl_outline/core/client.py +104 -0
  31. kctl_outline-0.6.1/src/kctl_outline/core/config.py +219 -0
  32. kctl_outline-0.6.1/src/kctl_outline/core/exceptions.py +52 -0
  33. kctl_outline-0.6.1/src/kctl_outline/core/output.py +125 -0
  34. kctl_outline-0.6.1/src/kctl_outline/core/sync_config.py +106 -0
  35. kctl_outline-0.6.1/src/kctl_outline/core/sync_planner.py +171 -0
  36. kctl_outline-0.6.1/src/kctl_outline/core/sync_pull.py +199 -0
  37. kctl_outline-0.6.1/src/kctl_outline/core/sync_ssot.py +40 -0
  38. kctl_outline-0.6.1/src/kctl_outline/core/sync_state.py +127 -0
  39. kctl_outline-0.6.1/tests/__init__.py +0 -0
  40. kctl_outline-0.6.1/tests/conftest.py +156 -0
  41. kctl_outline-0.6.1/tests/test_sync_config.py +113 -0
  42. kctl_outline-0.6.1/tests/test_sync_planner.py +132 -0
  43. kctl_outline-0.6.1/tests/test_sync_pull.py +194 -0
  44. kctl_outline-0.6.1/tests/test_sync_run_integration.py +92 -0
  45. kctl_outline-0.6.1/tests/test_sync_ssot.py +50 -0
  46. kctl_outline-0.6.1/tests/test_sync_state_migration.py +111 -0
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ *.egg
6
+ dist/
7
+ build/
8
+ .eggs/
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+
14
+ # IDE
15
+ .idea/
16
+ .vscode/
17
+ *.swp
18
+ *.swo
19
+
20
+ # Testing
21
+ .pytest_cache/
22
+ .coverage
23
+ htmlcov/
24
+ .mypy_cache/
25
+ .ruff_cache/
26
+
27
+ # OS
28
+ .DS_Store
29
+ Thumbs.db
30
+
31
+ # Environment
32
+ .env
33
+ .env.local
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: kctl-outline
3
+ Version: 0.6.1
4
+ Summary: Kodemeio Outline CLI — manage Outline wiki instances and sync markdown docs
5
+ Author-email: Kodemeio <dev@kodeme.io>
6
+ License-Expression: MIT
7
+ Keywords: cli,knowledge-base,kodemeio,outline,wiki
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: System Administrators
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: System :: Systems Administration
15
+ Requires-Python: >=3.12
16
+ Requires-Dist: httpx>=0.28.0
17
+ Requires-Dist: kctl-lib>=0.7.0
18
+ Requires-Dist: pydantic>=2.10.0
19
+ Requires-Dist: pyyaml>=6.0.2
20
+ Requires-Dist: rich>=13.9.0
21
+ Requires-Dist: typer>=0.15.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: mypy>=1.14.0; extra == 'dev'
24
+ Requires-Dist: pytest-httpx>=0.35.0; extra == 'dev'
25
+ Requires-Dist: pytest>=8.3.0; extra == 'dev'
26
+ Requires-Dist: ruff>=0.9.0; extra == 'dev'
27
+ Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # kctl-outline
31
+
32
+ Kodemeio Outline CLI — manages Outline wiki instances and syncs markdown documentation between git repositories and one or more Outline collections.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ cd packages/kctl-outline
38
+ uv sync --extra dev
39
+ uv run kctl-outline --help
40
+ ```
41
+
42
+ Or via the workspace from the repo root:
43
+
44
+ ```bash
45
+ uv sync
46
+ uv run --package kctl-outline kctl-outline --help
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ Like other `kctl-*` tools, configuration lives at `~/.config/kodemeio/config.yaml`. Each profile may declare an `outline` service block:
52
+
53
+ ```yaml
54
+ profiles:
55
+ kod:
56
+ outline:
57
+ url: https://outline.kodeme.io
58
+ token: env:OUTLINE_API_TOKEN_KOD
59
+ tpp:
60
+ outline:
61
+ url: https://outline.idtpp.com
62
+ token: env:OUTLINE_API_TOKEN_TPP
63
+ ```
64
+
65
+ Add a profile interactively:
66
+
67
+ ```bash
68
+ kctl-outline config init
69
+ kctl-outline config add tpp --url https://outline.idtpp.com --token <TOKEN>
70
+ kctl-outline config use kod
71
+ ```
72
+
73
+ ## Commands
74
+
75
+ | Group | Purpose |
76
+ |---|---|
77
+ | `documents` | List, create, update, delete, move documents |
78
+ | `collections` | Manage collections |
79
+ | `users`, `groups` | User and group management |
80
+ | `shares` | Public share links |
81
+ | `comments`, `events`, `revisions` | Read-only metadata |
82
+ | `templates`, `stars`, `tokens` | Misc admin |
83
+ | `health`, `dashboard`, `doctor` | Diagnostics (`doctor` checks URL + auth config) |
84
+ | `search` | Search across documents |
85
+ | `sync` | **Sync markdown docs between repos and Outline (see below)** |
86
+
87
+ ## Sync subcommand
88
+
89
+ `kctl-outline sync` is the primary integration point with `kodemeio-docs`. It supports multi-mapping configs (`.outline-sync.yaml` v2) with three direction modes:
90
+
91
+ - **`push`** — git is the source of truth. Markdown files are pushed to Outline.
92
+ - **`pull`** — Outline is the source of truth. Documents are pulled into the repo.
93
+ - **`mixed`** — per-file `.ssot` markers decide direction.
94
+
95
+ ```bash
96
+ # Dry-run a sync from a repo
97
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml
98
+
99
+ # Apply
100
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml --no-dry-run
101
+
102
+ # Filter to a specific direction
103
+ kctl-outline sync run . --config .outline-sync.kod.yaml --mode push --no-dry-run
104
+
105
+ # Inspect tracked state
106
+ kctl-outline sync status
107
+ kctl-outline sync diff /path/to/repo
108
+ ```
109
+
110
+ The full spec lives in `kodemeio-docs/superpowers/specs/2026-04-10-docs-outline-restructure-design.md`.
111
+
112
+ ## Profile-aware sync routing
113
+
114
+ When a sync config declares `profile: tpp`, `kctl-outline sync run` builds a fresh client using that profile's URL and token, regardless of the active CLI profile. This means the same machine can push to both `outline.kodeme.io` and `outline.idtpp.com` without switching profiles between commands.
115
+
116
+ ## Layout
117
+
118
+ ```
119
+ packages/kctl-outline/
120
+ ├── pyproject.toml
121
+ ├── README.md
122
+ ├── src/kctl_outline/
123
+ │ ├── cli.py # Typer entry point
124
+ │ ├── commands/ # one module per Outline subresource
125
+ │ │ ├── sync.py # the Plan A/D sync subcommand
126
+ │ │ ├── documents.py
127
+ │ │ ├── collections.py
128
+ │ │ └── …
129
+ │ └── core/
130
+ │ ├── client.py # httpx wrapper
131
+ │ ├── config.py # profile resolution
132
+ │ ├── sync_config.py # SyncConfig v2 schema + v1 auto-upgrade
133
+ │ ├── sync_planner.py # pure plan_push_mapping
134
+ │ ├── sync_pull.py # pull direction (Outline → disk)
135
+ │ ├── sync_state.py # MappingSyncEntry + v1→v2 migration
136
+ │ └── sync_ssot.py # .ssot marker walker
137
+ └── tests/ # 30+ tests (pytest)
138
+ ```
139
+
140
+ ## Tests
141
+
142
+ ```bash
143
+ cd packages/kctl-outline
144
+ uv run --extra dev pytest tests/ -v
145
+ ```
@@ -0,0 +1,116 @@
1
+ # kctl-outline
2
+
3
+ Kodemeio Outline CLI — manages Outline wiki instances and syncs markdown documentation between git repositories and one or more Outline collections.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ cd packages/kctl-outline
9
+ uv sync --extra dev
10
+ uv run kctl-outline --help
11
+ ```
12
+
13
+ Or via the workspace from the repo root:
14
+
15
+ ```bash
16
+ uv sync
17
+ uv run --package kctl-outline kctl-outline --help
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ Like other `kctl-*` tools, configuration lives at `~/.config/kodemeio/config.yaml`. Each profile may declare an `outline` service block:
23
+
24
+ ```yaml
25
+ profiles:
26
+ kod:
27
+ outline:
28
+ url: https://outline.kodeme.io
29
+ token: env:OUTLINE_API_TOKEN_KOD
30
+ tpp:
31
+ outline:
32
+ url: https://outline.idtpp.com
33
+ token: env:OUTLINE_API_TOKEN_TPP
34
+ ```
35
+
36
+ Add a profile interactively:
37
+
38
+ ```bash
39
+ kctl-outline config init
40
+ kctl-outline config add tpp --url https://outline.idtpp.com --token <TOKEN>
41
+ kctl-outline config use kod
42
+ ```
43
+
44
+ ## Commands
45
+
46
+ | Group | Purpose |
47
+ |---|---|
48
+ | `documents` | List, create, update, delete, move documents |
49
+ | `collections` | Manage collections |
50
+ | `users`, `groups` | User and group management |
51
+ | `shares` | Public share links |
52
+ | `comments`, `events`, `revisions` | Read-only metadata |
53
+ | `templates`, `stars`, `tokens` | Misc admin |
54
+ | `health`, `dashboard`, `doctor` | Diagnostics (`doctor` checks URL + auth config) |
55
+ | `search` | Search across documents |
56
+ | `sync` | **Sync markdown docs between repos and Outline (see below)** |
57
+
58
+ ## Sync subcommand
59
+
60
+ `kctl-outline sync` is the primary integration point with `kodemeio-docs`. It supports multi-mapping configs (`.outline-sync.yaml` v2) with three direction modes:
61
+
62
+ - **`push`** — git is the source of truth. Markdown files are pushed to Outline.
63
+ - **`pull`** — Outline is the source of truth. Documents are pulled into the repo.
64
+ - **`mixed`** — per-file `.ssot` markers decide direction.
65
+
66
+ ```bash
67
+ # Dry-run a sync from a repo
68
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml
69
+
70
+ # Apply
71
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml --no-dry-run
72
+
73
+ # Filter to a specific direction
74
+ kctl-outline sync run . --config .outline-sync.kod.yaml --mode push --no-dry-run
75
+
76
+ # Inspect tracked state
77
+ kctl-outline sync status
78
+ kctl-outline sync diff /path/to/repo
79
+ ```
80
+
81
+ The full spec lives in `kodemeio-docs/superpowers/specs/2026-04-10-docs-outline-restructure-design.md`.
82
+
83
+ ## Profile-aware sync routing
84
+
85
+ When a sync config declares `profile: tpp`, `kctl-outline sync run` builds a fresh client using that profile's URL and token, regardless of the active CLI profile. This means the same machine can push to both `outline.kodeme.io` and `outline.idtpp.com` without switching profiles between commands.
86
+
87
+ ## Layout
88
+
89
+ ```
90
+ packages/kctl-outline/
91
+ ├── pyproject.toml
92
+ ├── README.md
93
+ ├── src/kctl_outline/
94
+ │ ├── cli.py # Typer entry point
95
+ │ ├── commands/ # one module per Outline subresource
96
+ │ │ ├── sync.py # the Plan A/D sync subcommand
97
+ │ │ ├── documents.py
98
+ │ │ ├── collections.py
99
+ │ │ └── …
100
+ │ └── core/
101
+ │ ├── client.py # httpx wrapper
102
+ │ ├── config.py # profile resolution
103
+ │ ├── sync_config.py # SyncConfig v2 schema + v1 auto-upgrade
104
+ │ ├── sync_planner.py # pure plan_push_mapping
105
+ │ ├── sync_pull.py # pull direction (Outline → disk)
106
+ │ ├── sync_state.py # MappingSyncEntry + v1→v2 migration
107
+ │ └── sync_ssot.py # .ssot marker walker
108
+ └── tests/ # 30+ tests (pytest)
109
+ ```
110
+
111
+ ## Tests
112
+
113
+ ```bash
114
+ cd packages/kctl-outline
115
+ uv run --extra dev pytest tests/ -v
116
+ ```
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kctl-outline"
7
+ version = "0.6.1"
8
+ description = "Kodemeio Outline CLI — manage Outline wiki instances and sync markdown docs"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.12"
12
+ authors = [{ name = "Kodemeio", email = "dev@kodeme.io" }]
13
+ keywords = ["outline", "wiki", "knowledge-base", "cli", "kodemeio"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Environment :: Console",
17
+ "Intended Audience :: System Administrators",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: System :: Systems Administration",
22
+ ]
23
+ dependencies = [
24
+ "kctl-lib>=0.7.0",
25
+ "typer>=0.15.0",
26
+ "httpx>=0.28.0",
27
+ "rich>=13.9.0",
28
+ "pydantic>=2.10.0",
29
+ "pyyaml>=6.0.2",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=8.3.0",
35
+ "pytest-httpx>=0.35.0",
36
+ "ruff>=0.9.0",
37
+ "mypy>=1.14.0",
38
+ "types-PyYAML>=6.0.0",
39
+ ]
40
+
41
+ [project.scripts]
42
+ kctl-outline = "kctl_outline.cli:_run"
43
+
44
+ [tool.uv.sources]
45
+ kctl-lib = { workspace = true }
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["src/kctl_outline"]
49
+
50
+ [tool.ruff]
51
+ target-version = "py312"
52
+ line-length = 120
53
+
54
+ [tool.ruff.lint]
55
+ select = ["E", "F", "I", "W", "UP", "B", "SIM"]
56
+
57
+ [tool.mypy]
58
+ python_version = "3.12"
59
+ strict = true
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: outline-admin
3
+ description: >
4
+ Outline wiki/knowledge-base administration via kctl-outline CLI.
5
+ MUST use for ANY kctl-outline operation — documents, collections, users, groups,
6
+ shares, comments, events, health checks, AND markdown sync between repos and
7
+ one or more Outline instances.
8
+ Triggers on: "kctl-outline", "outline", "wiki", "knowledge base", "create document",
9
+ "collection", "share document", "outline.kodeme.io", "outline.idtpp.com",
10
+ "sync docs", "outline sync", "doc sync", ".outline-sync.yaml".
11
+ ---
12
+
13
+ # outline-admin — kctl-outline CLI Reference
14
+
15
+ ## Overview
16
+
17
+ **CLI:** `kctl-outline`
18
+ **Workspace:** `kodemeio-platform/packages/kctl-outline/`
19
+ **Install:** `cd packages/kctl-outline && uv sync --extra dev`
20
+ **Standalone install:** `uv tool install kctl-outline` (when published to PyPI)
21
+
22
+ ## Global Options
23
+
24
+ | Flag | Description |
25
+ |------|-------------|
26
+ | `--json` | JSON output |
27
+ | `--quiet`, `-q` | Suppress info messages |
28
+ | `--profile`, `-p` | Profile name (default from `~/.config/kodemeio/config.yaml`) |
29
+ | `--url` | Override API URL (e.g., `https://outline.idtpp.com`) |
30
+ | `--token` | Override API token |
31
+ | `--version`, `-V` | Show version |
32
+
33
+ ## Profiles
34
+
35
+ Configure once per Outline instance:
36
+
37
+ ```bash
38
+ kctl-outline config init # interactive
39
+ kctl-outline config add kod --url https://outline.kodeme.io --token <T>
40
+ kctl-outline config add tpp --url https://outline.idtpp.com --token <T>
41
+ kctl-outline config use kod # default
42
+ kctl-outline config current # show active
43
+ ```
44
+
45
+ ## Command Groups
46
+
47
+ | Group | Purpose |
48
+ |---|---|
49
+ | `config` | Profile management (init, add, use, show, profiles, current, test) |
50
+ | `documents` | Create / list / update / delete / move documents |
51
+ | `collections` | Manage collections |
52
+ | `users` | User management |
53
+ | `groups` | Group management |
54
+ | `shares` | Public share links |
55
+ | `comments`, `events`, `revisions` | Read-only metadata |
56
+ | `templates`, `stars`, `tokens` | Misc admin |
57
+ | `search` | Search across documents |
58
+ | `health` | Health checks and diagnostics |
59
+ | `dashboard` | System overview |
60
+ | **`sync`** | **Markdown sync between git repos and Outline (primary integration)** |
61
+
62
+ ## Sync subcommand — primary use case
63
+
64
+ `kctl-outline sync` is the integration point with `kodemeio-docs`. It supports multi-mapping `.outline-sync.yaml` v2 configs with three direction modes:
65
+
66
+ - **`push`** — git is the source of truth. Markdown files are pushed to Outline.
67
+ - **`pull`** — Outline is the source of truth. Documents are pulled into the repo. Reconciles deletions: docs removed in Outline are also removed from disk.
68
+ - **`mixed`** — per-file `.ssot` markers (containing `git` or `outline`) decide direction.
69
+
70
+ ### Commands
71
+
72
+ ```bash
73
+ # Dry-run (default) against the kod instance
74
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml
75
+
76
+ # Apply
77
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.kod.yaml --no-dry-run
78
+
79
+ # Filter to one direction (push only, skip pull mappings)
80
+ kctl-outline sync run . --config .outline-sync.kod.yaml --mode push --no-dry-run
81
+
82
+ # Same syntax against the TPP instance
83
+ kctl-outline sync run /path/to/kodemeio-docs --config .outline-sync.tpp.yaml --no-dry-run
84
+
85
+ # Inspect tracked state
86
+ kctl-outline sync status
87
+
88
+ # What would change on next push?
89
+ kctl-outline sync diff /path/to/kodemeio-docs
90
+
91
+ # Bootstrap a config stub
92
+ kctl-outline sync init /path/to/repo --collection 'My Docs'
93
+
94
+ # Wipe state (does NOT delete from Outline)
95
+ kctl-outline sync reset --force
96
+ ```
97
+
98
+ ### Profile-aware client routing
99
+
100
+ When a sync config declares `profile: tpp`, `sync run` builds a fresh client using **that profile's URL+token**, regardless of the active CLI profile. So the same machine can push to both `outline.kodeme.io` and `outline.idtpp.com` without `--profile` switching:
101
+
102
+ ```bash
103
+ kctl-outline sync run . --config .outline-sync.kod.yaml --no-dry-run # → outline.kodeme.io
104
+ kctl-outline sync run . --config .outline-sync.tpp.yaml --no-dry-run # → outline.idtpp.com
105
+ ```
106
+
107
+ ### .outline-sync.yaml v2 schema
108
+
109
+ ```yaml
110
+ instance: outline.kodeme.io # human-readable, optional
111
+ profile: kod # selects the kctl-outline profile
112
+
113
+ mappings:
114
+ - src: shared/ # path relative to the config file
115
+ collection: "Shared — Engineering"
116
+ mode: push # push | pull | mixed
117
+ subpath: "" # optional: nest under a doc title
118
+ include: # optional gitignore-style globs
119
+ - "01-*/**"
120
+ - "02-*/**"
121
+ exclude: # optional
122
+ - "**/draft/**"
123
+
124
+ - src: shared/06-business-processes
125
+ collection: "Shared — Business"
126
+ mode: pull # nightly cron pulls + reconciles deletions
127
+
128
+ - src: tenants/kod
129
+ collection: "Kod — Internal"
130
+ mode: mixed # per-file .ssot markers
131
+ ```
132
+
133
+ ### .ssot markers
134
+
135
+ Each leaf directory may contain a `.ssot` file with exactly one line: `git` or `outline`. In `mixed` mode the planner skips push actions for files under `outline`-marked directories (and vice versa). The kodemeio-docs pre-commit hook (`scripts/check_ssot.py`) enforces the same rule on commits.
136
+
137
+ ## Live URLs
138
+
139
+ | Profile | URL | Audience |
140
+ |---|---|---|
141
+ | `kod` | https://outline.kodeme.io | Kodemeio staff, MAC, Provetics, Terakidz |
142
+ | `tpp` | https://outline.idtpp.com | TPP Group customer-facing |
143
+
144
+ ## Tests
145
+
146
+ ```bash
147
+ cd packages/kctl-outline
148
+ uv run --extra dev pytest tests/ -v
149
+ # Expected: 32 tests passing
150
+ ```
151
+
152
+ ## See also
153
+
154
+ - Spec: `kodemeio-docs/superpowers/specs/2026-04-10-docs-outline-restructure-design.md`
155
+ - Plans: `kodemeio-docs/superpowers/plans/2026-04-10-{docs-restructure,kctl-outline-sync-enhancements,outline-tpp-instance}.md`
156
+ - Configs in use: `kodemeio-docs/.outline-sync.{kod,tpp}.yaml`
157
+ - Push CI: `kodemeio-docs/.github/workflows/outline-sync-push.yml`
158
+ - Nightly pull cron: `kodemeio-docs/scripts/cron/outline-sync-pull.sh`
@@ -0,0 +1,3 @@
1
+ """kctl-outline: Kodemeio Outline CLI."""
2
+
3
+ __version__ = "0.6.1"
@@ -0,0 +1,5 @@
1
+ """Allow running as: python -m kctl_outline."""
2
+
3
+ from kctl_outline.cli import app
4
+
5
+ app()
@@ -0,0 +1,120 @@
1
+ """Main CLI entry point for kctl-outline."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+ from kctl_lib.self_update import notify_if_outdated
9
+ from kctl_lib.tui import add_tui_command
10
+
11
+ from kctl_outline import __version__
12
+ from kctl_outline.commands.attachments import app as attachments_app
13
+ from kctl_outline.commands.collections import app as collections_app
14
+ from kctl_outline.commands.comments import app as comments_app
15
+ from kctl_outline.commands.config_cmd import app as config_app
16
+ from kctl_outline.commands.dashboard import app as dashboard_app
17
+ from kctl_outline.commands.doctor_cmd import app as doctor_app
18
+ from kctl_outline.commands.documents import app as documents_app
19
+ from kctl_outline.commands.events import app as events_app
20
+ from kctl_outline.commands.groups import app as groups_app
21
+ from kctl_outline.commands.health import app as health_app
22
+ from kctl_outline.commands.revisions import app as revisions_app
23
+ from kctl_outline.commands.search import search_command
24
+ from kctl_outline.commands.shares import app as shares_app
25
+ from kctl_outline.commands.stars import app as stars_app
26
+ from kctl_outline.commands.sync import app as sync_app
27
+ from kctl_outline.commands.templates import app as templates_app
28
+ from kctl_outline.commands.tokens import app as tokens_app
29
+ from kctl_outline.commands.users import app as users_app
30
+ from kctl_outline.core.callbacks import AppContext
31
+ from kctl_outline.core.exceptions import APIError, AuthenticationError, ConfigError, KctlError
32
+ from kctl_outline.core.exceptions import ConnectionError as KctlConnectionError
33
+
34
+
35
+ def version_callback(value: bool) -> None:
36
+ if value:
37
+ typer.echo(f"kctl-outline {__version__}")
38
+ raise typer.Exit()
39
+
40
+
41
+ app = typer.Typer(
42
+ name="kctl-outline",
43
+ help="Kodemeio Outline CLI - manage your Outline wiki instances.",
44
+ no_args_is_help=True,
45
+ rich_markup_mode="rich",
46
+ pretty_exceptions_enable=False,
47
+ )
48
+
49
+
50
+ @app.callback()
51
+ def main(
52
+ ctx: typer.Context,
53
+ json_output: Annotated[bool, typer.Option("--json", help="Output as JSON")] = False,
54
+ quiet: Annotated[bool, typer.Option("--quiet", "-q", help="Suppress info messages")] = False,
55
+ profile: Annotated[str | None, typer.Option("--profile", "-p", help="Config profile name")] = None,
56
+ url: Annotated[str | None, typer.Option("--url", help="API URL override")] = None,
57
+ token: Annotated[str | None, typer.Option("--token", help="API token override")] = None,
58
+ version: Annotated[
59
+ bool, typer.Option("--version", "-V", callback=version_callback, is_eager=True, help="Show version")
60
+ ] = False,
61
+ ) -> None:
62
+ """Kodemeio Outline CLI."""
63
+ ctx.ensure_object(dict)
64
+ ctx.obj = AppContext(
65
+ json_mode=json_output,
66
+ quiet=quiet,
67
+ profile=profile,
68
+ url_override=url,
69
+ token_override=token,
70
+ )
71
+ notify_if_outdated(ctx.obj.output, "kctl-outline", __version__)
72
+
73
+
74
+ # Register all command groups
75
+ app.add_typer(documents_app, name="documents")
76
+ app.add_typer(collections_app, name="collections")
77
+ app.add_typer(users_app, name="users")
78
+ app.add_typer(groups_app, name="groups")
79
+ app.add_typer(shares_app, name="shares")
80
+ app.add_typer(comments_app, name="comments")
81
+ app.add_typer(events_app, name="events")
82
+ app.add_typer(health_app, name="health")
83
+ app.add_typer(dashboard_app, name="dashboard")
84
+ app.add_typer(config_app, name="config")
85
+ app.add_typer(doctor_app, name="doctor")
86
+ app.add_typer(stars_app, name="stars")
87
+ app.add_typer(templates_app, name="templates")
88
+ app.add_typer(revisions_app, name="revisions")
89
+ app.add_typer(attachments_app, name="attachments")
90
+ app.add_typer(tokens_app, name="tokens")
91
+ app.add_typer(sync_app, name="sync")
92
+ add_tui_command(app, service_key="outline", version=__version__)
93
+
94
+ # Top-level search command
95
+ app.command("search")(search_command)
96
+
97
+
98
+ def _run() -> None:
99
+ """Entry point with error handling."""
100
+ try:
101
+ app()
102
+ except KctlConnectionError as e:
103
+ typer.echo(f"Connection error: {e}", err=True)
104
+ raise typer.Exit(1) from e
105
+ except AuthenticationError as e:
106
+ typer.echo(f"Auth error: {e}", err=True)
107
+ raise typer.Exit(1) from e
108
+ except APIError as e:
109
+ typer.echo(f"API error: {e}", err=True)
110
+ raise typer.Exit(1) from e
111
+ except ConfigError as e:
112
+ typer.echo(f"Config error: {e}", err=True)
113
+ raise typer.Exit(1) from e
114
+ except KctlError as e:
115
+ typer.echo(f"Error: {e}", err=True)
116
+ raise typer.Exit(1) from e
117
+
118
+
119
+ if __name__ == "__main__":
120
+ _run()