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,468 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+ import logging
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from ..config import AppConfig
10
+ from ..mcp.manager import McpHostToolBinding
11
+ from ..model_registry import ModelRegistry
12
+ from .asset_read_core import perform_asset_read
13
+ from .planner_tools import ASSET_READ_TOOL
14
+ from .surface import AssetSurface
15
+ from .untrusted_content import build_untrusted_asset_text_block
16
+ from .usage_logger import AssetUsageLogger
17
+ from .worker_mirror import MirroredAssetEntry, TaskAssetMirror, load_task_asset_mirror
18
+
19
+ LOGGER = logging.getLogger(__name__)
20
+
21
+ ASSET_LOAD_TOOL: dict[str, Any] = {
22
+ "type": "function",
23
+ "function": {
24
+ "name": "asset_load",
25
+ "description": (
26
+ "Load a may-need or pinned asset's full content into the working context. "
27
+ "For primary assets already inlined, use asset_read."
28
+ ),
29
+ "parameters": {
30
+ "type": "object",
31
+ "additionalProperties": False,
32
+ "required": ["asset_id"],
33
+ "properties": {
34
+ "asset_id": {"type": "string"},
35
+ },
36
+ },
37
+ },
38
+ }
39
+
40
+
41
+ class WorkerAssetToolRunner:
42
+ def __init__(
43
+ self,
44
+ *,
45
+ cfg: AppConfig,
46
+ surface: AssetSurface,
47
+ model_registry: ModelRegistry,
48
+ mirror: TaskAssetMirror,
49
+ usage_logger: AssetUsageLogger | None = None,
50
+ api_key: str | None = None,
51
+ ) -> None:
52
+ self.cfg = cfg
53
+ self.surface = surface
54
+ self.model_registry = model_registry
55
+ self.mirror = mirror
56
+ self.usage_logger = usage_logger
57
+ self.api_key = api_key
58
+ self.loaded_image_asset_ids: set[str] = set()
59
+
60
+ def asset_read(self, arguments: dict[str, Any]) -> dict[str, Any]:
61
+ asset_id = str(arguments.get("asset_id") or "").strip()
62
+ focus = _optional_string(arguments.get("focus"))
63
+ max_chars = _optional_int(arguments.get("max_chars"))
64
+ entry = _find_entry(self.mirror, asset_id)
65
+ if entry is not None and focus is None:
66
+ text = _read_from_mirror_entry(entry, max_chars=max_chars or 8000)
67
+ if self.usage_logger is not None:
68
+ self.usage_logger.asset_read(
69
+ asset_id=asset_id,
70
+ focus=False,
71
+ chars=len(text),
72
+ cached=False,
73
+ )
74
+ return {
75
+ "asset_id": asset_id,
76
+ "text": text,
77
+ "chars": len(text),
78
+ "cached": False,
79
+ "truncated": "...[truncated to asset block limit]..." in text,
80
+ }
81
+ result = perform_asset_read(
82
+ surface=self.surface,
83
+ asset_id=asset_id,
84
+ focus=focus,
85
+ max_chars=max_chars,
86
+ api_key=self.api_key,
87
+ cfg=self.cfg,
88
+ model_registry=self.model_registry,
89
+ )
90
+ if self.usage_logger is not None:
91
+ self.usage_logger.asset_read(
92
+ asset_id=asset_id,
93
+ focus=bool(focus),
94
+ chars=result.chars,
95
+ cached=result.cached,
96
+ )
97
+ return {
98
+ "asset_id": asset_id,
99
+ "text": result.text,
100
+ "chars": result.chars,
101
+ "cached": result.cached,
102
+ "truncated": result.truncated,
103
+ }
104
+
105
+ def asset_load(self, arguments: dict[str, Any]) -> dict[str, Any]:
106
+ asset_id = str(arguments.get("asset_id") or "").strip()
107
+ entry = _find_entry(self.mirror, asset_id)
108
+ if entry is None:
109
+ text = f"Asset {asset_id} is unavailable in this task workspace."
110
+ self._record_asset_load(asset_id=asset_id, kind="unknown", chars=len(text))
111
+ return {"asset_id": asset_id, "text": text, "chars": len(text), "available": False}
112
+ if entry.status == "deleted":
113
+ text = f'Asset {entry.asset_id} - "{entry.title}" has been deleted and is unavailable.'
114
+ self._record_asset_load(asset_id=entry.asset_id, kind=entry.kind, chars=len(text))
115
+ return {"asset_id": asset_id, "text": text, "chars": len(text), "available": False}
116
+ if entry.status == "missing":
117
+ text = f'Asset {entry.asset_id} - "{entry.title}" is missing from the mirror.'
118
+ self._record_asset_load(asset_id=entry.asset_id, kind=entry.kind, chars=len(text))
119
+ return {"asset_id": asset_id, "text": text, "chars": len(text), "available": False}
120
+ content = _load_entry_text(
121
+ entry,
122
+ max_chars=int(self.cfg.assets.worker.max_chars_per_asset_block),
123
+ )
124
+ text = _tool_result_text(
125
+ entry=entry,
126
+ content=content,
127
+ source="mirror_load",
128
+ truncated="...[truncated to asset block limit]..." in content,
129
+ )
130
+ if entry.kind == "image":
131
+ self.loaded_image_asset_ids.add(entry.asset_id)
132
+ self._record_asset_load(asset_id=entry.asset_id, kind=entry.kind, chars=len(text))
133
+ return {
134
+ "asset_id": entry.asset_id,
135
+ "kind": entry.kind,
136
+ "text": text,
137
+ "chars": len(text),
138
+ "available": True,
139
+ }
140
+
141
+ def _record_asset_load(self, *, asset_id: str, kind: str, chars: int) -> None:
142
+ if self.usage_logger is not None:
143
+ self.usage_logger.asset_load(
144
+ asset_id=asset_id,
145
+ kind=kind,
146
+ chars=chars,
147
+ )
148
+ LOGGER.info(
149
+ "asset_load task_id=%s asset_id=%s kind=%s chars=%s",
150
+ self.mirror.task_id or self.mirror.manifest_path.stem,
151
+ asset_id,
152
+ kind,
153
+ chars,
154
+ )
155
+
156
+
157
+ class AssetWorkerMcpManager:
158
+ def __init__(self, *, runner: WorkerAssetToolRunner) -> None:
159
+ self.runner = runner
160
+ self.resolved_config = _AssetToolResolvedConfig()
161
+ self._closed = False
162
+ asset_read = copy.deepcopy(ASSET_READ_TOOL["function"])
163
+ asset_load = copy.deepcopy(ASSET_LOAD_TOOL["function"])
164
+ self._bindings = (
165
+ McpHostToolBinding(
166
+ tool_name="asset_read",
167
+ tool_alias="asset_read",
168
+ description=str(asset_read["description"]),
169
+ parameters=dict(asset_read["parameters"]),
170
+ run_handler=self.runner.asset_read,
171
+ ),
172
+ McpHostToolBinding(
173
+ tool_name="asset_load",
174
+ tool_alias="asset_load",
175
+ description=str(asset_load["description"]),
176
+ parameters=dict(asset_load["parameters"]),
177
+ run_handler=self.runner.asset_load,
178
+ ),
179
+ )
180
+
181
+ @property
182
+ def tool_bindings(self) -> tuple[McpHostToolBinding, ...]:
183
+ return self._bindings
184
+
185
+ @property
186
+ def closed(self) -> bool:
187
+ return self._closed
188
+
189
+ def startup_metadata(self) -> dict[str, Any]:
190
+ return {
191
+ "config_present": True,
192
+ "user_config_present": False,
193
+ "project_config_present": False,
194
+ "resolved_server_count": 0,
195
+ "resolved_server_ids": [],
196
+ "active_server_count": 0,
197
+ "active_server_ids": [],
198
+ "live_tool_runtime_enabled": False,
199
+ "asset_worker_tools_enabled": True,
200
+ }
201
+
202
+ def catalog_snapshot_metadata(self) -> dict[str, Any]:
203
+ return {
204
+ "catalog_initialized": True,
205
+ "live_tool_runtime_enabled": False,
206
+ "active_server_ids": [],
207
+ "active_server_count": 0,
208
+ "server_catalogs": [],
209
+ "exposed_tool_aliases": [binding.tool_alias for binding in self._bindings],
210
+ "exposed_tool_names": [binding.tool_name for binding in self._bindings],
211
+ "exposed_tool_count": len(self._bindings),
212
+ "snapshotted_resource_count": 0,
213
+ "resource_tool_names": [],
214
+ "resource_tool_count": 0,
215
+ "asset_worker_tools_enabled": True,
216
+ }
217
+
218
+ def execution_context_summary(self) -> dict[str, Any]:
219
+ return {
220
+ "active_server_ids": [],
221
+ "servers": [],
222
+ "asset_worker_tools": [binding.tool_alias for binding in self._bindings],
223
+ }
224
+
225
+ def close(self) -> None:
226
+ self._closed = True
227
+
228
+
229
+ class CompositeWorkerMcpManager:
230
+ def __init__(
231
+ self,
232
+ *,
233
+ base_manager: Any | None,
234
+ asset_manager: AssetWorkerMcpManager,
235
+ ) -> None:
236
+ self.base_manager = base_manager
237
+ self.asset_manager = asset_manager
238
+ self.resolved_config = _AssetToolResolvedConfig(has_any_config=True)
239
+
240
+ @property
241
+ def tool_bindings(self) -> tuple[Any, ...]:
242
+ base_bindings = tuple(getattr(self.base_manager, "tool_bindings", ()) or ())
243
+ asset_bindings = tuple(self.asset_manager.tool_bindings)
244
+ asset_aliases = {str(getattr(binding, "tool_alias", "")) for binding in asset_bindings}
245
+ return (
246
+ *(
247
+ binding
248
+ for binding in base_bindings
249
+ if str(getattr(binding, "tool_alias", "")) not in asset_aliases
250
+ ),
251
+ *asset_bindings,
252
+ )
253
+
254
+ @property
255
+ def closed(self) -> bool:
256
+ base_closed = (
257
+ True if self.base_manager is None else bool(getattr(self.base_manager, "closed", False))
258
+ )
259
+ return base_closed and self.asset_manager.closed
260
+
261
+ def startup_metadata(self) -> dict[str, Any]:
262
+ if self.base_manager is None:
263
+ payload = self.asset_manager.startup_metadata()
264
+ else:
265
+ payload = copy.deepcopy(self.base_manager.startup_metadata())
266
+ payload["asset_worker_tools_enabled"] = True
267
+ payload["asset_worker_tool_count"] = len(self.asset_manager.tool_bindings)
268
+ return payload
269
+
270
+ def catalog_snapshot_metadata(self) -> dict[str, Any]:
271
+ if self.base_manager is None:
272
+ payload = self.asset_manager.catalog_snapshot_metadata()
273
+ else:
274
+ payload = copy.deepcopy(self.base_manager.catalog_snapshot_metadata())
275
+ asset_payload = self.asset_manager.catalog_snapshot_metadata()
276
+ aliases = _append_unique_strings(
277
+ payload.get("exposed_tool_aliases"),
278
+ asset_payload.get("exposed_tool_aliases"),
279
+ )
280
+ names = _append_unique_strings(
281
+ payload.get("exposed_tool_names"),
282
+ asset_payload.get("exposed_tool_names"),
283
+ )
284
+ payload["exposed_tool_aliases"] = aliases
285
+ payload["exposed_tool_names"] = names
286
+ payload["exposed_tool_count"] = len(aliases)
287
+ payload["asset_worker_tools_enabled"] = True
288
+ payload["asset_worker_tool_count"] = len(asset_payload.get("exposed_tool_aliases") or [])
289
+ return payload
290
+
291
+ def execution_context_summary(self) -> dict[str, Any]:
292
+ if self.base_manager is None:
293
+ payload = self.asset_manager.execution_context_summary()
294
+ else:
295
+ payload = copy.deepcopy(self.base_manager.execution_context_summary())
296
+ payload["asset_worker_tools"] = [
297
+ binding.tool_alias for binding in self.asset_manager.tool_bindings
298
+ ]
299
+ return payload
300
+
301
+ def close(self) -> None:
302
+ try:
303
+ self.asset_manager.close()
304
+ finally:
305
+ if self.base_manager is not None:
306
+ self.base_manager.close()
307
+
308
+
309
+ @dataclass(frozen=True)
310
+ class _AssetToolResolvedConfig:
311
+ has_any_config: bool = True
312
+
313
+
314
+ def build_worker_asset_mcp_manager(
315
+ *,
316
+ cfg: AppConfig,
317
+ surface: AssetSurface,
318
+ model_registry: ModelRegistry,
319
+ mirror: TaskAssetMirror,
320
+ usage_logger: AssetUsageLogger | None = None,
321
+ api_key: str | None = None,
322
+ ) -> AssetWorkerMcpManager:
323
+ return AssetWorkerMcpManager(
324
+ runner=WorkerAssetToolRunner(
325
+ cfg=cfg,
326
+ surface=surface,
327
+ model_registry=model_registry,
328
+ mirror=mirror,
329
+ usage_logger=usage_logger,
330
+ api_key=api_key,
331
+ )
332
+ )
333
+
334
+
335
+ def load_worker_asset_mcp_manager(
336
+ *,
337
+ cfg: AppConfig,
338
+ surface: AssetSurface,
339
+ model_registry: ModelRegistry,
340
+ workspace_path: Path,
341
+ usage_logger: AssetUsageLogger | None = None,
342
+ api_key: str | None = None,
343
+ ) -> AssetWorkerMcpManager:
344
+ return build_worker_asset_mcp_manager(
345
+ cfg=cfg,
346
+ surface=surface,
347
+ model_registry=model_registry,
348
+ mirror=load_task_asset_mirror(workspace_path=workspace_path),
349
+ usage_logger=usage_logger,
350
+ api_key=api_key,
351
+ )
352
+
353
+
354
+ def _find_entry(mirror: TaskAssetMirror, asset_id: str) -> MirroredAssetEntry | None:
355
+ for entry in [*mirror.primary, *mirror.may_need, *mirror.pinned]:
356
+ if entry.asset_id == asset_id:
357
+ return entry
358
+ return None
359
+
360
+
361
+ def compose_worker_asset_mcp_manager(
362
+ *,
363
+ base_manager: Any | None,
364
+ asset_manager: AssetWorkerMcpManager,
365
+ ) -> CompositeWorkerMcpManager:
366
+ return CompositeWorkerMcpManager(base_manager=base_manager, asset_manager=asset_manager)
367
+
368
+
369
+ def _load_entry_text(entry: MirroredAssetEntry, *, max_chars: int) -> str:
370
+ if entry.kind == "text" and entry.extracted_text_workspace_path is not None:
371
+ text = _read_text(entry.extracted_text_workspace_path)
372
+ elif entry.kind == "text" and entry.raw_workspace_path is not None:
373
+ text = _read_text(entry.raw_workspace_path)
374
+ else:
375
+ text = _image_entry_text(entry)
376
+ if len(text) > max_chars:
377
+ return text[:max_chars].rstrip() + "\n\n...[truncated to asset block limit]..."
378
+ return text
379
+
380
+
381
+ def _read_from_mirror_entry(entry: MirroredAssetEntry, *, max_chars: int) -> str:
382
+ if entry.status == "deleted":
383
+ return f'Asset {entry.asset_id} - "{entry.title}" has been deleted and is unavailable.'
384
+ if entry.status == "missing":
385
+ return f'Asset {entry.asset_id} - "{entry.title}" is missing from the mirror.'
386
+ content = _load_entry_text(entry, max_chars=max_chars)
387
+ return _tool_result_text(
388
+ entry=entry,
389
+ content=content,
390
+ source="mirror_read",
391
+ truncated="...[truncated to asset block limit]..." in content,
392
+ )
393
+
394
+
395
+ def _image_entry_text(entry: MirroredAssetEntry) -> str:
396
+ parts: list[str] = []
397
+ if entry.comprehension is not None:
398
+ comp = entry.comprehension
399
+ parts.append(f"Comprehension summary:\n{comp.data.semantic_summary}")
400
+ if comp.data.key_entities:
401
+ entities = [
402
+ f"{item.get('type')}={item.get('value')}"
403
+ for item in comp.data.key_entities
404
+ if isinstance(item, dict) and item.get("type") and item.get("value")
405
+ ]
406
+ if entities:
407
+ parts.append("Key entities:\n" + ", ".join(entities))
408
+ if entry.extracted_text_workspace_path is not None:
409
+ ocr_text = _read_text(entry.extracted_text_workspace_path)
410
+ if ocr_text:
411
+ parts.append("OCR text:\n" + ocr_text)
412
+ return "\n\n".join(part for part in parts if part.strip()) or "(no readable image content)"
413
+
414
+
415
+ def _read_text(path: Path) -> str:
416
+ try:
417
+ return path.read_text(encoding="utf-8", errors="replace")
418
+ except OSError:
419
+ return ""
420
+
421
+
422
+ def _optional_string(value: Any) -> str | None:
423
+ if value is None:
424
+ return None
425
+ text = str(value).strip()
426
+ return text or None
427
+
428
+
429
+ def _optional_int(value: Any) -> int | None:
430
+ if value is None:
431
+ return None
432
+ try:
433
+ return int(value)
434
+ except (TypeError, ValueError):
435
+ return None
436
+
437
+
438
+ def _tool_result_text(
439
+ *,
440
+ entry: MirroredAssetEntry,
441
+ content: str,
442
+ source: str,
443
+ truncated: bool,
444
+ ) -> str:
445
+ header = (
446
+ f'Asset {entry.asset_id} - "{entry.title}" '
447
+ f"({entry.kind}, mirrored workspace copy, source={source})"
448
+ )
449
+ framed = build_untrusted_asset_text_block(
450
+ asset_id=entry.asset_id,
451
+ text=content,
452
+ mime_type=entry.mime,
453
+ original_char_count=len(content),
454
+ truncated=truncated,
455
+ )
456
+ return f"{header}\n\nContent:\n{framed}".rstrip()
457
+
458
+
459
+ def _append_unique_strings(left: Any, right: Any) -> list[str]:
460
+ out: list[str] = []
461
+ seen: set[str] = set()
462
+ for item in [*(left or []), *(right or [])]:
463
+ value = str(item or "").strip()
464
+ if not value or value in seen:
465
+ continue
466
+ out.append(value)
467
+ seen.add(value)
468
+ return out
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import errno
4
+ import json
5
+ import os
6
+ import tempfile
7
+ from contextlib import suppress
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ __all__ = ["atomic_write_json", "atomic_write_text"]
12
+ _IGNORED_DIR_FSYNC_ERRNOS = frozenset(
13
+ {
14
+ errno.EINVAL,
15
+ getattr(errno, "ENOTSUP", errno.EINVAL),
16
+ getattr(errno, "EOPNOTSUPP", getattr(errno, "ENOTSUP", errno.EINVAL)),
17
+ }
18
+ )
19
+
20
+
21
+ def _atomic_temp_path(path: Path) -> tuple[int, Path]:
22
+ fd, temp_name = tempfile.mkstemp(
23
+ dir=path.parent,
24
+ prefix=f".{path.name}.",
25
+ suffix=".tmp",
26
+ )
27
+ return fd, Path(temp_name)
28
+
29
+
30
+ def _fsync_dir(path: Path) -> None:
31
+ if os.name == "nt":
32
+ return
33
+ try:
34
+ dir_fd = os.open(path, os.O_RDONLY)
35
+ except OSError as exc:
36
+ if exc.errno in _IGNORED_DIR_FSYNC_ERRNOS:
37
+ return
38
+ raise
39
+ try:
40
+ os.fsync(dir_fd)
41
+ except OSError as exc:
42
+ if exc.errno in _IGNORED_DIR_FSYNC_ERRNOS:
43
+ return
44
+ raise
45
+ finally:
46
+ os.close(dir_fd)
47
+
48
+
49
+ def atomic_write_text(path: Path, text: str, *, encoding: str = "utf-8") -> None:
50
+ path.parent.mkdir(parents=True, exist_ok=True)
51
+ fd, temp_path = _atomic_temp_path(path)
52
+ try:
53
+ with os.fdopen(fd, "w", encoding=encoding, newline="") as handle:
54
+ handle.write(text)
55
+ handle.flush()
56
+ os.fsync(handle.fileno())
57
+ os.replace(temp_path, path)
58
+ _fsync_dir(path.parent)
59
+ finally:
60
+ with suppress(FileNotFoundError):
61
+ temp_path.unlink()
62
+
63
+
64
+ def atomic_write_json(
65
+ path: Path,
66
+ payload: Any,
67
+ *,
68
+ indent: int = 2,
69
+ sort_keys: bool = True,
70
+ ensure_ascii: bool = False,
71
+ encoding: str = "utf-8",
72
+ ) -> None:
73
+ atomic_write_text(
74
+ path,
75
+ json.dumps(
76
+ payload,
77
+ indent=indent,
78
+ sort_keys=sort_keys,
79
+ ensure_ascii=ensure_ascii,
80
+ )
81
+ + "\n",
82
+ encoding=encoding,
83
+ )