open-code-review-toolkit 0.9.1__tar.gz → 0.10.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.
Files changed (128) hide show
  1. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/.gitignore +1 -0
  2. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/PKG-INFO +26 -3
  3. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/README.md +25 -2
  4. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/_version.py +2 -2
  5. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/cli.py +19 -2
  6. open_code_review_toolkit-0.10.0/src/ocr_toolkit/common/filesystem.py +68 -0
  7. open_code_review_toolkit-0.10.0/src/ocr_toolkit/posting/comments.py +21 -0
  8. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/formatting.py +46 -396
  9. open_code_review_toolkit-0.10.0/src/ocr_toolkit/posting/result.py +25 -0
  10. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/preflight.py +10 -3
  11. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/provider_config.py +33 -0
  12. open_code_review_toolkit-0.10.0/src/ocr_toolkit/providers/local.py +164 -0
  13. open_code_review_toolkit-0.10.0/src/ocr_toolkit/providers/local_config.py +14 -0
  14. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/__init__.py +1 -0
  15. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/dlp.py +197 -0
  16. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/metadata.py +90 -0
  17. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/model.py +127 -0
  18. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/outcome.py +86 -0
  19. {open_code_review_toolkit-0.9.1/src/ocr_toolkit/posting → open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting}/result.py +2 -2
  20. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/sections.py +82 -0
  21. open_code_review_toolkit-0.9.1/src/ocr_toolkit/posting/comments.py → open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/text.py +3 -3
  22. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/usage.py +224 -0
  23. open_code_review_toolkit-0.10.0/src/ocr_toolkit/review_debug.py +363 -0
  24. open_code_review_toolkit-0.10.0/src/ocr_toolkit/review_progress.py +126 -0
  25. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_receipt.py +4 -133
  26. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_runner.py +481 -36
  27. open_code_review_toolkit-0.9.1/src/ocr_toolkit/common/filesystem.py +0 -19
  28. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/LICENSE +0 -0
  29. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/pyproject.toml +0 -0
  30. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/__init__.py +0 -0
  31. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/__init__.py +0 -0
  32. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/git.py +0 -0
  33. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/language.py +0 -0
  34. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/markdown.py +0 -0
  35. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/redaction.py +0 -0
  36. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/config_writer.py +0 -0
  37. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/configure.py +0 -0
  38. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/__init__.py +0 -0
  39. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/adapters.py +0 -0
  40. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/broker.py +0 -0
  41. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/ci_outcomes.py +0 -0
  42. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/contracts.py +0 -0
  43. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/dlp.py +0 -0
  44. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/mcp.py +0 -0
  45. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/policy.py +0 -0
  46. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/recognizers.py +0 -0
  47. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/store.py +0 -0
  48. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/__init__.py +0 -0
  49. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/__main__.py +0 -0
  50. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/actions.py +0 -0
  51. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/artifacts.py +0 -0
  52. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/categorize.py +0 -0
  53. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collect.py +0 -0
  54. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/__init__.py +0 -0
  55. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/graphs.py +0 -0
  56. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/orchestration.py +0 -0
  57. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/projections.py +0 -0
  58. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/registry.py +0 -0
  59. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/sources.py +0 -0
  60. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/coverage.py +0 -0
  61. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/__init__.py +0 -0
  62. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/__init__.py +0 -0
  63. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/requirements.py +0 -0
  64. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/topology.py +0 -0
  65. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/contracts.py +0 -0
  66. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/go.py +0 -0
  67. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/javascript.py +0 -0
  68. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/php.py +0 -0
  69. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/python.py +0 -0
  70. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/__init__.py +0 -0
  71. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/contracts.py +0 -0
  72. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/detection.py +0 -0
  73. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/__init__.py +0 -0
  74. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/frontend.py +0 -0
  75. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/go.py +0 -0
  76. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/php.py +0 -0
  77. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/python.py +0 -0
  78. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/registry.py +0 -0
  79. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/schema.py +0 -0
  80. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/templates.py +0 -0
  81. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/infrastructure.py +0 -0
  82. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/invocation.py +0 -0
  83. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/mcp.py +0 -0
  84. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/model.py +0 -0
  85. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/__init__.py +0 -0
  86. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/contracts.py +0 -0
  87. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/decisions.py +0 -0
  88. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/guidance.py +0 -0
  89. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/registry.py +0 -0
  90. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/schema.py +0 -0
  91. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/scopes.py +0 -0
  92. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/project.py +0 -0
  93. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/repository.py +0 -0
  94. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/review_context.py +0 -0
  95. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/__init__.py +0 -0
  96. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/atomic.py +0 -0
  97. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/contracts.py +0 -0
  98. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/core.py +0 -0
  99. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/readback.py +0 -0
  100. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/values.py +0 -0
  101. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/mcp_config.py +0 -0
  102. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/ocr_result.py +0 -0
  103. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/__init__.py +0 -0
  104. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/__main__.py +0 -0
  105. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/approval.py +0 -0
  106. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/gitlab.py +0 -0
  107. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/gitlab_approval.py +0 -0
  108. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/markers.py +0 -0
  109. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/payloads.py +0 -0
  110. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/reconciliation.py +0 -0
  111. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/settings.py +0 -0
  112. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/snapshot.py +0 -0
  113. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/suggestions.py +0 -0
  114. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/transaction.py +0 -0
  115. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/workflow.py +0 -0
  116. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/pre_execution.py +0 -0
  117. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/provider_failure.py +0 -0
  118. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/__init__.py +0 -0
  119. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab.py +0 -0
  120. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_ci.py +0 -0
  121. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_context.py +0 -0
  122. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_discussions.py +0 -0
  123. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_identity.py +0 -0
  124. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_remediation.py +0 -0
  125. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/py.typed +0 -0
  126. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/result_contract.py +0 -0
  127. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/result_usage.py +0 -0
  128. {open_code_review_toolkit-0.9.1 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_identity.py +0 -0
@@ -12,6 +12,7 @@ build/
12
12
  dist/
13
13
  .review-context/
14
14
  .quality-logs/
15
+ .tgrep-index/
15
16
  .idea/
16
17
  *.log
17
18
  .codex
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-code-review-toolkit
3
- Version: 0.9.1
3
+ Version: 0.10.0
4
4
  Summary: Unofficial GitLab CI integration layer for Open Code Review
5
5
  Project-URL: Homepage, https://github.com/xeonvs/open-code-review-toolkit
6
6
  Project-URL: Repository, https://github.com/xeonvs/open-code-review-toolkit
@@ -234,7 +234,7 @@ Description-Content-Type: text/markdown
234
234
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/xeonvs/open-code-review-toolkit/badge)](https://securityscorecards.dev/viewer/?uri=github.com/xeonvs/open-code-review-toolkit)
235
235
  [![CodeQL](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml)
236
236
 
237
- Open Code Review Toolkit is an unofficial GitLab CI integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review). It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
237
+ Open Code Review Toolkit is an unofficial review control and integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review), with GitLab CI and standalone local providers. It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, local Markdown reports, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
238
238
 
