documentation-engine 0.3.0__tar.gz → 0.3.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 (123) hide show
  1. documentation_engine-0.3.1/.github/workflows/ci.yml +142 -0
  2. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/CHANGELOG.md +18 -1
  3. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/PKG-INFO +10 -2
  4. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/README.md +9 -1
  5. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/agent-contract.md +15 -0
  6. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/setup-guide.md +32 -4
  7. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/__init__.py +1 -1
  8. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/cli.py +21 -0
  9. documentation_engine-0.3.1/tests/test_cli_platform.py +122 -0
  10. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_release_workflows.py +21 -0
  11. documentation_engine-0.3.0/.github/workflows/ci.yml +0 -65
  12. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/ISSUE_TEMPLATE/adoption-finding.yml +0 -0
  13. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  14. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/ISSUE_TEMPLATE/core-bug.yml +0 -0
  15. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/ISSUE_TEMPLATE/docs-pattern-request.yml +0 -0
  16. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/ISSUE_TEMPLATE/runtime-report.yml +0 -0
  17. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  18. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/copilot-instructions.md +0 -0
  19. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.github/workflows/release.yml +0 -0
  20. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/.gitignore +0 -0
  21. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/AGENTS.md +0 -0
  22. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/CLAUDE.md +0 -0
  23. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/CONTRIBUTING.md +0 -0
  24. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/LICENSE +0 -0
  25. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/SECURITY.md +0 -0
  26. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/README.md +0 -0
  27. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/adopter-reporting.md +0 -0
  28. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/adoption.md +0 -0
  29. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/architecture.md +0 -0
  30. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/assets/context-reduction.svg +0 -0
  31. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/client-integration.md +0 -0
  32. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/context-delivery.md +0 -0
  33. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/context-efficiency.md +0 -0
  34. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/delivery-traceability.md +0 -0
  35. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/document-profiles.md +0 -0
  36. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/execution-admission.md +0 -0
  37. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/execution-handoff.md +0 -0
  38. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/federation.md +0 -0
  39. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/graph-health.md +0 -0
  40. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/idea-intake.md +0 -0
  41. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/knowledge-promotion.md +0 -0
  42. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/local-state-safety.md +0 -0
  43. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/mcp-adapter.md +0 -0
  44. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/metadata-inventory.md +0 -0
  45. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/program-plans.md +0 -0
  46. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/releasing.md +0 -0
  47. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/workspace-sources.md +0 -0
  48. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/workstream-branching.md +0 -0
  49. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/workstream-evidence.md +0 -0
  50. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/docs/workstream-lifecycle.md +0 -0
  51. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/execution-admission-request.json +0 -0
  52. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/execution-result.json +0 -0
  53. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/.docsystem.toml +0 -0
  54. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/README.md +0 -0
  55. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/plan/README.md +0 -0
  56. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/plan/design.md +0 -0
  57. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/plan/review.md +0 -0
  58. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/generic-adopter/plan/templates/document-template.md +0 -0
  59. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/idea-intake-request.json +0 -0
  60. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/workstream-branch-template.md +0 -0
  61. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/examples/workstream-record.json +0 -0
  62. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/pyproject.toml +0 -0
  63. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/scripts/installed_cli_smoke.sh +0 -0
  64. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/__main__.py +0 -0
  65. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/admission.py +0 -0
  66. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/catalog.py +0 -0
  67. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/change_plan.py +0 -0
  68. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/config.py +0 -0
  69. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/delivery.py +0 -0
  70. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/execution.py +0 -0
  71. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/federated_projection.py +0 -0
  72. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/federation.py +0 -0
  73. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/graph.py +0 -0
  74. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/health.py +0 -0
  75. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/intake.py +0 -0
  76. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/inventory.py +0 -0
  77. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/journal.py +0 -0
  78. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/lifecycle.py +0 -0
  79. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/maintenance.py +0 -0
  80. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/mcp_server.py +0 -0
  81. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/metadata.py +0 -0
  82. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/migration.py +0 -0
  83. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/profiles.py +0 -0
  84. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/program_plan.py +0 -0
  85. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/projection.py +0 -0
  86. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/promotion.py +0 -0
  87. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/readiness.py +0 -0
  88. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/sections.py +0 -0
  89. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/shared_finish.py +0 -0
  90. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/workspace.py +0 -0
  91. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/src/docsystem/workstream.py +0 -0
  92. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_admission.py +0 -0
  93. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_catalog.py +0 -0
  94. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_change_plan.py +0 -0
  95. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_change_plan_cli.py +0 -0
  96. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_cli.py +0 -0
  97. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_config.py +0 -0
  98. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_context_cli.py +0 -0
  99. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_delivery.py +0 -0
  100. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_execution_handoff.py +0 -0
  101. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_federated_projection.py +0 -0
  102. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_federated_write.py +0 -0
  103. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_federation.py +0 -0
  104. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_graph.py +0 -0
  105. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_health.py +0 -0
  106. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_intake.py +0 -0
  107. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_inventory.py +0 -0
  108. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_journal.py +0 -0
  109. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_lifecycle.py +0 -0
  110. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_maintenance.py +0 -0
  111. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_mcp_adapter.py +0 -0
  112. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_metadata.py +0 -0
  113. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_migration.py +0 -0
  114. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_profiles.py +0 -0
  115. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_program_plan.py +0 -0
  116. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_promotion.py +0 -0
  117. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_readiness.py +0 -0
  118. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_references_cli.py +0 -0
  119. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_sections.py +0 -0
  120. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_vertical.py +0 -0
  121. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_workspace.py +0 -0
  122. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/tests/test_workstream.py +0 -0
  123. {documentation_engine-0.3.0 → documentation_engine-0.3.1}/uv.lock +0 -0
