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,49 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from ..forge import RunPaths
6
+
7
+
8
+ def asset_store_dir(run_paths: RunPaths) -> Path:
9
+ return run_paths.asset_store_dir
10
+
11
+
12
+ def asset_raw_dir(run_paths: RunPaths, asset_id: str) -> Path:
13
+ return run_paths.assets_raw_dir / asset_id
14
+
15
+
16
+ def asset_raw_path(run_paths: RunPaths, asset_id: str, original_filename: str) -> Path:
17
+ return asset_raw_dir(run_paths, asset_id) / original_filename
18
+
19
+
20
+ def asset_extracted_text_path(run_paths: RunPaths, asset_id: str) -> Path:
21
+ return run_paths.assets_extracted_dir / f"{asset_id}.txt"
22
+
23
+
24
+ def asset_thumbnail_path(run_paths: RunPaths, asset_id: str) -> Path:
25
+ return run_paths.assets_extracted_dir / f"{asset_id}.thumb.png"
26
+
27
+
28
+ def asset_preview_path(run_paths: RunPaths, asset_id: str) -> Path:
29
+ return run_paths.assets_extracted_dir / f"{asset_id}.preview.png"
30
+
31
+
32
+ def asset_comprehension_dir(run_paths: RunPaths, asset_id: str) -> Path:
33
+ return run_paths.assets_comprehensions_dir / asset_id
34
+
35
+
36
+ def asset_comprehension_version_path(
37
+ run_paths: RunPaths,
38
+ asset_id: str,
39
+ version: int,
40
+ ) -> Path:
41
+ return asset_comprehension_dir(run_paths, asset_id) / f"v{version}.json"
42
+
43
+
44
+ def asset_comprehension_current_path(run_paths: RunPaths, asset_id: str) -> Path:
45
+ return asset_comprehension_dir(run_paths, asset_id) / "current.json"
46
+
47
+
48
+ def repo_rel(root: Path, path: Path) -> str:
49
+ return path.resolve().relative_to(root.resolve()).as_posix()
@@ -0,0 +1,326 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from collections.abc import Iterable
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+
8
+ from .models import AssetError
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class AssetBriefingEntry:
13
+ asset_id: str
14
+ rationale: str
15
+ expected_use: str
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class TaskAssetBriefing:
20
+ primary: list[AssetBriefingEntry]
21
+ may_need: list[AssetBriefingEntry]
22
+
23
+
24
+ _ASSET_INTENT_RE = re.compile(
25
+ r"\b(?:asset|attach(?:ed|ment)?|brief|design|image|mockup|note|pdf|"
26
+ r"screenshot|spec|uploaded|wireframe)\b",
27
+ re.IGNORECASE,
28
+ )
29
+ _SINGLE_ASSET_REFERENCE_RE = re.compile(
30
+ r"\b(?:asset|attach(?:ed|ment)?|brief|image|mockup|pdf|screenshot|uploaded|wireframe)\b",
31
+ re.IGNORECASE,
32
+ )
33
+ _WORD_RE = re.compile(r"[a-z0-9][a-z0-9_-]*", re.IGNORECASE)
34
+ _TOKEN_STOPWORDS = frozenset(
35
+ {
36
+ "and",
37
+ "for",
38
+ "from",
39
+ "into",
40
+ "the",
41
+ "this",
42
+ "that",
43
+ "task",
44
+ "use",
45
+ "using",
46
+ "with",
47
+ }
48
+ )
49
+ _IMPLICIT_ASSET_LIMIT = 3
50
+
51
+
52
+ def parse_task_asset_briefing(payload: Any | None) -> TaskAssetBriefing | None:
53
+ if payload is None:
54
+ return None
55
+ if not isinstance(payload, dict):
56
+ raise AssetError("asset_briefing must be an object")
57
+ _reject_unknown_keys(payload, allowed={"primary", "may_need"}, field="asset_briefing")
58
+ return TaskAssetBriefing(
59
+ primary=_parse_entries(payload.get("primary"), field="asset_briefing.primary"),
60
+ may_need=_parse_entries(payload.get("may_need"), field="asset_briefing.may_need"),
61
+ )
62
+
63
+
64
+ def serialize_task_asset_briefing(briefing: TaskAssetBriefing | None) -> dict[str, Any] | None:
65
+ if briefing is None:
66
+ return None
67
+ return {
68
+ "primary": [_entry_to_dict(entry) for entry in briefing.primary],
69
+ "may_need": [_entry_to_dict(entry) for entry in briefing.may_need],
70
+ }
71
+
72
+
73
+ def collect_referenced_asset_ids(plan: dict[str, Any]) -> set[str]:
74
+ referenced: set[str] = set()
75
+ for task in plan.get("tasks") or []:
76
+ if not isinstance(task, dict):
77
+ continue
78
+ briefing = task_asset_briefing(task)
79
+ if briefing is None:
80
+ continue
81
+ referenced.update(entry.asset_id for entry in briefing.primary)
82
+ referenced.update(entry.asset_id for entry in briefing.may_need)
83
+ return referenced
84
+
85
+
86
+ def task_asset_briefing(task: dict[str, Any]) -> TaskAssetBriefing | None:
87
+ return parse_task_asset_briefing(task.get("asset_briefing"))
88
+
89
+
90
+ def task_asset_briefing_for_execution(
91
+ task: dict[str, Any],
92
+ *,
93
+ records: Iterable[Any],
94
+ ) -> TaskAssetBriefing | None:
95
+ briefing = task_asset_briefing(task)
96
+ if briefing is not None and (briefing.primary or briefing.may_need):
97
+ return briefing
98
+ return infer_implicit_task_asset_briefing(task=task, records=records)
99
+
100
+
101
+ def infer_implicit_task_asset_briefing(
102
+ *,
103
+ task: dict[str, Any],
104
+ records: Iterable[Any],
105
+ ) -> TaskAssetBriefing | None:
106
+ active_records = [
107
+ record
108
+ for record in records
109
+ if getattr(record, "deleted_at", None) is None
110
+ and not bool(getattr(record, "pinned", False))
111
+ ]
112
+ if not active_records:
113
+ return None
114
+ task_text = _task_text(task)
115
+ if not task_text:
116
+ return None
117
+ has_asset_intent = bool(_ASSET_INTENT_RE.search(task_text))
118
+ has_single_asset_reference = bool(_SINGLE_ASSET_REFERENCE_RE.search(task_text))
119
+ scored: list[tuple[int, int, Any]] = []
120
+ for index, record in enumerate(active_records):
121
+ score = _asset_match_score(
122
+ task_text=task_text,
123
+ record=record,
124
+ single_active_asset=len(active_records) == 1,
125
+ has_asset_intent=has_asset_intent,
126
+ has_single_asset_reference=has_single_asset_reference,
127
+ )
128
+ if _asset_score_is_relevant(score=score, has_asset_intent=has_asset_intent):
129
+ scored.append((score, index, record))
130
+ if not scored:
131
+ return None
132
+ scored.sort(key=lambda item: (-item[0], item[1]))
133
+ entries = [
134
+ AssetBriefingEntry(
135
+ asset_id=str(getattr(record, "id", "") or "").strip(),
136
+ rationale=_implicit_asset_rationale(record),
137
+ expected_use="Read this asset before executing; it supplies task requirements or constraints.",
138
+ )
139
+ for _score, _index, record in scored[:_IMPLICIT_ASSET_LIMIT]
140
+ if str(getattr(record, "id", "") or "").strip()
141
+ ]
142
+ if not entries:
143
+ return None
144
+ return TaskAssetBriefing(primary=entries, may_need=[])
145
+
146
+
147
+ def bind_asset_to_matching_tasks(
148
+ *,
149
+ plan: dict[str, Any],
150
+ record: Any,
151
+ active_records: Iterable[Any],
152
+ ) -> list[str]:
153
+ tasks = plan.get("tasks")
154
+ if not isinstance(tasks, list):
155
+ return []
156
+ active = [
157
+ item
158
+ for item in active_records
159
+ if getattr(item, "deleted_at", None) is None and not bool(getattr(item, "pinned", False))
160
+ ]
161
+ bound_task_ids: list[str] = []
162
+ for task in tasks:
163
+ if not isinstance(task, dict):
164
+ continue
165
+ if _task_references_asset(task, str(getattr(record, "id", "") or "")):
166
+ continue
167
+ try:
168
+ current = task_asset_briefing(task)
169
+ except AssetError:
170
+ continue
171
+ if current is not None and (current.primary or current.may_need):
172
+ continue
173
+ inferred = infer_implicit_task_asset_briefing(task=task, records=active)
174
+ if inferred is None or not any(
175
+ entry.asset_id == str(getattr(record, "id", "") or "").strip()
176
+ for entry in inferred.primary
177
+ ):
178
+ continue
179
+ task["asset_briefing"] = serialize_task_asset_briefing(inferred)
180
+ task_id = str(task.get("id") or "").strip()
181
+ if task_id:
182
+ bound_task_ids.append(task_id)
183
+ return bound_task_ids
184
+
185
+
186
+ def _parse_entries(payload: Any, *, field: str) -> list[AssetBriefingEntry]:
187
+ if payload is None:
188
+ return []
189
+ if not isinstance(payload, list):
190
+ raise AssetError(f"{field} must be an array")
191
+ out: list[AssetBriefingEntry] = []
192
+ for index, raw_entry in enumerate(payload):
193
+ entry_field = f"{field}[{index}]"
194
+ if not isinstance(raw_entry, dict):
195
+ raise AssetError(f"{entry_field} must be an object")
196
+ _reject_unknown_keys(
197
+ raw_entry,
198
+ allowed={"asset_id", "rationale", "expected_use"},
199
+ field=entry_field,
200
+ )
201
+ asset_id = _required_string(raw_entry.get("asset_id"), field=f"{entry_field}.asset_id")
202
+ rationale = _required_string(raw_entry.get("rationale"), field=f"{entry_field}.rationale")
203
+ expected_use = _required_string(
204
+ raw_entry.get("expected_use"),
205
+ field=f"{entry_field}.expected_use",
206
+ )
207
+ out.append(
208
+ AssetBriefingEntry(
209
+ asset_id=asset_id,
210
+ rationale=rationale,
211
+ expected_use=expected_use,
212
+ )
213
+ )
214
+ return out
215
+
216
+
217
+ def _entry_to_dict(entry: AssetBriefingEntry) -> dict[str, str]:
218
+ return {
219
+ "asset_id": entry.asset_id,
220
+ "rationale": entry.rationale,
221
+ "expected_use": entry.expected_use,
222
+ }
223
+
224
+
225
+ def _required_string(value: Any, *, field: str) -> str:
226
+ if not isinstance(value, str):
227
+ raise AssetError(f"{field} must be a string")
228
+ text = value.strip()
229
+ if not text:
230
+ raise AssetError(f"{field} must be non-empty")
231
+ return text
232
+
233
+
234
+ def _reject_unknown_keys(payload: dict[str, Any], *, allowed: set[str], field: str) -> None:
235
+ unknown = sorted(set(payload) - allowed)
236
+ if unknown:
237
+ raise AssetError(f"{field} contains unsupported keys: {', '.join(unknown)}")
238
+
239
+
240
+ def _task_text(task: dict[str, Any]) -> str:
241
+ parts = [
242
+ str(task.get("id") or ""),
243
+ str(task.get("title") or ""),
244
+ str(task.get("description") or ""),
245
+ ]
246
+ acceptance = task.get("acceptance_criteria")
247
+ if isinstance(acceptance, list):
248
+ parts.extend(str(item or "") for item in acceptance)
249
+ scopes = [task.get("estimated_files"), task.get("write_scope")]
250
+ for scope in scopes:
251
+ if isinstance(scope, list):
252
+ parts.extend(str(item or "") for item in scope)
253
+ return "\n".join(parts)
254
+
255
+
256
+ def _asset_match_score(
257
+ *,
258
+ task_text: str,
259
+ record: Any,
260
+ single_active_asset: bool,
261
+ has_asset_intent: bool,
262
+ has_single_asset_reference: bool,
263
+ ) -> int:
264
+ folded_task = task_text.casefold()
265
+ asset_id = str(getattr(record, "id", "") or "").strip().casefold()
266
+ title = str(getattr(record, "title", "") or "").strip()
267
+ filename = str(getattr(record, "original_filename", "") or "").strip()
268
+ description = str(getattr(record, "description", "") or "").strip()
269
+ stored_path = str(getattr(record, "stored_path", "") or "").strip()
270
+ fields = [title, filename, description, stored_path]
271
+ score = 0
272
+ if asset_id and asset_id in folded_task:
273
+ score += 20
274
+ for field in fields:
275
+ folded = field.casefold()
276
+ if folded and folded in folded_task:
277
+ score += 8
278
+ for token in _asset_tokens(title):
279
+ if token in folded_task:
280
+ score += 4
281
+ for token in _asset_tokens(filename):
282
+ if token in folded_task:
283
+ score += 4
284
+ for token in _asset_tokens(description):
285
+ if token in folded_task:
286
+ score += 2
287
+ if has_single_asset_reference and single_active_asset:
288
+ score += 8
289
+ if has_asset_intent and score >= 4:
290
+ score += 2
291
+ return score
292
+
293
+
294
+ def _asset_score_is_relevant(*, score: int, has_asset_intent: bool) -> bool:
295
+ if score >= 8:
296
+ return True
297
+ return has_asset_intent and score > 0
298
+
299
+
300
+ def _asset_tokens(text: str) -> set[str]:
301
+ normalized = re.sub(r"[./\\_-]+", " ", str(text or "").casefold())
302
+ tokens = set()
303
+ for token in _WORD_RE.findall(normalized):
304
+ if len(token) <= 2 or token in _TOKEN_STOPWORDS:
305
+ continue
306
+ tokens.add(token)
307
+ return tokens
308
+
309
+
310
+ def _implicit_asset_rationale(record: Any) -> str:
311
+ title = str(getattr(record, "title", "") or "").strip()
312
+ if title:
313
+ return f'Task text references an attached or named asset matching "{title}".'
314
+ return "Task text references an attached or named asset matching this record."
315
+
316
+
317
+ def _task_references_asset(task: dict[str, Any], asset_id: str) -> bool:
318
+ if not asset_id:
319
+ return False
320
+ try:
321
+ briefing = task_asset_briefing(task)
322
+ except AssetError:
323
+ return False
324
+ if briefing is None:
325
+ return False
326
+ return any(entry.asset_id == asset_id for entry in [*briefing.primary, *briefing.may_need])