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,310 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import re
5
+ import tomllib
6
+ from contextlib import nullcontext
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Any, Literal
10
+
11
+ from .agentbox_client import AgentBoxClient
12
+ from .tools.registry import iter_builtin_tool_metadata
13
+ from .usage_tracker import UsageRecord
14
+
15
+ AgentBoxToolCategory = Literal["edit", "read", "exec", "net", "other"]
16
+
17
+ _TRUE_VALUES = {"1", "true", "yes", "on"}
18
+ _PATH_RE = re.compile(r"(?:~|\.{1,2}|/)?(?:[\w.-]+/)+[\w.-]+")
19
+ _INLINE_CODE_RE = re.compile(r"`[^`]*`")
20
+ _FENCED_CODE_RE = re.compile(r"```[\s\S]*?```")
21
+ _WORD_RE = re.compile(r"\s+")
22
+ _TOOL_CATEGORY_BY_NAME: dict[str, AgentBoxToolCategory] | None = None
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class _AgentBoxSettings:
27
+ plane_url: str
28
+ token: str
29
+ org_id: str | None
30
+ person_id: str | None
31
+ machine_id: str | None
32
+ agent_id: str | None
33
+ queue_dir: str | None
34
+ task_detail: Literal["topic", "category"]
35
+
36
+
37
+ def _load_agentbox_settings() -> _AgentBoxSettings | None:
38
+ config = _read_agentbox_config()
39
+ runtime = config.get("runtime", {})
40
+ alysis = runtime.get("alysis", {}) if isinstance(runtime, dict) else {}
41
+ if not isinstance(alysis, dict):
42
+ alysis = {}
43
+
44
+ plane_url = _env_or_config("AGENTBOX_PLANE_URL", config, "plane_url")
45
+ token = _env_or_config("AGENTBOX_TOKEN", config, "machine_token")
46
+ if plane_url is None or token is None:
47
+ return None
48
+
49
+ machine_id = _env_or_config("AGENTBOX_MACHINE_ID", config, "machine_id")
50
+ agent_id = _env_or_config("AGENTBOX_AGENT_ID", alysis, "agent_id")
51
+ if agent_id is None and machine_id is not None:
52
+ agent_id = f"{machine_id}_alysis"
53
+
54
+ return _AgentBoxSettings(
55
+ plane_url=plane_url,
56
+ token=token,
57
+ org_id=_env_or_config("AGENTBOX_ORG_ID", config, "org_id"),
58
+ person_id=_env_or_config("AGENTBOX_PERSON_ID", config, "person_id"),
59
+ machine_id=machine_id,
60
+ agent_id=agent_id,
61
+ queue_dir=_sdk_queue_dir(config),
62
+ task_detail=(
63
+ "category"
64
+ if _env_or_config("AGENTBOX_TASK_DETAIL", config, "task_detail") == "category"
65
+ else "topic"
66
+ ),
67
+ )
68
+
69
+
70
+ def _read_agentbox_config() -> dict[str, Any]:
71
+ configured_path = _text(os.environ.get("AGENTBOX_CONFIG"))
72
+ if configured_path is not None:
73
+ path = Path(configured_path).expanduser()
74
+ else:
75
+ home = Path(os.environ.get("AGENTBOX_HOME", Path.home() / ".agentbox"))
76
+ path = home.expanduser() / "config.toml"
77
+ try:
78
+ with path.open("rb") as handle:
79
+ parsed = tomllib.load(handle)
80
+ return parsed if isinstance(parsed, dict) else {}
81
+ except (OSError, tomllib.TOMLDecodeError, TypeError):
82
+ return {}
83
+
84
+
85
+ def _env_or_config(env_name: str, config: dict[str, Any], config_name: str) -> str | None:
86
+ return _text(os.environ.get(env_name)) or _text(config.get(config_name))
87
+
88
+
89
+ def _sdk_queue_dir(config: dict[str, Any]) -> str | None:
90
+ explicit = _text(os.environ.get("AGENTBOX_QUEUE_DIR"))
91
+ if explicit is not None:
92
+ return str(Path(explicit).expanduser())
93
+ connector_queue = _text(config.get("queue_dir"))
94
+ if connector_queue is None:
95
+ return None
96
+ return str(Path(connector_queue).expanduser().parent / "sdk-queue")
97
+
98
+
99
+ def _text(value: Any) -> str | None:
100
+ if not isinstance(value, str):
101
+ return None
102
+ stripped = value.strip()
103
+ return stripped or None
104
+
105
+
106
+ class AgentBoxTelemetry:
107
+ def __init__(self, *, client: Any, root: Path) -> None:
108
+ self._client = client
109
+ self._root = root
110
+ self._session_cm: Any | None = None
111
+ self._session: Any | None = None
112
+ self._turn_cm: Any | None = None
113
+ self._turn: Any | None = None
114
+ self._turn_input_tokens = 0
115
+ self._turn_output_tokens = 0
116
+ self._turn_usd: float | None = None
117
+ self._last_task = ""
118
+
119
+ @classmethod
120
+ def from_env(cls, *, root: Path, runtime_version: str) -> AgentBoxTelemetry | None:
121
+ if os.environ.get("AGENTBOX_ENABLED", "").strip().lower() not in _TRUE_VALUES:
122
+ return None
123
+ settings = _load_agentbox_settings()
124
+ if settings is None:
125
+ return None
126
+
127
+ try:
128
+ client = AgentBoxClient(
129
+ token=settings.token,
130
+ plane_url=settings.plane_url,
131
+ org_id=settings.org_id,
132
+ person_id=settings.person_id,
133
+ machine_id=settings.machine_id,
134
+ agent_id=settings.agent_id,
135
+ runtime_version=runtime_version,
136
+ queue_dir=settings.queue_dir,
137
+ task_detail=settings.task_detail,
138
+ )
139
+ telemetry = cls(client=client, root=root)
140
+ telemetry.start_session()
141
+ return telemetry
142
+ except Exception:
143
+ return None
144
+
145
+ def start_session(self) -> None:
146
+ if self._session is not None:
147
+ return
148
+ try:
149
+ self._session_cm = self._client.session(workspace=self._root.name)
150
+ self._session = self._session_cm.__enter__()
151
+ except Exception:
152
+ self._session_cm = None
153
+ self._session = None
154
+
155
+ def close(self, *, error: bool = False) -> None:
156
+ try:
157
+ if self._turn_cm is not None:
158
+ self._turn_cm.__exit__(None, None, None)
159
+ except Exception:
160
+ pass
161
+ finally:
162
+ self._turn_cm = None
163
+ self._turn = None
164
+
165
+ try:
166
+ if self._session_cm is not None:
167
+ exc_type = RuntimeError if error else None
168
+ exc = RuntimeError("session ended") if error else None
169
+ self._session_cm.__exit__(exc_type, exc, None)
170
+ except Exception:
171
+ pass
172
+ finally:
173
+ self._session_cm = None
174
+ self._session = None
175
+
176
+ close = getattr(self._client, "close", None)
177
+ if callable(close):
178
+ try:
179
+ close()
180
+ except Exception:
181
+ pass
182
+
183
+ def turn(self) -> Any:
184
+ if self._session is None:
185
+ return nullcontext()
186
+ return _AgentBoxTurnContext(self)
187
+
188
+ def task(self, objective: str) -> None:
189
+ if self._session is None:
190
+ return
191
+ hint = sanitize_task_hint(objective)
192
+ if not hint or hint == self._last_task:
193
+ return
194
+ self._last_task = hint
195
+ try:
196
+ self._session.task(hint)
197
+ except Exception:
198
+ pass
199
+
200
+ def tool(self, name: str) -> None:
201
+ if self._session is None:
202
+ return
203
+ clean_name = safe_tool_name(name)
204
+ try:
205
+ self._session.tool(clean_name, category=tool_category(clean_name))
206
+ except Exception:
207
+ pass
208
+
209
+ def record_usage(self, record: UsageRecord) -> None:
210
+ if self._turn_cm is None or self._session is None:
211
+ return
212
+ self._turn_input_tokens += max(0, int(record.prompt_tokens or 0))
213
+ self._turn_output_tokens += max(0, int(record.completion_tokens or 0))
214
+ if record.cost_usd is not None:
215
+ self._turn_usd = (self._turn_usd or 0.0) + max(0.0, float(record.cost_usd))
216
+ tokens = getattr(self._session, "tokens", None)
217
+ if not callable(tokens):
218
+ tokens = getattr(self._turn, "tokens", None)
219
+ if not callable(tokens):
220
+ return
221
+ try:
222
+ tokens(
223
+ in_=self._turn_input_tokens,
224
+ out=self._turn_output_tokens,
225
+ usd=self._turn_usd,
226
+ )
227
+ except Exception:
228
+ pass
229
+
230
+
231
+ class _AgentBoxTurnContext:
232
+ def __init__(self, telemetry: AgentBoxTelemetry) -> None:
233
+ self._telemetry = telemetry
234
+
235
+ def __enter__(self) -> AgentBoxTelemetry:
236
+ self._telemetry._turn_input_tokens = 0
237
+ self._telemetry._turn_output_tokens = 0
238
+ self._telemetry._turn_usd = None
239
+ try:
240
+ self._telemetry._turn_cm = self._telemetry._session.turn()
241
+ self._telemetry._turn = self._telemetry._turn_cm.__enter__()
242
+ except Exception:
243
+ self._telemetry._turn_cm = None
244
+ self._telemetry._turn = None
245
+ return self._telemetry
246
+
247
+ def __exit__(self, exc_type: object, exc: object, tb: object) -> bool:
248
+ try:
249
+ if self._telemetry._turn_cm is not None:
250
+ self._telemetry._turn_cm.__exit__(exc_type, exc, tb)
251
+ except Exception:
252
+ pass
253
+ finally:
254
+ self._telemetry._turn_cm = None
255
+ self._telemetry._turn = None
256
+ return False
257
+
258
+
259
+ def sanitize_task_hint(value: str) -> str:
260
+ text = str(value or "")
261
+ text = _FENCED_CODE_RE.sub(" ", text)
262
+ text = _INLINE_CODE_RE.sub(" ", text)
263
+ text = _PATH_RE.sub(" file ", text)
264
+ text = re.sub(r"\bfile(?:\s+file\b)+", "file", text)
265
+ text = _WORD_RE.sub(" ", text).strip()
266
+ text = re.sub(r"\s+([.,;:!?])", r"\1", text)
267
+ if not text:
268
+ return "working"
269
+ return text[:140].rstrip()
270
+
271
+
272
+ def safe_tool_name(value: str) -> str:
273
+ return re.sub(r"[^\w:.-]", "_", str(value or "unknown"))[:80] or "unknown"
274
+
275
+
276
+ def tool_category(tool_name: str) -> AgentBoxToolCategory:
277
+ global _TOOL_CATEGORY_BY_NAME
278
+ if _TOOL_CATEGORY_BY_NAME is None:
279
+ _TOOL_CATEGORY_BY_NAME = _build_tool_category_map()
280
+ return _TOOL_CATEGORY_BY_NAME.get(tool_name, _heuristic_tool_category(tool_name))
281
+
282
+
283
+ def _build_tool_category_map() -> dict[str, AgentBoxToolCategory]:
284
+ mapped: dict[str, AgentBoxToolCategory] = {}
285
+ for metadata in iter_builtin_tool_metadata():
286
+ tags = {tag.strip().lower() for tag in metadata.categories}
287
+ if "write" in tags:
288
+ mapped[metadata.name] = "edit"
289
+ elif "shell" in tags or "verify" in tags:
290
+ mapped[metadata.name] = "exec"
291
+ elif "web" in tags:
292
+ mapped[metadata.name] = "net"
293
+ elif "read" in tags or "search" in tags or "history" in tags:
294
+ mapped[metadata.name] = "read"
295
+ else:
296
+ mapped[metadata.name] = "other"
297
+ return mapped
298
+
299
+
300
+ def _heuristic_tool_category(tool_name: str) -> AgentBoxToolCategory:
301
+ normalized = tool_name.strip().lower()
302
+ if any(token in normalized for token in ("write", "edit", "patch", "delete", "move", "mkdir")):
303
+ return "edit"
304
+ if any(token in normalized for token in ("shell", "exec", "run", "verify", "test")):
305
+ return "exec"
306
+ if any(token in normalized for token in ("web", "http", "fetch", "search")):
307
+ return "net"
308
+ if any(token in normalized for token in ("read", "list", "history", "symbol", "grep", "rg")):
309
+ return "read"
310
+ return "other"
@@ -0,0 +1,152 @@
1
+ """Endpoints and identifiers for the hosted Alysis Code Pro service.
2
+
3
+ `alysis login` runs an RFC 8628-style device flow against Supabase Edge
4
+ Functions (`device-code` / `device-token`); the user approves the code on the
5
+ account website's /activate page. The CLI receives a gateway key (``slk_…``)
6
+ and talks to the Alysis Code LLM gateway — an OpenAI-compatible proxy that meters
7
+ the subscription's credits server-side. The CLI never holds upstream provider
8
+ keys for Pro; BYOK profiles are configured separately and take precedence.
9
+
10
+ Values can be overridden via environment variables to point at a different
11
+ deployment (e.g. a staging project or local stubs) during testing.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from urllib.parse import urlsplit
17
+
18
+ from .branding import env_get
19
+
20
+ # Supabase project hosting the device-login edge functions.
21
+ _DEFAULT_SUPABASE_URL = "https://vzigujbcjjmpntxhmyvr.supabase.co"
22
+
23
+ # Product site: serves the /activate device-approval page and /account.
24
+ #
25
+ # ---------------------------------------------------------------------------
26
+ # Everything user-visible that names the site derives from _DEFAULT_SITE_URL —
27
+ # help text, proxy error messages, the /activate and /account links, and the
28
+ # tests asserting on them. Keep it that way: re-hardcoding the host anywhere
29
+ # else is caught by test_rebrand_compatibility.py.
30
+ #
31
+ # The device-login flow depends on this host actually serving /activate against
32
+ # the Supabase project below. The CLI sends Pro users there to approve a login
33
+ # code, so the two must move together — a client pointed at a host that does
34
+ # not serve the page breaks sign-in with no client-side workaround.
35
+ #
36
+ # _LEGACY_SITE_URL is the pre-rebrand host. It is kept only so a 301 from it
37
+ # can be verified and so configs that still name it are recognisable; nothing
38
+ # reads it at runtime.
39
+ # ---------------------------------------------------------------------------
40
+ PRODUCT_SITE_URL = "https://alysiscode.com"
41
+ _LEGACY_SITE_URL = "https://sylliptor.alysisai.com"
42
+ _DEFAULT_SITE_URL = PRODUCT_SITE_URL
43
+
44
+ # Supabase "anon" key: a PUBLIC client identifier (shipped in the website's
45
+ # browser bundle too). It grants nothing by itself — the edge functions are
46
+ # either public-by-design (device flow) or JWT/secret-guarded server-side.
47
+ ANON_KEY = (
48
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
49
+ "eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZ6aWd1amJjamptcG50eGhteXZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODA5Mzc0NTIsImV4cCI6MjA5NjUxMzQ1Mn0."
50
+ "vLH9q-BNO8IWIZrVlvCw8pZWXdLgmKG4Tl9toTTD3pg"
51
+ )
52
+
53
+ # The profile/preset key used for the hosted Pro provider.
54
+ PROFILE_KEY = "alysis"
55
+
56
+ # LEGACY: base URL of the retired MiMo-trial proxy (an OpenRouter-forwarding
57
+ # Supabase Edge Function). The service is gone, but URL classifiers (web
58
+ # search / provider limits) still recognize it so configs from that era keep
59
+ # loading with sensible behavior instead of misclassifying.
60
+ DEFAULT_PROXY_BASE_URL = f"{_DEFAULT_SUPABASE_URL}/functions/v1/llm/v1"
61
+
62
+
63
+ # Loopback hosts may use http:// (local stubs / tests); every other host must
64
+ # be https so device codes and the gateway key never travel in cleartext.
65
+ _LOOPBACK_HOSTS = frozenset({"127.0.0.1", "localhost", "::1"})
66
+
67
+
68
+ class AlysisCloudConfigError(ValueError):
69
+ """Raised when a configured Alysis Code cloud URL is unsafe (e.g. cleartext http)."""
70
+
71
+
72
+ def _clean(url: str) -> str:
73
+ return str(url or "").strip().rstrip("/")
74
+
75
+
76
+ def _checked(url: str) -> str:
77
+ """Clean a URL and reject cleartext http:// for non-loopback hosts.
78
+
79
+ Device codes and the long-lived gateway key travel to these endpoints, so a
80
+ downgraded (http://) origin from an env override would leak them. https is
81
+ required unless the host is loopback (local stubs / tests) or
82
+ ALYSIS_ALLOW_INSECURE_URLS is explicitly set.
83
+ """
84
+ cleaned = _clean(url)
85
+ if not cleaned:
86
+ return cleaned
87
+ parts = urlsplit(cleaned)
88
+ if parts.scheme.lower() == "https":
89
+ return cleaned
90
+ host = (parts.hostname or "").lower()
91
+ if host in _LOOPBACK_HOSTS or env_get("ALYSIS_ALLOW_INSECURE_URLS"):
92
+ return cleaned
93
+ raise AlysisCloudConfigError(
94
+ f"Refusing to use insecure Alysis Code URL {cleaned!r}: https is required "
95
+ "(set ALYSIS_ALLOW_INSECURE_URLS=1 only for trusted local testing)."
96
+ )
97
+
98
+
99
+ def supabase_url() -> str:
100
+ return _checked(env_get("ALYSIS_SUPABASE_URL") or _DEFAULT_SUPABASE_URL)
101
+
102
+
103
+ def site_url() -> str:
104
+ return _checked(env_get("ALYSIS_SITE_URL") or _DEFAULT_SITE_URL)
105
+
106
+
107
+ def site_host() -> str:
108
+ """Bare hostname of the product site, for prose that reads better without a scheme."""
109
+ return urlsplit(site_url()).netloc
110
+
111
+
112
+ def account_url() -> str:
113
+ """Where a Pro user manages their plan and credits.
114
+
115
+ Everything user-visible that names the account page goes through here, so
116
+ moving the site is the single constant above and not a search-and-replace
117
+ across help text, error messages, and docs.
118
+ """
119
+ return f"{site_url()}/account"
120
+
121
+
122
+ def gateway_base_url() -> str:
123
+ """OpenAI-compatible base URL; the LLM client appends ``/chat/completions``.
124
+
125
+ The hosted proxy runs as the `llm` Supabase Edge Function (the same shape
126
+ the MiMo-trial proxy used), holding the upstream DeepSeek key server-side
127
+ and metering each account's allowance/credits.
128
+ """
129
+ override = env_get("ALYSIS_GATEWAY_URL")
130
+ if override:
131
+ return _checked(override)
132
+ return f"{supabase_url()}/functions/v1/llm/v1"
133
+
134
+
135
+ def device_code_url() -> str:
136
+ """POST here to start a device login (returns user_code + device_code)."""
137
+ return f"{supabase_url()}/functions/v1/device-code"
138
+
139
+
140
+ def device_token_url() -> str:
141
+ """POST device_code here until the user approves (returns the slk_ key)."""
142
+ return f"{supabase_url()}/functions/v1/device-token"
143
+
144
+
145
+ def activate_url() -> str:
146
+ """The website page where a signed-in user approves a device code."""
147
+ return f"{site_url()}/activate"
148
+
149
+
150
+ def models_url() -> str:
151
+ """The gateway's OpenAI-shaped model listing."""
152
+ return f"{gateway_base_url()}/models"