@@ -0,0 +1,142 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ env:
12
+ TMPDIR: /tmp
13
+ TMP: /tmp
14
+ TEMP: /tmp
15
+
16
+ jobs:
17
+ check:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v7
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v7
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Run pytest
28
+ run: uv run pytest
29
+
30
+ - name: Run ruff
31
+ run: uv run ruff check .
32
+
33
+ - name: Verify lockfile is current
34
+ run: uv lock --check
35
+
36
+ - name: Installed CLI smoke test
37
+ run: ./scripts/installed_cli_smoke.sh
38
+
39
+ # The smoke test builds and installs a wheel only. The release workflow
40
+ # uploads a wheel *and* an sdist, and an index rejects a distribution
41
+ # whose metadata or long description does not render. Check both
42
+ # artifacts here rather than during an irreversible upload.
43
+ - name: Build and check both distributions
44
+ run: |
45
+ dist_dir="$(mktemp -d)/dist"
46
+ uv build --out-dir "$dist_dir"
47
+ version="$(uv run python -c 'import docsystem; print(docsystem.__version__)')"
48
+ test -f "$dist_dir/documentation_engine-${version}-py3-none-any.whl"
49
+ test -f "$dist_dir/documentation_engine-${version}.tar.gz"
50
+ uvx --from 'twine>=6,<7' twine check --strict "$dist_dir"/*
51
+
52
+ # Dogfooding: walk the documented adoption sequence end-to-end against
53
+ # the public example profile, on a scratch copy so the fixture stays
54
+ # byte-identical in the repository.
55
+ - name: Example profile adoption walkthrough
56
+ run: |
57
+ profile="$(mktemp -d)/profile"
58
+ cp -r examples/generic-adopter "$profile"
59
+ uv run python -m docsystem readiness "$profile" --json
60
+ uv run python -m docsystem migrate "$profile" --apply
61
+ uv run python -m docsystem index "$profile" --write
62
+ uv run python -m docsystem readiness "$profile" --json
63
+ uv run python -m docsystem context DOC-002 "$profile" --depth 1
64
+ uv run python -m docsystem context DOC-002 "$profile" --depth 1 --json
65
+ uv run python -m docsystem changes "$profile" --json
66
+
67
+ windows:
68
+ runs-on: windows-latest
69
+ env:
70
+ PYTHONUTF8: "0"
71
+ steps:
72
+ - uses: actions/checkout@v7
73
+
74
+ - name: Install uv
75
+ uses: astral-sh/setup-uv@v7
76
+ with:
77
+ python-version: "3.12"
78
+
79
+ - name: Run Windows CLI tests without Python UTF-8 mode
80
+ shell: pwsh
81
+ run: |
82
+ $env:TMPDIR = $env:RUNNER_TEMP
83
+ $env:TMP = $env:RUNNER_TEMP
84
+ $env:TEMP = $env:RUNNER_TEMP
85
+ uv run pytest tests/test_cli.py tests/test_cli_platform.py `
86
+ tests/test_context_cli.py tests/test_mcp_adapter.py tests/test_readiness.py
87
+
88
+ - name: Installed CLI UTF-8 PowerShell smoke
89
+ shell: pwsh
90
+ run: |
91
+ $env:TMPDIR = $env:RUNNER_TEMP
92
+ $env:TMP = $env:RUNNER_TEMP
93
+ $env:TEMP = $env:RUNNER_TEMP
94
+ Remove-Item Env:PYTHONIOENCODING -ErrorAction SilentlyContinue
95
+ $dist = Join-Path $env:RUNNER_TEMP "docsystem-dist"
96
+ $venv = Join-Path $env:RUNNER_TEMP "docsystem-venv"
97
+ $project = Join-Path $env:RUNNER_TEMP "docsystem-unicode-project"
98
+ $output = Join-Path $env:RUNNER_TEMP "context.json"
99
+ $errors = Join-Path $env:RUNNER_TEMP "diagnostics.txt"
100
+
101
+ uv build --wheel --out-dir $dist
102
+ $wheel = Get-ChildItem $dist -Filter "documentation_engine-*.whl" -File
103
+ if ($wheel.Count -ne 1) { throw "expected exactly one wheel" }
104
+ uv venv $venv --python 3.12
105
+ $python = Join-Path $venv "Scripts/python.exe"
106
+ $docsystem = Join-Path $venv "Scripts/docsystem.exe"
107
+ uv pip install --python $python $wheel.FullName
108
+
109
+ $expectedVersion = (& $python -c "import docsystem; print(docsystem.__version__)").Trim()
110
+ $reportedVersion = (& $docsystem --version).Trim()
111
+ if ($reportedVersion -ne "docsystem $expectedVersion") {
112
+ throw "unexpected version output: $reportedVersion"
113
+ }
114
+
115
+ & $docsystem init $project
116
+ $architecture = Join-Path $project "plan/architecture"
117
+ New-Item -ItemType Directory -Path $architecture -Force | Out-Null
118
+ @"
119
+ ---
120
+ id: DOC-001
121
+ revision: 1
122
+ ---
123
+ # Привет
124
+ ## Резюме
125
+ Исходный текст остаётся доступен полностью.
126
+ "@ | Set-Content -Encoding utf8 (Join-Path $architecture "README.md")
127
+
128
+ & $docsystem context DOC-001 $project --json |
129
+ Set-Content -Encoding utf8 $output
130
+ if ($LASTEXITCODE -ne 0) { throw "context failed with $LASTEXITCODE" }
131
+ $payload = Get-Content -Raw -Encoding utf8 $output | ConvertFrom-Json
132
+ if ($payload.documents[0].navigation -notmatch "Привет") {
133
+ throw "context JSON lost Cyrillic source text"
134
+ }
135
+
136
+ & $docsystem read DOC-001 $project --anchor "отсутствует" 2> $errors
137
+ if ($LASTEXITCODE -ne 1) { throw "unknown anchor returned $LASTEXITCODE" }
138
+ $global:LASTEXITCODE = 0
139
+ $diagnostic = Get-Content -Raw -Encoding utf8 $errors
140
+ if ($diagnostic -notmatch "отсутствует") {
141
+ throw "stderr diagnostic was not UTF-8"
142
+ }
@@ -4,6 +4,22 @@ All notable changes to Documentation Engine are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.3.1] - 2026-07-19
8
+
9
+ ### Fixed
10
+
11
+ - CLI stdout and stderr now use UTF-8 independently of the host locale, so
12
+ redirected or piped Cyrillic and other Unicode Markdown works on Windows
13
+ without requiring `PYTHONUTF8=1`.
14
+ - Windows CI now runs focused CLI/context/MCP regressions with Python UTF-8
15
+ mode disabled and verifies an installed wheel through a PowerShell JSON pipe
16
+ and a Unicode stderr diagnostic.
17
+
18
+ ### Added
19
+
20
+ - `docsystem --version` reports the installed Documentation Engine version
21
+ without requiring a project or subcommand.
22
+
7
23
  ## [0.3.0] - 2026-07-15
8
24
 
9
25
  ### Highlights
@@ -181,7 +197,8 @@ documentation-engine` starts working only after the first successful release.
181
197
  - Measured context-reduction methodology and a reproducible consumer-install
182
198
  smoke test.
183
199
 
184
- [Unreleased]: https://github.com/Jafa7/DocumentationEngine/compare/v0.3.0...HEAD
200
+ [Unreleased]: https://github.com/Jafa7/DocumentationEngine/compare/v0.3.1...HEAD
201
+ [0.3.1]: https://github.com/Jafa7/DocumentationEngine/compare/v0.3.0...v0.3.1
185
202
  [0.3.0]: https://github.com/Jafa7/DocumentationEngine/compare/v0.2.0...v0.3.0
186
203
  [0.2.0]: https://github.com/Jafa7/DocumentationEngine/compare/v0.1.2...v0.2.0
187
204
  [0.1.2]: https://github.com/Jafa7/DocumentationEngine/compare/v0.1.1...v0.1.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: documentation-engine
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Provider-neutral structured Markdown documentation engine.
5
5
  Project-URL: Repository, https://github.com/Jafa7/DocumentationEngine
6
6
  Project-URL: Documentation, https://github.com/Jafa7/DocumentationEngine/tree/main/docs
@@ -130,12 +130,14 @@ unrelated globally installed `docsystem` executable.
130
130
  For a published-package installation:
131
131
 
132
132
  ```bash
133
+ docsystem --version
133
134
  docsystem --help
134
135
  ```
135
136
 
136
137
  For a contributor checkout:
137
138
 
138
139
  ```bash
140
+ uv run python -m docsystem --version
139
141
  uv run python -m docsystem --help
140
142
  ```
141
143
 
@@ -159,7 +161,8 @@ disposable projection. It does not require MCP.
159
161
  [docs/setup-guide.md](docs/setup-guide.md) step by step. It contains the
160
162
  connection/adoption flow, required user questions, backup-policy setup and
161
163
  checks.
162
- Do not improvise a local backup path or commit private planning paths.
164
+ Do not improvise a private documentation root or local backup path, and do not
165
+ commit private planning paths.
163
166
 
164
167
  **If you are a human using an AI agent**, paste this in the project you want to
165
168
  connect:
@@ -168,6 +171,11 @@ connect:
168
171
  Connect Documentation Engine to this project.
169
172
  Repository: https://github.com/Jafa7/DocumentationEngine
170
173
  Read docs/setup-guide.md in that repository and follow it exactly.
174
+ Ask me for the exact private-documentation location before creating or moving
175
+ documents. Recommend a dedicated external project directory, but do not invent
176
+ or create a shared workspace path. If private documents already exist inside
177
+ the project, copy and verify them first and leave the original untouched until
178
+ I explicitly authorize its removal.
171
179
  Ask me where local disaster-recovery backups should be stored before touching
172
180
  ignored/private documentation or local configuration.
173
181
  ```
@@ -113,12 +113,14 @@ unrelated globally installed `docsystem` executable.
113
113
  For a published-package installation:
114
114
 
115
115
  ```bash
116
+ docsystem --version
116
117
  docsystem --help
117
118
  ```
118
119
 
119
120
  For a contributor checkout:
120
121
 
121
122
  ```bash
123
+ uv run python -m docsystem --version
122
124
  uv run python -m docsystem --help
123
125
  ```
124
126
 
@@ -142,7 +144,8 @@ disposable projection. It does not require MCP.
142
144
  [docs/setup-guide.md](docs/setup-guide.md) step by step. It contains the
143
145
  connection/adoption flow, required user questions, backup-policy setup and
144
146
  checks.
145
- Do not improvise a local backup path or commit private planning paths.
147
+ Do not improvise a private documentation root or local backup path, and do not
148
+ commit private planning paths.
146
149
 
147
150
  **If you are a human using an AI agent**, paste this in the project you want to
148
151
  connect:
@@ -151,6 +154,11 @@ connect:
151
154
  Connect Documentation Engine to this project.
152
155
  Repository: https://github.com/Jafa7/DocumentationEngine
153
156
  Read docs/setup-guide.md in that repository and follow it exactly.
157
+ Ask me for the exact private-documentation location before creating or moving
158
+ documents. Recommend a dedicated external project directory, but do not invent
159
+ or create a shared workspace path. If private documents already exist inside
160
+ the project, copy and verify them first and leave the original untouched until
161
+ I explicitly authorize its removal.
154
162
  Ask me where local disaster-recovery backups should be stored before touching
155
163
  ignored/private documentation or local configuration.
156
164
  ```
@@ -84,6 +84,15 @@ Those files are still source-of-truth operational state. An agent must not
84
84
  use a clean git status as evidence that broad filesystem operations are safe:
85
85
  ignored files can be destroyed while git remains clean.
86
86
 
87
+ Before creating or moving private documentation, the agent must ask the user
88
+ in English for the exact storage path and whether an existing in-repository
89
+ documentation tree must be copied and verified. Recommend a dedicated external
90
+ project directory, but do not infer or create a shared workspace path. Never
91
+ remove the original tree without a separate explicit authorization. Use the
92
+ canonical questions and neutral placeholder from
93
+ [the setup guide](setup-guide.md#step-0-gather-facts) rather than inventing a
94
+ machine-specific example.
95
+
87
96
  Before recursive copy, move, delete or sync commands; generated migrations;
88
97
  bulk rewrites; cross-OS shell snippets; or any task that touches ignored
89
98
  local-only documentation, the agent must run the project's local backup
@@ -191,6 +200,12 @@ wiring and must never be committed or printed in a report.
191
200
 
192
201
  ## Prefer `--json` over parsing text
193
202
 
203
+ The CLI writes stdout and stderr as strict UTF-8 regardless of the host locale,
204
+ including redirected Windows streams. Callers should decode both streams as
205
+ UTF-8 and must not require `PYTHONUTF8` or locale-specific code pages. JSON
206
+ keeps original Unicode characters rather than ASCII-escaping authored text;
207
+ plain-text reads return the same UTF-8 Markdown content.
208
+
194
209
  `readiness`, `migration-report`, `catalog --explain`, `changes` and
195
210
  `context` accept `--json` and print one deterministic JSON value instead of
196
211
  tab-separated or prose text. An agent should use `--json` wherever it needs
@@ -9,7 +9,7 @@ not continue past a failing check — fix it or report the blocker to the user.
9
9
  Documentation Engine gives a project a stable Markdown documentation contract:
10
10
 
11
11
  - project-local `.docsystem.toml` configuration;
12
- - a configured documentation root such as `plan/`;
12
+ - a configured documentation root inside or outside the repository;
13
13
  - stable document IDs and relation metadata;
14
14
  - deterministic validation, context packets and projection cache;
15
15
  - local-only backup policy for private/ignored documentation state.
@@ -23,15 +23,43 @@ adopting project owns its local policy.
23
23
  Establish these before touching files. Ask the user rather than guessing.
24
24
 
25
25
  1. **Project root** — absolute path of the project to adopt.
26
- 2. **Documentation root** — where the project's Markdown knowledge should live
27
- (for example `plan/`, `docs/plan/` or an existing private docs folder).
26
+ 2. **Documentation root** — whether private Markdown should remain inside the
27
+ repository or use a dedicated external project directory, and its exact
28
+ absolute path. Recommend the external option for private documentation, but
29
+ do not invent or create a shared workspace path.
28
30
  3. **Language** — language of private/local documentation.
29
31
  4. **Public vs. private split** — which docs are allowed to be committed and
30
32
  which must remain local/ignored.
31
33
  5. **Backup destination** — where local disaster-recovery snapshots should be
32
34
  stored for ignored documentation/configuration/runtime files.
33
35
 
34
- Ask the backup question explicitly:
36
+ Before creating or moving private documentation, ask these placement questions
37
+ explicitly and in English:
38
+
39
+ ```text
40
+ Where should this project's private documentation be stored?
41
+
42
+ The recommended option is a dedicated directory outside the project repository,
43
+ for example:
44
+
45
+ <external-documentation-root>/projects/<project-slug>/
46
+
47
+ Please provide the exact path. I will not create, move, replace, or delete any
48
+ documentation until the location and migration procedure are explicitly
49
+ confirmed.
50
+
51
+ Does private documentation already exist inside the project, for example in
52
+ plan/? If so, I will copy and verify it first. The original directory will
53
+ remain untouched until you explicitly authorize its removal.
54
+ ```
55
+
56
+ The path above is a neutral placeholder, not a directory to create literally.
57
+ The user may select an in-repository, local, mounted or network location. Do
58
+ not treat a parent directory as readable authority: an external project root
59
+ authorizes only that exact scope unless the user separately authorizes another
60
+ path.
61
+
62
+ Ask the backup question separately:
35
63
 
36
64
  ```text
37
65
  Where should this project store local disaster-recovery backups for ignored
@@ -9,7 +9,7 @@ from docsystem.catalog import (
9
9
  from docsystem.metadata import DocumentMetadata, MetadataReference
10
10
  from docsystem.sections import MarkdownSection
11
11
 
12
- __version__ = "0.3.0"
12
+ __version__ = "0.3.1"
13
13
 
14
14
  __all__ = [
15
15
  "CatalogMembership",
@@ -205,6 +205,21 @@ from docsystem.workstream import (
205
205
  load_record,
206
206
  )
207
207
 
208
+
209
+ def _configure_utf8_stream(stream: object) -> None:
210
+ """Make one standard text stream deterministic across host locales."""
211
+
212
+ reconfigure = getattr(stream, "reconfigure", None)
213
+ if callable(reconfigure):
214
+ reconfigure(encoding="utf-8", errors="strict")
215
+
216
+
217
+ def _configure_standard_streams() -> None:
218
+ """Use UTF-8 for CLI output, including redirected Windows streams."""
219
+
220
+ _configure_utf8_stream(sys.stdout)
221
+ _configure_utf8_stream(sys.stderr)
222
+
208
223
  # Version of every `--json` root object. Bump only on a breaking change to
209
224
  # an existing field; adding new fields is compatible and does not bump it.
210
225
  JSON_SCHEMA_VERSION = 1
@@ -8086,6 +8101,11 @@ def _add_source_options(
8086
8101
 
8087
8102
  def build_parser() -> argparse.ArgumentParser:
8088
8103
  parser = argparse.ArgumentParser(description=__doc__)
8104
+ parser.add_argument(
8105
+ "--version",
8106
+ action="version",
8107
+ version=f"docsystem {__version__}",
8108
+ )
8089
8109
  subparsers = parser.add_subparsers(dest="command", required=True)
8090
8110
  for command, help_text in (
8091
8111
  ("init", "Create configuration and the documentation root."),
@@ -8908,6 +8928,7 @@ def build_parser() -> argparse.ArgumentParser:
8908
8928
 
8909
8929
 
8910
8930
  def main() -> int:
8931
+ _configure_standard_streams()
8911
8932
  args = build_parser().parse_args()
8912
8933
  if args.command == "workspace":
8913
8934
  if args.workspace_command == "list":
@@ -0,0 +1,122 @@
1
+ import io
2
+ import json
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import pytest
9
+
10
+ from docsystem import __version__
11
+ from docsystem.cli import _configure_utf8_stream, build_parser
12
+ from docsystem.config import CONFIG_FILENAME, DEFAULT_CONFIG
13
+
14
+
15
+ def _legacy_locale_environment() -> dict[str, str]:
16
+ environment = os.environ.copy()
17
+ environment["PYTHONUTF8"] = "0"
18
+ environment.pop("PYTHONIOENCODING", None)
19
+ return environment
20
+
21
+
22
+ def _write_unicode_project(project: Path) -> None:
23
+ (project / CONFIG_FILENAME).write_text(DEFAULT_CONFIG, encoding="utf-8")
24
+ architecture = project / "plan" / "architecture"
25
+ architecture.mkdir(parents=True)
26
+ (architecture / "README.md").write_text(
27
+ """\
28
+ ---
29
+ id: DOC-001
30
+ revision: 1
31
+ ---
32
+ # Привет
33
+ ## Резюме
34
+ Исходный текст остаётся доступен полностью.
35
+ """,
36
+ encoding="utf-8",
37
+ )
38
+
39
+
40
+ def test_utf8_stream_configuration_overrides_a_legacy_encoding() -> None:
41
+ buffer = io.BytesIO()
42
+ stream = io.TextIOWrapper(buffer, encoding="cp1252", errors="strict")
43
+
44
+ _configure_utf8_stream(stream)
45
+ stream.write("Привет")
46
+ stream.flush()
47
+
48
+ assert stream.encoding.lower() == "utf-8"
49
+ assert buffer.getvalue().decode("utf-8") == "Привет"
50
+
51
+
52
+ def test_global_version_option_uses_the_distribution_version(capsys) -> None:
53
+ with pytest.raises(SystemExit) as raised:
54
+ build_parser().parse_args(["--version"])
55
+
56
+ assert raised.value.code == 0
57
+ assert capsys.readouterr().out == f"docsystem {__version__}\n"
58
+
59
+
60
+ def test_module_cli_emits_utf8_json_without_python_utf8_mode(tmp_path: Path) -> None:
61
+ _write_unicode_project(tmp_path)
62
+
63
+ result = subprocess.run(
64
+ [
65
+ sys.executable,
66
+ "-m",
67
+ "docsystem",
68
+ "context",
69
+ "DOC-001",
70
+ str(tmp_path),
71
+ "--json",
72
+ ],
73
+ capture_output=True,
74
+ env=_legacy_locale_environment(),
75
+ check=False,
76
+ )
77
+
78
+ assert result.returncode == 0, result.stderr.decode("utf-8")
79
+ payload = json.loads(result.stdout.decode("utf-8"))
80
+ assert "# Привет" in payload["documents"][0]["navigation"]
81
+ assert "резюме" in payload["documents"][0]["omitted_h2"]
82
+
83
+
84
+ def test_module_cli_emits_utf8_diagnostics_without_python_utf8_mode(
85
+ tmp_path: Path,
86
+ ) -> None:
87
+ _write_unicode_project(tmp_path)
88
+
89
+ result = subprocess.run(
90
+ [
91
+ sys.executable,
92
+ "-m",
93
+ "docsystem",
94
+ "read",
95
+ "DOC-001",
96
+ str(tmp_path),
97
+ "--anchor",
98
+ "отсутствует",
99
+ ],
100
+ capture_output=True,
101
+ env=_legacy_locale_environment(),
102
+ check=False,
103
+ )
104
+
105
+ assert result.returncode == 1
106
+ assert result.stdout == b""
107
+ assert "отсутствует" in result.stderr.decode("utf-8")
108
+
109
+
110
+ def test_module_cli_version_is_available_without_a_subcommand() -> None:
111
+ result = subprocess.run(
112
+ [sys.executable, "-m", "docsystem", "--version"],
113
+ capture_output=True,
114
+ env=_legacy_locale_environment(),
115
+ check=False,
116
+ )
117
+
118
+ assert result.returncode == 0
119
+ assert result.stdout.decode("utf-8").splitlines() == [
120
+ f"docsystem {__version__}"
121
+ ]
122
+ assert result.stderr == b""
@@ -127,6 +127,27 @@ def test_ci_checks_the_sdist_that_the_smoke_test_never_builds(ci: dict) -> None:
127
127
  assert "twine check --strict" in body
128
128
 
129
129
 
130
+ def test_ci_runs_the_cli_utf8_contract_on_windows(ci: dict) -> None:
131
+ windows = ci["jobs"]["windows"]
132
+ assert windows["runs-on"] == "windows-latest"
133
+ assert windows["env"]["PYTHONUTF8"] == "0"
134
+ body = steps_text(windows)
135
+ for contract in (
136
+ "$env:TMPDIR = $env:RUNNER_TEMP",
137
+ "uv run pytest tests/test_cli.py tests/test_cli_platform.py",
138
+ "tests/test_context_cli.py tests/test_mcp_adapter.py tests/test_readiness.py",
139
+ "Remove-Item Env:PYTHONIOENCODING",
140
+ "uv build --wheel",
141
+ "docsystem.exe",
142
+ "--version",
143
+ "context DOC-001",
144
+ "ConvertFrom-Json",
145
+ 'read DOC-001 $project --anchor "отсутствует"',
146
+ "$global:LASTEXITCODE = 0",
147
+ ):
148
+ assert contract in body, f"Windows CI lost the {contract!r} contract"
149
+
150
+
130
151
  # --- Release: trigger and permissions -------------------------------------
131
152
 
132
153
 
@@ -1,65 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
-
8
- permissions:
9
- contents: read
10
-
11
- env:
12
- TMPDIR: /tmp
13
- TMP: /tmp
14
- TEMP: /tmp
15
-
16
- jobs:
17
- check:
18
- runs-on: ubuntu-latest
19
- steps:
20
- - uses: actions/checkout@v7
21
-
22
- - name: Install uv
23
- uses: astral-sh/setup-uv@v7
24
- with:
25
- python-version: "3.12"
26
-
27
- - name: Run pytest
28
- run: uv run pytest
29
-
30
- - name: Run ruff
31
- run: uv run ruff check .
32
-
33
- - name: Verify lockfile is current
34
- run: uv lock --check
35
-
36
- - name: Installed CLI smoke test
37
- run: ./scripts/installed_cli_smoke.sh
38
-
39
- # The smoke test builds and installs a wheel only. The release workflow
40
- # uploads a wheel *and* an sdist, and an index rejects a distribution
41
- # whose metadata or long description does not render. Check both
42
- # artifacts here rather than during an irreversible upload.
43
- - name: Build and check both distributions
44
- run: |
45
- dist_dir="$(mktemp -d)/dist"
46
- uv build --out-dir "$dist_dir"
47
- version="$(uv run python -c 'import docsystem; print(docsystem.__version__)')"
48
- test -f "$dist_dir/documentation_engine-${version}-py3-none-any.whl"
49
- test -f "$dist_dir/documentation_engine-${version}.tar.gz"
50
- uvx --from 'twine>=6,<7' twine check --strict "$dist_dir"/*
51
-
52
- # Dogfooding: walk the documented adoption sequence end-to-end against
53
- # the public example profile, on a scratch copy so the fixture stays
54
- # byte-identical in the repository.
55
- - name: Example profile adoption walkthrough
56
- run: |
57
- profile="$(mktemp -d)/profile"
58
- cp -r examples/generic-adopter "$profile"
59
- uv run python -m docsystem readiness "$profile" --json
60
- uv run python -m docsystem migrate "$profile" --apply
61
- uv run python -m docsystem index "$profile" --write
62
- uv run python -m docsystem readiness "$profile" --json
63
- uv run python -m docsystem context DOC-002 "$profile" --depth 1
64
- uv run python -m docsystem context DOC-002 "$profile" --depth 1 --json
65
- uv run python -m docsystem changes "$profile" --json