loopx 0.4.8__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 (811) hide show
  1. loopx/__init__.py +5 -0
  2. loopx/agent_onboarding.py +654 -0
  3. loopx/agent_registry.py +112 -0
  4. loopx/ark_managed_agent_host.py +59 -0
  5. loopx/authority.py +805 -0
  6. loopx/benchmark.py +2875 -0
  7. loopx/benchmark_adapters/__init__.py +1 -0
  8. loopx/benchmark_adapters/agentissue.py +2644 -0
  9. loopx/benchmark_adapters/agents_last_exam.py +3998 -0
  10. loopx/benchmark_adapters/edgebench.py +322 -0
  11. loopx/benchmark_adapters/skillsbench.py +5978 -0
  12. loopx/benchmark_adapters/skillsbench_acp_failure_policy.py +143 -0
  13. loopx/benchmark_adapters/skillsbench_acp_process.py +31 -0
  14. loopx/benchmark_adapters/skillsbench_acp_relay.py +4832 -0
  15. loopx/benchmark_adapters/skillsbench_batch.py +124 -0
  16. loopx/benchmark_adapters/skillsbench_bridge_guard.py +209 -0
  17. loopx/benchmark_adapters/skillsbench_bridge_summary.py +203 -0
  18. loopx/benchmark_adapters/skillsbench_codex_goal_recovery.py +271 -0
  19. loopx/benchmark_adapters/skillsbench_codex_goal_trace.py +81 -0
  20. loopx/benchmark_adapters/skillsbench_codex_runtime.py +339 -0
  21. loopx/benchmark_adapters/skillsbench_dockerfile_runtime.py +467 -0
  22. loopx/benchmark_adapters/skillsbench_failure_signals.py +652 -0
  23. loopx/benchmark_adapters/skillsbench_proxy_runtime.py +327 -0
  24. loopx/benchmark_adapters/skillsbench_remote_bridge.py +402 -0
  25. loopx/benchmark_adapters/skillsbench_result_discovery.py +143 -0
  26. loopx/benchmark_adapters/skillsbench_runner_profile.py +436 -0
  27. loopx/benchmark_adapters/skillsbench_runner_source.py +99 -0
  28. loopx/benchmark_adapters/skillsbench_setup_preflight.py +771 -0
  29. loopx/benchmark_adapters/skillsbench_signals.py +15 -0
  30. loopx/benchmark_adapters/skillsbench_task_source.py +141 -0
  31. loopx/benchmark_adapters/skillsbench_turn_route.py +723 -0
  32. loopx/benchmark_adapters/skillsbench_turn_runtime.py +1069 -0
  33. loopx/benchmark_adapters/skillsbench_typed_repair.py +689 -0
  34. loopx/benchmark_adapters/skillsbench_uv_cache.py +111 -0
  35. loopx/benchmark_adapters/skillsbench_verifier_bootstrap.py +227 -0
  36. loopx/benchmark_adapters/skillsbench_verifier_cache.py +138 -0
  37. loopx/benchmark_adapters/terminal_bench.py +10078 -0
  38. loopx/benchmark_case_analysis.py +1276 -0
  39. loopx/benchmark_case_state.py +1079 -0
  40. loopx/benchmark_core/__init__.py +239 -0
  41. loopx/benchmark_core/adapter.py +84 -0
  42. loopx/benchmark_core/artifacts.py +517 -0
  43. loopx/benchmark_core/attempts.py +199 -0
  44. loopx/benchmark_core/container_exec.py +216 -0
  45. loopx/benchmark_core/io.py +68 -0
  46. loopx/benchmark_core/lifecycle.py +211 -0
  47. loopx/benchmark_core/loop_protocol.py +689 -0
  48. loopx/benchmark_core/observable_handles.py +348 -0
  49. loopx/benchmark_core/parity.py +256 -0
  50. loopx/benchmark_core/remote_closeout.py +482 -0
  51. loopx/benchmark_core/rounds.py +215 -0
  52. loopx/benchmark_core/route_profile.py +509 -0
  53. loopx/benchmark_core/run_permissions.py +206 -0
  54. loopx/benchmark_core/split_control.py +925 -0
  55. loopx/benchmark_core/turn_fidelity.py +326 -0
  56. loopx/benchmark_ledger.py +3793 -0
  57. loopx/benchmark_ledger_countability.py +372 -0
  58. loopx/benchmark_ledger_current.py +724 -0
  59. loopx/benchmark_trajectory.py +405 -0
  60. loopx/benchmarks/__init__.py +1 -0
  61. loopx/benchmarks/qualification/__init__.py +1 -0
  62. loopx/benchmarks/qualification/release_outcome_baseline.py +360 -0
  63. loopx/benchmarks/read_models/__init__.py +1 -0
  64. loopx/benchmarks/read_models/benchmark_attempt_accounting.py +53 -0
  65. loopx/benchmarks/read_models/benchmark_comparison.py +414 -0
  66. loopx/benchmarks/read_models/benchmark_event_timeline.py +113 -0
  67. loopx/benchmarks/read_models/benchmark_experiment_report.py +475 -0
  68. loopx/benchmarks/read_models/benchmark_learning_ledger.py +137 -0
  69. loopx/benchmarks/read_models/benchmark_lifecycle_contracts.py +228 -0
  70. loopx/benchmarks/read_models/benchmark_projection.py +723 -0
  71. loopx/benchmarks/read_models/benchmark_result.py +146 -0
  72. loopx/benchmarks/read_models/benchmark_run_execution_contract.py +116 -0
  73. loopx/benchmarks/read_models/benchmark_run_failure.py +157 -0
  74. loopx/benchmarks/read_models/benchmark_run_metrics.py +213 -0
  75. loopx/benchmarks/read_models/benchmark_run_post_execution.py +635 -0
  76. loopx/benchmarks/read_models/benchmark_run_pre_execution.py +541 -0
  77. loopx/benchmarks/read_models/benchmark_status_compaction.py +1255 -0
  78. loopx/benchmarks/read_models/benchmark_status_runner.py +780 -0
  79. loopx/benchmarks/read_models/goal_start_control_score.py +857 -0
  80. loopx/benchmarks/read_models/skillsbench_post_run_debug.py +746 -0
  81. loopx/benchmarks/read_models/skillsbench_verifier_attribution.py +269 -0
  82. loopx/bootstrap.py +1116 -0
  83. loopx/bootstrap_command_pack.py +2167 -0
  84. loopx/boundary_authority.py +199 -0
  85. loopx/canary/__init__.py +1 -0
  86. loopx/canary/maintainability_ratchet.py +800 -0
  87. loopx/canary/planner.py +1984 -0
  88. loopx/canary/premerge.py +1130 -0
  89. loopx/canary/qualification_profiles.py +309 -0
  90. loopx/canary/quality_surface_catalog.py +838 -0
  91. loopx/canary/release_profiles.py +51 -0
  92. loopx/canary/runner.py +1107 -0
  93. loopx/canary/smoke_health.py +581 -0
  94. loopx/canary/smoke_profiles.py +212 -0
  95. loopx/capabilities/__init__.py +0 -0
  96. loopx/capabilities/agent_turn_recall/__init__.py +17 -0
  97. loopx/capabilities/agent_turn_recall/cli.py +369 -0
  98. loopx/capabilities/agent_turn_recall/core.py +296 -0
  99. loopx/capabilities/auto_research/__init__.py +16 -0
  100. loopx/capabilities/auto_research/bootstrap_contract.py +157 -0
  101. loopx/capabilities/auto_research/cli.py +1468 -0
  102. loopx/capabilities/auto_research/core.py +11 -0
  103. loopx/capabilities/auto_research/defaults.py +79 -0
  104. loopx/capabilities/auto_research/demo_e2e.py +1848 -0
  105. loopx/capabilities/auto_research/demo_supervisor.py +186 -0
  106. loopx/capabilities/auto_research/evidence_packet.py +767 -0
  107. loopx/capabilities/auto_research/human_view.py +794 -0
  108. loopx/capabilities/auto_research/kernel.py +191 -0
  109. loopx/capabilities/auto_research/knn_demo_workspace.py +322 -0
  110. loopx/capabilities/auto_research/live_evidence.py +248 -0
  111. loopx/capabilities/auto_research/preset.py +176 -0
  112. loopx/capabilities/auto_research/research_state.py +1085 -0
  113. loopx/capabilities/auto_research/role_profiles.py +394 -0
  114. loopx/capabilities/auto_research/rollout_append.py +97 -0
  115. loopx/capabilities/auto_research/terminal_result_contract.py +422 -0
  116. loopx/capabilities/auto_research/terminal_result_projection.py +171 -0
  117. loopx/capabilities/auto_research/terminal_result_query.py +233 -0
  118. loopx/capabilities/auto_research/terminal_results.py +349 -0
  119. loopx/capabilities/auto_research/user_contract.py +190 -0
  120. loopx/capabilities/auto_research/worker_loop.py +163 -0
  121. loopx/capabilities/auto_research/worker_runtime.py +777 -0
  122. loopx/capabilities/auto_research/worker_skill/SKILL.md +343 -0
  123. loopx/capabilities/benchmark_toolkit/__init__.py +19 -0
  124. loopx/capabilities/benchmark_toolkit/integrity.py +387 -0
  125. loopx/capabilities/catalog.py +1875 -0
  126. loopx/capabilities/change_quality/__init__.py +19 -0
  127. loopx/capabilities/change_quality/cli.py +171 -0
  128. loopx/capabilities/change_quality/context.py +156 -0
  129. loopx/capabilities/change_quality/oracles.py +269 -0
  130. loopx/capabilities/change_quality/policy.py +34 -0
  131. loopx/capabilities/change_quality/receipt.py +482 -0
  132. loopx/capabilities/change_quality/result.py +493 -0
  133. loopx/capabilities/change_quality/scope.py +171 -0
  134. loopx/capabilities/change_quality/shadow.py +680 -0
  135. loopx/capabilities/content_ops/__init__.py +0 -0
  136. loopx/capabilities/content_ops/cli.py +649 -0
  137. loopx/capabilities/content_ops/connector_packets.py +164 -0
  138. loopx/capabilities/content_ops/item_lifecycle.py +1000 -0
  139. loopx/capabilities/content_ops/layout.py +451 -0
  140. loopx/capabilities/content_ops/markdown.py +456 -0
  141. loopx/capabilities/content_ops/schemas.py +51 -0
  142. loopx/capabilities/content_ops/social_browser_x.py +107 -0
  143. loopx/capabilities/content_ops/surface.py +1956 -0
  144. loopx/capabilities/content_ops/templates/layout-catalog-v0.json +72 -0
  145. loopx/capabilities/context_providers/__init__.py +36 -0
  146. loopx/capabilities/context_providers/base.py +189 -0
  147. loopx/capabilities/context_providers/factory.py +32 -0
  148. loopx/capabilities/context_providers/openviking.py +702 -0
  149. loopx/capabilities/context_providers/service_ownership.py +185 -0
  150. loopx/capabilities/decision_context/__init__.py +129 -0
  151. loopx/capabilities/decision_context/architecture.py +83 -0
  152. loopx/capabilities/decision_context/assembler.py +849 -0
  153. loopx/capabilities/decision_context/catalog_entry.py +195 -0
  154. loopx/capabilities/decision_context/cli.py +310 -0
  155. loopx/capabilities/decision_context/cursor_commit.py +535 -0
  156. loopx/capabilities/decision_context/outcome_feedback.py +352 -0
  157. loopx/capabilities/decision_context/packets.py +654 -0
  158. loopx/capabilities/decision_context/private_state.py +189 -0
  159. loopx/capabilities/decision_context/profile.py +453 -0
  160. loopx/capabilities/decision_context/providers.py +228 -0
  161. loopx/capabilities/decision_context/review_settlement.py +136 -0
  162. loopx/capabilities/decision_context/runtime.py +273 -0
  163. loopx/capabilities/decision_context/sources.py +415 -0
  164. loopx/capabilities/explore/__init__.py +1 -0
  165. loopx/capabilities/explore/activation.py +198 -0
  166. loopx/capabilities/explore/adaptive_replay_planner.py +221 -0
  167. loopx/capabilities/explore/child_replay_runtime.py +463 -0
  168. loopx/capabilities/explore/composition_frontier.py +291 -0
  169. loopx/capabilities/explore/counterfactual_runtime.py +578 -0
  170. loopx/capabilities/explore/episode_runtime.py +647 -0
  171. loopx/capabilities/explore/harness_checkpoint.py +171 -0
  172. loopx/capabilities/explore/harness_gate.py +115 -0
  173. loopx/capabilities/explore/harness_runtime.py +1124 -0
  174. loopx/capabilities/explore/replay_metrics.py +206 -0
  175. loopx/capabilities/explore/replay_runtime.py +1271 -0
  176. loopx/capabilities/explore/resource_portfolio.py +173 -0
  177. loopx/capabilities/explore/result_log.py +974 -0
  178. loopx/capabilities/explore/router_state.py +432 -0
  179. loopx/capabilities/explore/source_history_reconcile.py +255 -0
  180. loopx/capabilities/explore/speculative_scheduler.py +498 -0
  181. loopx/capabilities/explore/todo_branch_plan.py +650 -0
  182. loopx/capabilities/explore/todo_evidence.py +141 -0
  183. loopx/capabilities/explore/trace_runtime.py +284 -0
  184. loopx/capabilities/explore/worker_branch_plan.py +1257 -0
  185. loopx/capabilities/integration_branch/__init__.py +13 -0
  186. loopx/capabilities/integration_branch/cli.py +148 -0
  187. loopx/capabilities/integration_branch/core.py +916 -0
  188. loopx/capabilities/issue_fix/__init__.py +19 -0
  189. loopx/capabilities/issue_fix/acceptance_loop.py +1050 -0
  190. loopx/capabilities/issue_fix/candidate_evidence.py +503 -0
  191. loopx/capabilities/issue_fix/candidate_preflight.py +676 -0
  192. loopx/capabilities/issue_fix/cli.py +1822 -0
  193. loopx/capabilities/issue_fix/cli_input.py +87 -0
  194. loopx/capabilities/issue_fix/content_ops_cli.py +148 -0
  195. loopx/capabilities/issue_fix/discovered_issue_promotion.py +947 -0
  196. loopx/capabilities/issue_fix/explore_projection.py +710 -0
  197. loopx/capabilities/issue_fix/feasibility.py +542 -0
  198. loopx/capabilities/issue_fix/github_public.py +661 -0
  199. loopx/capabilities/issue_fix/intake_surface.py +832 -0
  200. loopx/capabilities/issue_fix/metadata_preview.py +218 -0
  201. loopx/capabilities/issue_fix/metrics_projection.py +1340 -0
  202. loopx/capabilities/issue_fix/metrics_supplement.py +634 -0
  203. loopx/capabilities/issue_fix/metrics_supplement_cli.py +127 -0
  204. loopx/capabilities/issue_fix/outcome_projection.py +1235 -0
  205. loopx/capabilities/issue_fix/periodic_report.py +189 -0
  206. loopx/capabilities/issue_fix/pr_description.py +418 -0
  207. loopx/capabilities/issue_fix/pr_gate_reconcile.py +496 -0
  208. loopx/capabilities/issue_fix/pr_gate_reconcile_cli.py +464 -0
  209. loopx/capabilities/issue_fix/pr_lifecycle.py +1327 -0
  210. loopx/capabilities/issue_fix/pr_lifecycle_rollout.py +85 -0
  211. loopx/capabilities/issue_fix/pr_monitor_materialization.py +257 -0
  212. loopx/capabilities/issue_fix/pr_review_ack.py +439 -0
  213. loopx/capabilities/issue_fix/provider_hooks.py +24 -0
  214. loopx/capabilities/issue_fix/repository_commit_evidence.py +186 -0
  215. loopx/capabilities/issue_fix/repository_context.py +457 -0
  216. loopx/capabilities/issue_fix/repository_memory.py +459 -0
  217. loopx/capabilities/issue_fix/repository_memory_provider.py +1454 -0
  218. loopx/capabilities/issue_fix/repository_snapshot.py +454 -0
  219. loopx/capabilities/issue_fix/reviewer_cli.py +917 -0
  220. loopx/capabilities/issue_fix/reviewer_notification.py +882 -0
  221. loopx/capabilities/issue_fix/reviewer_notification_drain.py +942 -0
  222. loopx/capabilities/issue_fix/reviewer_recommendation.py +1057 -0
  223. loopx/capabilities/issue_fix/reviewer_request.py +1282 -0
  224. loopx/capabilities/issue_fix/reward_memory.py +879 -0
  225. loopx/capabilities/issue_fix/workflow_plan.py +1286 -0
  226. loopx/capabilities/material_lifecycle/__init__.py +161 -0
  227. loopx/capabilities/material_lifecycle/_validation.py +183 -0
  228. loopx/capabilities/material_lifecycle/apply.py +672 -0
  229. loopx/capabilities/material_lifecycle/architecture.py +122 -0
  230. loopx/capabilities/material_lifecycle/cli.py +161 -0
  231. loopx/capabilities/material_lifecycle/decision_planning.py +470 -0
  232. loopx/capabilities/material_lifecycle/explore_execution.py +306 -0
  233. loopx/capabilities/material_lifecycle/intake.py +869 -0
  234. loopx/capabilities/material_lifecycle/inventory.py +147 -0
  235. loopx/capabilities/material_lifecycle/lifecycle.py +98 -0
  236. loopx/capabilities/material_lifecycle/preparation.py +147 -0
  237. loopx/capabilities/material_lifecycle/project_skill.py +83 -0
  238. loopx/capabilities/material_lifecycle/ranking.py +267 -0
  239. loopx/capabilities/material_lifecycle/readable_projection.py +500 -0
  240. loopx/capabilities/material_lifecycle/rebuild.py +480 -0
  241. loopx/capabilities/material_lifecycle/settlement.py +238 -0
  242. loopx/capabilities/periodic_report/__init__.py +71 -0
  243. loopx/capabilities/periodic_report/adapters.py +939 -0
  244. loopx/capabilities/periodic_report/archive.py +422 -0
  245. loopx/capabilities/periodic_report/bindings.py +705 -0
  246. loopx/capabilities/periodic_report/cli.py +277 -0
  247. loopx/capabilities/periodic_report/core.py +691 -0
  248. loopx/capabilities/periodic_report/extension_envelope.py +66 -0
  249. loopx/capabilities/periodic_report/presets.py +103 -0
  250. loopx/capabilities/periodic_report/profile.py +235 -0
  251. loopx/capabilities/periodic_report/project_progress.py +179 -0
  252. loopx/capabilities/periodic_report/triggers.py +452 -0
  253. loopx/capabilities/pr_review_queue/__init__.py +17 -0
  254. loopx/capabilities/pr_review_queue/core.py +506 -0
  255. loopx/capabilities/pr_review_queue/review_contract.py +506 -0
  256. loopx/capabilities/registry.py +192 -0
  257. loopx/capabilities/reward_memory/__init__.py +75 -0
  258. loopx/capabilities/reward_memory/application.py +819 -0
  259. loopx/capabilities/reward_memory/architecture.py +572 -0
  260. loopx/capabilities/reward_memory/candidate_review.py +511 -0
  261. loopx/capabilities/reward_memory/cli.py +469 -0
  262. loopx/capabilities/reward_memory/dogfood.py +574 -0
  263. loopx/capabilities/reward_memory/evaluation.py +296 -0
  264. loopx/capabilities/reward_memory/evaluation_fixtures.py +362 -0
  265. loopx/capabilities/reward_memory/experiment.py +567 -0
  266. loopx/capabilities/reward_memory/health.py +222 -0
  267. loopx/capabilities/reward_memory/ingestion.py +519 -0
  268. loopx/capabilities/reward_memory/registry.py +600 -0
  269. loopx/capabilities/reward_memory/runtime_hooks.py +312 -0
  270. loopx/capabilities/reward_memory/scoped_feedback.py +173 -0
  271. loopx/capabilities/semantic_preference/__init__.py +12 -0
  272. loopx/capabilities/semantic_preference/cli.py +189 -0
  273. loopx/capabilities/semantic_preference/contract.py +592 -0
  274. loopx/capabilities/semantic_preference/reward_memory.py +62 -0
  275. loopx/capabilities/value_connectors/__init__.py +1 -0
  276. loopx/capabilities/value_connectors/cli.py +401 -0
  277. loopx/capabilities/value_connectors/finance_extension_migration.py +108 -0
  278. loopx/capabilities/value_connectors/install_check.py +147 -0
  279. loopx/capabilities/value_connectors/planner.py +733 -0
  280. loopx/capabilities/value_connectors/source_map.py +446 -0
  281. loopx/claude_goal_baseline.py +138 -0
  282. loopx/claude_goal_mode/__init__.py +23 -0
  283. loopx/claude_goal_mode/hooks/goal_policy.py +212 -0
  284. loopx/claude_goal_mode/hooks/goal_state.py +139 -0
  285. loopx/claude_goal_mode/mcp/loopx_mcp.py +167 -0
  286. loopx/claude_goal_mode/scripts/connect.py +103 -0
  287. loopx/claude_goal_mode/scripts/goalmode_cmd.py +241 -0
  288. loopx/claude_goal_mode/scripts/install.py +328 -0
  289. loopx/claude_goal_mode/statusline/goal_status.py +97 -0
  290. loopx/cli.py +836 -0
  291. loopx/cli_commands/__init__.py +334 -0
  292. loopx/cli_commands/_host_thread.py +13 -0
  293. loopx/cli_commands/agentissue_runner_flow.py +447 -0
  294. loopx/cli_commands/agents_last_exam.py +160 -0
  295. loopx/cli_commands/agents_last_exam_baked_input.py +302 -0
  296. loopx/cli_commands/agents_last_exam_host_codex.py +374 -0
  297. loopx/cli_commands/agents_last_exam_launch_dry_run.py +372 -0
  298. loopx/cli_commands/agents_last_exam_local_plan.py +322 -0
  299. loopx/cli_commands/agents_last_exam_runner_source.py +352 -0
  300. loopx/cli_commands/agents_last_exam_task_material.py +335 -0
  301. loopx/cli_commands/agents_last_exam_validation_gate.py +236 -0
  302. loopx/cli_commands/benchmark_boundary.py +499 -0
  303. loopx/cli_commands/benchmark_dispatch.py +161 -0
  304. loopx/cli_commands/benchmark_release_outcome.py +123 -0
  305. loopx/cli_commands/benchmark_review_lifecycle.py +1275 -0
  306. loopx/cli_commands/benchmark_run_ledger.py +763 -0
  307. loopx/cli_commands/benchmark_run_ledger_case_analysis.py +249 -0
  308. loopx/cli_commands/benchmark_run_ledger_classification.py +45 -0
  309. loopx/cli_commands/benchmark_run_ledger_maintenance.py +486 -0
  310. loopx/cli_commands/benchmark_run_ledger_maintenance_registration.py +342 -0
  311. loopx/cli_commands/benchmark_run_ledger_maintenance_rendering.py +233 -0
  312. loopx/cli_commands/benchmark_run_ledger_parity.py +92 -0
  313. loopx/cli_commands/bootstrap_connect.py +238 -0
  314. loopx/cli_commands/canary.py +707 -0
  315. loopx/cli_commands/canary_release_qualification.py +79 -0
  316. loopx/cli_commands/capability.py +96 -0
  317. loopx/cli_commands/doctor.py +43 -0
  318. loopx/cli_commands/dreaming.py +143 -0
  319. loopx/cli_commands/edgebench.py +205 -0
  320. loopx/cli_commands/evidence_log.py +275 -0
  321. loopx/cli_commands/explore.py +989 -0
  322. loopx/cli_commands/explore_planning_commands.py +157 -0
  323. loopx/cli_commands/extension.py +271 -0
  324. loopx/cli_commands/first_run_report.py +73 -0
  325. loopx/cli_commands/goal_channel.py +656 -0
  326. loopx/cli_commands/handoff_mode.py +158 -0
  327. loopx/cli_commands/history.py +622 -0
  328. loopx/cli_commands/host_mode_plan.py +113 -0
  329. loopx/cli_commands/lark_inbox.py +431 -0
  330. loopx/cli_commands/lark_kanban.py +629 -0
  331. loopx/cli_commands/ml_experiment.py +321 -0
  332. loopx/cli_commands/multi_agent.py +211 -0
  333. loopx/cli_commands/opencode2_goal_worker.py +217 -0
  334. loopx/cli_commands/pr_review.py +167 -0
  335. loopx/cli_commands/presentation.py +218 -0
  336. loopx/cli_commands/preset.py +96 -0
  337. loopx/cli_commands/project.py +150 -0
  338. loopx/cli_commands/project_lifecycle.py +915 -0
  339. loopx/cli_commands/quota.py +859 -0
  340. loopx/cli_commands/quota_registration.py +241 -0
  341. loopx/cli_commands/quota_request.py +113 -0
  342. loopx/cli_commands/ready_score.py +110 -0
  343. loopx/cli_commands/registry_admin.py +975 -0
  344. loopx/cli_commands/registry_admin_configure.py +344 -0
  345. loopx/cli_commands/registry_admin_peer.py +84 -0
  346. loopx/cli_commands/registry_authority.py +218 -0
  347. loopx/cli_commands/review_batch.py +146 -0
  348. loopx/cli_commands/slash_commands.py +145 -0
  349. loopx/cli_commands/start_goal.py +251 -0
  350. loopx/cli_commands/starter.py +175 -0
  351. loopx/cli_commands/starter_bootstrap.py +179 -0
  352. loopx/cli_commands/starter_bootstrap_registration.py +198 -0
  353. loopx/cli_commands/starter_runtime_idle.py +107 -0
  354. loopx/cli_commands/starter_scheduler.py +207 -0
  355. loopx/cli_commands/starter_session_runtime.py +152 -0
  356. loopx/cli_commands/starter_visible_common.py +54 -0
  357. loopx/cli_commands/starter_visible_driver.py +161 -0
  358. loopx/cli_commands/starter_visible_pilot.py +278 -0
  359. loopx/cli_commands/status.py +867 -0
  360. loopx/cli_commands/status_registration.py +239 -0
  361. loopx/cli_commands/summary_all.py +222 -0
  362. loopx/cli_commands/support_control.py +809 -0
  363. loopx/cli_commands/support_control_registry.py +68 -0
  364. loopx/cli_commands/support_control_supervisor.py +289 -0
  365. loopx/cli_commands/task_lease.py +306 -0
  366. loopx/cli_commands/terminal_bench_adapter.py +717 -0
  367. loopx/cli_commands/terminal_bench_environment_result.py +1246 -0
  368. loopx/cli_commands/todo.py +940 -0
  369. loopx/cli_commands/todo_argument_validation.py +572 -0
  370. loopx/cli_commands/todo_event.py +114 -0
  371. loopx/cli_commands/turn.py +804 -0
  372. loopx/cli_commands/version.py +46 -0
  373. loopx/cli_commands/worker_bridge.py +659 -0
  374. loopx/cli_rollout.py +314 -0
  375. loopx/codex_cli_goal_tui.py +672 -0
  376. loopx/codex_cli_probe.py +1530 -0
  377. loopx/codex_cli_probe_markdown.py +935 -0
  378. loopx/codex_cli_runtime_probe.py +733 -0
  379. loopx/codex_cli_scheduler.py +564 -0
  380. loopx/codex_goal_baseline.py +620 -0
  381. loopx/configuration_catalog.py +617 -0
  382. loopx/configure_goal.py +1375 -0
  383. loopx/contract.py +996 -0
  384. loopx/control_plane/__init__.py +71 -0
  385. loopx/control_plane/agents/__init__.py +1 -0
  386. loopx/control_plane/agents/agent_lane_recommendation.py +516 -0
  387. loopx/control_plane/agents/agent_scope.py +1578 -0
  388. loopx/control_plane/agents/agent_scope_frontier.py +60 -0
  389. loopx/control_plane/agents/capability_gate.py +531 -0
  390. loopx/control_plane/agents/identity.py +140 -0
  391. loopx/control_plane/agents/legacy_migration.py +169 -0
  392. loopx/control_plane/agents/management_projection.py +658 -0
  393. loopx/control_plane/agents/material_frontier.py +608 -0
  394. loopx/control_plane/agents/material_handoff.py +156 -0
  395. loopx/control_plane/agents/multi_agent/__init__.py +1 -0
  396. loopx/control_plane/agents/multi_agent/codex_executable.py +207 -0
  397. loopx/control_plane/agents/multi_agent/collective_round_ledger.py +387 -0
  398. loopx/control_plane/agents/multi_agent/contract.py +474 -0
  399. loopx/control_plane/agents/multi_agent/recipe.py +110 -0
  400. loopx/control_plane/agents/multi_agent/role_successor.py +297 -0
  401. loopx/control_plane/agents/multi_agent/runtime_scripts.py +426 -0
  402. loopx/control_plane/agents/multi_agent/visible_launch_policy.py +149 -0
  403. loopx/control_plane/agents/multi_agent/visible_wake_scheduler.py +392 -0
  404. loopx/control_plane/agents/profile.py +216 -0
  405. loopx/control_plane/agents/runtime_model.py +73 -0
  406. loopx/control_plane/agents/subagent_activity.py +164 -0
  407. loopx/control_plane/agents/supervisor.py +544 -0
  408. loopx/control_plane/agents/supervisor_events.py +462 -0
  409. loopx/control_plane/agents/supervisor_inject.py +204 -0
  410. loopx/control_plane/agents/work_mode.py +56 -0
  411. loopx/control_plane/agents/workspace_guard.py +364 -0
  412. loopx/control_plane/effect_program.py +644 -0
  413. loopx/control_plane/goals/__init__.py +1 -0
  414. loopx/control_plane/goals/active_state_event_projection.py +103 -0
  415. loopx/control_plane/goals/active_state_metadata.py +47 -0
  416. loopx/control_plane/goals/active_state_sections.py +58 -0
  417. loopx/control_plane/goals/configure_goal_service.py +354 -0
  418. loopx/control_plane/goals/contract_health.py +132 -0
  419. loopx/control_plane/goals/dreaming.py +152 -0
  420. loopx/control_plane/goals/global_registry_health.py +199 -0
  421. loopx/control_plane/goals/global_registry_shadow.py +33 -0
  422. loopx/control_plane/goals/goal_channel.py +34 -0
  423. loopx/control_plane/goals/goal_channel_projection.py +560 -0
  424. loopx/control_plane/goals/goal_frontier/__init__.py +1917 -0
  425. loopx/control_plane/goals/goal_frontier/ack_policy.py +149 -0
  426. loopx/control_plane/goals/goal_frontier/outcome_continuity.py +437 -0
  427. loopx/control_plane/goals/goal_frontier/replan_rules.py +210 -0
  428. loopx/control_plane/goals/goal_frontier/semantic_history.py +314 -0
  429. loopx/control_plane/goals/goal_frontier/terminal.py +180 -0
  430. loopx/control_plane/goals/goal_vision.py +443 -0
  431. loopx/control_plane/goals/goal_vision_policy.py +36 -0
  432. loopx/control_plane/goals/goal_vision_state.py +62 -0
  433. loopx/control_plane/goals/goal_vision_wait.py +290 -0
  434. loopx/control_plane/goals/path_resolution.py +20 -0
  435. loopx/control_plane/goals/start_contract.py +206 -0
  436. loopx/control_plane/goals/vision_checkpoint.py +92 -0
  437. loopx/control_plane/handoff/__init__.py +1 -0
  438. loopx/control_plane/handoff/cross_runtime_impl_review.py +311 -0
  439. loopx/control_plane/handoff/delivery_contract.py +161 -0
  440. loopx/control_plane/handoff/handoff_runs.py +71 -0
  441. loopx/control_plane/handoff/project_handoff.py +155 -0
  442. loopx/control_plane/handoff/review_batch.py +463 -0
  443. loopx/control_plane/handoff/review_packet_context.py +216 -0
  444. loopx/control_plane/heartbeat/agent.py +173 -0
  445. loopx/control_plane/heartbeat/budget.py +66 -0
  446. loopx/control_plane/heartbeat/builder.py +501 -0
  447. loopx/control_plane/heartbeat/host.py +64 -0
  448. loopx/control_plane/heartbeat/rules.py +68 -0
  449. loopx/control_plane/heartbeat/task_body.py +759 -0
  450. loopx/control_plane/heartbeat/visible_goal.py +86 -0
  451. loopx/control_plane/projects/__init__.py +1 -0
  452. loopx/control_plane/projects/contract.py +25 -0
  453. loopx/control_plane/projects/registry.py +663 -0
  454. loopx/control_plane/quota/__init__.py +1 -0
  455. loopx/control_plane/quota/cli_projection.py +704 -0
  456. loopx/control_plane/quota/decision_summary.py +431 -0
  457. loopx/control_plane/quota/effect_program.py +152 -0
  458. loopx/control_plane/quota/error_codes.py +19 -0
  459. loopx/control_plane/quota/goal_boundary.py +464 -0
  460. loopx/control_plane/quota/heartbeat_receipt.py +277 -0
  461. loopx/control_plane/quota/heartbeat_recommendation.py +718 -0
  462. loopx/control_plane/quota/host_poll_receipts.py +162 -0
  463. loopx/control_plane/quota/live_decision.py +142 -0
  464. loopx/control_plane/quota/monitor_poll.py +786 -0
  465. loopx/control_plane/quota/policy_constants.py +40 -0
  466. loopx/control_plane/quota/projection_repair.py +262 -0
  467. loopx/control_plane/quota/recent_runs.py +210 -0
  468. loopx/control_plane/quota/scheduler_ack.py +490 -0
  469. loopx/control_plane/quota/selected_todo_projection.py +139 -0
  470. loopx/control_plane/quota/settlement.py +437 -0
  471. loopx/control_plane/quota/settlement_cli.py +246 -0
  472. loopx/control_plane/quota/settlement_validation.py +64 -0
  473. loopx/control_plane/quota/settlement_workspace_causality.py +180 -0
  474. loopx/control_plane/quota/should_run.py +249 -0
  475. loopx/control_plane/quota/should_run_packet.py +1165 -0
  476. loopx/control_plane/quota/should_run_prepare.py +675 -0
  477. loopx/control_plane/quota/slot_accounting.py +1123 -0
  478. loopx/control_plane/quota/spend_sources.py +11 -0
  479. loopx/control_plane/quota/stall_repair.py +397 -0
  480. loopx/control_plane/quota/states.py +29 -0
  481. loopx/control_plane/quota/task_orchestration.py +448 -0
  482. loopx/control_plane/quota/task_orchestration_admission.py +497 -0
  483. loopx/control_plane/quota/turn_envelope.py +889 -0
  484. loopx/control_plane/quota/usage_summary.py +140 -0
  485. loopx/control_plane/reward_memory.py +43 -0
  486. loopx/control_plane/runtime/__init__.py +2 -0
  487. loopx/control_plane/runtime/active_user_assisted_pilot.py +275 -0
  488. loopx/control_plane/runtime/agent_scoped_evidence_log.py +435 -0
  489. loopx/control_plane/runtime/decision_freshness.py +203 -0
  490. loopx/control_plane/runtime/event_ledger.py +197 -0
  491. loopx/control_plane/runtime/event_store_migration_bridge.py +196 -0
  492. loopx/control_plane/runtime/goal_project_route.py +70 -0
  493. loopx/control_plane/runtime/local_state_write_correctness.py +242 -0
  494. loopx/control_plane/runtime/promotion_readiness.py +152 -0
  495. loopx/control_plane/runtime/public_safety.py +120 -0
  496. loopx/control_plane/runtime/run_artifacts.py +78 -0
  497. loopx/control_plane/runtime/run_compaction.py +397 -0
  498. loopx/control_plane/runtime/run_context_retention.py +241 -0
  499. loopx/control_plane/runtime/run_history.py +132 -0
  500. loopx/control_plane/runtime/run_index_duplicates.py +205 -0
  501. loopx/control_plane/runtime/run_index_rebuild.py +263 -0
  502. loopx/control_plane/runtime/run_ingest_health.py +336 -0
  503. loopx/control_plane/runtime/runtime_projection_route.py +624 -0
  504. loopx/control_plane/runtime/runtime_projection_writer.py +98 -0
  505. loopx/control_plane/runtime/session_runtime.py +339 -0
  506. loopx/control_plane/runtime/shared_runtime_material_projection.py +332 -0
  507. loopx/control_plane/runtime/shared_runtime_refresh_projection.py +183 -0
  508. loopx/control_plane/runtime/stale_latest_run.py +90 -0
  509. loopx/control_plane/runtime/status_classifications.py +49 -0
  510. loopx/control_plane/runtime/status_projection_cache.py +235 -0
  511. loopx/control_plane/runtime/stride_observation.py +144 -0
  512. loopx/control_plane/runtime/time.py +39 -0
  513. loopx/control_plane/runtime/trajectory_hygiene.py +149 -0
  514. loopx/control_plane/runtime/validation_command.py +69 -0
  515. loopx/control_plane/scheduler/__init__.py +1 -0
  516. loopx/control_plane/scheduler/ack.py +329 -0
  517. loopx/control_plane/scheduler/arbitration.py +188 -0
  518. loopx/control_plane/scheduler/automation_liveness.py +183 -0
  519. loopx/control_plane/scheduler/execution_context.py +555 -0
  520. loopx/control_plane/scheduler/external_evidence_observation.py +428 -0
  521. loopx/control_plane/scheduler/monitor_display.py +143 -0
  522. loopx/control_plane/scheduler/monitor_poll_policy.py +161 -0
  523. loopx/control_plane/scheduler/monitor_poll_writeback.py +351 -0
  524. loopx/control_plane/scheduler/monitor_target.py +64 -0
  525. loopx/control_plane/scheduler/monitor_todo.py +146 -0
  526. loopx/control_plane/scheduler/monitor_wait.py +237 -0
  527. loopx/control_plane/scheduler/scheduler_hint.py +1284 -0
  528. loopx/control_plane/scheduler/state.py +354 -0
  529. loopx/control_plane/scheduler/state_transition_rules.py +179 -0
  530. loopx/control_plane/scheduler/time.py +10 -0
  531. loopx/control_plane/settlement_driver.py +293 -0
  532. loopx/control_plane/status/__init__.py +6 -0
  533. loopx/control_plane/status/active_state_projection.py +105 -0
  534. loopx/control_plane/status/agent_lane_projection.py +375 -0
  535. loopx/control_plane/status/attention_projection.py +74 -0
  536. loopx/control_plane/status/autonomous_replan_projection.py +103 -0
  537. loopx/control_plane/status/collection.py +140 -0
  538. loopx/control_plane/status/contract_projection.py +31 -0
  539. loopx/control_plane/status/dreaming_projection.py +52 -0
  540. loopx/control_plane/status/goal_attention_projection.py +157 -0
  541. loopx/control_plane/status/lifecycle_projection.py +110 -0
  542. loopx/control_plane/status/monitor_display_projection.py +69 -0
  543. loopx/control_plane/status/registry_health_projection.py +75 -0
  544. loopx/control_plane/status/run_projection.py +70 -0
  545. loopx/control_plane/status/runtime_summaries.py +161 -0
  546. loopx/control_plane/testing/__init__.py +1 -0
  547. loopx/control_plane/testing/actual_default_model_behavior_portfolio.py +1371 -0
  548. loopx/control_plane/testing/canary_harness.py +182 -0
  549. loopx/control_plane/testing/capability_monitor_repair_tool_behavior.py +674 -0
  550. loopx/control_plane/testing/cli_output_budget.py +807 -0
  551. loopx/control_plane/testing/cli_output_differential.py +250 -0
  552. loopx/control_plane/testing/cli_output_semantics.py +87 -0
  553. loopx/control_plane/testing/control_plane_composition_scenarios.py +225 -0
  554. loopx/control_plane/testing/decision_replay.py +268 -0
  555. loopx/control_plane/testing/doubao_model_behavior_actor.py +559 -0
  556. loopx/control_plane/testing/model_behavior_corpus.py +344 -0
  557. loopx/control_plane/testing/model_behavior_qualification.py +769 -0
  558. loopx/control_plane/testing/model_behavior_retained_cases.py +235 -0
  559. loopx/control_plane/testing/model_tool_behavior.py +536 -0
  560. loopx/control_plane/testing/onboarding_model_behavior_qualification.py +642 -0
  561. loopx/control_plane/testing/quota_fixtures.py +208 -0
  562. loopx/control_plane/testing/quota_should_run_parity.py +57 -0
  563. loopx/control_plane/testing/release_commit_qualification.py +671 -0
  564. loopx/control_plane/testing/replan_semantic_action_behavior.py +1302 -0
  565. loopx/control_plane/testing/scoped_gate_successor_tool_behavior.py +527 -0
  566. loopx/control_plane/testing/selected_todo_tool_behavior.py +1002 -0
  567. loopx/control_plane/testing/terminal_settlement_tool_behavior.py +656 -0
  568. loopx/control_plane/todos/__init__.py +1 -0
  569. loopx/control_plane/todos/active_state_editing.py +296 -0
  570. loopx/control_plane/todos/active_state_todo_parser.py +138 -0
  571. loopx/control_plane/todos/active_state_todos.py +175 -0
  572. loopx/control_plane/todos/addition.py +103 -0
  573. loopx/control_plane/todos/claim_visibility.py +253 -0
  574. loopx/control_plane/todos/completed_archive.py +139 -0
  575. loopx/control_plane/todos/completion_fence.py +49 -0
  576. loopx/control_plane/todos/completion_policy.py +153 -0
  577. loopx/control_plane/todos/completion_validation.py +248 -0
  578. loopx/control_plane/todos/completion_validation_accountability.py +27 -0
  579. loopx/control_plane/todos/completion_validation_projection.py +57 -0
  580. loopx/control_plane/todos/contract.py +1476 -0
  581. loopx/control_plane/todos/decision_scope.py +554 -0
  582. loopx/control_plane/todos/deferred_resume.py +546 -0
  583. loopx/control_plane/todos/durable_completion.py +201 -0
  584. loopx/control_plane/todos/event_writeback.py +484 -0
  585. loopx/control_plane/todos/frontier_deadline.py +132 -0
  586. loopx/control_plane/todos/handoff_gate.py +283 -0
  587. loopx/control_plane/todos/handoff_mode.py +444 -0
  588. loopx/control_plane/todos/handoff_note.py +202 -0
  589. loopx/control_plane/todos/line_update.py +361 -0
  590. loopx/control_plane/todos/list_projection.py +205 -0
  591. loopx/control_plane/todos/markdown.py +199 -0
  592. loopx/control_plane/todos/monitor_metadata.py +88 -0
  593. loopx/control_plane/todos/mutation_authority.py +299 -0
  594. loopx/control_plane/todos/projection.py +655 -0
  595. loopx/control_plane/todos/quota_summary.py +1138 -0
  596. loopx/control_plane/todos/route_continuation.py +267 -0
  597. loopx/control_plane/todos/succession_warning.py +174 -0
  598. loopx/control_plane/todos/summary_item.py +223 -0
  599. loopx/control_plane/todos/text.py +30 -0
  600. loopx/control_plane/todos/todo_index.py +226 -0
  601. loopx/control_plane/todos/todo_summary.py +1458 -0
  602. loopx/control_plane/todos/unblock_resume.py +326 -0
  603. loopx/control_plane/todos/user_gate.py +263 -0
  604. loopx/control_plane/todos/write_hint.py +63 -0
  605. loopx/control_plane/todos/write_policy.py +135 -0
  606. loopx/control_plane/turn_driver/__init__.py +85 -0
  607. loopx/control_plane/turn_driver/codex_cli.py +502 -0
  608. loopx/control_plane/turn_driver/driver.py +355 -0
  609. loopx/control_plane/turn_driver/executor.py +1468 -0
  610. loopx/control_plane/turn_driver/loop_controller.py +669 -0
  611. loopx/control_plane/turn_driver/settlement.py +318 -0
  612. loopx/control_plane/turn_driver/transaction.py +375 -0
  613. loopx/control_plane/work_items/__init__.py +1 -0
  614. loopx/control_plane/work_items/attention_fields.py +56 -0
  615. loopx/control_plane/work_items/attention_item.py +77 -0
  616. loopx/control_plane/work_items/attention_queue.py +322 -0
  617. loopx/control_plane/work_items/attention_routing.py +213 -0
  618. loopx/control_plane/work_items/autonomous_candidates.py +135 -0
  619. loopx/control_plane/work_items/autonomous_replan_ack.py +276 -0
  620. loopx/control_plane/work_items/autonomous_replan_obligation.py +786 -0
  621. loopx/control_plane/work_items/backlog_hygiene.py +59 -0
  622. loopx/control_plane/work_items/capability_monitor_fallback.py +221 -0
  623. loopx/control_plane/work_items/delivery_batch_scale.py +66 -0
  624. loopx/control_plane/work_items/delivery_outcome.py +152 -0
  625. loopx/control_plane/work_items/delivery_signals.py +113 -0
  626. loopx/control_plane/work_items/execution_obligation.py +235 -0
  627. loopx/control_plane/work_items/goal_route_hint.py +320 -0
  628. loopx/control_plane/work_items/interaction_contract.py +1540 -0
  629. loopx/control_plane/work_items/issue_meta_surface.py +159 -0
  630. loopx/control_plane/work_items/lifecycle.py +139 -0
  631. loopx/control_plane/work_items/operator_inbox.py +266 -0
  632. loopx/control_plane/work_items/outcome_followthrough.py +69 -0
  633. loopx/control_plane/work_items/primary_action.py +326 -0
  634. loopx/control_plane/work_items/progress_observation.py +630 -0
  635. loopx/control_plane/work_items/project_asset.py +675 -0
  636. loopx/control_plane/work_items/repair_delta.py +693 -0
  637. loopx/control_plane/work_items/runtime_capability_reentry.py +168 -0
  638. loopx/control_plane/work_items/semantic_replan_writeback.py +177 -0
  639. loopx/control_plane/work_items/status_contract.py +49 -0
  640. loopx/control_plane/work_items/task_graph.py +1046 -0
  641. loopx/control_plane/work_items/task_lease.py +1254 -0
  642. loopx/control_plane/work_items/task_lease_settlement.py +422 -0
  643. loopx/control_plane/work_items/work_lane.py +510 -0
  644. loopx/control_plane/work_items/work_lane_context.py +161 -0
  645. loopx/demo.py +247 -0
  646. loopx/diagnose.py +633 -0
  647. loopx/doctor.py +1251 -0
  648. loopx/domain_packs/__init__.py +1 -0
  649. loopx/domain_packs/issue_fix.py +571 -0
  650. loopx/domain_packs/ml_experiment.py +854 -0
  651. loopx/domain_state.py +137 -0
  652. loopx/dreaming.py +706 -0
  653. loopx/entrypoint.py +16 -0
  654. loopx/event_sourced_state.py +981 -0
  655. loopx/execution_profile.py +286 -0
  656. loopx/experiments/__init__.py +1 -0
  657. loopx/experiments/planner_worker/__init__.py +1 -0
  658. loopx/experiments/planner_worker/contract.py +523 -0
  659. loopx/experiments/planner_worker/runtime.py +391 -0
  660. loopx/experiments/planner_worker/traex.py +461 -0
  661. loopx/explore_graph.py +11 -0
  662. loopx/extensions/__init__.py +1 -0
  663. loopx/extensions/bundled.py +28 -0
  664. loopx/extensions/execution_envelope.py +126 -0
  665. loopx/extensions/lark/__init__.py +11 -0
  666. loopx/extensions/lark/event_collector.py +478 -0
  667. loopx/extensions/lark/event_collector_runtime.py +506 -0
  668. loopx/extensions/lark/event_inbox.py +454 -0
  669. loopx/extensions/lark/extension.toml +88 -0
  670. loopx/extensions/lark/goal_channel.py +44 -0
  671. loopx/extensions/lark/goal_channel_contracts.py +388 -0
  672. loopx/extensions/lark/goal_channel_lifecycle.py +218 -0
  673. loopx/extensions/lark/goal_channel_runtime.py +792 -0
  674. loopx/extensions/lark/goal_channel_setup.py +805 -0
  675. loopx/extensions/lark/goal_channel_targets.py +215 -0
  676. loopx/extensions/lark/goal_channel_transport.py +281 -0
  677. loopx/extensions/lark/inbox_reactions.py +650 -0
  678. loopx/extensions/lark/inbox_reply.py +430 -0
  679. loopx/extensions/lark/presentation/__init__.py +11 -0
  680. loopx/extensions/lark/presentation/explore_results.py +2276 -0
  681. loopx/extensions/lark/presentation/explore_singleflight.py +127 -0
  682. loopx/extensions/lark/presentation/explore_source_guard.py +121 -0
  683. loopx/extensions/lark/presentation/explore_stage_document.py +703 -0
  684. loopx/extensions/lark/presentation/explore_visual_integrity.py +122 -0
  685. loopx/extensions/lark/presentation/explore_visual_readback.py +452 -0
  686. loopx/extensions/lark/presentation/explore_visual_styles.py +156 -0
  687. loopx/extensions/lark/presentation/issue_fix_surface.py +612 -0
  688. loopx/extensions/lark/presentation/kanban.py +2791 -0
  689. loopx/extensions/lark/presentation/message_card.py +112 -0
  690. loopx/extensions/lark/presentation/periodic_report.py +261 -0
  691. loopx/extensions/lark/presentation/projection_rows.py +600 -0
  692. loopx/extensions/lark/presentation/record_io.py +95 -0
  693. loopx/extensions/lark/presentation/sync_receipt.py +145 -0
  694. loopx/extensions/lark/private_json.py +40 -0
  695. loopx/extensions/lark/provider.py +86 -0
  696. loopx/extensions/lark/reviewer_notification.py +604 -0
  697. loopx/extensions/manifest.py +385 -0
  698. loopx/extensions/openviking_periodic_report/__init__.py +17 -0
  699. loopx/extensions/openviking_periodic_report/activation.py +173 -0
  700. loopx/extensions/openviking_periodic_report/extension.toml +17 -0
  701. loopx/extensions/openviking_periodic_report/provider.py +355 -0
  702. loopx/extensions/openviking_periodic_report/sink.py +117 -0
  703. loopx/extensions/openviking_semantic_preference/__init__.py +5 -0
  704. loopx/extensions/openviking_semantic_preference/extension.toml +16 -0
  705. loopx/extensions/openviking_semantic_preference/history_export.py +484 -0
  706. loopx/extensions/openviking_semantic_preference/project_peer.py +68 -0
  707. loopx/extensions/openviking_semantic_preference/provider.py +312 -0
  708. loopx/extensions/presentation.py +979 -0
  709. loopx/extensions/process_runtime.py +204 -0
  710. loopx/extensions/readiness.py +168 -0
  711. loopx/extensions/runtime.py +931 -0
  712. loopx/extensions/scaffold.py +335 -0
  713. loopx/feedback.py +581 -0
  714. loopx/file_lock.py +382 -0
  715. loopx/global_registry.py +842 -0
  716. loopx/global_risks.py +970 -0
  717. loopx/global_todos.py +568 -0
  718. loopx/handoff_budget.py +28 -0
  719. loopx/heartbeat_prequota.py +80 -0
  720. loopx/heartbeat_prompt.py +159 -0
  721. loopx/help_surface.py +516 -0
  722. loopx/history.py +1507 -0
  723. loopx/host_loop_activation.py +1311 -0
  724. loopx/host_mode_planner.py +991 -0
  725. loopx/install_contract.py +1 -0
  726. loopx/interface_budget.py +196 -0
  727. loopx/long_task_cadence.py +208 -0
  728. loopx/materials.py +185 -0
  729. loopx/ml_experiment.py +3 -0
  730. loopx/onboarding.py +214 -0
  731. loopx/opencode2_goal_mode/README.md +81 -0
  732. loopx/opencode2_goal_mode/__init__.py +9 -0
  733. loopx/opencode2_goal_mode/opencode2-goal-worker.mjs +1018 -0
  734. loopx/opencode_goal_mode/README.md +99 -0
  735. loopx/opencode_goal_mode/__init__.py +13 -0
  736. loopx/opencode_goal_mode/goal-bridge-runtime.mjs +858 -0
  737. loopx/opencode_goal_mode/loopx-goal.js +8 -0
  738. loopx/operator_gate.py +420 -0
  739. loopx/orchestration.py +127 -0
  740. loopx/paths.py +59 -0
  741. loopx/pi_goal_mode/README.md +67 -0
  742. loopx/pi_goal_mode/__init__.py +13 -0
  743. loopx/pi_goal_mode/loopx-goal.ts +254 -0
  744. loopx/pi_goal_mode/pi-goal-loop-runtime.mjs +574 -0
  745. loopx/pr_review.py +1206 -0
  746. loopx/presentation/__init__.py +1 -0
  747. loopx/presentation/explore_views.py +1334 -0
  748. loopx/presentation/markdown.py +61 -0
  749. loopx/presentation/projection_source_reconcile.py +140 -0
  750. loopx/presentation/public_safety.py +42 -0
  751. loopx/presentation/renderers/__init__.py +17 -0
  752. loopx/presentation/renderers/goal_channel_html.py +269 -0
  753. loopx/presentation/renderers/periodic_report_html.py +786 -0
  754. loopx/presentation/renderers/periodic_report_markdown.py +184 -0
  755. loopx/presentation/renderers/quota_event_markdown.py +116 -0
  756. loopx/presentation/renderers/quota_markdown.py +1112 -0
  757. loopx/presentation/renderers/status_markdown.py +1570 -0
  758. loopx/presentation/renderers/trajectory_hygiene_markdown.py +39 -0
  759. loopx/presentation/renderers/turn_envelope_markdown.py +33 -0
  760. loopx/presentation/sinks/__init__.py +5 -0
  761. loopx/presentation/sinks/openviking_periodic_report.py +7 -0
  762. loopx/presentation/static_site.py +691 -0
  763. loopx/presets.py +369 -0
  764. loopx/project_alias.py +217 -0
  765. loopx/project_map.py +589 -0
  766. loopx/project_prompt.py +1153 -0
  767. loopx/project_skill_cli.py +125 -0
  768. loopx/project_skill_delivery.py +470 -0
  769. loopx/project_uninstall.py +462 -0
  770. loopx/promotion_gate.py +197 -0
  771. loopx/quota.py +1197 -0
  772. loopx/ready_score.py +413 -0
  773. loopx/registry.py +621 -0
  774. loopx/registry_writability.py +64 -0
  775. loopx/release_candidate.py +148 -0
  776. loopx/release_manifest.py +316 -0
  777. loopx/repository_identity.py +100 -0
  778. loopx/review_packet.py +1024 -0
  779. loopx/rollout_event_log.py +505 -0
  780. loopx/runtime.py +112 -0
  781. loopx/self_update.py +750 -0
  782. loopx/session_runtime.py +418 -0
  783. loopx/skill_install_readback.py +500 -0
  784. loopx/slash_command_install.py +1393 -0
  785. loopx/slash_commands.py +264 -0
  786. loopx/state_backup.py +573 -0
  787. loopx/state_migration.py +350 -0
  788. loopx/state_projection.py +809 -0
  789. loopx/state_refresh.py +1416 -0
  790. loopx/status.py +1383 -0
  791. loopx/status_server.py +935 -0
  792. loopx/summary_all.py +725 -0
  793. loopx/terminal_bench_agent.py +2056 -0
  794. loopx/thread_agent_binding.py +408 -0
  795. loopx/todo_followups.py +168 -0
  796. loopx/todo_suggestion_prompt.py +204 -0
  797. loopx/todos.py +2229 -0
  798. loopx/turn_identity.py +17 -0
  799. loopx/upgrade.py +1083 -0
  800. loopx/visible_governance.py +667 -0
  801. loopx/visible_multi_agent_launcher.py +1253 -0
  802. loopx/visible_multi_agent_tmux.py +429 -0
  803. loopx/worker_bridge.py +1574 -0
  804. loopx-0.4.8.dist-info/METADATA +708 -0
  805. loopx-0.4.8.dist-info/RECORD +811 -0
  806. loopx-0.4.8.dist-info/WHEEL +5 -0
  807. loopx-0.4.8.dist-info/entry_points.txt +5 -0
  808. loopx-0.4.8.dist-info/licenses/LICENSE +202 -0
  809. loopx-0.4.8.dist-info/licenses/LICENSE-MIT +21 -0
  810. loopx-0.4.8.dist-info/licenses/NOTICE +6 -0
  811. loopx-0.4.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,931 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable, Mapping, Sequence