239
239
  > [!NOTE]
240
240
  > The project is under active development; the public API, CLI, environment contract, and generated schemas may evolve before 1.0.
@@ -282,7 +282,30 @@ The toolkit defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low
282
282
 
283
283
  Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
284
284
 
285
- ## How reviews evolve
285
+ ## Standalone local quick start
286
+
287
+ With the qualified OCR binary and LLM environment configured, review an immutable
288
+ commit without forge credentials:
289
+
290
+ ```console
291
+ ocr-ci preflight --local
292
+ ocr-ci review --local --result review.json --stderr review.stderr --report review.md -- --commit HEAD
293
+ ```
294
+
295
+ Local execution uses the same OCR, mandatory evidence MCP, validation and DLP
296
+ pipeline as CI. It publishes every admitted finding to a fresh private Markdown
297
+ file and the console, without GitLab acquisition, suppression, approval or a
298
+ fabricated publication receipt. See [local review](docs/local.md) for ranges,
299
+ failure behavior and optional private `--debug-dir` bundles.
300
+
301
+ Optional [reasoning and progress controls](docs/configuration.md#provider-endpoint-and-completion-cap-contract)
302
+ do not change review rounds or budgets. Reasoning is unset by default; explicit
303
+ `none` is a wire value whose support depends on the provider/model. Progress is
304
+ off by default and emits only bounded toolkit phases to an interactive terminal
305
+ or an explicitly nonblocking embedding stream; a conventional CI stderr pipe is
306
+ intentionally not used because it can block a review.
307
+
308
+ ## How GitLab reviews evolve
286
309
 
287
310
  On a successful rerun, the toolkit replaces untouched OCR-only notes instead of accumulating stale reviews. A human reply transfers that discussion to the team: the conversation is preserved and a matching finding is suppressed. Reply with `/ocr suppress` or `@<live-bot-username> suppress` to keep a discussion open without future repeats; use the corresponding `resolve` command to resolve it after the next successful posting transaction. For example, a bot named `mr.bot` accepts the exact reply `@mr.bot resolve`.
288
311
 
@@ -7,7 +7,7 @@
7
7
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/xeonvs/open-code-review-toolkit/badge)](https://securityscorecards.dev/viewer/?uri=github.com/xeonvs/open-code-review-toolkit)
8
8
  [![CodeQL](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml)
9
9
 
10
- Open Code Review Toolkit is an unofficial GitLab CI integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review). It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
10
+ Open Code Review Toolkit is an unofficial review control and integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review), with GitLab CI and standalone local providers. It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, local Markdown reports, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
11
11
 
