agentic-project-kit 1.0.1__py3-none-any.whl

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 (310) hide show
  1. agentic_project_kit/__init__.py +1 -0
  2. agentic_project_kit/absolute_path_portability_audit.py +241 -0
  3. agentic_project_kit/access_level_policy.py +14 -0
  4. agentic_project_kit/access_levels.py +22 -0
  5. agentic_project_kit/action_registry.py +195 -0
  6. agentic_project_kit/action_specs.py +286 -0
  7. agentic_project_kit/agent_command_runner.py +516 -0
  8. agentic_project_kit/audit_test_matrix.py +36 -0
  9. agentic_project_kit/audit_test_matrix_cli.py +43 -0
  10. agentic_project_kit/chat_bootloader.py +257 -0
  11. agentic_project_kit/chat_entrypoint_contract.py +297 -0
  12. agentic_project_kit/checks.py +511 -0
  13. agentic_project_kit/ci_readiness.py +211 -0
  14. agentic_project_kit/cli.py +147 -0
  15. agentic_project_kit/cli_commands/__init__.py +1 -0
  16. agentic_project_kit/cli_commands/absolute_path_audit.py +25 -0
  17. agentic_project_kit/cli_commands/actions.py +21 -0
  18. agentic_project_kit/cli_commands/artifact_gc.py +240 -0
  19. agentic_project_kit/cli_commands/boot.py +55 -0
  20. agentic_project_kit/cli_commands/chat.py +34 -0
  21. agentic_project_kit/cli_commands/checks.py +305 -0
  22. agentic_project_kit/cli_commands/cockpit.py +103 -0
  23. agentic_project_kit/cli_commands/command_taxonomy.py +25 -0
  24. agentic_project_kit/cli_commands/commands.py +129 -0
  25. agentic_project_kit/cli_commands/dev.py +23 -0
  26. agentic_project_kit/cli_commands/direction.py +92 -0
  27. agentic_project_kit/cli_commands/doc_currency_audit.py +25 -0
  28. agentic_project_kit/cli_commands/doc_registry.py +126 -0
  29. agentic_project_kit/cli_commands/docs.py +223 -0
  30. agentic_project_kit/cli_commands/dpa.py +1338 -0
  31. agentic_project_kit/cli_commands/evidence.py +251 -0
  32. agentic_project_kit/cli_commands/github.py +34 -0
  33. agentic_project_kit/cli_commands/governance.py +14 -0
  34. agentic_project_kit/cli_commands/gui.py +23 -0
  35. agentic_project_kit/cli_commands/gui_readiness_gate.py +27 -0
  36. agentic_project_kit/cli_commands/handoff.py +183 -0
  37. agentic_project_kit/cli_commands/human_workflows.py +430 -0
  38. agentic_project_kit/cli_commands/init.py +132 -0
  39. agentic_project_kit/cli_commands/instruction.py +75 -0
  40. agentic_project_kit/cli_commands/mutation_lock_audit.py +24 -0
  41. agentic_project_kit/cli_commands/ns_legacy_audit.py +25 -0
  42. agentic_project_kit/cli_commands/pass_already_done.py +66 -0
  43. agentic_project_kit/cli_commands/patch_failure_discipline_audit.py +26 -0
  44. agentic_project_kit/cli_commands/patch_preflight.py +37 -0
  45. agentic_project_kit/cli_commands/path_literal_audit.py +39 -0
  46. agentic_project_kit/cli_commands/patterns.py +40 -0
  47. agentic_project_kit/cli_commands/planning_docs_audit.py +25 -0
  48. agentic_project_kit/cli_commands/pr.py +133 -0
  49. agentic_project_kit/cli_commands/pr_hygiene.py +27 -0
  50. agentic_project_kit/cli_commands/profiles.py +26 -0
  51. agentic_project_kit/cli_commands/program_redundancy_audit.py +25 -0
  52. agentic_project_kit/cli_commands/project_direction.py +25 -0
  53. agentic_project_kit/cli_commands/release.py +392 -0
  54. agentic_project_kit/cli_commands/release_publish_orchestration.py +36 -0
  55. agentic_project_kit/cli_commands/remote_branch_hygiene.py +152 -0
  56. agentic_project_kit/cli_commands/remote_next.py +57 -0
  57. agentic_project_kit/cli_commands/removed_ns_commands.py +65 -0
  58. agentic_project_kit/cli_commands/rule_registry.py +129 -0
  59. agentic_project_kit/cli_commands/rules.py +222 -0
  60. agentic_project_kit/cli_commands/scaffold.py +46 -0
  61. agentic_project_kit/cli_commands/slice.py +21 -0
  62. agentic_project_kit/cli_commands/standard_gates_audit_suite.py +27 -0
  63. agentic_project_kit/cli_commands/state.py +51 -0
  64. agentic_project_kit/cli_commands/status_current_state_audit.py +30 -0
  65. agentic_project_kit/cli_commands/todo.py +53 -0
  66. agentic_project_kit/cli_commands/transfer.py +19 -0
  67. agentic_project_kit/cli_commands/transfer_context_flow.py +398 -0
  68. agentic_project_kit/cli_commands/transfer_context_helpers.py +398 -0
  69. agentic_project_kit/cli_commands/transfer_diagnostics.py +767 -0
  70. agentic_project_kit/cli_commands/transfer_evidence_flow.py +368 -0
  71. agentic_project_kit/cli_commands/transfer_handoff_flow.py +594 -0
  72. agentic_project_kit/cli_commands/transfer_order_contract.py +74 -0
  73. agentic_project_kit/cli_commands/transfer_post_merge_complete.py +442 -0
  74. agentic_project_kit/cli_commands/transfer_post_merge_settle.py +171 -0
  75. agentic_project_kit/cli_commands/transfer_pr_closeout_complete.py +124 -0
  76. agentic_project_kit/cli_commands/transfer_pr_create_flow.py +743 -0
  77. agentic_project_kit/cli_commands/transfer_pr_merge_flow.py +547 -0
  78. agentic_project_kit/cli_commands/transfer_repo_after_pr.py +160 -0
  79. agentic_project_kit/cli_commands/transfer_repo_pre_pr.py +664 -0
  80. agentic_project_kit/cli_commands/transfer_runner_flow.py +131 -0
  81. agentic_project_kit/cli_commands/transfer_runtime_initial.py +194 -0
  82. agentic_project_kit/cli_commands/transfer_shared.py +274 -0
  83. agentic_project_kit/cli_commands/validation.py +200 -0
  84. agentic_project_kit/cli_commands/version.py +27 -0
  85. agentic_project_kit/cli_commands/work_orders.py +219 -0
  86. agentic_project_kit/cli_commands/workflow.py +471 -0
  87. agentic_project_kit/cli_commands/workflow_guard.py +26 -0
  88. agentic_project_kit/cli_commands/workspace.py +252 -0
  89. agentic_project_kit/cockpit.py +608 -0
  90. agentic_project_kit/cockpit_readiness.py +67 -0
  91. agentic_project_kit/command_authority_audit.py +192 -0
  92. agentic_project_kit/command_inbox_check.py +103 -0
  93. agentic_project_kit/command_manifest.py +591 -0
  94. agentic_project_kit/command_queue_contract.py +161 -0
  95. agentic_project_kit/command_selector.py +245 -0
  96. agentic_project_kit/command_taxonomy.py +264 -0
  97. agentic_project_kit/commit_guard.py +67 -0
  98. agentic_project_kit/communication_artifact_gc.py +495 -0
  99. agentic_project_kit/communication_rule_context.py +437 -0
  100. agentic_project_kit/communication_state.py +115 -0
  101. agentic_project_kit/composed_wrapper_invariants.py +97 -0
  102. agentic_project_kit/composite_short_circuit.py +140 -0
  103. agentic_project_kit/contract.py +251 -0
  104. agentic_project_kit/control_state.py +83 -0
  105. agentic_project_kit/doc_currency_audit.py +536 -0
  106. agentic_project_kit/doc_lifecycle.py +1179 -0
  107. agentic_project_kit/doc_lifecycle_signals.py +446 -0
  108. agentic_project_kit/doc_lifecycle_sweep.py +639 -0
  109. agentic_project_kit/doc_mesh.py +491 -0
  110. agentic_project_kit/doctor.py +379 -0
  111. agentic_project_kit/documentation_registry.py +1122 -0
  112. agentic_project_kit/documentation_system_audit.py +310 -0
  113. agentic_project_kit/dpa_current_handoff_lifecycle.py +549 -0
  114. agentic_project_kit/dpa_dp2_decision_readiness.py +362 -0
  115. agentic_project_kit/dpa_dp3_dp4_adjudication.py +604 -0
  116. agentic_project_kit/dpa_dp5_block_new_gate.py +294 -0
  117. agentic_project_kit/dpa_dp5_stage_adoption.py +615 -0
  118. agentic_project_kit/dpa_dp5_strict_gate.py +187 -0
  119. agentic_project_kit/dpa_final_closeout.py +627 -0
  120. agentic_project_kit/dpa_fixture_evidence.py +680 -0
  121. agentic_project_kit/dpa_maintainer_record_check.py +711 -0
  122. agentic_project_kit/dpa_post_dp2_scope_assessment.py +734 -0
  123. agentic_project_kit/dpa_probe_002_readiness.py +509 -0
  124. agentic_project_kit/dpa_probe_003_readiness.py +417 -0
  125. agentic_project_kit/dpa_probe_004_readiness.py +437 -0
  126. agentic_project_kit/dpa_readiness.py +505 -0
  127. agentic_project_kit/dpa_readonly_probe_execution.py +500 -0
  128. agentic_project_kit/dpa_registry_contracts.py +312 -0
  129. agentic_project_kit/dpa_renderer_readiness.py +407 -0
  130. agentic_project_kit/dpa_repo_adoption_assessment.py +574 -0
  131. agentic_project_kit/dpa_stable_readiness.py +743 -0
  132. agentic_project_kit/dpa_successor_projection.py +168 -0
  133. agentic_project_kit/dpa_workspace_init_projection.py +93 -0
  134. agentic_project_kit/dpa_wrt_ch001_evidence.py +327 -0
  135. agentic_project_kit/entrypoint_slice_runner.py +153 -0
  136. agentic_project_kit/evidence_clean.py +152 -0
  137. agentic_project_kit/evidence_commit_paths.py +214 -0
  138. agentic_project_kit/evidence_finalize_log.py +204 -0
  139. agentic_project_kit/evidence_guard.py +114 -0
  140. agentic_project_kit/evidence_inspector.py +507 -0
  141. agentic_project_kit/evidence_state_contract.py +99 -0
  142. agentic_project_kit/execution_mode_state.py +148 -0
  143. agentic_project_kit/final_summary_contract.py +85 -0
  144. agentic_project_kit/finalize_guard.py +139 -0
  145. agentic_project_kit/gatekeeper_core.py +232 -0
  146. agentic_project_kit/github.py +25 -0
  147. agentic_project_kit/governance.py +59 -0
  148. agentic_project_kit/gui_action_execution.py +105 -0
  149. agentic_project_kit/gui_action_renderer.py +81 -0
  150. agentic_project_kit/gui_action_run_intent.py +98 -0
  151. agentic_project_kit/gui_action_views.py +195 -0
  152. agentic_project_kit/gui_activity_log.py +76 -0
  153. agentic_project_kit/gui_button_catalog.py +605 -0
  154. agentic_project_kit/gui_cockpit.py +365 -0
  155. agentic_project_kit/gui_cockpit_actions.py +695 -0
  156. agentic_project_kit/gui_cockpit_common.py +172 -0
  157. agentic_project_kit/gui_cockpit_header.py +501 -0
  158. agentic_project_kit/gui_cockpit_sidebar.py +387 -0
  159. agentic_project_kit/gui_cockpit_task.py +748 -0
  160. agentic_project_kit/gui_command_projection.py +355 -0
  161. agentic_project_kit/gui_communication_modes.py +130 -0
  162. agentic_project_kit/gui_dry_run.py +219 -0
  163. agentic_project_kit/gui_gatekeeper_status.py +259 -0
  164. agentic_project_kit/gui_layout_plan.py +148 -0
  165. agentic_project_kit/gui_open_folder.py +18 -0
  166. agentic_project_kit/gui_output_status_panel.py +61 -0
  167. agentic_project_kit/gui_panel_state.py +47 -0
  168. agentic_project_kit/gui_presenter.py +62 -0
  169. agentic_project_kit/gui_readiness_gate.py +206 -0
  170. agentic_project_kit/gui_release_flow.py +59 -0
  171. agentic_project_kit/gui_task_editor.py +1077 -0
  172. agentic_project_kit/gui_tk_widgets.py +177 -0
  173. agentic_project_kit/gui_tkinter_renderer.py +87 -0
  174. agentic_project_kit/gui_tkinter_shell.py +1176 -0
  175. agentic_project_kit/gui_transfer_contract.py +28 -0
  176. agentic_project_kit/gui_viewmodel.py +698 -0
  177. agentic_project_kit/gui_window_guard.py +46 -0
  178. agentic_project_kit/handoff_freshness.py +390 -0
  179. agentic_project_kit/handoff_prompt.py +180 -0
  180. agentic_project_kit/handoff_state.py +254 -0
  181. agentic_project_kit/instruction_lint.py +455 -0
  182. agentic_project_kit/llm_context_carriers.py +66 -0
  183. agentic_project_kit/llm_execution_context.py +285 -0
  184. agentic_project_kit/local_command_stack.py +133 -0
  185. agentic_project_kit/local_feature_gate.py +82 -0
  186. agentic_project_kit/local_garbage_collector.py +269 -0
  187. agentic_project_kit/models.py +18 -0
  188. agentic_project_kit/mutation_lock_audit.py +421 -0
  189. agentic_project_kit/next_turn_evidence.py +253 -0
  190. agentic_project_kit/next_turn_merge_if_green.py +459 -0
  191. agentic_project_kit/next_turn_pr_status.py +255 -0
  192. agentic_project_kit/next_turn_result.py +183 -0
  193. agentic_project_kit/next_turn_runner.py +159 -0
  194. agentic_project_kit/next_turn_slot.py +107 -0
  195. agentic_project_kit/next_turn_status.py +274 -0
  196. agentic_project_kit/ns_legacy_reference_audit.py +258 -0
  197. agentic_project_kit/ns_slice_runner.py +16 -0
  198. agentic_project_kit/operational_handoff_projection.py +124 -0
  199. agentic_project_kit/output_contract.py +80 -0
  200. agentic_project_kit/output_repair.py +61 -0
  201. agentic_project_kit/pass_already_done.py +216 -0
  202. agentic_project_kit/patch_artifact_preflight.py +147 -0
  203. agentic_project_kit/patch_cycle_workflow.py +440 -0
  204. agentic_project_kit/patch_failure_discipline_audit.py +223 -0
  205. agentic_project_kit/patch_preflight.py +215 -0
  206. agentic_project_kit/path_literal_audit.py +612 -0
  207. agentic_project_kit/patterns.py +99 -0
  208. agentic_project_kit/planning_docs_consolidation_audit.py +313 -0
  209. agentic_project_kit/portability_shell_gate.py +40 -0
  210. agentic_project_kit/post_merge_handoff_refresh.py +56 -0
  211. agentic_project_kit/post_release.py +252 -0
  212. agentic_project_kit/post_release_closeout.py +616 -0
  213. agentic_project_kit/pr_cleanup.py +172 -0
  214. agentic_project_kit/pr_closeout.py +50 -0
  215. agentic_project_kit/pr_closeout_complete.py +344 -0
  216. agentic_project_kit/pr_create_or_skip.py +71 -0
  217. agentic_project_kit/pr_hygiene.py +210 -0
  218. agentic_project_kit/program_redundancy_audit.py +251 -0
  219. agentic_project_kit/project_direction.py +840 -0
  220. agentic_project_kit/protected_change_planner.py +194 -0
  221. agentic_project_kit/release.py +401 -0
  222. agentic_project_kit/release_doi_safety.py +24 -0
  223. agentic_project_kit/release_gate_core.py +174 -0
  224. agentic_project_kit/release_metadata_authority_gate.py +328 -0
  225. agentic_project_kit/release_metadata_prep.py +43 -0
  226. agentic_project_kit/release_notes.py +823 -0
  227. agentic_project_kit/release_prep_core.py +204 -0
  228. agentic_project_kit/release_prepare.py +369 -0
  229. agentic_project_kit/release_process_guardrails.py +247 -0
  230. agentic_project_kit/release_publish_core.py +114 -0
  231. agentic_project_kit/release_publish_orchestration.py +469 -0
  232. agentic_project_kit/release_state.py +552 -0
  233. agentic_project_kit/release_verify_core.py +175 -0
  234. agentic_project_kit/remote_branch_hygiene.py +223 -0
  235. agentic_project_kit/remote_next.py +89 -0
  236. agentic_project_kit/remote_next_closeout.py +101 -0
  237. agentic_project_kit/remote_next_order_contract.py +391 -0
  238. agentic_project_kit/removed_ns_commands.py +458 -0
  239. agentic_project_kit/removed_source_audit.py +225 -0
  240. agentic_project_kit/rendering.py +13 -0
  241. agentic_project_kit/repair_report.py +79 -0
  242. agentic_project_kit/repo_identity.py +59 -0
  243. agentic_project_kit/result_report_classifier.py +57 -0
  244. agentic_project_kit/rule_ack.py +105 -0
  245. agentic_project_kit/rule_preservation.py +58 -0
  246. agentic_project_kit/rule_refresh.py +174 -0
  247. agentic_project_kit/rule_registry_registration.py +322 -0
  248. agentic_project_kit/rule_registry_report.py +206 -0
  249. agentic_project_kit/rule_registry_validator.py +704 -0
  250. agentic_project_kit/rule_snapshot.py +98 -0
  251. agentic_project_kit/rule_source_validator.py +133 -0
  252. agentic_project_kit/run_summary.py +68 -0
  253. agentic_project_kit/run_summary_renderer.py +238 -0
  254. agentic_project_kit/runtime_validator.py +68 -0
  255. agentic_project_kit/safe_file_replace.py +35 -0
  256. agentic_project_kit/safe_patch.py +47 -0
  257. agentic_project_kit/safe_push.py +218 -0
  258. agentic_project_kit/safe_remove_diagnostic.py +51 -0
  259. agentic_project_kit/scaffold.py +69 -0
  260. agentic_project_kit/site_claims.py +444 -0
  261. agentic_project_kit/site_generator.py +1140 -0
  262. agentic_project_kit/slice_gate.py +225 -0
  263. agentic_project_kit/slice_runner.py +75 -0
  264. agentic_project_kit/standard_gates_audit_suite.py +167 -0
  265. agentic_project_kit/state_freshness.py +135 -0
  266. agentic_project_kit/status_current_state_audit.py +762 -0
  267. agentic_project_kit/successor_handoff_package.py +1763 -0
  268. agentic_project_kit/templates.py +292 -0
  269. agentic_project_kit/terminal_block_guard.py +166 -0
  270. agentic_project_kit/terminal_logging.py +275 -0
  271. agentic_project_kit/todo.py +97 -0
  272. agentic_project_kit/transfer_closeout.py +136 -0
  273. agentic_project_kit/transfer_continue.py +215 -0
  274. agentic_project_kit/transfer_local_runner.py +101 -0
  275. agentic_project_kit/transfer_operation_monitor.py +236 -0
  276. agentic_project_kit/transfer_post_merge_lifecycle.py +356 -0
  277. agentic_project_kit/transfer_post_merge_settle.py +383 -0
  278. agentic_project_kit/transfer_pr_actions.py +164 -0
  279. agentic_project_kit/transfer_remote_next.py +959 -0
  280. agentic_project_kit/transfer_repo_actions.py +2253 -0
  281. agentic_project_kit/transfer_runner.py +347 -0
  282. agentic_project_kit/transfer_safety_context.py +291 -0
  283. agentic_project_kit/transfer_state.py +483 -0
  284. agentic_project_kit/transfer_uplink.py +471 -0
  285. agentic_project_kit/transfer_workflow_next.py +148 -0
  286. agentic_project_kit/typed_work_order_evidence.py +58 -0
  287. agentic_project_kit/typed_work_order_queue.py +166 -0
  288. agentic_project_kit/typed_work_order_runner.py +168 -0
  289. agentic_project_kit/work_cycle.py +317 -0
  290. agentic_project_kit/work_discard_changes.py +129 -0
  291. agentic_project_kit/work_order_patch.py +199 -0
  292. agentic_project_kit/work_order_runner.py +120 -0
  293. agentic_project_kit/work_order_uploader.py +220 -0
  294. agentic_project_kit/work_order_validator.py +185 -0
  295. agentic_project_kit/work_orders.py +246 -0
  296. agentic_project_kit/workflow_guard.py +262 -0
  297. agentic_project_kit/workflow_summary_runner.py +124 -0
  298. agentic_project_kit/workspace.py +665 -0
  299. agentic_project_kit/workspace_adopt.py +471 -0
  300. agentic_project_kit/workspace_dpa_intake.py +406 -0
  301. agentic_project_kit/workspace_init.py +487 -0
  302. agentic_project_kit/workspace_lock.py +129 -0
  303. agentic_project_kit/workspace_remove.py +381 -0
  304. agentic_project_kit/workspace_upgrade.py +324 -0
  305. agentic_project_kit/wrapper_live_status.py +104 -0
  306. agentic_project_kit-1.0.1.dist-info/METADATA +724 -0
  307. agentic_project_kit-1.0.1.dist-info/RECORD +310 -0
  308. agentic_project_kit-1.0.1.dist-info/WHEEL +4 -0
  309. agentic_project_kit-1.0.1.dist-info/entry_points.txt +3 -0
  310. agentic_project_kit-1.0.1.dist-info/licenses/LICENSE +10 -0
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Literal
6
+
7
+ import typer
8
+
9
+ from agentic_project_kit.project_direction import (
10
+ audit_project_direction_drift,
11
+ load_project_direction,
12
+ render_direction_drift_audit,
13
+ render_direction_validation,
14
+ render_project_direction,
15
+ validate_project_direction,
16
+ )
17
+
18
+ direction_app = typer.Typer(help="Validate, render, and audit project direction state.")
19
+
20
+ Section = Literal["all", "strategy", "roadmap", "plans", "ideas", "done", "discarded"]
21
+ OutputFormat = Literal["text", "markdown", "json"]
22
+
23
+
24
+ @direction_app.command("validate")
25
+ def direction_validate_command(
26
+ root: Path = typer.Option(Path("."), "--root", help="Repository root."),
27
+ strict_planning_files: bool = typer.Option(
28
+ False,
29
+ "--strict-planning-files",
30
+ help="Fail when free docs/planning files are not canonical files or listed sources.",
31
+ ),
32
+ json_output: bool = typer.Option(False, "--json", help="Emit machine-readable JSON."),
33
+ ) -> None:
34
+ """Validate docs/planning/PROJECT_DIRECTION.yaml."""
35
+ result = validate_project_direction(root, strict_planning_files=strict_planning_files)
36
+ if json_output:
37
+ typer.echo(json.dumps(result.as_dict(), indent=2, sort_keys=True))
38
+ else:
39
+ typer.echo(render_direction_validation(result), nl=False)
40
+ if not result.ok:
41
+ raise typer.Exit(code=result.returncode)
42
+
43
+
44
+ @direction_app.command("render")
45
+ def direction_render_command(
46
+ root: Path = typer.Option(Path("."), "--root", help="Repository root."),
47
+ section: Section = typer.Option(
48
+ "all",
49
+ "--section",
50
+ help="all, strategy, roadmap, plans, ideas, done, or discarded.",
51
+ ),
52
+ output_format: OutputFormat = typer.Option("text", "--format", help="text, markdown, or json."),
53
+ output: Path | None = typer.Option(
54
+ None,
55
+ "--output",
56
+ help="Optional tmp/*.md, tmp/*.txt, or tmp/*.json output path.",
57
+ ),
58
+ ) -> None:
59
+ """Render project direction without overwriting committed projections."""
60
+ rendered = render_project_direction(
61
+ load_project_direction(root),
62
+ section=section,
63
+ output_format=output_format,
64
+ )
65
+ if output is None:
66
+ typer.echo(rendered, nl=False)
67
+ return
68
+
69
+ root_path = root.resolve()
70
+ output_path = output if output.is_absolute() else root_path / output
71
+ try:
72
+ relative = output_path.resolve().relative_to(root_path)
73
+ except ValueError as exc:
74
+ raise typer.BadParameter("output must stay inside the repository") from exc
75
+ if not relative.as_posix().startswith("tmp/"):
76
+ raise typer.BadParameter("output must be under tmp/")
77
+ output_path.parent.mkdir(parents=True, exist_ok=True)
78
+ output_path.write_text(rendered, encoding="utf-8")
79
+ typer.echo(f"PROJECT_DIRECTION_RENDER\nSTATUS=PASS\nOUTPUT={relative.as_posix()}")
80
+
81
+
82
+ @direction_app.command("audit-drift")
83
+ def direction_audit_drift_command(
84
+ root: Path = typer.Option(Path("."), "--root", help="Repository root."),
85
+ json_output: bool = typer.Option(False, "--json", help="Emit machine-readable JSON."),
86
+ ) -> None:
87
+ """Report planning files that are not yet represented in project direction."""
88
+ result = audit_project_direction_drift(root)
89
+ if json_output:
90
+ typer.echo(json.dumps(result.as_dict(), indent=2, sort_keys=True))
91
+ else:
92
+ typer.echo(render_direction_drift_audit(result), nl=False)
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ import typer
7
+
8
+ from agentic_project_kit.doc_currency_audit import (
9
+ audit_doc_currency,
10
+ render_doc_currency_audit,
11
+ )
12
+
13
+
14
+ def audit_doc_currency_command(
15
+ root: Path = typer.Option(Path("."), "--root"),
16
+ json_output: bool = typer.Option(False, "--json"),
17
+ ) -> None:
18
+ """Audit current release/documentation currency across handoff and release docs."""
19
+ result = audit_doc_currency(root.resolve())
20
+ if json_output:
21
+ typer.echo(json.dumps(result.as_dict(), indent=2, sort_keys=True))
22
+ else:
23
+ typer.echo(render_doc_currency_audit(result), nl=False)
24
+ if not result.ok:
25
+ raise typer.Exit(code=result.returncode)
@@ -0,0 +1,126 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from agentic_project_kit.documentation_registry import (
10
+ build_doc_registry_reconcile_report,
11
+ render_doc_registry_reconcile_report,
12
+ build_unregistered_document_candidates_report,
13
+ register_documentation_registry_entry,
14
+ )
15
+
16
+ doc_registry_app = typer.Typer(help="Register reviewed documentation registry entries.")
17
+
18
+
19
+ @doc_registry_app.command("register")
20
+ def doc_registry_register(
21
+ document_path: Annotated[str, typer.Option("--path", help="Repository-relative document path.")],
22
+ document_class: Annotated[str, typer.Option("--class", help="Allowed documentation registry class.")],
23
+ owner: Annotated[str, typer.Option("--owner", help="Document owner recorded in the registry.")] = "maintainers",
24
+ project_root: Annotated[Path, typer.Option("--root", help="Project root.")] = Path("."),
25
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
26
+ ) -> None:
27
+ """Add one reviewed document entry to the documentation registry."""
28
+ result = register_documentation_registry_entry(
29
+ project_root.resolve(),
30
+ document_path=document_path,
31
+ document_class=document_class,
32
+ owner=owner,
33
+ )
34
+ if json_output:
35
+ typer.echo(json.dumps(result, indent=2, sort_keys=True))
36
+ else:
37
+ typer.echo("DOC_REGISTRY_REGISTER")
38
+ typer.echo(f"STATUS={result['result_status']}")
39
+ typer.echo(f"CODE={result['code']}")
40
+ typer.echo(f"PATH={result['path']}")
41
+ typer.echo(f"CLASS={result['class']}")
42
+ typer.echo(f"WRITTEN={result['written']}")
43
+ if result.get("result_status") != "PASS":
44
+ raise typer.Exit(code=1)
45
+
46
+
47
+
48
+ @doc_registry_app.command("reconcile")
49
+ def doc_registry_reconcile(
50
+ project_root: Annotated[Path, typer.Option("--root", help="Project root.")] = Path("."),
51
+ execute: Annotated[
52
+ bool,
53
+ typer.Option(
54
+ "--execute",
55
+ help="Reserved for a later slice; current implementation is dry-run only.",
56
+ ),
57
+ ] = False,
58
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
59
+ ) -> None:
60
+ """Reconcile documentation registry, declared scope, and decision projection."""
61
+ if execute:
62
+ payload = {
63
+ "schema_version": 1,
64
+ "kind": "doc_registry_reconcile_report",
65
+ "result_status": "BLOCK",
66
+ "mode": "execute",
67
+ "message": "--execute is reserved for a later K2c slice; dry-run only.",
68
+ }
69
+ if json_output:
70
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
71
+ else:
72
+ typer.echo("DOC_REGISTRY_RECONCILE")
73
+ typer.echo("STATE: BLOCK")
74
+ typer.echo("MODE: execute")
75
+ typer.echo("MESSAGE: --execute is reserved for a later K2c slice; dry-run only.")
76
+ raise typer.Exit(2)
77
+
78
+ report = build_doc_registry_reconcile_report(project_root.resolve())
79
+ if json_output:
80
+ typer.echo(json.dumps(report, indent=2, sort_keys=True))
81
+ else:
82
+ typer.echo(render_doc_registry_reconcile_report(report))
83
+
84
+ if report["result_status"] == "BLOCK":
85
+ raise typer.Exit(2)
86
+
87
+ @doc_registry_app.command("check-unregistered")
88
+ def doc_registry_check_unregistered(
89
+ project_root: Annotated[Path, typer.Option("--root", help="Project root.")] = Path("."),
90
+ strict_scope: Annotated[
91
+ bool,
92
+ typer.Option(
93
+ "--strict-scope",
94
+ help="Fail when unregistered Markdown files violate declared required scope paths.",
95
+ ),
96
+ ] = False,
97
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
98
+ ) -> None:
99
+ """List unregistered docs candidates with optional strict declared-scope failure."""
100
+ report = build_unregistered_document_candidates_report(
101
+ project_root.resolve(),
102
+ strict_scope=strict_scope,
103
+ )
104
+ if json_output:
105
+ typer.echo(json.dumps(report, indent=2, sort_keys=True))
106
+ else:
107
+ typer.echo("DOC_REGISTRY_UNREGISTERED")
108
+ typer.echo(f"STATUS={report['result_status']}")
109
+ typer.echo(f"CANDIDATES={report['candidate_count']}")
110
+ for candidate in report["candidates"]:
111
+ typer.echo(f"- {candidate}")
112
+ if report["scope_present"] and (
113
+ report["scope_required_path_count"]
114
+ or report["scope_exempt_path_count"]
115
+ or report["scope_violation_count"]
116
+ or report["scope_errors"]
117
+ ):
118
+ typer.echo(f"STRICT_SCOPE={report['strict_scope']}")
119
+ typer.echo(f"EXEMPTED={report['exempted_count']}")
120
+ typer.echo(f"SCOPE_VIOLATIONS={report['scope_violation_count']}")
121
+ for violation in report["scope_violations"]:
122
+ typer.echo(f"SCOPE-VIOLATION {violation}")
123
+ for error in report["scope_errors"]:
124
+ typer.echo(f"SCOPE-ERROR {error}")
125
+ if report.get("result_status") == "FAIL":
126
+ raise typer.Exit(code=1)
@@ -0,0 +1,223 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from agentic_project_kit.doc_lifecycle import (
10
+ build_doc_lifecycle_apply_payload,
11
+ build_doc_lifecycle_evidence_report_payload,
12
+ build_doc_lifecycle_plan_payload,
13
+ build_doc_lifecycle_triage_payload,
14
+ render_doc_lifecycle_apply_report,
15
+ render_doc_lifecycle_evidence_report_result,
16
+ render_doc_lifecycle_plan_report,
17
+ render_doc_lifecycle_triage_report,
18
+ )
19
+ from agentic_project_kit.doc_lifecycle_sweep import (
20
+ build_doc_lifecycle_bootstrap_payload,
21
+ build_doc_lifecycle_propose_delete_payload,
22
+ build_doc_lifecycle_sweep_payload,
23
+ json_dumps,
24
+ render_doc_lifecycle_bootstrap,
25
+ render_doc_lifecycle_propose_delete,
26
+ render_doc_lifecycle_sweep,
27
+ )
28
+ from agentic_project_kit.removed_source_audit import (
29
+ DEFAULT_CENTRAL_TARGET,
30
+ build_removed_source_audit,
31
+ render_removed_source_audit,
32
+ )
33
+
34
+ docs_app = typer.Typer(help="Documentation maintenance and migration guards.")
35
+ lifecycle_app = typer.Typer(help="Safe documentation lifecycle triage and planning.")
36
+ docs_app.add_typer(lifecycle_app, name="lifecycle")
37
+
38
+
39
+ @lifecycle_app.command("bootstrap")
40
+ def docs_lifecycle_bootstrap_command(
41
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
42
+ dry_run: Annotated[
43
+ bool,
44
+ typer.Option("--dry-run/--execute", help="Preview or stamp missing lifecycle headers."),
45
+ ] = True,
46
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
47
+ ) -> None:
48
+ """Stamp missing lifecycle headers without claiming semantic currency."""
49
+ payload = build_doc_lifecycle_bootstrap_payload(
50
+ root.resolve(),
51
+ execute=not dry_run,
52
+ )
53
+ if json_output:
54
+ typer.echo(json_dumps(payload))
55
+ else:
56
+ typer.echo(render_doc_lifecycle_bootstrap(payload), nl=False)
57
+ if payload["result_status"] == "BLOCK":
58
+ raise typer.Exit(code=2)
59
+
60
+
61
+ @lifecycle_app.command("propose-delete")
62
+ def docs_lifecycle_propose_delete_command(
63
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
64
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
65
+ ) -> None:
66
+ """List archive documents that may be old enough for manual deletion review."""
67
+ payload = build_doc_lifecycle_propose_delete_payload(root.resolve())
68
+ if json_output:
69
+ typer.echo(json_dumps(payload))
70
+ else:
71
+ typer.echo(render_doc_lifecycle_propose_delete(payload), nl=False)
72
+
73
+
74
+ @lifecycle_app.command("sweep")
75
+ def docs_lifecycle_sweep_command(
76
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
77
+ dry_run: Annotated[
78
+ bool,
79
+ typer.Option("--dry-run/--execute", help="Preview or apply selected lifecycle hygiene actions."),
80
+ ] = True,
81
+ only: Annotated[
82
+ str,
83
+ typer.Option("--only", help="Comma-separated finding id(s) to execute. Required with --execute."),
84
+ ] = "",
85
+ until: Annotated[
86
+ str | None,
87
+ typer.Option("--until", help="YYYY-MM-DD deferral date for selected defer actions."),
88
+ ] = None,
89
+ review_after: Annotated[
90
+ str | None,
91
+ typer.Option("--review-after", help="Optional registry review_after value for confirm-current actions."),
92
+ ] = None,
93
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
94
+ ) -> None:
95
+ """Build or apply a bounded documentation lifecycle sweep plan."""
96
+ payload = build_doc_lifecycle_sweep_payload(
97
+ root.resolve(),
98
+ execute=not dry_run,
99
+ only=only,
100
+ until=until,
101
+ review_after=review_after,
102
+ )
103
+ if json_output:
104
+ typer.echo(json_dumps(payload))
105
+ else:
106
+ typer.echo(render_doc_lifecycle_sweep(payload), nl=False)
107
+ if payload["result_status"] == "BLOCK":
108
+ raise typer.Exit(code=2)
109
+
110
+
111
+
112
+
113
+ @lifecycle_app.command("apply")
114
+ def docs_lifecycle_apply_command(
115
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
116
+ scope: Annotated[str, typer.Option("--scope", help="Repository-relative documentation scope.")] = "docs",
117
+ only: Annotated[str, typer.Option("--only", help="Plan step id to apply.")] = "",
118
+ execute: Annotated[bool, typer.Option("--execute", help="Required explicit execution flag.")] = False,
119
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
120
+ ) -> None:
121
+ """Apply one safe documentation lifecycle plan step."""
122
+ payload = build_doc_lifecycle_apply_payload(
123
+ root.resolve(),
124
+ scope,
125
+ only,
126
+ execute=execute,
127
+ )
128
+ if json_output:
129
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
130
+ else:
131
+ typer.echo(render_doc_lifecycle_apply_report(payload), nl=False)
132
+ if payload["result_status"] == "BLOCK":
133
+ raise typer.Exit(code=2)
134
+
135
+
136
+
137
+ @lifecycle_app.command("report")
138
+ def docs_lifecycle_report_command(
139
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
140
+ scope: Annotated[str, typer.Option("--scope", help="Repository-relative documentation scope.")] = "docs",
141
+ output: Annotated[Path, typer.Option("--output", help="Evidence JSON output path.")] = Path(
142
+ "docs/architecture/evidence/doc-lifecycle-report.json"
143
+ ),
144
+ execute: Annotated[bool, typer.Option("--execute", help="Write the evidence report.")] = False,
145
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
146
+ ) -> None:
147
+ """Build or write one documentation lifecycle evidence report."""
148
+ payload = build_doc_lifecycle_evidence_report_payload(
149
+ root.resolve(),
150
+ scope,
151
+ output,
152
+ execute=execute,
153
+ )
154
+ if json_output:
155
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
156
+ else:
157
+ typer.echo(render_doc_lifecycle_evidence_report_result(payload), nl=False)
158
+ if payload["result_status"] == "BLOCK":
159
+ raise typer.Exit(code=2)
160
+
161
+
162
+ @lifecycle_app.command("plan")
163
+ def docs_lifecycle_plan_command(
164
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
165
+ scope: Annotated[str, typer.Option("--scope", help="Repository-relative documentation scope.")] = "docs",
166
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
167
+ ) -> None:
168
+ """Build a dry-run lifecycle plan for one documentation scope."""
169
+ payload = build_doc_lifecycle_plan_payload(root.resolve(), scope)
170
+ if json_output:
171
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
172
+ else:
173
+ typer.echo(render_doc_lifecycle_plan_report(payload), nl=False)
174
+ if payload["result_status"] == "BLOCK":
175
+ raise typer.Exit(code=2)
176
+
177
+
178
+ @lifecycle_app.command("triage")
179
+ def docs_lifecycle_triage_command(
180
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
181
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
182
+ ) -> None:
183
+ """Propose safe documentation lifecycle actions without applying changes."""
184
+ payload = build_doc_lifecycle_triage_payload(root.resolve())
185
+ if json_output:
186
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
187
+ else:
188
+ typer.echo(render_doc_lifecycle_triage_report(payload), nl=False)
189
+ if payload["result_status"] == "BLOCK":
190
+ raise typer.Exit(code=2)
191
+
192
+
193
+ @docs_app.command("removed-source-audit")
194
+ def removed_source_audit_command(
195
+ root: Annotated[Path, typer.Option("--root", help="Repository root.")] = Path("."),
196
+ path: Annotated[
197
+ list[str] | None,
198
+ typer.Option(
199
+ "--path",
200
+ help=(
201
+ "Repository-relative removed source path to audit. "
202
+ "May be supplied multiple times. Defaults to removed_source paths in PROJECT_DIRECTION.yaml."
203
+ ),
204
+ ),
205
+ ] = None,
206
+ central_target: Annotated[
207
+ str,
208
+ typer.Option("--central-target", help="Repository-relative central document that may retain removed_source metadata."),
209
+ ] = DEFAULT_CENTRAL_TARGET,
210
+ json_output: Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON.")] = False,
211
+ ) -> None:
212
+ """Fail if removed documentation sources still have live refs or registry refs."""
213
+ result = build_removed_source_audit(
214
+ root.resolve(),
215
+ paths=path,
216
+ central_target=central_target,
217
+ )
218
+ if json_output:
219
+ typer.echo(json.dumps(result.as_dict(), indent=2, sort_keys=True))
220
+ else:
221
+ typer.echo(render_removed_source_audit(result), nl=False)
222
+ if not result.ok:
223
+ raise typer.Exit(code=result.returncode)