4
+ from contextlib import nullcontext
5
+ from copy import deepcopy
6
+ import hashlib
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from ..file_lock import exclusive_file_lock
13
+ from .process_runtime import run_capped_process
14
+ from .manifest import load_extension_manifest
15
+ from .readiness import (
16
+ EXTENSION_DOCTOR_SCHEMA_VERSION,
17
+ ResolvedRuntimeEntrypoint,
18
+ extension_doctor,
19
+ extension_runtime,
20
+ resolve_runtime_entrypoint,
21
+ )
22
+
23
+
24
+ EXTENSION_STATE_SCHEMA_VERSION = "loopx_extension_state_v0"
25
+ EXTENSION_OPERATION_SCHEMA_VERSION = "loopx_extension_operation_v0"
26
+ EXTENSION_BINDING_SCHEMA_VERSION = "loopx_extension_runtime_binding_v0"
27
+ EXTENSION_ACTIVATION_SCHEMA_VERSION = "loopx_extension_activation_v0"
28
+ EXTENSION_RUN_SCHEMA_VERSION = "loopx_extension_run_receipt_v0"
29
+ MAX_REVISIONS = 5
30
+ MAX_EXTENSION_REQUEST_BYTES = 1_000_000
31
+ MAX_EXTENSION_RESPONSE_BYTES = 1_000_000
32
+
33
+
34
+ def default_extension_state_file(runtime_root: str | Path | None = None) -> Path:
35
+ root = (
36
+ Path(runtime_root).expanduser()
37
+ if runtime_root is not None
38
+ else Path.home() / ".codex" / "loopx"
39
+ )
40
+ return root / "extensions" / "state.json"
41
+
42
+
43
+ def _empty_state() -> dict[str, Any]:
44
+ return {
45
+ "schema_version": EXTENSION_STATE_SCHEMA_VERSION,
46
+ "extensions": {},
47
+ }
48
+
49
+
50
+ def _read_state(path: Path) -> dict[str, Any]:
51
+ if not path.exists():
52
+ return _empty_state()
53
+ try:
54
+ payload = json.loads(path.read_text(encoding="utf-8"))
55
+ except (OSError, json.JSONDecodeError) as exc:
56
+ raise ValueError("extension runtime state is unreadable") from exc
57
+ if (
58
+ not isinstance(payload, dict)
59
+ or payload.get("schema_version") != EXTENSION_STATE_SCHEMA_VERSION
60
+ or not isinstance(payload.get("extensions"), dict)
61
+ ):
62
+ raise ValueError(
63
+ f"extension runtime state must use {EXTENSION_STATE_SCHEMA_VERSION}"
64
+ )
65
+ return payload
66
+
67
+
68
+ def _write_state(path: Path, payload: Mapping[str, Any]) -> None:
69
+ path.parent.mkdir(parents=True, exist_ok=True)
70
+ temporary = path.with_name(f".{path.name}.tmp.{os.getpid()}")
71
+ temporary.write_text(
72
+ json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
73
+ encoding="utf-8",
74
+ )
75
+ temporary.chmod(0o600)
76
+ os.replace(temporary, path)
77
+
78
+
79
+ def _revision(manifest: Mapping[str, Any]) -> str:
80
+ serialized = json.dumps(
81
+ manifest,
82
+ ensure_ascii=False,
83
+ sort_keys=True,
84
+ separators=(",", ":"),
85
+ )
86
+ return hashlib.sha256(serialized.encode("utf-8")).hexdigest()[:16]
87
+
88
+
89
+ def _runtime(manifest: Mapping[str, Any]) -> Mapping[str, Any]:
90
+ return extension_runtime(manifest)
91
+
92
+
93
+ def _manifest_snapshot(manifest: Mapping[str, Any]) -> dict[str, Any]:
94
+ return deepcopy(dict(manifest))
95
+
96
+
97
+ def _entry_for_revision(entry: Mapping[str, Any], revision: str) -> dict[str, Any]:
98
+ revisions = entry.get("revisions")
99
+ if not isinstance(revisions, list):
100
+ raise ValueError("extension revision history is invalid")
101
+ for item in revisions:
102
+ if isinstance(item, dict) and item.get("revision") == revision:
103
+ return item
104
+ raise ValueError("extension active revision is missing")
105
+
106
+
107
+ def _retain_revisions(
108
+ revisions: list[dict[str, Any]],
109
+ new_revision: dict[str, Any],
110
+ *,
111
+ required_revision: str | None,
112
+ ) -> list[dict[str, Any]]:
113
+ deduplicated = [
114
+ item
115
+ for item in revisions
116
+ if item.get("revision") != new_revision.get("revision")
117
+ ]
118
+ required = next(
119
+ (
120
+ item
121
+ for item in deduplicated
122
+ if required_revision and item.get("revision") == required_revision
123
+ ),
124
+ None,
125
+ )
126
+ retained = [*deduplicated, new_revision][-MAX_REVISIONS:]
127
+ if required is not None and required not in retained:
128
+ retained = [required, *retained[-(MAX_REVISIONS - 1) :]]
129
+ return retained
130
+
131
+
132
+ def install_extension(
133
+ manifest_path: str | Path,
134
+ *,
135
+ state_file: str | Path,
136
+ operation: str = "install",
137
+ execute: bool = False,
138
+ ) -> dict[str, Any]:
139
+ if operation not in {"install", "upgrade"}:
140
+ raise ValueError("extension operation must be install or upgrade")
141
+ manifest = load_extension_manifest(manifest_path)
142
+ _runtime(manifest)
143
+ provider = manifest["provider"]
144
+ extension_id = str(provider["id"])
145
+ revision = _revision(manifest)
146
+ doctor = extension_doctor(manifest, execute=execute)
147
+ if execute and not doctor["verified"]:
148
+ raise ValueError(
149
+ f"extension `{extension_id}` doctor is not ready: {doctor['status']}"
150
+ )
151
+ path = Path(state_file).expanduser()
152
+ changed = False
153
+ lock = exclusive_file_lock(path) if execute else nullcontext()
154
+ with lock:
155
+ state = _read_state(path)
156
+ extensions = state["extensions"]
157
+ existing = extensions.get(extension_id)
158
+ if operation == "install" and existing is not None:
159
+ raise ValueError(f"extension `{extension_id}` is already installed")
160
+ if operation == "upgrade" and not isinstance(existing, dict):
161
+ raise ValueError(f"extension `{extension_id}` is not installed")
162
+ if isinstance(existing, dict) and existing.get("active_revision") == revision:
163
+ raise ValueError(f"extension `{extension_id}` revision is already active")
164
+ previous_revision = (
165
+ str(existing.get("active_revision")) if isinstance(existing, dict) else None
166
+ )
167
+ if execute:
168
+ revisions = (
169
+ list(existing.get("revisions") or [])
170
+ if isinstance(existing, dict)
171
+ else []
172
+ )
173
+ revisions = _retain_revisions(
174
+ revisions,
175
+ {
176
+ "revision": revision,
177
+ "version": provider["version"],
178
+ "manifest": _manifest_snapshot(manifest),
179
+ },
180
+ required_revision=previous_revision,
181
+ )
182
+ extensions[extension_id] = {
183
+ "id": extension_id,
184
+ "enabled": True,
185
+ "active_revision": revision,
186
+ "rollback_revision": previous_revision,
187
+ "doctor_verified_revision": revision,
188
+ "doctor_verified_entrypoint_identity": doctor["entrypoint_identity"],
189
+ "revisions": revisions,
190
+ }
191
+ _write_state(path, state)
192
+ changed = True
193
+ return {
194
+ "ok": True,
195
+ "schema_version": EXTENSION_OPERATION_SCHEMA_VERSION,
196
+ "operation": operation,
197
+ "dry_run": not execute,
198
+ "changed": changed,
199
+ "extension_id": extension_id,
200
+ "version": provider["version"],
201
+ "revision": revision,
202
+ "previous_revision": previous_revision,
203
+ "enabled": True if execute else None,
204
+ "doctor": doctor,
205
+ "rollback_available": previous_revision is not None,
206
+ }
207
+
208
+
209
+ def enable_extension(
210
+ extension_id: str,
211
+ *,
212
+ state_file: str | Path,
213
+ execute: bool = False,
214
+ ) -> dict[str, Any]:
215
+ path = Path(state_file).expanduser()
216
+ state = _read_state(path)
217
+ entry = state["extensions"].get(extension_id)
218
+ if not isinstance(entry, dict):
219
+ raise ValueError(f"extension `{extension_id}` is not installed")
220
+ active_revision = str(entry.get("active_revision") or "")
221
+ snapshot = _entry_for_revision(entry, active_revision)
222
+ manifest = snapshot.get("manifest")
223
+ if not isinstance(manifest, Mapping):
224
+ raise ValueError("extension active manifest is invalid")
225
+ already_enabled = bool(entry.get("enabled"))
226
+ doctor = extension_doctor(manifest, execute=execute)
227
+ if execute and not doctor["verified"]:
228
+ with exclusive_file_lock(path):
229
+ current_state = _read_state(path)
230
+ current_entry = current_state["extensions"].get(extension_id)
231
+ if (
232
+ not isinstance(current_entry, dict)
233
+ or current_entry.get("active_revision") != active_revision
234
+ or bool(current_entry.get("enabled")) != already_enabled
235
+ ):
236
+ raise ValueError("extension state changed during enable; retry")
237
+ current_entry.pop("doctor_verified_revision", None)
238
+ current_entry.pop("doctor_verified_entrypoint_identity", None)
239
+ _write_state(path, current_state)
240
+ raise ValueError(
241
+ f"extension `{extension_id}` enable doctor is not ready: {doctor['status']}"
242
+ )
243
+ changed = False
244
+ if execute:
245
+ with exclusive_file_lock(path):
246
+ current_state = _read_state(path)
247
+ current_entry = current_state["extensions"].get(extension_id)
248
+ if (
249
+ not isinstance(current_entry, dict)
250
+ or current_entry.get("active_revision") != active_revision
251
+ or bool(current_entry.get("enabled")) != already_enabled
252
+ ):
253
+ raise ValueError("extension state changed during enable; retry")
254
+ current_entry["enabled"] = True
255
+ current_entry["doctor_verified_revision"] = active_revision
256
+ current_entry["doctor_verified_entrypoint_identity"] = doctor[
257
+ "entrypoint_identity"
258
+ ]
259
+ _write_state(path, current_state)
260
+ changed = not already_enabled
261
+ return {
262
+ "ok": True,
263
+ "schema_version": EXTENSION_OPERATION_SCHEMA_VERSION,
264
+ "operation": "enable",
265
+ "dry_run": not execute,
266
+ "changed": changed,
267
+ "would_change": not already_enabled,
268
+ "extension_id": extension_id,
269
+ "enabled": True if execute else already_enabled,
270
+ "active_revision": active_revision,
271
+ "doctor": doctor,
272
+ }
273
+
274
+
275
+ def disable_extension(
276
+ extension_id: str,
277
+ *,
278
+ state_file: str | Path,
279
+ execute: bool = False,
280
+ ) -> dict[str, Any]:
281
+ path = Path(state_file).expanduser()
282
+ lock = exclusive_file_lock(path) if execute else nullcontext()
283
+ with lock:
284
+ state = _read_state(path)
285
+ entry = state["extensions"].get(extension_id)
286
+ if not isinstance(entry, dict):
287
+ raise ValueError(f"extension `{extension_id}` is not installed")
288
+ changed = bool(entry.get("enabled"))
289
+ if execute and changed:
290
+ entry["enabled"] = False
291
+ _write_state(path, state)
292
+ return {
293
+ "ok": True,
294
+ "schema_version": EXTENSION_OPERATION_SCHEMA_VERSION,
295
+ "operation": "disable",
296
+ "dry_run": not execute,
297
+ "changed": changed if execute else False,
298
+ "would_change": changed,
299
+ "extension_id": extension_id,
300
+ "enabled": False if execute else bool(entry.get("enabled")),
301
+ "active_revision": entry.get("active_revision"),
302
+ }
303
+
304
+
305
+ def rollback_extension(
306
+ extension_id: str,
307
+ *,
308
+ state_file: str | Path,
309
+ execute: bool = False,
310
+ ) -> dict[str, Any]:
311
+ path = Path(state_file).expanduser()
312
+ state = _read_state(path)
313
+ entry = state["extensions"].get(extension_id)
314
+ if not isinstance(entry, dict):
315
+ raise ValueError(f"extension `{extension_id}` is not installed")
316
+ target_revision = str(entry.get("rollback_revision") or "")
317
+ if not target_revision:
318
+ raise ValueError(f"extension `{extension_id}` has no rollback revision")
319
+ target = _entry_for_revision(entry, target_revision)
320
+ manifest = target.get("manifest")
321
+ if not isinstance(manifest, dict):
322
+ raise ValueError("extension rollback manifest is invalid")
323
+ doctor = extension_doctor(manifest, execute=execute)
324
+ if execute and not doctor["verified"]:
325
+ raise ValueError(
326
+ f"extension `{extension_id}` rollback doctor is not ready: {doctor['status']}"
327
+ )
328
+ previous_revision = str(entry.get("active_revision") or "")
329
+ if execute:
330
+ with exclusive_file_lock(path):
331
+ current_state = _read_state(path)
332
+ current_entry = current_state["extensions"].get(extension_id)
333
+ if not isinstance(current_entry, dict):
334
+ raise ValueError(f"extension `{extension_id}` is not installed")
335
+ if (
336
+ current_entry.get("active_revision") != previous_revision
337
+ or current_entry.get("rollback_revision") != target_revision
338
+ ):
339
+ raise ValueError("extension state changed during rollback; retry")
340
+ current_entry["active_revision"] = target_revision
341
+ current_entry["rollback_revision"] = previous_revision
342
+ current_entry["doctor_verified_revision"] = target_revision
343
+ current_entry["doctor_verified_entrypoint_identity"] = doctor[
344
+ "entrypoint_identity"
345
+ ]
346
+ current_entry["enabled"] = True
347
+ _write_state(path, current_state)
348
+ return {
349
+ "ok": True,
350
+ "schema_version": EXTENSION_OPERATION_SCHEMA_VERSION,
351
+ "operation": "rollback",
352
+ "dry_run": not execute,
353
+ "changed": execute,
354
+ "extension_id": extension_id,
355
+ "version": target.get("version"),
356
+ "revision": target_revision,
357
+ "previous_revision": previous_revision,
358
+ "enabled": True if execute else bool(entry.get("enabled")),
359
+ "doctor": doctor,
360
+ }
361
+
362
+
363
+ def extension_status(
364
+ *,
365
+ state_file: str | Path,
366
+ extension_id: str | None = None,
367
+ ) -> dict[str, Any]:
368
+ state = _read_state(Path(state_file).expanduser())
369
+ entries = state["extensions"]
370
+ if extension_id is not None:
371
+ entry = entries.get(extension_id)
372
+ if not isinstance(entry, dict):
373
+ raise ValueError(f"extension `{extension_id}` is not installed")
374
+ visible = [entry]
375
+ else:
376
+ visible = [entry for entry in entries.values() if isinstance(entry, dict)]
377
+ return {
378
+ "ok": True,
379
+ "schema_version": EXTENSION_STATE_SCHEMA_VERSION,
380
+ "extensions": [
381
+ {
382
+ "id": entry.get("id"),
383
+ "enabled": bool(entry.get("enabled")),
384
+ "active_revision": entry.get("active_revision"),
385
+ "rollback_available": bool(entry.get("rollback_revision")),
386
+ "doctor_verified": bool(entry.get("enabled"))
387
+ and _verified_entrypoint(entry) is not None,
388
+ "revision_count": len(entry.get("revisions") or []),
389
+ }
390
+ for entry in visible
391
+ ],
392
+ }
393
+
394
+
395
+ def doctor_installed_extension(
396
+ extension_id: str,
397
+ *,
398
+ state_file: str | Path,
399
+ execute: bool = False,
400
+ ) -> dict[str, Any]:
401
+ path = Path(state_file).expanduser()
402
+ state = _read_state(path)
403
+ entry = state["extensions"].get(extension_id)
404
+ if not isinstance(entry, dict):
405
+ raise ValueError(f"extension `{extension_id}` is not installed")
406
+ if not entry.get("enabled"):
407
+ return {
408
+ "ok": True,
409
+ "schema_version": EXTENSION_DOCTOR_SCHEMA_VERSION,
410
+ "extension_id": extension_id,
411
+ "status": "disabled",
412
+ "available": False,
413
+ "verified": False,
414
+ "entrypoint_identity": None,
415
+ "failure_kind": None,
416
+ "external_writes_performed": False,
417
+ }
418
+ active_revision = str(entry.get("active_revision") or "")
419
+ snapshot = _entry_for_revision(entry, active_revision)
420
+ manifest = snapshot.get("manifest")
421
+ if not isinstance(manifest, Mapping):
422
+ raise ValueError("extension active manifest is invalid")
423
+ doctor = extension_doctor(manifest, execute=execute)
424
+ if execute:
425
+ with exclusive_file_lock(path):
426
+ current_state = _read_state(path)
427
+ current_entry = current_state["extensions"].get(extension_id)
428
+ if (
429
+ not isinstance(current_entry, dict)
430
+ or current_entry.get("active_revision") != active_revision
431
+ or not current_entry.get("enabled")
432
+ ):
433
+ raise ValueError("extension state changed during doctor; retry")
434
+ if doctor["verified"]:
435
+ current_entry["doctor_verified_revision"] = active_revision
436
+ current_entry["doctor_verified_entrypoint_identity"] = doctor[
437
+ "entrypoint_identity"
438
+ ]
439
+ else:
440
+ current_entry.pop("doctor_verified_revision", None)
441
+ current_entry.pop("doctor_verified_entrypoint_identity", None)
442
+ _write_state(path, current_state)
443
+ return doctor
444
+
445
+
446
+ def _verified_entrypoint(
447
+ entry: Mapping[str, Any],
448
+ ) -> ResolvedRuntimeEntrypoint | None:
449
+ active_revision = str(entry.get("active_revision") or "")
450
+ if entry.get("doctor_verified_revision") != active_revision:
451
+ return None
452
+ try:
453
+ snapshot = _entry_for_revision(entry, active_revision)
454
+ except ValueError:
455
+ return None
456
+ manifest = snapshot.get("manifest")
457
+ if not isinstance(manifest, Mapping):
458
+ return None
459
+ runtime = _runtime(manifest)
460
+ identity = resolve_runtime_entrypoint(runtime)
461
+ if identity is None or identity.identity != entry.get(
462
+ "doctor_verified_entrypoint_identity"
463
+ ):
464
+ return None
465
+ return identity
466
+
467
+
468
+ def _active_manifest(entry: Mapping[str, Any]) -> Mapping[str, Any]:
469
+ active_revision = str(entry.get("active_revision") or "")
470
+ snapshot = _entry_for_revision(entry, active_revision)
471
+ manifest = snapshot.get("manifest")
472
+ if not isinstance(manifest, Mapping):
473
+ raise ValueError("extension active manifest is invalid")
474
+ return manifest
475
+
476
+
477
+ def extension_catalog_entries(
478
+ extension_manifest_paths: Iterable[str | Path] = (),
479
+ *,
480
+ state_file: str | Path | None = None,
481
+ ) -> list[dict[str, Any]]:
482
+ """Compose declared manifests with installed runtime lifecycle state."""
483
+
484
+ manifests: dict[str, Mapping[str, Any]] = {}
485
+ lifecycle: dict[str, dict[str, Any]] = {}
486
+ for manifest_path in extension_manifest_paths:
487
+ manifest = load_extension_manifest(manifest_path)
488
+ extension_id = str(manifest["provider"]["id"])
489
+ if extension_id in manifests:
490
+ raise ValueError(f"duplicate capability provider `{extension_id}`")
491
+ manifests[extension_id] = manifest
492
+ lifecycle[extension_id] = {
493
+ "declared": True,
494
+ "installed": False,
495
+ "enabled": False,
496
+ "ready": False,
497
+ }
498
+
499
+ if state_file is not None:
500
+ state = _read_state(Path(state_file).expanduser())
501
+ for extension_id, entry in state["extensions"].items():
502
+ if not isinstance(entry, Mapping):
503
+ raise ValueError(f"extension `{extension_id}` runtime entry is invalid")
504
+ manifest = _active_manifest(entry)
505
+ provider = manifest.get("provider")
506
+ if not isinstance(provider, Mapping) or provider.get("id") != extension_id:
507
+ raise ValueError(
508
+ f"extension `{extension_id}` active manifest is invalid"
509
+ )
510
+ manifests[extension_id] = manifest
511
+ enabled = bool(entry.get("enabled"))
512
+ lifecycle[extension_id] = {
513
+ "declared": True,
514
+ "installed": True,
515
+ "enabled": enabled,
516
+ "ready": enabled and _verified_entrypoint(entry) is not None,
517
+ "active_revision": str(entry.get("active_revision") or ""),
518
+ }
519
+
520
+ entries: list[dict[str, Any]] = []
521
+ for extension_id, manifest in manifests.items():
522
+ normalized = deepcopy(dict(manifest))
523
+ normalized["provider"] = (
524
+ deepcopy(dict(manifest["provider"])) | lifecycle[extension_id]
525
+ )
526
+ entries.append(normalized)
527
+ return entries
528
+
529
+
530
+ def resolve_capability_extension_id(
531
+ *,
532
+ state_file: str | Path,
533
+ capability_id: str,
534
+ protocol: str,
535
+ ) -> str:
536
+ """Resolve one ready extension implementation without caller aliases."""
537
+
538
+ matching: list[str] = []
539
+ for entry in extension_catalog_entries(state_file=state_file):
540
+ provider = entry.get("provider")
541
+ if not isinstance(provider, Mapping) or not provider.get("ready"):
542
+ continue
543
+ implementations = entry.get("implementations")
544
+ if not isinstance(implementations, list):
545
+ continue
546
+ if any(
547
+ isinstance(item, Mapping)
548
+ and item.get("capability_id") == capability_id
549
+ and item.get("protocol") == protocol
550
+ for item in implementations
551
+ ):
552
+ matching.append(str(entry["provider"]["id"]))
553
+ if not matching:
554
+ raise ValueError(
555
+ f"no enabled, doctor-ready extension implements `{capability_id}` "
556
+ f"with protocol `{protocol}`"
557
+ )
558
+ if len(matching) != 1:
559
+ raise ValueError(
560
+ f"multiple enabled, doctor-ready extensions implement `{capability_id}` "
561
+ f"with protocol `{protocol}`: {matching}"
562
+ )
563
+ return matching[0]
564
+
565
+
566
+ def _resolved_active_extension(
567
+ extension_id: str,
568
+ *,
569
+ state_file: str | Path,
570
+ ) -> tuple[str, ResolvedRuntimeEntrypoint, Mapping[str, Any]]:
571
+ state = _read_state(Path(state_file).expanduser())
572
+ entry = state["extensions"].get(extension_id)
573
+ if not isinstance(entry, dict):
574
+ raise ValueError(f"extension `{extension_id}` is not installed")
575
+ if not entry.get("enabled"):
576
+ raise ValueError(f"extension `{extension_id}` is disabled")
577
+ active_revision = str(entry.get("active_revision") or "")
578
+ verified_entrypoint = _verified_entrypoint(entry)
579
+ if verified_entrypoint is None:
580
+ raise ValueError(f"extension `{extension_id}` doctor readiness is stale")
581
+ manifest = _active_manifest(entry)
582
+ return active_revision, verified_entrypoint, manifest
583
+
584
+
585
+ def resolve_extension_activation(
586
+ extension_id: str,
587
+ *,
588
+ state_file: str | Path,
589
+ required_permissions: Sequence[str] = (),
590
+ ) -> dict[str, Any]:
591
+ """Resolve one enabled, revision-bound extension compatibility delegate."""
592
+
593
+ active_revision, _, manifest = _resolved_active_extension(
594
+ extension_id,
595
+ state_file=state_file,
596
+ )
597
+ provider = manifest.get("provider")
598
+ if not isinstance(provider, Mapping):
599
+ raise ValueError("extension active manifest is incomplete")
600
+ declared_permissions = {
601
+ str(permission)
602
+ for permission in provider.get("permissions") or []
603
+ if str(permission).strip()
604
+ }
605
+ required = {
606
+ str(permission).strip()
607
+ for permission in required_permissions
608
+ if str(permission).strip()
609
+ }
610
+ missing = sorted(required - declared_permissions)
611
+ if missing:
612
+ raise ValueError(
613
+ f"extension `{extension_id}` does not declare permissions {missing}"
614
+ )
615
+ return {
616
+ "schema_version": EXTENSION_ACTIVATION_SCHEMA_VERSION,
617
+ "extension_id": extension_id,
618
+ "provider_version": provider.get("version"),
619
+ "revision": active_revision,
620
+ "enabled": True,
621
+ "doctor_verified": True,
622
+ "required_permissions": sorted(required),
623
+ }
624
+
625
+
626
+ def resolve_extension_binding(
627
+ extension_id: str,
628
+ *,
629
+ state_file: str | Path,
630
+ capability_id: str,
631
+ protocol: str,
632
+ permission: str,
633
+ ) -> dict[str, Any]:
634
+ active_revision, verified_entrypoint, manifest = _resolved_active_extension(
635
+ extension_id,
636
+ state_file=state_file,
637
+ )
638
+ provider = manifest.get("provider")
639
+ runtime = _runtime(manifest)
640
+ implementations = manifest.get("implementations")
641
+ if not isinstance(provider, Mapping) or not isinstance(implementations, list):
642
+ raise ValueError("extension active manifest is incomplete")
643
+ if permission not in (provider.get("permissions") or []):
644
+ raise ValueError(
645
+ f"extension `{extension_id}` does not declare permission `{permission}`"
646
+ )
647
+ if permission not in (runtime.get("required_permissions") or []):
648
+ raise ValueError(
649
+ f"extension `{extension_id}` runtime does not require permission "
650
+ f"`{permission}`"
651
+ )
652
+ matching = [
653
+ item
654
+ for item in implementations
655
+ if isinstance(item, Mapping)
656
+ and item.get("capability_id") == capability_id
657
+ and item.get("protocol") == protocol
658
+ ]
659
+ if len(matching) != 1 or runtime.get("protocol") != protocol:
660
+ raise ValueError(
661
+ f"extension `{extension_id}` does not implement `{capability_id}` "
662
+ f"with protocol `{protocol}`"
663
+ )
664
+ return {
665
+ "schema_version": EXTENSION_BINDING_SCHEMA_VERSION,
666
+ "extension_id": extension_id,
667
+ "provider_version": provider.get("version"),
668
+ "revision": active_revision,
669
+ "protocol": protocol,
670
+ "argv": [*verified_entrypoint.argv_prefix, *(runtime.get("args") or [])],
671
+ "doctor_argv": [
672
+ *verified_entrypoint.argv_prefix,
673
+ *(runtime.get("args") or []),
674
+ *(runtime.get("doctor_args") or []),
675
+ ],
676
+ "timeout_seconds": runtime["timeout_seconds"],
677
+ }
678
+
679
+
680
+ def resolve_extension_runtime_binding(
681
+ extension_id: str,
682
+ *,
683
+ state_file: str | Path,
684
+ protocol: str,
685
+ permission: str,
686
+ ) -> dict[str, Any]:
687
+ """Resolve an extension runtime without coupling dispatch to capability metadata."""
688
+
689
+ active_revision, verified_entrypoint, manifest = _resolved_active_extension(
690
+ extension_id,
691
+ state_file=state_file,
692
+ )
693
+ provider = manifest.get("provider")
694
+ runtime = _runtime(manifest)
695
+ if not isinstance(provider, Mapping):
696
+ raise ValueError("extension active manifest is incomplete")
697
+ if permission not in (provider.get("permissions") or []):
698
+ raise ValueError(
699
+ f"extension `{extension_id}` does not declare permission `{permission}`"
700
+ )
701
+ if permission not in (runtime.get("required_permissions") or []):
702
+ raise ValueError(
703
+ f"extension `{extension_id}` runtime does not require permission "
704
+ f"`{permission}`"
705
+ )
706
+ if runtime.get("protocol") != protocol:
707
+ raise ValueError(
708
+ f"extension `{extension_id}` does not expose runtime protocol `{protocol}`"
709
+ )
710
+ return {
711
+ "schema_version": EXTENSION_BINDING_SCHEMA_VERSION,
712
+ "extension_id": extension_id,
713
+ "provider_version": provider.get("version"),
714
+ "revision": active_revision,
715
+ "protocol": protocol,
716
+ "argv": [*verified_entrypoint.argv_prefix, *(runtime.get("args") or [])],
717
+ "doctor_argv": [
718
+ *verified_entrypoint.argv_prefix,
719
+ *(runtime.get("args") or []),
720
+ *(runtime.get("doctor_args") or []),
721
+ ],
722
+ "timeout_seconds": runtime["timeout_seconds"],
723
+ }
724
+
725
+
726
+ def run_standalone_extension(
727
+ extension_id: str,
728
+ *,
729
+ state_file: str | Path,
730
+ request: Mapping[str, Any],
731
+ execute: bool = False,
732
+ ) -> dict[str, Any]:
733
+ """Run one lifecycle-gated standalone extension over bounded JSON stdin/stdout."""
734
+
735
+ active_revision, verified_entrypoint, manifest = _resolved_active_extension(
736
+ extension_id,
737
+ state_file=state_file,
738
+ )
739
+ provider = manifest.get("provider")
740
+ runtime = _runtime(manifest)
741
+ if not isinstance(provider, Mapping):
742
+ raise ValueError("extension active manifest is incomplete")
743
+ if manifest.get("capabilities") or manifest.get("implementations"):
744
+ raise ValueError(
745
+ "extension run only accepts standalone extensions; invoke capability "
746
+ "providers through their capability or domain command"
747
+ )
748
+ if not isinstance(request, Mapping):
749
+ raise ValueError("extension run request must be a JSON object")
750
+
751
+ required_permissions = [
752
+ str(value) for value in runtime.get("required_permissions") or []
753
+ ]
754
+ declared_permissions = {str(value) for value in provider.get("permissions") or []}
755
+ missing_permissions = sorted(set(required_permissions) - declared_permissions)
756
+ if missing_permissions:
757
+ raise ValueError(
758
+ f"extension `{extension_id}` does not declare permissions "
759
+ f"{missing_permissions}"
760
+ )
761
+ if declared_permissions:
762
+ raise ValueError(
763
+ f"extension `{extension_id}` declares permissions "
764
+ f"{sorted(declared_permissions)}; standalone extension run grants no "
765
+ "effect dispatch, so use a capability or domain command that owns "
766
+ "policy checks and a request-bound execution envelope"
767
+ )
768
+
769
+ try:
770
+ request_bytes = json.dumps(
771
+ dict(request),
772
+ ensure_ascii=False,
773
+ separators=(",", ":"),
774
+ ).encode("utf-8")
775
+ except (TypeError, ValueError) as exc:
776
+ raise ValueError("extension run request must be JSON serializable") from exc
777
+ if len(request_bytes) > MAX_EXTENSION_REQUEST_BYTES:
778
+ raise ValueError("extension run request exceeds the 1000000-byte limit")
779
+
780
+ receipt: dict[str, Any] = {
781
+ "ok": True,
782
+ "schema_version": EXTENSION_RUN_SCHEMA_VERSION,
783
+ "operation": "run",
784
+ "extension_id": extension_id,
785
+ "provider_version": provider.get("version"),
786
+ "revision": active_revision,
787
+ "protocol": runtime["protocol"],
788
+ "required_permissions": required_permissions,
789
+ "dry_run": not execute,
790
+ "executed": False,
791
+ "status": "ready" if not execute else "running",
792
+ "input_schema_version": request.get("schema_version"),
793
+ }
794
+ if not execute:
795
+ return receipt
796
+
797
+ argv = [*verified_entrypoint.argv_prefix, *(runtime.get("args") or [])]
798
+ try:
799
+ completed = run_capped_process(
800
+ argv,
801
+ stdin=request_bytes,
802
+ timeout_seconds=int(runtime["timeout_seconds"]),
803
+ output_limit_bytes=MAX_EXTENSION_RESPONSE_BYTES,
804
+ )
805
+ except OSError:
806
+ return {
807
+ **receipt,
808
+ "ok": False,
809
+ "executed": True,
810
+ "status": "provider_failed",
811
+ "failure_kind": "execution_failed",
812
+ "exit_code": None,
813
+ }
814
+ if completed.failure_kind is not None:
815
+ response_too_large = completed.failure_kind == "response_too_large"
816
+ return {
817
+ **receipt,
818
+ "ok": False,
819
+ "executed": True,
820
+ "status": (
821
+ "invalid_provider_output" if response_too_large else "provider_failed"
822
+ ),
823
+ "failure_kind": completed.failure_kind,
824
+ "exit_code": (
825
+ None if completed.failure_kind == "timeout" else completed.returncode
826
+ ),
827
+ }
828
+
829
+ try:
830
+ provider_result = json.loads(completed.stdout.decode("utf-8"))
831
+ except (UnicodeDecodeError, json.JSONDecodeError):
832
+ provider_result = None
833
+ if not isinstance(provider_result, dict):
834
+ return {
835
+ **receipt,
836
+ "ok": False,
837
+ "executed": True,
838
+ "status": "invalid_provider_output",
839
+ "failure_kind": "response_not_json_object",
840
+ "exit_code": completed.returncode,
841
+ }
842
+ succeeded = completed.returncode == 0 and provider_result.get("ok") is not False
843
+ return {
844
+ **receipt,
845
+ "ok": succeeded,
846
+ "executed": True,
847
+ "status": "succeeded" if succeeded else "provider_failed",
848
+ "exit_code": completed.returncode,
849
+ "provider_result": provider_result,
850
+ }
851
+
852
+
853
+ def resolve_capability_binding(
854
+ *,
855
+ state_file: str | Path,
856
+ capability_id: str,
857
+ protocol: str,
858
+ permission: str,
859
+ ) -> dict[str, Any]:
860
+ extension_id = resolve_capability_extension_id(
861
+ state_file=state_file,
862
+ capability_id=capability_id,
863
+ protocol=protocol,
864
+ )
865
+ return resolve_extension_binding(
866
+ extension_id,
867
+ state_file=state_file,
868
+ capability_id=capability_id,
869
+ protocol=protocol,
870
+ permission=permission,
871
+ )
872
+
873
+
874
+ def execute_extension_runtime_binding(
875
+ binding: Mapping[str, Any],
876
+ *,
877
+ request: Mapping[str, Any],
878
+ environment: Mapping[str, str] | None = None,
879
+ ) -> dict[str, Any]:
880
+ """Execute a resolved binding after its capability authorizes the request."""
881
+
882
+ if binding.get("schema_version") != EXTENSION_BINDING_SCHEMA_VERSION:
883
+ raise ValueError(
884
+ f"extension runtime binding must use {EXTENSION_BINDING_SCHEMA_VERSION}"
885
+ )
886
+ argv = binding.get("argv")
887
+ if (
888
+ not isinstance(argv, list)
889
+ or not argv
890
+ or not all(isinstance(value, str) and value for value in argv)
891
+ ):
892
+ raise ValueError("extension runtime binding argv is invalid")
893
+ try:
894
+ timeout_seconds = int(binding.get("timeout_seconds"))
895
+ except (TypeError, ValueError) as exc:
896
+ raise ValueError("extension runtime binding timeout is invalid") from exc
897
+ if not 1 <= timeout_seconds <= 120:
898
+ raise ValueError("extension runtime binding timeout is invalid")
899
+ try:
900
+ request_bytes = json.dumps(
901
+ dict(request),
902
+ ensure_ascii=False,
903
+ separators=(",", ":"),
904
+ ).encode("utf-8")
905
+ except (TypeError, ValueError) as exc:
906
+ raise ValueError("extension runtime request must be JSON serializable") from exc
907
+ if len(request_bytes) > MAX_EXTENSION_REQUEST_BYTES:
908
+ raise ValueError("extension runtime request exceeds the 1000000-byte limit")
909
+ try:
910
+ completed = run_capped_process(
911
+ argv,
912
+ stdin=request_bytes,
913
+ timeout_seconds=timeout_seconds,
914
+ output_limit_bytes=MAX_EXTENSION_RESPONSE_BYTES,
915
+ env=environment,
916
+ )
917
+ except OSError as exc:
918
+ raise RuntimeError("extension provider execution failed") from exc
919
+ if completed.failure_kind is not None:
920
+ raise RuntimeError(
921
+ f"extension provider execution failed: {completed.failure_kind}"
922
+ )
923
+ try:
924
+ provider_result = json.loads(completed.stdout.decode("utf-8"))
925
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
926
+ raise RuntimeError("extension provider returned invalid JSON") from exc
927
+ if not isinstance(provider_result, dict):
928
+ raise RuntimeError("extension provider returned a non-object")
929
+ if completed.returncode != 0 or provider_result.get("ok") is False:
930
+ raise RuntimeError("extension provider reported failure")
931
+ return provider_result