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,101 @@
1
+ """Mutable view-model for the full-screen TUI.
2
+
3
+ Holds only what the footer/header need to render. The footer HUD fields
4
+ (``context_pct`` / ``tokens`` / ``cost_usd``) are wired live: ``loop.py`` seeds
5
+ them when the session is built and refreshes them after each turn (and mid-turn,
6
+ throttled) from the session's usage summary + context cache. Other fields are
7
+ toggled by the user via Tab (persona) / Shift+Tab (execution mode).
8
+
9
+ ``exec_mode`` mirrors ``session.mode`` and is the single authority for what the
10
+ agent is allowed to do without asking. There is deliberately no second
11
+ approval-policy flag here: an independent "auto-approve" toggle could silently
12
+ answer every gate that ``review`` mode raised, leaving the footer advertising a
13
+ guarded mode while the session behaved like ``fullaccess``.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import dataclass
19
+
20
+ PLAN_MODE = "plan"
21
+ ACT_MODE = "act"
22
+
23
+ # Shift+Tab cycles the execution mode in this order (wrapping). This is the same
24
+ # set the /mode picker offers, kept in escalating-capability order so the cycle
25
+ # reads as "loosen the guards one notch" rather than an arbitrary rotation.
26
+ # ``fullaccess`` is included deliberately — the caller echoes its warning every
27
+ # time the cycle lands there, so reaching the unguarded mode is never silent.
28
+ EXEC_MODE_CYCLE: tuple[str, ...] = ("readonly", "review", "auto", "fullaccess")
29
+
30
+
31
+ def next_exec_mode(current: str) -> str:
32
+ """Return the execution mode one step along :data:`EXEC_MODE_CYCLE`.
33
+
34
+ An unknown or empty ``current`` starts the cycle at its first entry, so a
35
+ session whose mode has not been synced yet still advances predictably
36
+ instead of raising.
37
+ """
38
+ normalized = str(current or "").strip().lower()
39
+ try:
40
+ index = EXEC_MODE_CYCLE.index(normalized)
41
+ except ValueError:
42
+ return EXEC_MODE_CYCLE[0]
43
+ return EXEC_MODE_CYCLE[(index + 1) % len(EXEC_MODE_CYCLE)]
44
+
45
+
46
+ @dataclass
47
+ class TuiState:
48
+ model_name: str = ""
49
+ # Non-empty while the shell is available but model calls are not (for
50
+ # example, a selected subscription still needs browser authentication).
51
+ connection_status: str = ""
52
+ tokens: int = 0
53
+ # Session cost. ``None`` means pricing is unknown (an unmetered/free model with
54
+ # real usage) — the footer renders that as "n/a" rather than a misleading
55
+ # "$0.0000". A literal 0.0 means nothing has been spent yet.
56
+ cost_usd: float | None = 0.0
57
+ cost_unknown_calls: int = 0 # calls whose cost couldn't be metered (footer "+N")
58
+ # Preformatted billing status (for example ``subscription`` or ``~$0.0123``).
59
+ # Empty retains the legacy numeric fallback for callers that do not have a
60
+ # UsageSummary available yet.
61
+ cost_display: str = ""
62
+ mode: str = ACT_MODE # "plan" | "act"
63
+ exec_mode: str = "" # execution mode: review | auto | readonly | fullaccess
64
+ # Active persona (code|architect|ask|debug); "" or "code" renders no
65
+ # persona badge — the execution-mode badge alone stays authoritative.
66
+ persona: str = ""
67
+ # Forge: True while the user is inside a Forge planning session (ui_mode ==
68
+ # "forge"); drives the footer FORGE badge + the forge-specific placeholder.
69
+ forge_mode: bool = False
70
+ forge_run_id: str = "" # short run id shown in the FORGE badge, e.g. "run-1a2b"
71
+ # Name of the subagent currently running through auto-delegation; drives
72
+ # the footer badge so the user knows nested work is active. Empty otherwise.
73
+ active_subagent: str = ""
74
+ # Every concurrently running subagent, in start order. ``active_subagent``
75
+ # remains the compatibility view of the most recently started survivor.
76
+ active_subagents: tuple[str, ...] = ()
77
+ username: str = ""
78
+ workspace: str = "" # short display form, e.g. "~/coder-plugin-install"
79
+ branch: str = "" # git branch name, e.g. "feat/tui-rebuild"
80
+ usage_hud_enabled: bool = True
81
+ # Conversation headroom %, seeded from the session before first paint.
82
+ # ``None`` means "not measured yet" so a failed compute reads n/a in the
83
+ # footer instead of a fabricated 100%.
84
+ context_pct: float | None = None
85
+
86
+ @property
87
+ def plan_mode(self) -> bool:
88
+ return self.mode == PLAN_MODE
89
+
90
+ def toggle_mode(self) -> str:
91
+ self.mode = PLAN_MODE if self.mode == ACT_MODE else ACT_MODE
92
+ return self.mode
93
+
94
+
95
+ __all__ = [
96
+ "TuiState",
97
+ "PLAN_MODE",
98
+ "ACT_MODE",
99
+ "EXEC_MODE_CYCLE",
100
+ "next_exec_mode",
101
+ ]
@@ -0,0 +1,66 @@
1
+ """Per-subagent visual identity — accent colour only.
2
+
3
+ One tiny authority (like ``forge_status``) so the transcript spawn line, the
4
+ live status, and the footer badge can never disagree about who a given
5
+ subagent is. Activity comes from runtime events, never from role narration.
6
+ Result attribution prints the registry name alone and deliberately does not
7
+ consult this module — a subagent wears no per-agent symbol, so there is
8
+ nothing to keep in sync.
9
+
10
+ The name is the identity: the shared ``↪``/``↩`` marks say only that a nested
11
+ run started or ended, never which agent it was. Colours are distinct from the
12
+ fixed mode accents (green chat, violet forge, cyan brand) so a
13
+ subagent badge never impersonates a mode. Custom subagents get a colour picked
14
+ deterministically from the name — the same agent looks the same every run.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import zlib
20
+ from dataclasses import dataclass
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class SubagentIdentity:
25
+ color: str
26
+
27
+
28
+ _BUILTIN_IDENTITIES: dict[str, SubagentIdentity] = {
29
+ "frontend-engineer": SubagentIdentity("#a371f7"),
30
+ # Silver keeps delegated work visually distinct from the main modes.
31
+ "visual-designer": SubagentIdentity("#c9d1d9"),
32
+ "explorer": SubagentIdentity("#58a6ff"),
33
+ "implementer": SubagentIdentity("#f0883e"),
34
+ "debugger": SubagentIdentity("#f47067"),
35
+ "verifier": SubagentIdentity("#79c0ff"),
36
+ "code-reviewer": SubagentIdentity("#db61a2"),
37
+ "dependency-scout": SubagentIdentity("#8c959f"),
38
+ }
39
+
40
+ _FALLBACK_COLORS: tuple[str, ...] = (
41
+ "#58a6ff",
42
+ "#f0883e",
43
+ "#db61a2",
44
+ "#39c5cf",
45
+ "#f47067",
46
+ "#d2a8ff",
47
+ )
48
+
49
+
50
+ def subagent_identity(name: str) -> SubagentIdentity:
51
+ """Identity for ``name`` (built-in aliases resolved, e.g. explore→explorer)."""
52
+ clean = str(name or "").strip().lower()
53
+ try:
54
+ from ...subagents import canonical_subagent_name
55
+
56
+ clean = canonical_subagent_name(clean) or clean
57
+ except Exception: # noqa: BLE001 - identity lookup must never raise
58
+ pass
59
+ known = _BUILTIN_IDENTITIES.get(clean)
60
+ if known is not None:
61
+ return known
62
+ digest = zlib.crc32(clean.encode("utf-8", "replace"))
63
+ return SubagentIdentity(_FALLBACK_COLORS[digest % len(_FALLBACK_COLORS)])
64
+
65
+
66
+ __all__ = ["SubagentIdentity", "subagent_identity"]
@@ -0,0 +1,186 @@
1
+ """Pure row construction for the terminal TUI's live subagent panel.
2
+
3
+ The panel is a bounded live tail, not a transcript. This module deliberately
4
+ owns no prompt_toolkit state: callers supply the latest child status and the
5
+ entries accumulated from incremental scheduler reads.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+
12
+ from ...subagent_labels import subagent_identity
13
+
14
+ ENTRY_BUFFER_CAP = 240
15
+
16
+ _MIDDLE_DOT = "\u00b7"
17
+ _ELLIPSIS = "\u2026"
18
+
19
+ _S_HEAD = "class:tui.subpanel.head"
20
+ _S_STATE = "class:tui.subpanel.state"
21
+ _S_DIM = "class:tui.subpanel.dim"
22
+ _S_TOOL = "class:tui.subpanel.tool"
23
+ _S_RESULT = "class:tui.subpanel.result"
24
+ _S_ASSISTANT = "class:tui.subpanel.assistant"
25
+ _S_USER = "class:tui.subpanel.user"
26
+ _S_HINT = "class:tui.subpanel.hint"
27
+
28
+ _ENTRY_STYLE = {
29
+ "tool": (_S_TOOL, "\u25b8 "),
30
+ "tool_result": (_S_RESULT, "\u2713 "),
31
+ "tool_error": (_S_RESULT, "\u2717 "),
32
+ "assistant": (_S_ASSISTANT, "a: "),
33
+ "user": (_S_USER, "u: "),
34
+ }
35
+
36
+
37
+ def append_bounded_entries(
38
+ existing: list[dict[str, str]],
39
+ incoming: list[dict[str, str]],
40
+ *,
41
+ limit: int = ENTRY_BUFFER_CAP,
42
+ ) -> list[dict[str, str]]:
43
+ """Append normalized entries while retaining only the newest ``limit``."""
44
+ cap = max(1, int(limit))
45
+ combined = [*existing, *incoming]
46
+ return combined[-cap:]
47
+
48
+
49
+ def _fit_segments(segments: list[tuple[str, str]], width: int) -> list[tuple[str, str]]:
50
+ out: list[tuple[str, str]] = []
51
+ used = 0
52
+ for style, value in segments:
53
+ text = str(value or "")
54
+ if not text:
55
+ continue
56
+ room = width - used
57
+ if room <= 0:
58
+ break
59
+ if len(text) <= room:
60
+ out.append((style, text))
61
+ used += len(text)
62
+ continue
63
+ clipped = text[: room - 1].rstrip() + _ELLIPSIS if room >= 2 else _ELLIPSIS
64
+ out.append((style, clipped[:room]))
65
+ break
66
+ return out
67
+
68
+
69
+ def _elapsed_label(value: Any) -> str:
70
+ try:
71
+ elapsed_ms = max(0, int(value or 0))
72
+ except (TypeError, ValueError):
73
+ elapsed_ms = 0
74
+ if elapsed_ms < 1000:
75
+ return f"{elapsed_ms}ms"
76
+ seconds = elapsed_ms // 1000
77
+ if seconds < 60:
78
+ return f"{seconds}s"
79
+ minutes, seconds = divmod(seconds, 60)
80
+ if minutes < 60:
81
+ return f"{minutes}m {seconds}s"
82
+ hours, minutes = divmod(minutes, 60)
83
+ return f"{hours}h {minutes}m"
84
+
85
+
86
+ def quiet_time_label(status: dict[str, Any]) -> str:
87
+ """Return a deterministic quiet-age label once the existing interval passes."""
88
+ if str(status.get("state") or "").strip().lower() != "running":
89
+ return ""
90
+ try:
91
+ age_s = max(0.0, float(status.get("last_event_age_s") or 0.0))
92
+ threshold_s = max(0.0, float(status.get("activity_threshold_s") or 0.0))
93
+ except (TypeError, ValueError):
94
+ return ""
95
+ if threshold_s <= 0.0 or age_s < threshold_s:
96
+ return ""
97
+ return f"quiet {_elapsed_label(int(age_s * 1000))}"
98
+
99
+
100
+ def _header_row(
101
+ status: dict[str, Any],
102
+ *,
103
+ width: int,
104
+ position: int,
105
+ total: int,
106
+ ) -> list[tuple[str, str]]:
107
+ name = subagent_identity(
108
+ status.get("subagent") or status.get("run_id") or "subagent",
109
+ status.get("label"),
110
+ )
111
+ state = str(status.get("state") or "unknown").strip()
112
+ workspace = str(status.get("workspace_view") or "shared").strip()
113
+ try:
114
+ steps = max(0, int(status.get("steps_completed") or 0))
115
+ except (TypeError, ValueError):
116
+ steps = 0
117
+ separator = f" {_MIDDLE_DOT} "
118
+ quiet = quiet_time_label(status)
119
+ return _fit_segments(
120
+ [
121
+ (_S_HEAD, name),
122
+ (_S_DIM, separator),
123
+ (_S_STATE, state),
124
+ (_S_DIM, separator),
125
+ (_S_DIM, _elapsed_label(status.get("elapsed_ms"))),
126
+ (_S_DIM, separator),
127
+ (_S_DIM, f"{steps} step{'s' if steps != 1 else ''}"),
128
+ (_S_DIM, separator),
129
+ (_S_DIM, workspace),
130
+ (_S_DIM, separator if quiet else ""),
131
+ (_S_DIM, quiet),
132
+ (_S_DIM, f" view {max(1, position)}/{max(1, total)}"),
133
+ ],
134
+ width,
135
+ )
136
+
137
+
138
+ def _entry_rows(entry: dict[str, str], width: int) -> list[list[tuple[str, str]]]:
139
+ kind = str(entry.get("kind") or "").strip()
140
+ style, lead = _ENTRY_STYLE.get(kind, (_S_DIM, "- "))
141
+ summary = " ".join(str(entry.get("summary") or "").split())
142
+ return [_fit_segments([(_S_DIM, lead), (style, summary)], width)]
143
+
144
+
145
+ def subagent_panel_rows(
146
+ status: dict[str, Any],
147
+ entries: list[dict[str, str]],
148
+ *,
149
+ width: int,
150
+ height: int,
151
+ position: int,
152
+ total: int,
153
+ ) -> list[list[tuple[str, str]]]:
154
+ """Render header, newest body entries, and footer within ``height`` rows."""
155
+ width = max(12, int(width))
156
+ height = max(2, int(height))
157
+ body_height = max(0, height - 2)
158
+ selected: list[list[list[tuple[str, str]]]] = []
159
+ used = 0
160
+ for entry in reversed(entries):
161
+ wrapped = _entry_rows(entry, width)
162
+ if used and used + len(wrapped) > body_height:
163
+ break
164
+ room = body_height - used
165
+ if room <= 0:
166
+ break
167
+ selected.append(wrapped[:room])
168
+ used += min(len(wrapped), room)
169
+ body_rows = [row for group in reversed(selected) for row in group]
170
+ footer = _fit_segments(
171
+ [(_S_HINT, f"ctrl+b / ctrl+n to switch {_MIDDLE_DOT} esc to close")],
172
+ width,
173
+ )
174
+ return [
175
+ _header_row(status, width=width, position=position, total=total),
176
+ *body_rows,
177
+ footer,
178
+ ]
179
+
180
+
181
+ __all__ = [
182
+ "ENTRY_BUFFER_CAP",
183
+ "append_bounded_entries",
184
+ "quiet_time_label",
185
+ "subagent_panel_rows",
186
+ ]