alysis-code 0.13.0__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 (458) hide show
  1. alysis_code/__init__.py +3 -0
  2. alysis_code/__main__.py +4 -0
  3. alysis_code/_build_info.py +14 -0
  4. alysis_code/account_login.py +468 -0
  5. alysis_code/agent/README.md +35 -0
  6. alysis_code/agent/__init__.py +11 -0
  7. alysis_code/agent/acceptance_contract.py +2217 -0
  8. alysis_code/agent/blast_radius.py +1403 -0
  9. alysis_code/agent/cache_keepalive.py +227 -0
  10. alysis_code/agent/completion_certificate.py +366 -0
  11. alysis_code/agent/completion_gate.py +306 -0
  12. alysis_code/agent/empty_response_stall.py +403 -0
  13. alysis_code/agent/errors.py +28 -0
  14. alysis_code/agent/llm_calls.py +475 -0
  15. alysis_code/agent/mutation_classification.py +227 -0
  16. alysis_code/agent/prompt_context.py +2508 -0
  17. alysis_code/agent/read_ledger.py +253 -0
  18. alysis_code/agent/regression_baseline.py +642 -0
  19. alysis_code/agent/reproduction_first.py +610 -0
  20. alysis_code/agent/sensitive_output.py +629 -0
  21. alysis_code/agent/session.py +3218 -0
  22. alysis_code/agent/steering.py +191 -0
  23. alysis_code/agent/subagent_execution.py +5177 -0
  24. alysis_code/agent/subagent_workspace.py +666 -0
  25. alysis_code/agent/tools_assembly.py +4728 -0
  26. alysis_code/agent/turn/__init__.py +101 -0
  27. alysis_code/agent/turn/core.py +8483 -0
  28. alysis_code/agent/turn/events.py +113 -0
  29. alysis_code/agent/turn/exploration.py +590 -0
  30. alysis_code/agent/turn/interventions.py +65 -0
  31. alysis_code/agent/turn/read_cache.py +420 -0
  32. alysis_code/agent/turn/snapshot.py +179 -0
  33. alysis_code/agent/turn_contract.py +661 -0
  34. alysis_code/agent/turn_path.py +129 -0
  35. alysis_code/agent/verification.py +2885 -0
  36. alysis_code/agent/verification_commands.py +512 -0
  37. alysis_code/agent/verification_evidence.py +738 -0
  38. alysis_code/agent_loop.py +693 -0
  39. alysis_code/agent_runtimes/__init__.py +51 -0
  40. alysis_code/agent_runtimes/base.py +114 -0
  41. alysis_code/agent_runtimes/builtins.py +129 -0
  42. alysis_code/agent_runtimes/codex_cli.py +664 -0
  43. alysis_code/agent_runtimes/host.py +263 -0
  44. alysis_code/agent_runtimes/registry.py +64 -0
  45. alysis_code/agent_runtimes/service.py +150 -0
  46. alysis_code/agentbox_client.py +416 -0
  47. alysis_code/agentbox_integration.py +310 -0
  48. alysis_code/alysis_cloud.py +152 -0
  49. alysis_code/approval_scope.py +276 -0
  50. alysis_code/assets/README.md +33 -0
  51. alysis_code/assets/__init__.py +126 -0
  52. alysis_code/assets/asset_read_core.py +281 -0
  53. alysis_code/assets/budget_allocator.py +456 -0
  54. alysis_code/assets/comprehender.py +759 -0
  55. alysis_code/assets/index.py +654 -0
  56. alysis_code/assets/ingestion.py +275 -0
  57. alysis_code/assets/legacy_migration.py +413 -0
  58. alysis_code/assets/models.py +263 -0
  59. alysis_code/assets/ocr.py +239 -0
  60. alysis_code/assets/owl/ascii/f-000.txt +13 -0
  61. alysis_code/assets/owl/ascii/f-001.txt +13 -0
  62. alysis_code/assets/owl/ascii/f-002.txt +13 -0
  63. alysis_code/assets/owl/ascii/f-003.txt +13 -0
  64. alysis_code/assets/owl/ascii/f-004.txt +13 -0
  65. alysis_code/assets/owl/ascii/f-005.txt +13 -0
  66. alysis_code/assets/owl/ascii/f-006.txt +13 -0
  67. alysis_code/assets/owl/ascii/f-007.txt +13 -0
  68. alysis_code/assets/owl/ascii/f-008.txt +13 -0
  69. alysis_code/assets/owl/ascii/f-009.txt +13 -0
  70. alysis_code/assets/owl/ascii/f-010.txt +13 -0
  71. alysis_code/assets/owl/ascii/f-011.txt +13 -0
  72. alysis_code/assets/owl/ascii/f-012.txt +13 -0
  73. alysis_code/assets/owl/ascii/f-013.txt +13 -0
  74. alysis_code/assets/owl/ascii/f-014.txt +13 -0
  75. alysis_code/assets/owl/ascii/f-015.txt +13 -0
  76. alysis_code/assets/owl/ascii/f-016.txt +13 -0
  77. alysis_code/assets/owl/ascii/f-017.txt +13 -0
  78. alysis_code/assets/owl/ascii/f-018.txt +13 -0
  79. alysis_code/assets/owl/ascii/f-019.txt +13 -0
  80. alysis_code/assets/owl/ascii/f-020.txt +13 -0
  81. alysis_code/assets/owl/index.html +98 -0
  82. alysis_code/assets/owl/show-owl.sh +761 -0
  83. alysis_code/assets/paths.py +49 -0
  84. alysis_code/assets/plan_binding.py +326 -0
  85. alysis_code/assets/planner_context.py +466 -0
  86. alysis_code/assets/planner_tools.py +184 -0
  87. alysis_code/assets/prompts.py +101 -0
  88. alysis_code/assets/replanner_context.py +239 -0
  89. alysis_code/assets/surface.py +521 -0
  90. alysis_code/assets/untrusted_content.py +48 -0
  91. alysis_code/assets/usage_logger.py +94 -0
  92. alysis_code/assets/worker_mirror.py +428 -0
  93. alysis_code/assets/worker_section.py +303 -0
  94. alysis_code/assets/worker_tools.py +468 -0
  95. alysis_code/atomic_io.py +83 -0
  96. alysis_code/auth_diagnostics.py +272 -0
  97. alysis_code/background_runner.py +366 -0
  98. alysis_code/branding.py +270 -0
  99. alysis_code/budget_policy.py +390 -0
  100. alysis_code/build_identity.py +465 -0
  101. alysis_code/builtin_hooks/__init__.py +7 -0
  102. alysis_code/builtin_hooks/notify_done_windows.py +65 -0
  103. alysis_code/bwrap_etc.py +76 -0
  104. alysis_code/cancellation.py +41 -0
  105. alysis_code/capabilities.py +137 -0
  106. alysis_code/chatgpt_codex_static_provider.py +133 -0
  107. alysis_code/cli.py +51 -0
  108. alysis_code/cli_impl/__init__.py +1 -0
  109. alysis_code/cli_impl/assets_cli.py +537 -0
  110. alysis_code/cli_impl/assets_modal.py +412 -0
  111. alysis_code/cli_impl/chat/__init__.py +156 -0
  112. alysis_code/cli_impl/chat/commands.py +2616 -0
  113. alysis_code/cli_impl/chat/loop.py +4508 -0
  114. alysis_code/cli_impl/chat/mid_turn_policy.py +125 -0
  115. alysis_code/cli_impl/chat/rendering.py +444 -0
  116. alysis_code/cli_impl/chat/state.py +124 -0
  117. alysis_code/cli_impl/chat_resume.py +830 -0
  118. alysis_code/cli_impl/chat_slash_completer.py +258 -0
  119. alysis_code/cli_impl/commands/__init__.py +11 -0
  120. alysis_code/cli_impl/commands/_shared.py +89 -0
  121. alysis_code/cli_impl/commands/auth.py +623 -0
  122. alysis_code/cli_impl/commands/chat_resume_helpers.py +1531 -0
  123. alysis_code/cli_impl/commands/chat_state.py +158 -0
  124. alysis_code/cli_impl/commands/chat_status.py +1248 -0
  125. alysis_code/cli_impl/commands/chat_terminal.py +942 -0
  126. alysis_code/cli_impl/commands/chat_tui_panels.py +1018 -0
  127. alysis_code/cli_impl/commands/cli_common.py +1223 -0
  128. alysis_code/cli_impl/commands/cli_surface.py +77 -0
  129. alysis_code/cli_impl/commands/config.py +131 -0
  130. alysis_code/cli_impl/commands/conventions.py +85 -0
  131. alysis_code/cli_impl/commands/execution_helpers.py +350 -0
  132. alysis_code/cli_impl/commands/extensions.py +401 -0
  133. alysis_code/cli_impl/commands/forge.py +1282 -0
  134. alysis_code/cli_impl/commands/forge_asset_view.py +121 -0
  135. alysis_code/cli_impl/commands/forge_helpers.py +1215 -0
  136. alysis_code/cli_impl/commands/hooks.py +737 -0
  137. alysis_code/cli_impl/commands/ide_bridge.py +31 -0
  138. alysis_code/cli_impl/commands/mcp.py +700 -0
  139. alysis_code/cli_impl/commands/profile.py +453 -0
  140. alysis_code/cli_impl/commands/prompt_helpers.py +307 -0
  141. alysis_code/cli_impl/commands/report.py +88 -0
  142. alysis_code/cli_impl/commands/root.py +1118 -0
  143. alysis_code/cli_impl/commands/sandbox.py +184 -0
  144. alysis_code/cli_impl/commands/server.py +54 -0
  145. alysis_code/cli_impl/commands/sessions.py +252 -0
  146. alysis_code/cli_impl/commands/skills.py +404 -0
  147. alysis_code/cli_impl/commands/startup.py +946 -0
  148. alysis_code/cli_impl/commands/tools.py +335 -0
  149. alysis_code/cli_impl/commands/update.py +364 -0
  150. alysis_code/cli_impl/commands/welcome.py +972 -0
  151. alysis_code/cli_impl/config_menu.py +3882 -0
  152. alysis_code/cli_impl/forge.py +4509 -0
  153. alysis_code/cli_impl/forge_recovery.py +485 -0
  154. alysis_code/cli_impl/setup_wizard.py +2409 -0
  155. alysis_code/cli_impl/tui/__init__.py +58 -0
  156. alysis_code/cli_impl/tui/app.py +4551 -0
  157. alysis_code/cli_impl/tui/config.py +32 -0
  158. alysis_code/cli_impl/tui/config_flow.py +2754 -0
  159. alysis_code/cli_impl/tui/config_overlay.py +566 -0
  160. alysis_code/cli_impl/tui/content.py +78 -0
  161. alysis_code/cli_impl/tui/footer.py +218 -0
  162. alysis_code/cli_impl/tui/forge_status.py +136 -0
  163. alysis_code/cli_impl/tui/markdown.py +244 -0
  164. alysis_code/cli_impl/tui/owl.py +109 -0
  165. alysis_code/cli_impl/tui/plan_meta.py +477 -0
  166. alysis_code/cli_impl/tui/setup_app.py +519 -0
  167. alysis_code/cli_impl/tui/setup_flow.py +1622 -0
  168. alysis_code/cli_impl/tui/state.py +101 -0
  169. alysis_code/cli_impl/tui/subagent_identity.py +66 -0
  170. alysis_code/cli_impl/tui/subagent_panel.py +186 -0
  171. alysis_code/cli_impl/tui/surface.py +796 -0
  172. alysis_code/cli_impl/tui/transcript.py +514 -0
  173. alysis_code/cli_impl/tui/update_prompt.py +79 -0
  174. alysis_code/cli_impl/tui/workspace_guard.py +384 -0
  175. alysis_code/clipboard.py +172 -0
  176. alysis_code/code_review.py +1211 -0
  177. alysis_code/compaction/__init__.py +28 -0
  178. alysis_code/compaction/conversation_compactor.py +2932 -0
  179. alysis_code/compaction/importance.py +177 -0
  180. alysis_code/compaction/settings.py +297 -0
  181. alysis_code/compaction/tool_output_offload.py +447 -0
  182. alysis_code/config.py +3509 -0
  183. alysis_code/conflict_auto_resolver.py +895 -0
  184. alysis_code/context/__init__.py +1 -0
  185. alysis_code/context/tool_schema_budgeter.py +220 -0
  186. alysis_code/crash_diagnostics.py +282 -0
  187. alysis_code/custom_tools/README.md +34 -0
  188. alysis_code/custom_tools/__init__.py +43 -0
  189. alysis_code/custom_tools/discovery.py +903 -0
  190. alysis_code/custom_tools/runtime.py +1516 -0
  191. alysis_code/custom_tools/session.py +227 -0
  192. alysis_code/custom_tools/trust.py +232 -0
  193. alysis_code/diff_paths.py +113 -0
  194. alysis_code/direction_change.py +293 -0
  195. alysis_code/dispatch_timing.py +306 -0
  196. alysis_code/durable_service_manager.py +1236 -0
  197. alysis_code/edit_discipline.py +659 -0
  198. alysis_code/error_text.py +73 -0
  199. alysis_code/execution_budget.py +411 -0
  200. alysis_code/execution_context.py +915 -0
  201. alysis_code/execution_deadline.py +1065 -0
  202. alysis_code/execution_shared.py +1904 -0
  203. alysis_code/extensions/README.md +30 -0
  204. alysis_code/extensions/__init__.py +93 -0
  205. alysis_code/extensions/activation.py +138 -0
  206. alysis_code/extensions/install.py +1436 -0
  207. alysis_code/extensions/manifest.py +487 -0
  208. alysis_code/extensions/models.py +74 -0
  209. alysis_code/extensions/paths.py +56 -0
  210. alysis_code/extensions/registry.json +4 -0
  211. alysis_code/extensions/registry.py +52 -0
  212. alysis_code/extensions/state.py +83 -0
  213. alysis_code/extensions/workspace_trust.py +101 -0
  214. alysis_code/failed_task_evidence.py +369 -0
  215. alysis_code/failure_category.py +315 -0
  216. alysis_code/feedback_report.py +1647 -0
  217. alysis_code/file_classification.py +485 -0
  218. alysis_code/forge.py +2064 -0
  219. alysis_code/forge_completion.py +362 -0
  220. alysis_code/forge_events.py +475 -0
  221. alysis_code/frontmatter_utils.py +95 -0
  222. alysis_code/git_evidence.py +1181 -0
  223. alysis_code/git_ops.py +560 -0
  224. alysis_code/git_safe.py +62 -0
  225. alysis_code/git_worktrees.py +190 -0
  226. alysis_code/hooks/README.md +33 -0
  227. alysis_code/hooks/__init__.py +67 -0
  228. alysis_code/hooks/audit.py +171 -0
  229. alysis_code/hooks/config.py +225 -0
  230. alysis_code/hooks/dispatcher.py +1110 -0
  231. alysis_code/hooks/models.py +447 -0
  232. alysis_code/hooks/trust.py +202 -0
  233. alysis_code/host_actions.py +543 -0
  234. alysis_code/host_browser.py +103 -0
  235. alysis_code/ide/__init__.py +5 -0
  236. alysis_code/ide/activity_events.py +399 -0
  237. alysis_code/ide/approvals.py +337 -0
  238. alysis_code/ide/artifacts.py +153 -0
  239. alysis_code/ide/browser_egress_proxy.py +1076 -0
  240. alysis_code/ide/cdp_websocket_transport.py +1192 -0
  241. alysis_code/ide/change_ledger.py +1721 -0
  242. alysis_code/ide/context_blocks.py +979 -0
  243. alysis_code/ide/event_stream.py +531 -0
  244. alysis_code/ide/forge_protocol.py +3112 -0
  245. alysis_code/ide/forge_request_ledger.py +737 -0
  246. alysis_code/ide/health.py +965 -0
  247. alysis_code/ide/managed_browser.py +2251 -0
  248. alysis_code/ide/management_protocol.py +3414 -0
  249. alysis_code/ide/mcp_oauth_coordinator.py +744 -0
  250. alysis_code/ide/mcp_oauth_lifecycle.py +1504 -0
  251. alysis_code/ide/prompt_queue.py +1070 -0
  252. alysis_code/ide/protocol.py +191 -0
  253. alysis_code/ide/resumable_swarm.py +1543 -0
  254. alysis_code/ide/session_search.py +295 -0
  255. alysis_code/ide/stdio_bridge.py +9935 -0
  256. alysis_code/ide/structured_state.py +1579 -0
  257. alysis_code/ide/swarm_protocol.py +816 -0
  258. alysis_code/integration_gate.py +506 -0
  259. alysis_code/interactive_input_guard.py +39 -0
  260. alysis_code/interactive_plan_mode.py +26 -0
  261. alysis_code/internal_artifacts.py +179 -0
  262. alysis_code/knowledge_base.py +1409 -0
  263. alysis_code/knowledge_capture.py +1190 -0
  264. alysis_code/knowledge_librarian.py +605 -0
  265. alysis_code/language_policy.py +34 -0
  266. alysis_code/litellm_static_provider.py +535 -0
  267. alysis_code/llm/__init__.py +1 -0
  268. alysis_code/llm/anthropic_messages.py +2288 -0
  269. alysis_code/llm/base.py +71 -0
  270. alysis_code/llm/cache_capabilities.py +985 -0
  271. alysis_code/llm/cache_control_blocks.py +244 -0
  272. alysis_code/llm/cache_policy.py +388 -0
  273. alysis_code/llm/factory.py +373 -0
  274. alysis_code/llm/gemini_generate_content.py +2652 -0
  275. alysis_code/llm/gemini_interactions.py +739 -0
  276. alysis_code/llm/metadata.py +450 -0
  277. alysis_code/llm/openai_compat.py +2947 -0
  278. alysis_code/llm/openai_responses.py +2604 -0
  279. alysis_code/llm/protocols.py +609 -0
  280. alysis_code/llm/provider_limits.py +525 -0
  281. alysis_code/llm/request_plan.py +389 -0
  282. alysis_code/llm/request_shape.py +238 -0
  283. alysis_code/llm/streaming.py +108 -0
  284. alysis_code/llm/temperature_compat.py +78 -0
  285. alysis_code/llm/types.py +195 -0
  286. alysis_code/llm/usage_normalization.py +222 -0
  287. alysis_code/llm_error_display.py +315 -0
  288. alysis_code/logging_redaction.py +326 -0
  289. alysis_code/managed_host_deadline.py +196 -0
  290. alysis_code/mcp/README.md +33 -0
  291. alysis_code/mcp/__init__.py +24 -0
  292. alysis_code/mcp/client.py +1137 -0
  293. alysis_code/mcp/config.py +597 -0
  294. alysis_code/mcp/errors.py +113 -0
  295. alysis_code/mcp/forge_scope.py +154 -0
  296. alysis_code/mcp/jsonrpc.py +214 -0
  297. alysis_code/mcp/manager.py +2308 -0
  298. alysis_code/mcp/models.py +666 -0
  299. alysis_code/mcp/oauth.py +972 -0
  300. alysis_code/mcp/oauth_runtime.py +310 -0
  301. alysis_code/mcp/oauth_store.py +276 -0
  302. alysis_code/mcp/prompts.py +329 -0
  303. alysis_code/mcp/resources.py +295 -0
  304. alysis_code/mcp/roots.py +106 -0
  305. alysis_code/mcp/server_requests.py +75 -0
  306. alysis_code/mcp/token_store.py +859 -0
  307. alysis_code/mcp/transport_http.py +1338 -0
  308. alysis_code/mcp/transport_stdio.py +1267 -0
  309. alysis_code/mcp/untrusted_content.py +119 -0
  310. alysis_code/merge_conflict_reviewer.py +729 -0
  311. alysis_code/model_catalog/__init__.py +1 -0
  312. alysis_code/model_catalog/chatgpt_codex_subscription_snapshot.json +186 -0
  313. alysis_code/model_catalog/litellm_model_prices_snapshot.json +44715 -0
  314. alysis_code/model_catalog/litellm_model_prices_snapshot.meta.json +17 -0
  315. alysis_code/model_metadata_policy.py +223 -0
  316. alysis_code/model_metadata_utils.py +103 -0
  317. alysis_code/model_registry.py +1420 -0
  318. alysis_code/model_router.py +147 -0
  319. alysis_code/permission_policy.py +1016 -0
  320. alysis_code/personas.py +451 -0
  321. alysis_code/pipeline_facts.py +233 -0
  322. alysis_code/plan_assistant.py +4763 -0
  323. alysis_code/plan_mode.py +393 -0
  324. alysis_code/plan_reconciliation.py +1228 -0
  325. alysis_code/plan_repair.py +652 -0
  326. alysis_code/plan_validation.py +1099 -0
  327. alysis_code/planning_constraints.py +904 -0
  328. alysis_code/policy.py +95 -0
  329. alysis_code/preview_server.py +457 -0
  330. alysis_code/process_reaping.py +566 -0
  331. alysis_code/profile_presets.py +1834 -0
  332. alysis_code/profiles.py +666 -0
  333. alysis_code/provider_auth/__init__.py +29 -0
  334. alysis_code/provider_auth/base.py +99 -0
  335. alysis_code/provider_auth/openai_codex.py +951 -0
  336. alysis_code/provider_auth/registry.py +76 -0
  337. alysis_code/provider_auth/store.py +125 -0
  338. alysis_code/provider_diagnostics.py +1209 -0
  339. alysis_code/provider_model_catalog.py +685 -0
  340. alysis_code/provider_telemetry.py +1699 -0
  341. alysis_code/provider_url.py +75 -0
  342. alysis_code/reasoning_contracts.py +911 -0
  343. alysis_code/remote_sync.py +350 -0
  344. alysis_code/replanning.py +1195 -0
  345. alysis_code/repo_scan.py +1152 -0
  346. alysis_code/request_estimation.py +296 -0
  347. alysis_code/review_gate.py +617 -0
  348. alysis_code/run_lock.py +1141 -0
  349. alysis_code/run_outcome.py +58 -0
  350. alysis_code/run_provenance.py +774 -0
  351. alysis_code/run_state.py +445 -0
  352. alysis_code/runtime_artifacts.py +116 -0
  353. alysis_code/runtime_context_features.py +78 -0
  354. alysis_code/runtime_kind.py +52 -0
  355. alysis_code/safety/__init__.py +11 -0
  356. alysis_code/safety/mcp_sanitize.py +29 -0
  357. alysis_code/safety/safe_http.py +297 -0
  358. alysis_code/safety/subagent_report.py +184 -0
  359. alysis_code/sandbox_doctor.py +682 -0
  360. alysis_code/sandbox_runner.py +1025 -0
  361. alysis_code/sandbox_settings.py +423 -0
  362. alysis_code/serialized_paths.py +355 -0
  363. alysis_code/server/__init__.py +3 -0
  364. alysis_code/server/app.py +367 -0
  365. alysis_code/server/auth.py +34 -0
  366. alysis_code/server/job_config.py +30 -0
  367. alysis_code/server/settings.py +215 -0
  368. alysis_code/server/store.py +193 -0
  369. alysis_code/server/worker_runner.py +657 -0
  370. alysis_code/service_persistence.py +355 -0
  371. alysis_code/session_artifacts.py +108 -0
  372. alysis_code/session_metrics.py +331 -0
  373. alysis_code/session_store.py +624 -0
  374. alysis_code/skills/README.md +34 -0
  375. alysis_code/skills/__init__.py +104 -0
  376. alysis_code/skills/conventions.py +84 -0
  377. alysis_code/skills/discovery.py +176 -0
  378. alysis_code/skills/eval_models.py +232 -0
  379. alysis_code/skills/eval_runner.py +372 -0
  380. alysis_code/skills/evals.py +1344 -0
  381. alysis_code/skills/install.py +293 -0
  382. alysis_code/skills/loader.py +118 -0
  383. alysis_code/skills/matching.py +103 -0
  384. alysis_code/skills/models.py +71 -0
  385. alysis_code/skills/paths.py +56 -0
  386. alysis_code/skills/prompting.py +500 -0
  387. alysis_code/skills/scaffold.py +142 -0
  388. alysis_code/skills/state.py +441 -0
  389. alysis_code/skills/transactions.py +125 -0
  390. alysis_code/skills/validation.py +304 -0
  391. alysis_code/step_budget.py +238 -0
  392. alysis_code/subagent_labels.py +49 -0
  393. alysis_code/subagents.py +1072 -0
  394. alysis_code/surface/__init__.py +80 -0
  395. alysis_code/surface/base.py +305 -0
  396. alysis_code/surface/console.py +387 -0
  397. alysis_code/surface/events.py +372 -0
  398. alysis_code/surface/hidden_surface.py +529 -0
  399. alysis_code/surface/noop_surface.py +219 -0
  400. alysis_code/surface/rich_surface.py +1555 -0
  401. alysis_code/surface/styles.py +67 -0
  402. alysis_code/surface/theme.py +455 -0
  403. alysis_code/surface/types.py +100 -0
  404. alysis_code/swarm_backend.py +926 -0
  405. alysis_code/swarm_orchestrator.py +4020 -0
  406. alysis_code/swarm_scheduler.py +441 -0
  407. alysis_code/swarm_trace.py +429 -0
  408. alysis_code/swarm_worker.py +2119 -0
  409. alysis_code/swarm_write_guard.py +348 -0
  410. alysis_code/task_dependencies.py +170 -0
  411. alysis_code/task_readiness.py +992 -0
  412. alysis_code/task_scope.py +2148 -0
  413. alysis_code/terminal_manager.py +762 -0
  414. alysis_code/terminal_ownership.py +460 -0
  415. alysis_code/text_normalization.py +30 -0
  416. alysis_code/token_budget.py +97 -0
  417. alysis_code/tools/README.md +34 -0
  418. alysis_code/tools/__init__.py +1 -0
  419. alysis_code/tools/artifacts.py +127 -0
  420. alysis_code/tools/availability.py +188 -0
  421. alysis_code/tools/fs.py +1456 -0
  422. alysis_code/tools/git.py +461 -0
  423. alysis_code/tools/history.py +229 -0
  424. alysis_code/tools/http_timeout.py +78 -0
  425. alysis_code/tools/image_generation.py +552 -0
  426. alysis_code/tools/registry.py +2936 -0
  427. alysis_code/tools/repo_map.py +476 -0
  428. alysis_code/tools/search.py +563 -0
  429. alysis_code/tools/shell.py +135 -0
  430. alysis_code/tools/symbols.py +1350 -0
  431. alysis_code/tools/test_discovery.py +643 -0
  432. alysis_code/tools/web.py +482 -0
  433. alysis_code/tools/web_search.py +2012 -0
  434. alysis_code/tools/web_search_dashscope.py +557 -0
  435. alysis_code/tools/web_search_ddgs.py +221 -0
  436. alysis_code/tools/web_search_provider_adapters.py +1429 -0
  437. alysis_code/tools/web_search_tavily.py +194 -0
  438. alysis_code/updates.py +933 -0
  439. alysis_code/usage_tracker.py +1990 -0
  440. alysis_code/verification_command_analysis.py +1004 -0
  441. alysis_code/verification_contract.py +574 -0
  442. alysis_code/verification_failure_summary.py +273 -0
  443. alysis_code/verification_repair.py +385 -0
  444. alysis_code/verify_gate.py +3129 -0
  445. alysis_code/web_research.py +1872 -0
  446. alysis_code/web_search_adapters.py +66 -0
  447. alysis_code/web_search_policy.py +27 -0
  448. alysis_code/workspace_binding.py +389 -0
  449. alysis_code/workspace_binding_ui.py +408 -0
  450. alysis_code/workspace_context.py +273 -0
  451. alysis_code/workspace_isolation.py +138 -0
  452. alysis_code/workspace_provisioning.py +455 -0
  453. alysis_code-0.13.0.dist-info/METADATA +507 -0
  454. alysis_code-0.13.0.dist-info/RECORD +458 -0
  455. alysis_code-0.13.0.dist-info/WHEEL +4 -0
  456. alysis_code-0.13.0.dist-info/entry_points.txt +3 -0
  457. alysis_code-0.13.0.dist-info/licenses/LICENSE +176 -0
  458. alysis_code-0.13.0.dist-info/licenses/NOTICE +4 -0