12
12
  > [!NOTE]
13
13
  > The project is under active development; the public API, CLI, environment contract, and generated schemas may evolve before 1.0.
@@ -55,7 +55,30 @@ The toolkit defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low
55
55
 
56
56
  Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
57
57
 
58
- ## How reviews evolve
58
+ ## Standalone local quick start
59
+
60
+ With the qualified OCR binary and LLM environment configured, review an immutable
61
+ commit without forge credentials:
62
+
63
+ ```console
64
+ ocr-ci preflight --local
65
+ ocr-ci review --local --result review.json --stderr review.stderr --report review.md -- --commit HEAD
66
+ ```
67
+
68
+ Local execution uses the same OCR, mandatory evidence MCP, validation and DLP
69
+ pipeline as CI. It publishes every admitted finding to a fresh private Markdown
70
+ file and the console, without GitLab acquisition, suppression, approval or a
71
+ fabricated publication receipt. See [local review](docs/local.md) for ranges,
72
+ failure behavior and optional private `--debug-dir` bundles.
73
+
74
+ Optional [reasoning and progress controls](docs/configuration.md#provider-endpoint-and-completion-cap-contract)
75
+ do not change review rounds or budgets. Reasoning is unset by default; explicit
76
+ `none` is a wire value whose support depends on the provider/model. Progress is
77
+ off by default and emits only bounded toolkit phases to an interactive terminal
78
+ or an explicitly nonblocking embedding stream; a conventional CI stderr pipe is
79
+ intentionally not used because it can block a review.
80
+
81
+ ## How GitLab reviews evolve
59
82
 
60
83
  On a successful rerun, the toolkit replaces untouched OCR-only notes instead of accumulating stale reviews. A human reply transfers that discussion to the team: the conversation is preserved and a matching finding is suppressed. Reply with `/ocr suppress` or `@<live-bot-username> suppress` to keep a discussion open without future repeats; use the corresponding `resolve` command to resolve it after the next successful posting transaction. For example, a bot named `mr.bot` accepts the exact reply `@mr.bot resolve`.
61
84
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.9.1'
22
- __version_tuple__ = version_tuple = (0, 9, 1)
21
+ __version__ = version = '0.10.0'
22
+ __version_tuple__ = version_tuple = (0, 10, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -24,7 +24,12 @@ def build_parser() -> argparse.ArgumentParser:
24
24
  version=f"%(prog)s {__version__}",
25
25
  )
26
26
  subparsers = parser.add_subparsers(dest="command", required=True)
27
- subparsers.add_parser("preflight", help="Validate OCR, GitLab, and LLM access.")
27
+ preflight_parser = subparsers.add_parser(
28
+ "preflight", help="Validate review prerequisites and configured access."
29
+ )
30
+ preflight_parser.add_argument(
31
+ "--local", action="store_true", help="Validate standalone local review prerequisites."
32
+ )
28
33
  subparsers.add_parser("configure", help="Write the OCR runtime configuration.")
29
34
  subparsers.add_parser("mcp-config", help="Write OCR MCP server configuration.")
30
35
  review_parser = subparsers.add_parser(
@@ -32,6 +37,15 @@ def build_parser() -> argparse.ArgumentParser:
32
37
  )
33
38
  review_parser.add_argument("--result", required=True, help="OCR JSON output path.")
34
39
  review_parser.add_argument("--stderr", required=True, help="Full OCR stderr artifact path.")
40
+ review_parser.add_argument(
41
+ "--local", action="store_true", help="Review immutable Git refs and publish local Markdown."
42
+ )
43
+ review_parser.add_argument(
44
+ "--report", help="Fresh local Markdown path (default: --result path plus .md)."
45
+ )
46
+ review_parser.add_argument(
47
+ "--debug-dir", help="Fresh private diagnostic bundle directory (requires --local)."
48
+ )
35
49
  review_parser.add_argument(
36
50
  "--preserve-private-artifacts",
37
51
  action="store_true",
@@ -62,7 +76,7 @@ def main(argv: Sequence[str] | None = None) -> int:
62
76
 
63
77
  args = build_parser().parse_args(argv)
64
78
  if args.command == "preflight":
65
- return preflight.main()
79
+ return preflight.main(local=True) if args.local else preflight.main()
66
80
  if args.command == "configure":
67
81
  return configure.main()
68
82
  if args.command == "mcp-config":
@@ -75,6 +89,9 @@ def main(argv: Sequence[str] | None = None) -> int:
75
89
  Path(args.stderr),
76
90
  ocr_args,
77
91
  preserve_private_artifacts=args.preserve_private_artifacts,
92
+ **({"local": True} if args.local else {}),
93
+ **({"report_path": Path(args.report)} if args.report is not None else {}),
94
+ **({"debug_dir": Path(args.debug_dir)} if args.debug_dir is not None else {}),
78
95
  )
79
96
  except review_runner.ReviewRunnerError as exc:
80
97
  print(f"Cannot run Open Code Review: {exc}", file=sys.stderr)
@@ -0,0 +1,68 @@
1
+ """Small cross-platform filesystem durability helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import errno
6
+ import os
7
+ import stat
8
+ from pathlib import Path
9
+
10
+
11
+ def fsync_directory(descriptor: int) -> None:
12
+ """Persist a directory-entry change when the platform supports it."""
13
+
14
+ try:
15
+ os.fsync(descriptor)
16
+ except OSError as exc:
17
+ # Some supported filesystems reject directory fsync even though the
18
+ # atomic rename itself succeeded. Ignore only documented unsupported
19
+ # descriptor/filesystem cases; propagate genuine durability failures.
20
+ if exc.errno not in {errno.EINVAL, errno.ENOTSUP, errno.EBADF}:
21
+ raise
22
+
23
+
24
+ def open_private_parent_directory(path: Path) -> tuple[int, str]:
25
+ """Open a path's parent without following replaceable pathname components.
26
+
27
+ The returned descriptor pins the parent directory. Callers must use
28
+ descriptor-relative operations and close it themselves; returning an
29
+ absolute pathname would reintroduce the ancestor replacement race this
30
+ helper avoids.
31
+ """
32
+
33
+ absolute = path.absolute()
34
+ parts = [part for part in absolute.parts if part != os.path.sep]
35
+ if not parts:
36
+ raise ValueError("private output path must name a file or directory")
37
+ descriptor = os.open(os.path.sep, os.O_RDONLY | os.O_DIRECTORY)
38
+ try:
39
+ for component in parts[:-1]:
40
+ flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
41
+ try:
42
+ child = os.open(component, flags, dir_fd=descriptor)
43
+ except FileNotFoundError:
44
+ try:
45
+ os.mkdir(component, mode=0o700, dir_fd=descriptor)
46
+ except FileExistsError:
47
+ pass
48
+ try:
49
+ child = os.open(component, flags, dir_fd=descriptor)
50
+ except OSError as exc:
51
+ raise ValueError("private output parent must not be a symlink") from exc
52
+ except OSError as exc:
53
+ raise ValueError("private output parent must not be a symlink") from exc
54
+ os.close(descriptor)
55
+ descriptor = child
56
+ parent = os.fstat(descriptor)
57
+ if not stat.S_ISDIR(parent.st_mode):
58
+ raise OSError("private output parent is not a directory")
59
+ return descriptor, parts[-1]
60
+ except BaseException:
61
+ os.close(descriptor)
62
+ raise
63
+
64
+
65
+ def same_file_identity(left: os.stat_result, right: os.stat_result) -> bool:
66
+ """Compare two pinned filesystem identities without following pathnames."""
67
+
68
+ return left.st_dev == right.st_dev and left.st_ino == right.st_ino
@@ -0,0 +1,21 @@
1
+ """Posting facade for shared report value normalization."""
2
+
3
+ from ocr_toolkit.reporting.text import (
4
+ clean_text,
5
+ code_text,
6
+ comment_line,
7
+ compact_control_text,
8
+ compact_escaped_text,
9
+ compact_text,
10
+ line_number,
11
+ )
12
+
13
+ __all__ = [
14
+ "clean_text",
15
+ "code_text",
16
+ "comment_line",
17
+ "compact_control_text",
18
+ "compact_escaped_text",
19
+ "compact_text",
20
+ "line_number",
21
+ ]