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,393 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections.abc import Callable
5
+ from typing import Any
6
+
7
+ from .llm.types import LLMError
8
+ from .plan_assistant import compact_workspace_context_for_planner
9
+ from .usage_tracker import build_usage_record, usage_context_from_client_response
10
+
11
+ PLAN_CONTEXT_MAX_MESSAGES = 20
12
+ TOOL_RESULT_SUMMARY_CHARS = 200
13
+ _APPROVED_PLAN_MARKER = "Approved plan:\n"
14
+ _APPROVED_PLAN_EXECUTE_MARKER = "Now execute this task"
15
+
16
+ PLAN_MODE_SYSTEM_PROMPT = """You are an execution planner for a local coding agent.
17
+
18
+ Produce a concise, actionable draft implementation plan only.
19
+
20
+ Rules:
21
+ - Output 3-7 numbered steps.
22
+ - Mention likely files/modules to change when possible.
23
+ - Include verification/tests to run.
24
+ - If user-facing behavior changes, include docs/help/README updates.
25
+ - Keep scope reviewable and practical.
26
+ - Treat host-provided workspace context as the source of truth for repo structure and likely test commands.
27
+ - Mention repo-relative files, modules, frameworks, and markup only when they are supported by host-provided workspace context or prior conversation evidence.
28
+ - If the available context does not support an exact path/framework/file, describe the area generically instead of inventing details.
29
+ - Do not claim that commands were run or files were inspected.
30
+ - Do not execute tools or propose tool calls; planning text only.
31
+ - Choose the natural response language from the user's request and recent visible conversation.
32
+ - Follow explicit language/script requests when present.
33
+ - For empty, malformed, ambiguous, gibberish, or code-only input, use English with Latin script.
34
+ - Never translate code identifiers, file paths, CLI commands, config keys, or code blocks; keep them exactly as written.
35
+ """
36
+
37
+
38
+ def _to_text(value: Any) -> str:
39
+ if isinstance(value, str):
40
+ return value
41
+ if value is None:
42
+ return ""
43
+ try:
44
+ return json.dumps(value, ensure_ascii=True)
45
+ except Exception:
46
+ return str(value)
47
+
48
+
49
+ def _truncate(value: str, max_len: int) -> str:
50
+ text = value.strip()
51
+ if len(text) <= max_len:
52
+ return text
53
+ return text[:max_len].rstrip() + "..."
54
+
55
+
56
+ def _workspace_context_block(workspace_context: dict[str, Any] | None) -> str:
57
+ if workspace_context is None:
58
+ return ""
59
+ digest = compact_workspace_context_for_planner(workspace_context)
60
+ if not digest:
61
+ return ""
62
+ return (
63
+ "Workspace context JSON:\n"
64
+ f"{json.dumps(digest, ensure_ascii=False, sort_keys=True)}\n\n"
65
+ "Grounding rules:\n"
66
+ "- Only mention repo-relative files, modules, frameworks, or markup that this workspace context supports.\n"
67
+ "- Prefer the provided likely_test_commands when suggesting verification.\n"
68
+ "- If exact details are not supported here or in prior conversation context, describe the area generically."
69
+ )
70
+
71
+
72
+ def _normalize_plan_history_entries(
73
+ session_messages: list[dict[str, Any]],
74
+ *,
75
+ max_history_messages: int,
76
+ tool_result_chars: int,
77
+ ) -> list[dict[str, str]]:
78
+ filtered: list[dict[str, str]] = []
79
+ tool_call_names: dict[str, str] = {}
80
+
81
+ for entry in session_messages:
82
+ if not isinstance(entry, dict):
83
+ continue
84
+ role = str(entry.get("role") or "").strip().lower()
85
+
86
+ if role == "user":
87
+ text = _to_text(entry.get("content"))
88
+ if text.strip():
89
+ filtered.append({"role": "user", "content": text})
90
+ continue
91
+
92
+ if role == "assistant":
93
+ tool_calls_raw = entry.get("tool_calls")
94
+ tool_calls = tool_calls_raw if isinstance(tool_calls_raw, list) else []
95
+ if tool_calls:
96
+ for call in tool_calls:
97
+ if not isinstance(call, dict):
98
+ continue
99
+ call_id = str(call.get("id") or "").strip()
100
+ if not call_id:
101
+ continue
102
+ tool_call_names[call_id] = _extract_tool_call_name(call)
103
+ filtered.append(
104
+ {
105
+ "role": "assistant",
106
+ "content": _summarize_assistant_tool_calls(
107
+ entry,
108
+ tool_result_chars=tool_result_chars,
109
+ ),
110
+ }
111
+ )
112
+ continue
113
+
114
+ text = _to_text(entry.get("content"))
115
+ if text.strip():
116
+ filtered.append({"role": "assistant", "content": text})
117
+ continue
118
+
119
+ if role == "tool":
120
+ filtered.append(
121
+ {
122
+ "role": "tool",
123
+ "content": _summarize_tool_result(
124
+ entry,
125
+ tool_call_names=tool_call_names,
126
+ tool_result_chars=tool_result_chars,
127
+ ),
128
+ }
129
+ )
130
+
131
+ if max_history_messages > 0 and len(filtered) > max_history_messages:
132
+ return filtered[-max_history_messages:]
133
+ return filtered
134
+
135
+
136
+ def _plan_context_user_prompt(
137
+ *,
138
+ history_entries: list[dict[str, str]],
139
+ workspace_context: dict[str, Any] | None,
140
+ user_message: str,
141
+ previous_plan: str | None = None,
142
+ feedback: str | None = None,
143
+ ) -> str:
144
+ user_text = user_message.strip()
145
+ prompt_parts = [
146
+ "Recent conversation transcript JSON:",
147
+ json.dumps(history_entries, ensure_ascii=False, indent=2),
148
+ "",
149
+ ]
150
+ workspace_block = _workspace_context_block(workspace_context)
151
+ if workspace_block:
152
+ prompt_parts.extend([workspace_block, ""])
153
+ prompt_parts.extend(
154
+ [
155
+ "Draft an execution plan for this request:",
156
+ user_text,
157
+ "",
158
+ "Return only the plan text in plain markdown.",
159
+ ]
160
+ )
161
+ prev = (previous_plan or "").strip()
162
+ notes = (feedback or "").strip()
163
+ if prev and notes:
164
+ prompt_parts.extend(
165
+ [
166
+ "",
167
+ "Revise this previous draft plan based on user feedback.",
168
+ "Previous draft plan:",
169
+ prev,
170
+ "",
171
+ "User feedback:",
172
+ notes,
173
+ ]
174
+ )
175
+ prompt_parts.extend(
176
+ [
177
+ "",
178
+ "Grounding rules:",
179
+ "- Base exact path/module/framework references only on host-provided workspace context or prior conversation evidence.",
180
+ "- If exact file/framework details are uncertain, keep the plan generic instead of guessing.",
181
+ ]
182
+ )
183
+ return "\n".join(prompt_parts)
184
+
185
+
186
+ def extract_approved_plan_user_message(text: str) -> str | None:
187
+ clean = str(text or "").strip()
188
+ if not clean:
189
+ return None
190
+ plan_idx = clean.find(_APPROVED_PLAN_MARKER)
191
+ execute_idx = clean.find(_APPROVED_PLAN_EXECUTE_MARKER)
192
+ if plan_idx < 0 or execute_idx < 0 or plan_idx >= execute_idx:
193
+ return None
194
+ base = clean[:plan_idx].rstrip()
195
+ if not base:
196
+ return None
197
+ return base
198
+
199
+
200
+ def _extract_tool_call_name(raw_call: Any) -> str:
201
+ if not isinstance(raw_call, dict):
202
+ return "unknown_tool"
203
+ fn = raw_call.get("function")
204
+ if isinstance(fn, dict):
205
+ name = str(fn.get("name") or "").strip()
206
+ if name:
207
+ return name
208
+ name = str(raw_call.get("name") or "").strip()
209
+ return name or "unknown_tool"
210
+
211
+
212
+ def _summarize_assistant_tool_calls(
213
+ message: dict[str, Any],
214
+ *,
215
+ tool_result_chars: int,
216
+ ) -> str:
217
+ tool_calls_raw = message.get("tool_calls")
218
+ tool_calls = tool_calls_raw if isinstance(tool_calls_raw, list) else []
219
+ names: list[str] = []
220
+ for item in tool_calls[:8]:
221
+ name = _extract_tool_call_name(item)
222
+ if name and name not in names:
223
+ names.append(name)
224
+ names_text = ", ".join(names) if names else "unknown_tool"
225
+ content = _to_text(message.get("content"))
226
+ if content.strip():
227
+ return (
228
+ f"Assistant requested tool calls: {names_text}. "
229
+ f"Assistant note: {_truncate(content, tool_result_chars)}"
230
+ )
231
+ return f"Assistant requested tool calls: {names_text}."
232
+
233
+
234
+ def _summarize_tool_result(
235
+ message: dict[str, Any],
236
+ *,
237
+ tool_call_names: dict[str, str],
238
+ tool_result_chars: int,
239
+ ) -> str:
240
+ call_id = str(message.get("tool_call_id") or "").strip()
241
+ tool_name = tool_call_names.get(call_id) or "unknown_tool"
242
+ content = _to_text(message.get("content"))
243
+ if not content.strip():
244
+ return f"Tool result ({tool_name}): (empty)"
245
+ return f"Tool result ({tool_name}): {_truncate(content, tool_result_chars)}"
246
+
247
+
248
+ def build_plan_context_messages(
249
+ session_messages: list[dict[str, Any]],
250
+ user_message: str,
251
+ previous_plan: str | None = None,
252
+ feedback: str | None = None,
253
+ workspace_context: dict[str, Any] | None = None,
254
+ *,
255
+ plan_system_prompt: str = PLAN_MODE_SYSTEM_PROMPT,
256
+ max_history_messages: int = PLAN_CONTEXT_MAX_MESSAGES,
257
+ tool_result_chars: int = TOOL_RESULT_SUMMARY_CHARS,
258
+ ) -> list[dict[str, Any]]:
259
+ # Keep planner transport invariant simple and provider-safe: exactly one system
260
+ # message and one user message, with capped normalized history serialized into
261
+ # the final user prompt rather than flattened as chat-message turns.
262
+ history_entries = _normalize_plan_history_entries(
263
+ session_messages,
264
+ max_history_messages=max_history_messages,
265
+ tool_result_chars=tool_result_chars,
266
+ )
267
+ return [
268
+ {"role": "system", "content": plan_system_prompt},
269
+ {
270
+ "role": "user",
271
+ "content": _plan_context_user_prompt(
272
+ history_entries=history_entries,
273
+ workspace_context=workspace_context,
274
+ user_message=user_message,
275
+ previous_plan=previous_plan,
276
+ feedback=feedback,
277
+ ),
278
+ },
279
+ ]
280
+
281
+
282
+ def generate_plan_draft(
283
+ client: Any,
284
+ session_messages: list[dict[str, Any]],
285
+ user_message: str,
286
+ previous_plan: str | None = None,
287
+ feedback: str | None = None,
288
+ workspace_context: dict[str, Any] | None = None,
289
+ stream: bool = False,
290
+ on_text_delta: Callable[[str], None] | None = None,
291
+ *,
292
+ details: dict[str, Any] | None = None,
293
+ ) -> str:
294
+ if client is None:
295
+ raise RuntimeError("Plan generation unavailable: missing session client.")
296
+
297
+ request_messages = build_plan_context_messages(
298
+ session_messages=session_messages,
299
+ user_message=user_message,
300
+ previous_plan=previous_plan,
301
+ feedback=feedback,
302
+ workspace_context=workspace_context,
303
+ )
304
+ try:
305
+ response = client.chat(
306
+ messages=request_messages,
307
+ tools=None,
308
+ stream=bool(stream),
309
+ on_text_delta=on_text_delta if stream else None,
310
+ )
311
+ except LLMError as e:
312
+ raise RuntimeError(f"Plan generation failed: {e}") from e
313
+
314
+ plan_text = str(getattr(response, "content", "") or "").strip()
315
+ if not plan_text:
316
+ raise RuntimeError("Plan generation returned an empty response.")
317
+
318
+ if details is not None:
319
+ details["request_messages"] = request_messages
320
+ details["response"] = response
321
+ return plan_text
322
+
323
+
324
+ def instruction_with_approved_plan(*, user_message: str, approved_plan: str) -> str:
325
+ base = user_message.strip()
326
+ plan_text = approved_plan.strip()
327
+ if not plan_text:
328
+ return base
329
+ return (
330
+ f"{base}\n\n"
331
+ f"{_APPROVED_PLAN_MARKER}{plan_text}\n\n"
332
+ "Now execute this task in the repository and follow the approved plan."
333
+ )
334
+
335
+
336
+ def record_plan_usage(
337
+ *,
338
+ session: Any,
339
+ request_messages: list[dict[str, Any]],
340
+ response: Any,
341
+ ) -> None:
342
+ try:
343
+ requested_model = str(getattr(getattr(session, "client", None), "model", "") or "").strip()
344
+ if not requested_model:
345
+ return
346
+ registry = getattr(session, "model_registry", None)
347
+ usage_summary = getattr(session, "usage_summary", None)
348
+ if registry is None or usage_summary is None:
349
+ return
350
+ response_tool_calls = []
351
+ for tc in list(getattr(response, "tool_calls", []) or []):
352
+ response_tool_calls.append(
353
+ {
354
+ "id": str(getattr(tc, "id", "") or ""),
355
+ "name": str(getattr(tc, "name", "") or ""),
356
+ "arguments": getattr(tc, "arguments", {}) or {},
357
+ }
358
+ )
359
+ usage = getattr(response, "usage", None)
360
+ usage_record = build_usage_record(
361
+ role="plan",
362
+ requested_model=requested_model,
363
+ response_model=getattr(response, "response_model", None),
364
+ messages=request_messages,
365
+ response_content=str(getattr(response, "content", "") or ""),
366
+ response_tool_calls=response_tool_calls,
367
+ api_prompt_tokens=(
368
+ getattr(usage, "prompt_tokens", None) if usage is not None else None
369
+ ),
370
+ api_usage=usage,
371
+ api_cached_prompt_tokens=(
372
+ getattr(usage, "cached_prompt_tokens", None) if usage is not None else None
373
+ ),
374
+ api_completion_tokens=(
375
+ getattr(usage, "completion_tokens", None) if usage is not None else None
376
+ ),
377
+ api_total_tokens=(getattr(usage, "total_tokens", None) if usage is not None else None),
378
+ registry=registry,
379
+ **usage_context_from_client_response(
380
+ client=getattr(session, "client", None),
381
+ response=response,
382
+ operation="plan_llm",
383
+ ),
384
+ )
385
+ add_record = getattr(usage_summary, "add_record", None)
386
+ if callable(add_record):
387
+ add_record(usage_record)
388
+ store = getattr(session, "store", None)
389
+ append = getattr(store, "append", None)
390
+ if callable(append):
391
+ append("llm_usage", usage_record.to_payload())
392
+ except Exception:
393
+ return