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,608 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ from typing import Callable
10
+
11
+ from agentic_project_kit.access_levels import ACCESS_LEVEL_ORDER, DEFAULT_ACCESS_LEVEL, AccessLevel
12
+ from agentic_project_kit.command_manifest import SURFACE_VALUES, load_manifest
13
+ from agentic_project_kit.gui_command_projection import (
14
+ GUI_SURFACE_LAYERS,
15
+ claim_evidence_for_command,
16
+ diagnostic_priority_for_command,
17
+ resolve_manifest_command,
18
+ safety_review_for_command,
19
+ )
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class CockpitAction:
24
+ action_id: str
25
+ label: str
26
+ category: str
27
+ command: tuple[str, ...]
28
+ safety: str
29
+ description: str
30
+ short_description: str
31
+ min_access_level: AccessLevel = DEFAULT_ACCESS_LEVEL
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class CockpitStatus:
36
+ project_root: Path
37
+ git_branch: str
38
+ git_dirty: bool
39
+ workflow_state: str
40
+ current_work_present: bool
41
+ current_work_state: str | None
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class CockpitActionResult:
46
+ action_id: str
47
+ allowed: bool
48
+ executed: bool
49
+ returncode: int | None
50
+ stdout: str
51
+ stderr: str
52
+ message: str
53
+ result_status: str = "PENDING"
54
+ safety: str = "unknown"
55
+ terminal_log: str | None = None
56
+ command_report: str | None = None
57
+ dirty_state: str = "unknown"
58
+ next_allowed_actions: tuple[str, ...] = ()
59
+
60
+
61
+ READ_ONLY = "read_only"
62
+ BOUNDED = "bounded"
63
+ DESTRUCTIVE = "destructive"
64
+
65
+ RESULT_PASS = "PASS"
66
+ RESULT_FAIL = "FAIL"
67
+ RESULT_PENDING = "PENDING"
68
+ RESULT_HARD_FAIL = "HARD-FAIL"
69
+
70
+ CommandExecutor = Callable[[tuple[str, ...], Path], subprocess.CompletedProcess[str]]
71
+
72
+
73
+ def cockpit_actions() -> list[CockpitAction]:
74
+ return [
75
+ CockpitAction(
76
+ "git.status",
77
+ "Git status",
78
+ "git",
79
+ ("git", "status", "--short"),
80
+ READ_ONLY,
81
+ "Show uncommitted local changes.",
82
+ "Show local uncommitted changes",
83
+ ),
84
+ CockpitAction(
85
+ "workflow.state",
86
+ "Workflow state",
87
+ "workflow",
88
+ ("agentic-kit", "workflow", "state"),
89
+ READ_ONLY,
90
+ "Show guided workflow state and recommended next step.",
91
+ "Show current state and recommended next step",
92
+ ),
93
+ CockpitAction(
94
+ "transfer.restore-known-volatile",
95
+ "Restore Volatile",
96
+ "transfer",
97
+ ("agentic-kit", "transfer", "restore-known-volatile", "--json"),
98
+ BOUNDED,
99
+ "Restore only known volatile transfer files; never reset product files.",
100
+ "Restore known volatile transfer artifacts",
101
+ ),
102
+ CockpitAction(
103
+ "dialog.rn",
104
+ "Run Next Work Order",
105
+ "dialog",
106
+ ("agentic-kit", "rn"),
107
+ BOUNDED,
108
+ "Synchronize main and run the next typed work order.",
109
+ "Run the next queued work order",
110
+ ),
111
+ CockpitAction(
112
+ "dialog.rnc",
113
+ "Close Out Last Run",
114
+ "dialog",
115
+ ("agentic-kit", "rnc"),
116
+ BOUNDED,
117
+ "Commit and push the expected closeout paths from the last remote-next run.",
118
+ "Commit and push the last run's closeout paths",
119
+ ),
120
+ CockpitAction(
121
+ "workflow.list",
122
+ "Workflow items",
123
+ "workflow",
124
+ ("agentic-kit", "workflow", "list"),
125
+ READ_ONLY,
126
+ "List stored local workflow items.",
127
+ "List queued workflow items",
128
+ ),
129
+ CockpitAction(
130
+ "gate.check-docs",
131
+ "Documentation gate",
132
+ "gate",
133
+ ("agentic-kit", "check-docs"),
134
+ READ_ONLY,
135
+ "Run deterministic documentation gates.",
136
+ "Run documentation checks",
137
+ ),
138
+ CockpitAction(
139
+ "gate.doctor",
140
+ "Doctor",
141
+ "gate",
142
+ ("agentic-kit", "doctor"),
143
+ READ_ONLY,
144
+ "Run compact project health checks.",
145
+ "Run project health checks",
146
+ ),
147
+ CockpitAction(
148
+ "audit.doc-mesh",
149
+ "Document mesh audit",
150
+ "audit",
151
+ ("agentic-kit", "doc-mesh-audit"),
152
+ READ_ONLY,
153
+ "Audit cross-document state and governance drift.",
154
+ "Audit cross-document drift",
155
+ min_access_level="maintainer",
156
+ ),
157
+ CockpitAction(
158
+ "audit.doc-lifecycle",
159
+ "Document lifecycle audit",
160
+ "audit",
161
+ ("agentic-kit", "doc-lifecycle-audit"),
162
+ READ_ONLY,
163
+ "Audit lifecycle metadata for governed planning documents.",
164
+ "Audit document lifecycle metadata",
165
+ min_access_level="maintainer",
166
+ ),
167
+ CockpitAction(
168
+ "audit.pr-hygiene",
169
+ "PR hygiene",
170
+ "audit",
171
+ ("agentic-kit", "pr-hygiene"),
172
+ READ_ONLY,
173
+ "Diagnose stale, duplicate, or empty pull-request and branch hygiene signals.",
174
+ "Inspect pull-request hygiene",
175
+ min_access_level="maintainer",
176
+ ),
177
+ CockpitAction(
178
+ "rules.communication-refresh",
179
+ "Communication Rules Refresh",
180
+ "rules",
181
+ ("agentic-kit", "rules", "communication-refresh", "--publish", "--json"),
182
+ BOUNDED,
183
+ "Generate the communication rule capsule and d2 pending state.",
184
+ "Refresh communication rules (writes files)",
185
+ min_access_level="advanced",
186
+ ),
187
+ CockpitAction(
188
+ "rules.handoff-refresh",
189
+ "Handoff Rules Refresh",
190
+ "rules",
191
+ ("agentic-kit", "rules", "handoff-refresh"),
192
+ BOUNDED,
193
+ "Generate the repo-backed handoff rules refresh file for d3.",
194
+ "Refresh handoff rules (writes files)",
195
+ min_access_level="advanced",
196
+ ),
197
+ CockpitAction(
198
+ "handoff.successor-prompt",
199
+ "Successor Handoff Package",
200
+ "handoff",
201
+ ("agentic-kit", "transfer", "chat-switch-complete", "--render-prompt"),
202
+ BOUNDED,
203
+ "Render the copy-and-paste successor chat prompt through the guarded transfer command.",
204
+ "Render the successor handoff prompt",
205
+ min_access_level="advanced",
206
+ ),
207
+ CockpitAction(
208
+ "release.plan",
209
+ "Release plan",
210
+ "release",
211
+ ("agentic-kit", "release-plan"),
212
+ READ_ONLY,
213
+ "Print release preparation checklist.",
214
+ "Show the release preparation checklist",
215
+ min_access_level="advanced",
216
+ ),
217
+ CockpitAction(
218
+ "release.check",
219
+ "Release check",
220
+ "release",
221
+ ("agentic-kit", "release-check"),
222
+ READ_ONLY,
223
+ "Validate release state for a target version.",
224
+ "Validate release readiness",
225
+ min_access_level="advanced",
226
+ ),
227
+ CockpitAction(
228
+ "release.post-check",
229
+ "Post-release check",
230
+ "release",
231
+ ("agentic-kit", "post-release-check"),
232
+ READ_ONLY,
233
+ "Validate GitHub and Zenodo post-release state.",
234
+ "Validate post-release state",
235
+ min_access_level="advanced",
236
+ ),
237
+ CockpitAction(
238
+ "workflow.go",
239
+ "Run one bounded workflow step",
240
+ "workflow",
241
+ ("agentic-kit", "workflow", "go"),
242
+ BOUNDED,
243
+ "Request and run one bounded workflow step.",
244
+ "Run one guarded workflow step",
245
+ ),
246
+ ]
247
+
248
+
249
+ def action_by_id(action_id: str, actions: list[CockpitAction] | None = None) -> CockpitAction | None:
250
+ selected = actions if actions is not None else cockpit_actions()
251
+ for action in selected:
252
+ if action.action_id == action_id:
253
+ return action
254
+ return None
255
+
256
+
257
+
258
+
259
+ def validate_cockpit_action_registry(actions: list[CockpitAction] | None = None) -> list[str]:
260
+ selected = actions if actions is not None else cockpit_actions()
261
+ errors: list[str] = []
262
+ seen: set[str] = set()
263
+ allowed_safety = {READ_ONLY, BOUNDED, DESTRUCTIVE}
264
+ allowed_access = set(ACCESS_LEVEL_ORDER)
265
+ for action in selected:
266
+ if not action.action_id.strip():
267
+ errors.append('empty action_id')
268
+ if action.action_id in seen:
269
+ errors.append(f'duplicate action_id: {action.action_id}')
270
+ seen.add(action.action_id)
271
+ if action.safety not in allowed_safety:
272
+ errors.append(f'invalid safety for {action.action_id}: {action.safety}')
273
+ if action.min_access_level not in allowed_access:
274
+ errors.append(f'invalid min_access_level for {action.action_id}: {action.min_access_level}')
275
+ if not action.command:
276
+ errors.append(f'empty command for {action.action_id}')
277
+ if any(not part for part in action.command):
278
+ errors.append(f'empty command part for {action.action_id}')
279
+ if not action.category.strip():
280
+ errors.append(f'empty category for {action.action_id}')
281
+ if not action.label.strip():
282
+ errors.append(f'empty label for {action.action_id}')
283
+ if not action.description.strip():
284
+ errors.append(f'empty description for {action.action_id}')
285
+ if not action.short_description.strip():
286
+ errors.append(f'empty short_description for {action.action_id}')
287
+ return errors
288
+
289
+
290
+ def cockpit_registry_contract_as_json_data(actions: list[CockpitAction] | None = None) -> dict[str, object]:
291
+ selected = actions if actions is not None else cockpit_actions()
292
+ errors = validate_cockpit_action_registry(selected)
293
+ return {
294
+ 'schema_version': 1,
295
+ 'registry_only': True,
296
+ 'valid': not errors,
297
+ 'errors': errors,
298
+ 'allowed_action_ids': [action.action_id for action in selected],
299
+ 'allowed_safety_classes': [READ_ONLY, BOUNDED, DESTRUCTIVE],
300
+ 'allowed_access_levels': list(ACCESS_LEVEL_ORDER),
301
+ }
302
+
303
+ def run_cockpit_action(
304
+ action_id: str,
305
+ project_root: Path,
306
+ *,
307
+ allow_bounded: bool = False,
308
+ actions: list[CockpitAction] | None = None,
309
+ executor: CommandExecutor | None = None,
310
+ ) -> CockpitActionResult:
311
+ action = action_by_id(action_id, actions)
312
+ if action is None:
313
+ return CockpitActionResult(action_id, False, False, None, "", "", f"Unknown cockpit action: {action_id}", RESULT_FAIL, "unknown", next_allowed_actions=("cockpit.actions",))
314
+ if action.safety == DESTRUCTIVE:
315
+ return CockpitActionResult(action.action_id, False, False, None, "", "", f"Blocked destructive cockpit action: {action.action_id}", RESULT_HARD_FAIL, action.safety, next_allowed_actions=("cockpit.actions",))
316
+ if action.safety == BOUNDED and not allow_bounded:
317
+ return CockpitActionResult(action.action_id, False, False, None, "", "", f"Blocked bounded cockpit action without explicit allow flag: {action.action_id}", RESULT_PENDING, action.safety, next_allowed_actions=("cockpit.actions",))
318
+ if action.safety not in {READ_ONLY, BOUNDED}:
319
+ return CockpitActionResult(action.action_id, False, False, None, "", "", f"Blocked cockpit action with unknown safety class: {action.safety}", RESULT_HARD_FAIL, action.safety, next_allowed_actions=("cockpit.actions",))
320
+
321
+ runner = executor if executor is not None else _run_command
322
+ completed = runner(action.command, project_root.resolve())
323
+
324
+ return CockpitActionResult(
325
+ action.action_id,
326
+ True,
327
+ True,
328
+ completed.returncode,
329
+ completed.stdout.strip(),
330
+ completed.stderr.strip(),
331
+ "Cockpit action executed.",
332
+ RESULT_PASS if completed.returncode == 0 else RESULT_FAIL,
333
+ action.safety,
334
+ next_allowed_actions=("cockpit.actions",),
335
+ )
336
+
337
+
338
+ def build_cockpit_status(project_root: Path) -> CockpitStatus:
339
+ root = project_root.resolve()
340
+ workflow_state = _read_text(root / ".agentic" / "workflow_state", "missing").strip() or "missing"
341
+ current_work_path = root / ".agentic" / "current_work.yaml"
342
+ return CockpitStatus(
343
+ project_root=root,
344
+ git_branch=_git_stdout(root, ["branch", "--show-current"], "unknown"),
345
+ git_dirty=bool(_git_stdout(root, ["status", "--porcelain"], "").strip()),
346
+ workflow_state=workflow_state,
347
+ current_work_present=current_work_path.exists(),
348
+ current_work_state=_read_current_work_state(current_work_path) if current_work_path.exists() else None,
349
+ )
350
+
351
+
352
+ def render_cockpit_status(status: CockpitStatus) -> str:
353
+ lines = [
354
+ "Local cockpit status",
355
+ f"project_root={status.project_root}",
356
+ f"git_branch={status.git_branch}",
357
+ f"git_dirty={str(status.git_dirty).lower()}",
358
+ f"workflow_state={status.workflow_state}",
359
+ f"current_work={_present(status.current_work_present)}",
360
+ ]
361
+ if status.current_work_state is not None:
362
+ lines.append(f"current_work_state={status.current_work_state}")
363
+ lines.extend([
364
+ "",
365
+ "Safety:",
366
+ "- This command is read-only.",
367
+ "- Cockpit action execution allows read-only actions only by default.",
368
+ "",
369
+ "Next:",
370
+ "- Use cockpit actions to inspect the available action inventory.",
371
+ ])
372
+ return "\n".join(lines)
373
+
374
+
375
+ def action_inventory_as_json_data(
376
+ actions: list[CockpitAction] | None = None,
377
+ *,
378
+ manifest: dict[str, object] | None = None,
379
+ ) -> dict[str, object]:
380
+ selected = actions if actions is not None else cockpit_actions()
381
+ reference = manifest if manifest is not None else _load_manifest_or_empty(Path("."))
382
+ return {
383
+ "schema_version": 1,
384
+ "actions": [
385
+ {
386
+ "action_id": action.action_id,
387
+ "label": action.label,
388
+ "category": action.category,
389
+ "safety": action.safety,
390
+ "command": list(action.command),
391
+ "description": action.description,
392
+ "short_description": action.short_description,
393
+ "min_access_level": action.min_access_level,
394
+ "manifest_surface": _manifest_surface_for_action(action, reference),
395
+ "gui_layer": _gui_layer_for_action(action, reference),
396
+ "gui_diagnostic_priority": _gui_diagnostic_priority_for_action(action, reference),
397
+ "claim_evidence": _claim_evidence_for_action(action, reference),
398
+ "safety_review": _safety_review_for_action(action, reference),
399
+ }
400
+ for action in selected
401
+ ],
402
+ }
403
+
404
+
405
+
406
+
407
+
408
+ def action_result_as_json_data(result: CockpitActionResult) -> dict[str, object]:
409
+ return {
410
+ "schema_version": 1,
411
+ "action_id": result.action_id,
412
+ "result_status": result.result_status,
413
+ "allowed": result.allowed,
414
+ "executed": result.executed,
415
+ "returncode": result.returncode,
416
+ "safety": result.safety,
417
+ "dirty_state": result.dirty_state,
418
+ "terminal_log": result.terminal_log,
419
+ "command_report": result.command_report,
420
+ "next_allowed_actions": list(result.next_allowed_actions),
421
+ "message": result.message,
422
+ "stdout": result.stdout,
423
+ "stderr": result.stderr,
424
+ }
425
+
426
+ def render_action_inventory(
427
+ actions: list[CockpitAction] | None = None,
428
+ *,
429
+ manifest: dict[str, object] | None = None,
430
+ ) -> str:
431
+ selected = actions if actions is not None else cockpit_actions()
432
+ reference = manifest if manifest is not None else _load_manifest_or_empty(Path("."))
433
+ lines = ["Local cockpit actions"]
434
+ for action in selected:
435
+ command = " ".join(action.command)
436
+ surface = _manifest_surface_for_action(action, reference)
437
+ layer = _gui_layer_for_action(action, reference)
438
+ diagnostic_priority = _gui_diagnostic_priority_for_action(action, reference)
439
+ claim_evidence = _claim_evidence_for_action(action, reference)
440
+ safety_review = _safety_review_for_action(action, reference)
441
+ lines.append(f"- {action.action_id} [{action.category}/{action.safety}/{surface}/{layer}] {command}")
442
+ lines.append(
443
+ " metadata: "
444
+ f"diagnostic_priority={diagnostic_priority}; "
445
+ f"claim_evidence={claim_evidence}; "
446
+ f"safety_review={safety_review}"
447
+ )
448
+ lines.append(f" {action.description}")
449
+ return "\n".join(lines)
450
+
451
+
452
+ def render_action_selection(actions: list[CockpitAction] | None = None) -> str:
453
+ selected = actions if actions is not None else cockpit_actions()
454
+ lines = [
455
+ "Local cockpit action selection",
456
+ "Safety: selection is inspect-only; no action is executed.",
457
+ "",
458
+ ]
459
+ for index, action in enumerate(selected, start=1):
460
+ command = " ".join(action.command)
461
+ lines.append(f"{index:2d}) {action.action_id} [{action.category}/{action.safety}]")
462
+ lines.append(f" label: {action.label}")
463
+ lines.append(f" command: {command}")
464
+ lines.append(f" {action.description}")
465
+ lines.extend([
466
+ "",
467
+ "Next:",
468
+ "- Run read-only actions explicitly with: agentic-kit cockpit run <action-id>",
469
+ "- Bounded actions remain blocked unless the run command receives an explicit allow flag.",
470
+ ])
471
+ return "\n".join(lines)
472
+
473
+
474
+ def _read_text(path: Path, default: str) -> str:
475
+ if not path.exists():
476
+ return default
477
+ return path.read_text(encoding="utf-8")
478
+
479
+
480
+ def _read_current_work_state(path: Path) -> str:
481
+ for line in path.read_text(encoding="utf-8").splitlines():
482
+ stripped = line.strip()
483
+ if stripped.startswith("state:"):
484
+ return stripped.split(":", 1)[1].strip().upper() or "READY"
485
+ return "READY"
486
+
487
+
488
+ def _git_stdout(root: Path, args: list[str], default: str) -> str:
489
+ completed = subprocess.run(["git", *args], cwd=root, text=True, capture_output=True, check=False)
490
+ if completed.returncode != 0:
491
+ return default
492
+ return completed.stdout.strip() or default
493
+
494
+
495
+ def _resolve_command(command: tuple[str, ...], root: Path) -> list[str]:
496
+ if not command:
497
+ return []
498
+ first, *rest = command
499
+ if first != "agentic-kit":
500
+ return list(command)
501
+
502
+ candidates: list[Path] = [
503
+ root / ".venv" / "bin" / "agentic-kit",
504
+ root / ".venv" / "Scripts" / "agentic-kit.exe",
505
+ ]
506
+ if sys.executable:
507
+ executable = Path(sys.executable)
508
+ candidates.append(executable.with_name("agentic-kit"))
509
+ for candidate in candidates:
510
+ if candidate.exists():
511
+ return [str(candidate), *rest]
512
+
513
+ found = shutil.which("agentic-kit")
514
+ if found:
515
+ return [found, *rest]
516
+
517
+ # Keep the original command. _run_command catches FileNotFoundError and
518
+ # returns a structured failure instead of leaking a Tkinter callback traceback.
519
+ return list(command)
520
+
521
+
522
+ def _completed_process_for_missing_command(
523
+ command: tuple[str, ...],
524
+ error: FileNotFoundError,
525
+ ) -> subprocess.CompletedProcess[str]:
526
+ missing = str(error.filename or (command[0] if command else "<empty>"))
527
+ return subprocess.CompletedProcess(
528
+ list(command),
529
+ 127,
530
+ "",
531
+ (
532
+ "Command executable not found: "
533
+ + missing
534
+ + ". Start the GUI from the project virtual environment or keep "
535
+ + ".venv/bin/agentic-kit available for cockpit actions."
536
+ ),
537
+ )
538
+
539
+
540
+ def _run_command(command: tuple[str, ...], root: Path) -> subprocess.CompletedProcess[str]:
541
+ try:
542
+ return subprocess.run(
543
+ _resolve_command(command, root),
544
+ cwd=root,
545
+ text=True,
546
+ capture_output=True,
547
+ check=False,
548
+ env=os.environ.copy(),
549
+ )
550
+ except FileNotFoundError as exc:
551
+ return _completed_process_for_missing_command(command, exc)
552
+
553
+
554
+ def _present(value: bool) -> str:
555
+ return "present" if value else "missing"
556
+
557
+
558
+ def _load_manifest_or_empty(root: Path) -> dict[str, object]:
559
+ try:
560
+ return load_manifest(root)
561
+ except Exception:
562
+ return {"commands": []}
563
+
564
+
565
+ def _manifest_surface_for_action(action: CockpitAction, manifest: dict[str, object]) -> str:
566
+ if not action.command or action.command[0] != "agentic-kit":
567
+ return "external"
568
+ command = resolve_manifest_command(action.command, manifest)
569
+ if command is None:
570
+ return "unregistered"
571
+ surface = str(command.get("surface") or "")
572
+ if surface not in SURFACE_VALUES:
573
+ return "invalid"
574
+ return surface
575
+
576
+
577
+ def _gui_layer_for_action(action: CockpitAction, manifest: dict[str, object]) -> str:
578
+ surface = _manifest_surface_for_action(action, manifest)
579
+ if surface in GUI_SURFACE_LAYERS:
580
+ return GUI_SURFACE_LAYERS[surface]
581
+ return surface
582
+
583
+
584
+ def _manifest_command_for_action(action: CockpitAction, manifest: dict[str, object]) -> dict[str, object] | None:
585
+ if not action.command or action.command[0] != "agentic-kit":
586
+ return None
587
+ return resolve_manifest_command(action.command, manifest)
588
+
589
+
590
+ def _gui_diagnostic_priority_for_action(action: CockpitAction, manifest: dict[str, object]) -> str:
591
+ command = _manifest_command_for_action(action, manifest)
592
+ if command is None:
593
+ return "external"
594
+ return diagnostic_priority_for_command(command)
595
+
596
+
597
+ def _claim_evidence_for_action(action: CockpitAction, manifest: dict[str, object]) -> str:
598
+ command = _manifest_command_for_action(action, manifest)
599
+ if command is None:
600
+ return "none"
601
+ return claim_evidence_for_command(command)
602
+
603
+
604
+ def _safety_review_for_action(action: CockpitAction, manifest: dict[str, object]) -> str:
605
+ command = _manifest_command_for_action(action, manifest)
606
+ if command is None:
607
+ return action.safety
608
+ return safety_review_for_command(command)
@@ -0,0 +1,67 @@
1
+ """Read-only cockpit readiness report."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import Counter
6
+
7
+ from agentic_project_kit.action_registry import SafetyClass, list_actions
8
+
9
+
10
+ def build_cockpit_readiness_rows() -> list[dict[str, object]]:
11
+ rows: list[dict[str, object]] = []
12
+ for action in list_actions():
13
+ rows.append(
14
+ {
15
+ "name": action.name,
16
+ "safety_class": action.safety_class.value,
17
+ "mutation_scope": action.mutation_scope,
18
+ "dry_run_supported": action.dry_run_supported,
19
+ "outcome_contract": list(action.outcome_contract),
20
+ "summary": action.summary,
21
+ }
22
+ )
23
+ return rows
24
+
25
+
26
+ def build_cockpit_readiness_summary() -> dict[str, object]:
27
+ rows = build_cockpit_readiness_rows()
28
+ counts = Counter(str(row["safety_class"]) for row in rows)
29
+ missing_outcomes = [str(row["name"]) for row in rows if not row["outcome_contract"]]
30
+ read_only_with_mutation = [
31
+ str(row["name"])
32
+ for row in rows
33
+ if row["safety_class"] == SafetyClass.READ_ONLY.value and row["mutation_scope"] != "none"
34
+ ]
35
+ return {
36
+ "action_count": len(rows),
37
+ "safety_class_counts": dict(sorted(counts.items())),
38
+ "missing_outcomes": missing_outcomes,
39
+ "read_only_with_mutation": read_only_with_mutation,
40
+ "ready_for_read_only_cockpit": not missing_outcomes and not read_only_with_mutation,
41
+ }
42
+
43
+
44
+ def render_cockpit_readiness_markdown() -> str:
45
+ summary = build_cockpit_readiness_summary()
46
+ rows = build_cockpit_readiness_rows()
47
+ lines = [
48
+ "# Cockpit Readiness",
49
+ "",
50
+ "This report is read-only and derived from static action metadata.",
51
+ "",
52
+ "## Summary",
53
+ "",
54
+ f"- Action count: {summary['action_count']}",
55
+ f"- Ready for read-only cockpit: {summary['ready_for_read_only_cockpit']}",
56
+ f"- Missing outcomes: {summary['missing_outcomes']}",
57
+ f"- Read-only actions with mutation scope: {summary['read_only_with_mutation']}",
58
+ "",
59
+ "## Actions",
60
+ "",
61
+ "| Action | Safety class | Mutation scope | Dry-run | Outcomes |",
62
+ "|---|---|---|---|---|",
63
+ ]
64
+ for row in rows:
65
+ outcomes = ", ".join(str(item) for item in row["outcome_contract"])
66
+ lines.append(f"| `{row['name']}` | {row['safety_class']} | {row['mutation_scope']} | {row['dry_run_supported']} | {outcomes} |")
67
+ return "\n".join(lines) + "\n"