@@ -0,0 +1,506 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Literal
8
+
9
+ from .atomic_io import atomic_write_json, atomic_write_text
10
+ from .config import AppConfig
11
+ from .forge import RunPaths, ensure_execution_dirs, now_iso
12
+ from .knowledge_base import (
13
+ KnowledgeEntry,
14
+ KnowledgeIndexEntry,
15
+ is_effectively_open_status,
16
+ load_knowledge_index,
17
+ rebuild_knowledge_index,
18
+ write_issue_entry_for_task_id,
19
+ )
20
+ from .repo_scan import RepoScanResult
21
+ from .verify_gate import (
22
+ CONFIG_VERIFY_COMMANDS_GENERIC_PRESET_SOURCE,
23
+ ResolvedVerifyCommands,
24
+ VerifyError,
25
+ VerifyRunResult,
26
+ is_generic_fallback_verify_command_selection,
27
+ resolve_verify_command_selection,
28
+ run_task_verification,
29
+ )
30
+
31
+ IntegrationVerifyMode = Literal["off", "warn", "strict"]
32
+
33
+
34
+ class IntegrationGateError(RuntimeError):
35
+ pass
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class ResolvedIntegrationCommands:
40
+ commands: tuple[str, ...]
41
+ source: str
42
+
43
+ def to_payload(self) -> dict[str, object]:
44
+ return {
45
+ "source": self.source,
46
+ "commands": list(self.commands),
47
+ }
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class IntegrationGateResult:
52
+ batch_index: int
53
+ batch_label: str
54
+ mode: IntegrationVerifyMode
55
+ command_source: str
56
+ commands: tuple[str, ...]
57
+ merged_task_ids: tuple[str, ...]
58
+ merged_paths: tuple[str, ...]
59
+ verify_result: VerifyRunResult
60
+ artifact_dir: Path
61
+ result_path: Path
62
+ commands_path: Path
63
+ stdout_path: Path
64
+ stderr_path: Path
65
+ summary_path: Path
66
+ verify_artifact_path: Path
67
+ phase: str = "post_merge"
68
+ verified_root: Path | None = None
69
+
70
+ @property
71
+ def passed(self) -> bool:
72
+ return self.verify_result.all_passed
73
+
74
+ @property
75
+ def summary(self) -> str:
76
+ return self.verify_result.summary
77
+
78
+ @property
79
+ def policy_outcome(self) -> str:
80
+ if self.passed:
81
+ return "passed"
82
+ if self.mode == "warn":
83
+ return "failed_tolerated_by_warn_policy"
84
+ return "failed_blocking"
85
+
86
+ def to_payload(self, *, root: Path) -> dict[str, object]:
87
+ verified_root = self.verified_root or root
88
+ return {
89
+ "schema_version": 1,
90
+ "generated_at": now_iso(),
91
+ "batch_index": self.batch_index,
92
+ "batch_label": self.batch_label,
93
+ "mode": self.mode,
94
+ "phase": self.phase,
95
+ "passed": self.passed,
96
+ "policy_outcome": self.policy_outcome,
97
+ "tolerated_failure": self.policy_outcome == "failed_tolerated_by_warn_policy",
98
+ "summary": self.summary,
99
+ "failure_category": self.verify_result.failure_category_value,
100
+ "command_source": self.command_source,
101
+ "commands": list(self.commands),
102
+ "merged_task_ids": list(self.merged_task_ids),
103
+ "merged_paths": list(self.merged_paths),
104
+ "verified_root": _display_path(root, verified_root),
105
+ "verify_artifact_path": _repo_rel(root, self.verify_artifact_path),
106
+ "commands_path": _repo_rel(root, self.commands_path),
107
+ "stdout_path": _repo_rel(root, self.stdout_path),
108
+ "stderr_path": _repo_rel(root, self.stderr_path),
109
+ "summary_path": _repo_rel(root, self.summary_path),
110
+ "result_path": _repo_rel(root, self.result_path),
111
+ "command_results": [
112
+ {
113
+ "command": item.command,
114
+ "effective_command": item.effective_command or item.command,
115
+ "exit_code": item.exit_code,
116
+ "ok": item.ok,
117
+ "real_execution": item.real_execution,
118
+ "non_execution_reason": item.non_execution_reason,
119
+ "fallback_used": item.fallback_used,
120
+ "fallback_reason": item.fallback_reason,
121
+ }
122
+ for item in self.verify_result.command_results
123
+ ],
124
+ }
125
+
126
+
127
+ def normalize_integration_verify_mode(mode: str) -> IntegrationVerifyMode:
128
+ value = mode.strip().lower()
129
+ if value not in {"off", "warn", "strict"}:
130
+ raise IntegrationGateError(
131
+ "Invalid integration verify mode. Use one of: off, warn, strict."
132
+ )
133
+ return value # type: ignore[return-value]
134
+
135
+
136
+ def resolve_integration_verify_mode(
137
+ *,
138
+ cfg: AppConfig,
139
+ integration_verify: str | None,
140
+ ) -> IntegrationVerifyMode:
141
+ raw = integration_verify if integration_verify is not None else cfg.integration_verify_mode
142
+ return normalize_integration_verify_mode(raw)
143
+
144
+
145
+ def resolve_integration_verify_commands(
146
+ *,
147
+ cfg: AppConfig,
148
+ integration_verify_cmd: list[str] | None,
149
+ verify_cmd: list[str] | None = None,
150
+ root: Path | None = None,
151
+ repo_scan: RepoScanResult | None = None,
152
+ ) -> ResolvedIntegrationCommands:
153
+ def _resolve_verify_selection(scan: RepoScanResult | None) -> ResolvedVerifyCommands:
154
+ try:
155
+ return resolve_verify_command_selection(
156
+ cfg=cfg,
157
+ verify_cmd=verify_cmd,
158
+ root=root,
159
+ repo_scan=scan,
160
+ )
161
+ except VerifyError as e:
162
+ if str(e) == "Configured verify_commands is empty.":
163
+ raise IntegrationGateError(
164
+ "No integration verify commands are configured. Set integration_verify_commands or verify_commands."
165
+ ) from e
166
+ raise IntegrationGateError(str(e)) from e
167
+
168
+ if integration_verify_cmd:
169
+ commands = tuple(cmd.strip() for cmd in integration_verify_cmd if cmd.strip())
170
+ if not commands:
171
+ raise IntegrationGateError("--integration-verify-cmd values cannot be empty.")
172
+ return ResolvedIntegrationCommands(
173
+ commands=commands,
174
+ source="cli.integration_verify_cmd",
175
+ )
176
+
177
+ configured_integration = tuple(
178
+ cmd.strip() for cmd in cfg.integration_verify_commands if cmd.strip()
179
+ )
180
+ if configured_integration:
181
+ return ResolvedIntegrationCommands(
182
+ commands=configured_integration,
183
+ source="config.integration_verify_commands",
184
+ )
185
+
186
+ verify_resolution = _resolve_verify_selection(repo_scan)
187
+
188
+ raw_source = verify_resolution.source
189
+ source = {
190
+ "cli.verify_cmd": "cli.verify_cmd_fallback",
191
+ "config.verify_commands": "config.verify_commands_fallback",
192
+ "repo_scan.likely_test_commands": "repo_scan.likely_test_commands_fallback",
193
+ "config.verify_commands_fallback": "config.verify_commands_fallback",
194
+ CONFIG_VERIFY_COMMANDS_GENERIC_PRESET_SOURCE: (
195
+ "config.verify_commands_generic_preset_fallback"
196
+ ),
197
+ }.get(raw_source, raw_source)
198
+ if is_generic_fallback_verify_command_selection(verify_resolution) and (
199
+ root is not None or repo_scan is not None
200
+ ):
201
+ return ResolvedIntegrationCommands(
202
+ commands=(),
203
+ source="repo_scan.no_authoritative_commands_fallback",
204
+ )
205
+ return ResolvedIntegrationCommands(
206
+ commands=verify_resolution.commands,
207
+ source=source,
208
+ )
209
+
210
+
211
+ def run_integration_gate(
212
+ *,
213
+ paths: RunPaths,
214
+ cfg: AppConfig,
215
+ batch_index: int,
216
+ mode: IntegrationVerifyMode,
217
+ merged_task_ids: list[str],
218
+ merged_paths: list[str],
219
+ integration_verify_cmd: list[str] | None = None,
220
+ verify_cmd: list[str] | None = None,
221
+ root: Path | None = None,
222
+ repo_scan: RepoScanResult | None = None,
223
+ phase: str = "post_merge",
224
+ ) -> IntegrationGateResult:
225
+ ensure_execution_dirs(paths)
226
+ resolved_root = (root or paths.root).resolve()
227
+ batch_label = f"batch_{batch_index:03d}"
228
+ artifact_dir = paths.execution_integration_dir / batch_label
229
+ artifact_dir.mkdir(parents=True, exist_ok=True)
230
+ command_resolution = resolve_integration_verify_commands(
231
+ cfg=cfg,
232
+ integration_verify_cmd=integration_verify_cmd,
233
+ verify_cmd=verify_cmd,
234
+ root=resolved_root,
235
+ repo_scan=repo_scan,
236
+ )
237
+ verify_artifact_path = artifact_dir / "verify.txt"
238
+ verify_result = run_task_verification(
239
+ root=resolved_root,
240
+ commands=list(command_resolution.commands),
241
+ artifact_path=verify_artifact_path,
242
+ cfg=cfg,
243
+ )
244
+ commands_path = artifact_dir / "commands.json"
245
+ stdout_path = artifact_dir / "stdout.txt"
246
+ stderr_path = artifact_dir / "stderr.txt"
247
+ summary_path = artifact_dir / "summary.md"
248
+ result_path = artifact_dir / "result.json"
249
+ atomic_write_json(
250
+ commands_path,
251
+ {
252
+ "schema_version": 1,
253
+ "generated_at": now_iso(),
254
+ "batch_index": batch_index,
255
+ "batch_label": batch_label,
256
+ "mode": mode,
257
+ "phase": phase,
258
+ "command_source": command_resolution.source,
259
+ "commands": list(command_resolution.commands),
260
+ "merged_task_ids": list(merged_task_ids),
261
+ "verified_root": _display_path(paths.root, resolved_root),
262
+ },
263
+ )
264
+ atomic_write_text(stdout_path, _render_command_stream(verify_result, stream_name="stdout"))
265
+ atomic_write_text(stderr_path, _render_command_stream(verify_result, stream_name="stderr"))
266
+
267
+ result = IntegrationGateResult(
268
+ batch_index=batch_index,
269
+ batch_label=batch_label,
270
+ mode=mode,
271
+ command_source=command_resolution.source,
272
+ commands=command_resolution.commands,
273
+ merged_task_ids=tuple(merged_task_ids),
274
+ merged_paths=tuple(_dedupe_preserve_order(merged_paths)),
275
+ verify_result=verify_result,
276
+ artifact_dir=artifact_dir,
277
+ result_path=result_path,
278
+ commands_path=commands_path,
279
+ stdout_path=stdout_path,
280
+ stderr_path=stderr_path,
281
+ summary_path=summary_path,
282
+ verify_artifact_path=verify_artifact_path,
283
+ phase=phase,
284
+ verified_root=resolved_root,
285
+ )
286
+ atomic_write_text(summary_path, _render_integration_summary(result=result, root=paths.root))
287
+ atomic_write_json(result_path, result.to_payload(root=paths.root))
288
+ return result
289
+
290
+
291
+ def integration_issue_signature_for_commands(commands: tuple[str, ...] | list[str]) -> str:
292
+ normalized_commands = [
293
+ " ".join(str(command).strip().split()) for command in commands if str(command).strip()
294
+ ]
295
+ payload = json.dumps(normalized_commands, ensure_ascii=False, separators=(",", ":"))
296
+ digest = hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]
297
+ return f"integration_gate_v1:{digest}"
298
+
299
+
300
+ def write_integration_failure_issue(
301
+ *,
302
+ paths: RunPaths,
303
+ result: IntegrationGateResult,
304
+ ) -> KnowledgeEntry:
305
+ title = f"{result.batch_label}: integration verification failed"
306
+ summary = result.summary
307
+ issue = write_issue_entry_for_task_id(
308
+ paths=paths,
309
+ task_id=result.batch_label,
310
+ source="integration_gate",
311
+ title=title,
312
+ summary=summary,
313
+ paths_in_scope=list(result.merged_paths),
314
+ report_path=result.summary_path,
315
+ verify_artifact_path=result.verify_artifact_path,
316
+ related_tasks=list(result.merged_task_ids),
317
+ tags=["integration_gate", "integration_failure", result.mode],
318
+ status="open",
319
+ signature=integration_issue_signature_for_commands(result.commands),
320
+ )
321
+ return issue
322
+
323
+
324
+ def _matching_open_integration_issues(
325
+ *,
326
+ paths: RunPaths,
327
+ signature: str,
328
+ ) -> tuple[KnowledgeIndexEntry, ...]:
329
+ index = load_knowledge_index(paths, rebuild=True)
330
+ matches = [
331
+ entry
332
+ for entry in index.entries
333
+ if entry.kind == "issue"
334
+ and entry.source == "integration_gate"
335
+ and entry.signature == signature
336
+ and is_effectively_open_status(entry.effective_status or entry.status)
337
+ ]
338
+ return tuple(matches)
339
+
340
+
341
+ def write_integration_resolution_issue(
342
+ *,
343
+ paths: RunPaths,
344
+ result: IntegrationGateResult,
345
+ resolved_issue_ids: tuple[str, ...],
346
+ signature: str,
347
+ ) -> KnowledgeEntry:
348
+ return write_issue_entry_for_task_id(
349
+ paths=paths,
350
+ task_id=result.batch_label,
351
+ source="integration_gate",
352
+ title=f"{result.batch_label}: integration verification passed",
353
+ summary=result.summary,
354
+ paths_in_scope=list(result.merged_paths),
355
+ report_path=result.summary_path,
356
+ verify_artifact_path=result.verify_artifact_path,
357
+ related_tasks=list(result.merged_task_ids),
358
+ tags=["integration_gate", "integration_resolution", result.mode],
359
+ status="resolved",
360
+ signature=signature,
361
+ resolves=list(resolved_issue_ids),
362
+ )
363
+
364
+
365
+ def write_integration_issue_summary(paths: RunPaths) -> Path:
366
+ ensure_execution_dirs(paths)
367
+ index = load_knowledge_index(paths, rebuild=True)
368
+ open_issues = [
369
+ entry
370
+ for entry in index.entries
371
+ if entry.kind == "issue"
372
+ and entry.source == "integration_gate"
373
+ and is_effectively_open_status(entry.effective_status or entry.status)
374
+ ]
375
+ lines = [
376
+ "# Integration Issues",
377
+ "",
378
+ f"- Generated At: `{now_iso()}`",
379
+ "",
380
+ ]
381
+ if not open_issues:
382
+ lines.append("- No open integration issues.")
383
+ else:
384
+ for entry in open_issues:
385
+ line = f"- `{entry.id}` {entry.title}"
386
+ if entry.related_tasks:
387
+ line += f" related tasks: {', '.join(entry.related_tasks)}"
388
+ if entry.paths:
389
+ line += f" paths: {', '.join(entry.paths[:5])}"
390
+ line += f" file: `{entry.knowledge_file_path}`"
391
+ lines.append(line)
392
+ paths.execution_integration_issues_path.parent.mkdir(parents=True, exist_ok=True)
393
+ atomic_write_text(paths.execution_integration_issues_path, "\n".join(lines).rstrip() + "\n")
394
+ return paths.execution_integration_issues_path
395
+
396
+
397
+ def record_integration_failure_knowledge(
398
+ *,
399
+ paths: RunPaths,
400
+ result: IntegrationGateResult,
401
+ ) -> tuple[KnowledgeEntry, Path]:
402
+ issue = write_integration_failure_issue(paths=paths, result=result)
403
+ rebuild_knowledge_index(paths)
404
+ summary_path = write_integration_issue_summary(paths)
405
+ return issue, summary_path
406
+
407
+
408
+ def record_integration_resolution_knowledge(
409
+ *,
410
+ paths: RunPaths,
411
+ result: IntegrationGateResult,
412
+ ) -> tuple[KnowledgeEntry | None, Path]:
413
+ signature = integration_issue_signature_for_commands(result.commands)
414
+ open_issues = _matching_open_integration_issues(paths=paths, signature=signature)
415
+ resolution_entry: KnowledgeEntry | None = None
416
+ if open_issues:
417
+ resolution_entry = write_integration_resolution_issue(
418
+ paths=paths,
419
+ result=result,
420
+ resolved_issue_ids=tuple(entry.id for entry in open_issues),
421
+ signature=signature,
422
+ )
423
+ rebuild_knowledge_index(paths)
424
+ summary_path = write_integration_issue_summary(paths)
425
+ return resolution_entry, summary_path
426
+
427
+
428
+ def _dedupe_preserve_order(values: list[str]) -> list[str]:
429
+ seen: set[str] = set()
430
+ out: list[str] = []
431
+ for value in values:
432
+ item = str(value).strip()
433
+ if not item or item in seen:
434
+ continue
435
+ seen.add(item)
436
+ out.append(item)
437
+ return out
438
+
439
+
440
+ def _repo_rel(root: Path, path: Path) -> str:
441
+ return path.resolve().relative_to(root.resolve()).as_posix()
442
+
443
+
444
+ def _display_path(root: Path, path: Path) -> str:
445
+ try:
446
+ return _repo_rel(root, path)
447
+ except ValueError:
448
+ return path.resolve().as_posix()
449
+
450
+
451
+ def _render_command_stream(result: VerifyRunResult, *, stream_name: str) -> str:
452
+ lines = [f"# Integration {stream_name.title()}"]
453
+ for index, item in enumerate(result.command_results, start=1):
454
+ text = item.stdout if stream_name == "stdout" else item.stderr
455
+ lines.extend(
456
+ [
457
+ "",
458
+ f"## Command {index}",
459
+ f"requested_command: {item.command}",
460
+ f"effective_command: {item.effective_command or item.command}",
461
+ text.rstrip() or "(no output)",
462
+ ]
463
+ )
464
+ return "\n".join(lines).rstrip() + "\n"
465
+
466
+
467
+ def _render_integration_summary(*, result: IntegrationGateResult, root: Path) -> str:
468
+ verified_root = result.verified_root or root
469
+ if result.phase == "pre_merge_candidate":
470
+ phase_label = "pre-merge candidate"
471
+ task_heading = "Batch Tasks"
472
+ elif result.phase == "final_repo":
473
+ phase_label = "final repo"
474
+ task_heading = "Final Repo Tasks"
475
+ else:
476
+ phase_label = "post-merge base"
477
+ task_heading = "Merged Tasks"
478
+ lines = [
479
+ "# Integration Gate Summary",
480
+ "",
481
+ f"- Batch: `{result.batch_label}`",
482
+ f"- Phase: `{phase_label}`",
483
+ f"- Mode: `{result.mode}`",
484
+ f"- Passed: `{'yes' if result.passed else 'no'}`",
485
+ f"- Policy Outcome: `{result.policy_outcome}`",
486
+ f"- Summary: {result.summary}",
487
+ f"- Command Source: `{result.command_source}`",
488
+ f"- Verified Root: `{_display_path(root, verified_root)}`",
489
+ f"- Commands Artifact: `{_repo_rel(root, result.commands_path)}`",
490
+ f"- Verify Artifact: `{_repo_rel(root, result.verify_artifact_path)}`",
491
+ f"- Stdout Artifact: `{_repo_rel(root, result.stdout_path)}`",
492
+ f"- Stderr Artifact: `{_repo_rel(root, result.stderr_path)}`",
493
+ "",
494
+ f"## {task_heading}",
495
+ "",
496
+ ]
497
+ if result.merged_task_ids:
498
+ lines.extend(f"- `{task_id}`" for task_id in result.merged_task_ids)
499
+ else:
500
+ lines.append("- (none)")
501
+ lines.extend(["", "## Commands", ""])
502
+ if result.commands:
503
+ lines.extend(f"- `{cmd}`" for cmd in result.commands)
504
+ else:
505
+ lines.append("- (none)")
506
+ return "\n".join(lines).rstrip() + "\n"
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+ from contextlib import contextmanager
5
+
6
+ _ACTIVE_PROMPT_DEPTH = 0
7
+ _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH = 0
8
+ _ACTIVE_PROMPT_LOCK = threading.Lock()
9
+ _ACTIVE_PROMPT_EVENT = threading.Event()
10
+
11
+
12
+ def is_interactive_prompt_active() -> bool:
13
+ return _ACTIVE_PROMPT_EVENT.is_set()
14
+
15
+
16
+ def is_interactive_prompt_terminal_owner() -> bool:
17
+ with _ACTIVE_PROMPT_LOCK:
18
+ return _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH > 0
19
+
20
+
21
+ @contextmanager
22
+ def interactive_prompt_guard(*, owns_terminal: bool = False) -> None:
23
+ global _ACTIVE_PROMPT_DEPTH, _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH
24
+ with _ACTIVE_PROMPT_LOCK:
25
+ _ACTIVE_PROMPT_DEPTH += 1
26
+ if owns_terminal:
27
+ _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH += 1
28
+ _ACTIVE_PROMPT_EVENT.set()
29
+ try:
30
+ yield
31
+ finally:
32
+ with _ACTIVE_PROMPT_LOCK:
33
+ _ACTIVE_PROMPT_DEPTH = max(0, _ACTIVE_PROMPT_DEPTH - 1)
34
+ if owns_terminal:
35
+ _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH = max(
36
+ 0, _ACTIVE_PROMPT_TERMINAL_OWNER_DEPTH - 1
37
+ )
38
+ if _ACTIVE_PROMPT_DEPTH == 0:
39
+ _ACTIVE_PROMPT_EVENT.clear()
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ INTERACTIVE_PLAN_MODE_SYSTEM_PROMPT = """You are handling one turn inside interactive chat Plan Mode.
4
+
5
+ Interactive chat Plan Mode is persistent readonly analysis/planning.
6
+
7
+ Hard constraints:
8
+ - Use prior conversation context first and stay grounded in the repository context that is already available to you.
9
+ - You may inspect repository context read-only if helpful.
10
+ - The host owns Plan Mode state transitions and execution gating.
11
+ - The normal plan -> approval -> execution flow in chat is /plan <task>; Plan Mode is the secondary readonly overlay.
12
+ - Do not execute the task.
13
+ - Do not write files.
14
+ - Do not run shell commands.
15
+ - Do not run verification commands.
16
+ - Do not claim changes were made.
17
+ - Do not imply that execution already started.
18
+
19
+ Response policy:
20
+ - If the user message is a concrete implementation request (for example a build/fix/change/refactor/add/remove/migrate/update request covering code, tests, docs, or configuration), do not execute it. Respond with a concise numbered implementation plan instead.
21
+ - If the user is asking to stop planning and start execution now (for example "do it", "go ahead", "implement it", or similar approval-style follow-ups), do not restate the plan. Tell them Plan Mode is still readonly, that the host controls approval/exit behavior, and that exact /plan approve or /plan off (or Esc at an empty prompt in interactive chat) must be used before execution can start.
22
+ - If the user message is a question, review request, discussion request, acknowledgement, pleasantry, or unclear ask, respond conversationally instead of switching into a formal plan.
23
+ - Ask at most one concise clarification question only when it is genuinely needed to move the discussion forward.
24
+ - Brief social acknowledgements or pleasantries should get a brief natural reply and should not cause you to restate the previous technical answer.
25
+ - When you provide a numbered implementation plan, keep it concise, actionable, and self-contained because the host may store the latest draft for exact /plan approve.
26
+ """