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.

Potentially problematic release.


This version of alysis-code might be problematic. Click here for more details.

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,67 @@
1
+ """Semantic Rich styles for terminal UI rendering."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Literal
6
+
7
+ TerminalTheme = Literal["light", "dark", "neutral"]
8
+
9
+ STYLE_EMPHASIS = "bold"
10
+ STYLE_CONTENT = ""
11
+ STYLE_DIM = "dim"
12
+ STYLE_CHROME = "bright_black"
13
+ STYLE_SELECTED_LABEL = "bold"
14
+ STYLE_SELECTED_DESC = "bold"
15
+ STYLE_DESELECTED_LABEL = "dim"
16
+ STYLE_DESELECTED_DESC = "dim"
17
+ STYLE_ACCENT = "cyan"
18
+ STYLE_WARN = "yellow"
19
+ STYLE_ERROR = "red"
20
+ STYLE_SUCCESS = "green"
21
+ STYLE_SUBAGENT = "bright_cyan"
22
+
23
+ _BASE_STYLES: dict[str, str] = {
24
+ "STYLE_EMPHASIS": STYLE_EMPHASIS,
25
+ "STYLE_CONTENT": STYLE_CONTENT,
26
+ "STYLE_DIM": STYLE_DIM,
27
+ "STYLE_CHROME": STYLE_CHROME,
28
+ "STYLE_SELECTED_LABEL": STYLE_SELECTED_LABEL,
29
+ "STYLE_SELECTED_DESC": STYLE_SELECTED_DESC,
30
+ "STYLE_DESELECTED_LABEL": STYLE_DESELECTED_LABEL,
31
+ "STYLE_DESELECTED_DESC": STYLE_DESELECTED_DESC,
32
+ "STYLE_WARN": STYLE_WARN,
33
+ "STYLE_ERROR": STYLE_ERROR,
34
+ "STYLE_SUCCESS": STYLE_SUCCESS,
35
+ "STYLE_SUBAGENT": STYLE_SUBAGENT,
36
+ }
37
+
38
+
39
+ def theme_aware_styles(theme: TerminalTheme) -> dict[str, str]:
40
+ """Return semantic styles whose accents are tuned for the detected theme."""
41
+ styles = dict(_BASE_STYLES)
42
+ if theme == "light":
43
+ styles["STYLE_ACCENT"] = "blue"
44
+ elif theme == "dark":
45
+ styles["STYLE_ACCENT"] = STYLE_ACCENT
46
+ else:
47
+ styles["STYLE_ACCENT"] = ""
48
+ return styles
49
+
50
+
51
+ __all__ = [
52
+ "STYLE_ACCENT",
53
+ "STYLE_CHROME",
54
+ "STYLE_CONTENT",
55
+ "STYLE_DESELECTED_DESC",
56
+ "STYLE_DESELECTED_LABEL",
57
+ "STYLE_DIM",
58
+ "STYLE_EMPHASIS",
59
+ "STYLE_ERROR",
60
+ "STYLE_SELECTED_DESC",
61
+ "STYLE_SELECTED_LABEL",
62
+ "STYLE_SUBAGENT",
63
+ "STYLE_SUCCESS",
64
+ "STYLE_WARN",
65
+ "TerminalTheme",
66
+ "theme_aware_styles",
67
+ ]
@@ -0,0 +1,455 @@
1
+ """Terminal background theme detection shared by Rich and owl renderers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ import json
7
+ import os
8
+ import re
9
+ import select
10
+ import sys
11
+ import time
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ from ..branding import env_get
16
+ from .styles import TerminalTheme
17
+
18
+
19
+ def _stream_is_tty(stream: Any | None) -> bool:
20
+ isatty = getattr(stream, "isatty", None)
21
+ if not callable(isatty):
22
+ return False
23
+ try:
24
+ return bool(isatty())
25
+ except Exception:
26
+ return False
27
+
28
+
29
+ def _theme_debug(message: str) -> None:
30
+ if env_get("ALYSIS_THEME_DEBUG"):
31
+ print(f"[alysis-theme] {message}", file=sys.stderr)
32
+
33
+
34
+ def _truthy_env(name: str) -> bool:
35
+ return str(env_get(name) or "").strip().lower() in {"1", "true", "yes", "on"}
36
+
37
+
38
+ def _is_wsl() -> bool:
39
+ if os.name == "nt":
40
+ return False
41
+ if os.environ.get("WSL_DISTRO_NAME") or os.environ.get("WSL_INTEROP"):
42
+ return True
43
+ try:
44
+ with open("/proc/version", encoding="utf-8") as fh:
45
+ return "microsoft" in fh.read().lower()
46
+ except OSError:
47
+ return False
48
+
49
+
50
+ def _normalize_theme(value: str | None) -> TerminalTheme | None:
51
+ raw = str(value or "").strip().lower()
52
+ if raw in {"light", "dark", "neutral"}:
53
+ return raw # type: ignore[return-value]
54
+ return None
55
+
56
+
57
+ def _theme_from_colorfgbg(value: str | None) -> TerminalTheme | None:
58
+ if not value:
59
+ return None
60
+ bg = value.rsplit(";", 1)[-1].strip()
61
+ if not bg.isdigit():
62
+ return None
63
+ bg_code = int(bg)
64
+ return "dark" if bg_code <= 6 or bg_code == 8 else "light"
65
+
66
+
67
+ def _hex_to_8bit(value: str) -> int:
68
+ max_value = (16 ** len(value)) - 1
69
+ if max_value <= 0:
70
+ return 0
71
+ return int(value, 16) * 255 // max_value
72
+
73
+
74
+ def _theme_from_osc11(stream: Any | None) -> TerminalTheme | None:
75
+ # OSC 11 is unreliable through Windows ConPTY/WSL: replies can arrive
76
+ # after our timeout and leak into the next /dev/tty reader.
77
+ if _is_wsl():
78
+ _theme_debug("OSC11=skipped (WSL)")
79
+ return None
80
+ if not _stream_is_tty(stream):
81
+ _theme_debug("OSC11=skipped (stream is not a TTY)")
82
+ return None
83
+ try:
84
+ import termios
85
+ import tty
86
+
87
+ tty_fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
88
+ except Exception:
89
+ return None
90
+ old_attrs = None
91
+ response = ""
92
+ try:
93
+ old_attrs = termios.tcgetattr(tty_fd)
94
+ tty.setraw(tty_fd, termios.TCSANOW)
95
+ os.write(tty_fd, b"\033]11;?\007")
96
+ ready, _, _ = select.select([tty_fd], [], [], 0.5)
97
+ if not ready:
98
+ _theme_debug("OSC11=timeout -> none")
99
+ return None
100
+ response = os.read(tty_fd, 128).decode("ascii", errors="ignore")
101
+ except Exception:
102
+ return None
103
+ finally:
104
+ # Best-effort drain: consume trailing terminal response bytes before
105
+ # prompt_toolkit or another /dev/tty reader can see them as input.
106
+ with contextlib.suppress(Exception):
107
+ os.set_blocking(tty_fd, False)
108
+ deadline = time.monotonic() + 0.025
109
+ while True:
110
+ timeout = max(0.0, deadline - time.monotonic())
111
+ if timeout <= 0:
112
+ break
113
+ ready, _, _ = select.select([tty_fd], [], [], min(timeout, 0.005))
114
+ if not ready:
115
+ continue
116
+ if not os.read(tty_fd, 4096):
117
+ break
118
+ if old_attrs is not None:
119
+ with contextlib.suppress(Exception):
120
+ termios.tcsetattr(tty_fd, termios.TCSANOW, old_attrs)
121
+ with contextlib.suppress(Exception):
122
+ os.close(tty_fd)
123
+
124
+ match = re.search(r"rgb:([0-9A-Fa-f]+)/([0-9A-Fa-f]+)/([0-9A-Fa-f]+)", response)
125
+ if not match:
126
+ _theme_debug(f"OSC11={response!r} -> none")
127
+ return None
128
+ red = _hex_to_8bit(match.group(1))
129
+ green = _hex_to_8bit(match.group(2))
130
+ blue = _hex_to_8bit(match.group(3))
131
+ brightness = (red * 299 + green * 587 + blue * 114) // 1000
132
+ detected: TerminalTheme = "light" if brightness >= 128 else "dark"
133
+ _theme_debug(f"OSC11=rgb:{match.group(1)}/{match.group(2)}/{match.group(3)} -> {detected}")
134
+ return detected
135
+
136
+
137
+ def _strip_json_comments(value: str) -> str:
138
+ output: list[str] = []
139
+ in_string = False
140
+ escaped = False
141
+ in_line_comment = False
142
+ in_block_comment = False
143
+ index = 0
144
+ while index < len(value):
145
+ char = value[index]
146
+ next_char = value[index + 1] if index + 1 < len(value) else ""
147
+ if in_line_comment:
148
+ if char == "\n":
149
+ in_line_comment = False
150
+ output.append(char)
151
+ index += 1
152
+ continue
153
+ if in_block_comment:
154
+ if char == "*" and next_char == "/":
155
+ in_block_comment = False
156
+ index += 2
157
+ else:
158
+ index += 1
159
+ continue
160
+ if in_string:
161
+ output.append(char)
162
+ if escaped:
163
+ escaped = False
164
+ elif char == "\\":
165
+ escaped = True
166
+ elif char == '"':
167
+ in_string = False
168
+ index += 1
169
+ continue
170
+ if char == '"':
171
+ in_string = True
172
+ output.append(char)
173
+ index += 1
174
+ continue
175
+ if char == "/" and next_char == "/":
176
+ in_line_comment = True
177
+ index += 2
178
+ continue
179
+ if char == "/" and next_char == "*":
180
+ in_block_comment = True
181
+ index += 2
182
+ continue
183
+ output.append(char)
184
+ index += 1
185
+ return re.sub(r",(\s*[}\]])", r"\1", "".join(output))
186
+
187
+
188
+ def _safe_is_dir(path: Path) -> bool:
189
+ with contextlib.suppress(OSError):
190
+ return path.is_dir()
191
+ return False
192
+
193
+
194
+ def _safe_is_file(path: Path) -> bool:
195
+ with contextlib.suppress(OSError):
196
+ return path.is_file()
197
+ return False
198
+
199
+
200
+ def _safe_sorted_glob(path: Path, pattern: str) -> list[Path]:
201
+ with contextlib.suppress(OSError):
202
+ return sorted(path.glob(pattern))
203
+ return []
204
+
205
+
206
+ def _safe_sorted_iterdir(path: Path) -> list[Path]:
207
+ with contextlib.suppress(OSError):
208
+ return sorted(path.iterdir())
209
+ return []
210
+
211
+
212
+ def _windows_terminal_settings_paths() -> list[Path]:
213
+ override = env_get("ALYSIS_WINDOWS_TERMINAL_SETTINGS")
214
+ if override:
215
+ return [Path(override).expanduser()]
216
+
217
+ paths: list[Path] = []
218
+ drive_roots = [
219
+ *_safe_sorted_glob(Path("/mnt"), "[a-z]"),
220
+ *_safe_sorted_glob(Path("/mnt/host"), "[a-z]"),
221
+ ]
222
+ for drive_root in dict.fromkeys(drive_roots):
223
+ users_dir = drive_root / "Users"
224
+ if not _safe_is_dir(users_dir):
225
+ continue
226
+ for user_dir in _safe_sorted_iterdir(users_dir):
227
+ local_app_data = user_dir / "AppData" / "Local"
228
+ packages_dir = local_app_data / "Packages"
229
+ paths.extend(
230
+ _safe_sorted_glob(
231
+ packages_dir,
232
+ "Microsoft.WindowsTerminal*_8wekyb3d8bbwe/LocalState/settings.json",
233
+ )
234
+ )
235
+ paths.append(local_app_data / "Microsoft" / "Windows Terminal" / "settings.json")
236
+ return paths
237
+
238
+
239
+ def _load_jsonc_file(path: Path) -> dict[str, Any] | None:
240
+ try:
241
+ return json.loads(_strip_json_comments(path.read_text(encoding="utf-8")))
242
+ except Exception:
243
+ return None
244
+
245
+
246
+ def _theme_from_hex_background(value: Any) -> TerminalTheme | None:
247
+ if not isinstance(value, str):
248
+ return None
249
+ raw = value.strip().lstrip("#")
250
+ if len(raw) == 3:
251
+ raw = "".join(char * 2 for char in raw)
252
+ if len(raw) != 6 or re.search(r"[^0-9A-Fa-f]", raw):
253
+ return None
254
+ red = int(raw[0:2], 16)
255
+ green = int(raw[2:4], 16)
256
+ blue = int(raw[4:6], 16)
257
+ brightness = (red * 299 + green * 587 + blue * 114) // 1000
258
+ return "light" if brightness >= 128 else "dark"
259
+
260
+
261
+ def _windows_terminal_builtin_scheme_theme(name: str) -> TerminalTheme | None:
262
+ normalized = re.sub(r"[^a-z0-9+]+", " ", name.lower()).strip()
263
+ normalized = re.sub(r"\s+", " ", normalized)
264
+ known: dict[str, TerminalTheme] = {
265
+ "atom one dark": "dark",
266
+ "atom one light": "light",
267
+ "ayu dark": "dark",
268
+ "ayu light": "light",
269
+ "ayu mirage": "dark",
270
+ "campbell": "dark",
271
+ "campbell powershell": "dark",
272
+ "dark+": "dark",
273
+ "dracula": "dark",
274
+ "dracula+": "dark",
275
+ "github dark": "dark",
276
+ "github light": "light",
277
+ "gruvbox dark": "dark",
278
+ "gruvbox light": "light",
279
+ "light+": "light",
280
+ "material dark": "dark",
281
+ "material light": "light",
282
+ "monokai": "dark",
283
+ "monokai pro": "dark",
284
+ "nord": "dark",
285
+ "one half dark": "dark",
286
+ "one half light": "light",
287
+ "powershell": "dark",
288
+ "solarized dark": "dark",
289
+ "solarized light": "light",
290
+ "tango dark": "dark",
291
+ "tango light": "light",
292
+ "tokyo night": "dark",
293
+ "tokyo night light": "light",
294
+ "tokyo night storm": "dark",
295
+ "ubuntu": "dark",
296
+ "vintage": "dark",
297
+ }
298
+ return known.get(normalized)
299
+
300
+
301
+ def _windows_terminal_scheme_name(settings: dict[str, Any]) -> str | None:
302
+ profiles = settings.get("profiles")
303
+ profiles = profiles if isinstance(profiles, dict) else {}
304
+ profile_list = profiles.get("list")
305
+ profile_list = profile_list if isinstance(profile_list, list) else []
306
+ profile_defaults = profiles.get("defaults")
307
+ profile_defaults = profile_defaults if isinstance(profile_defaults, dict) else {}
308
+ profile_id = str(os.environ.get("WT_PROFILE_ID") or "").strip().strip("{}").lower()
309
+
310
+ profile: dict[str, Any] | None = None
311
+ if profile_id:
312
+ for candidate in profile_list:
313
+ if not isinstance(candidate, dict):
314
+ continue
315
+ guid = str(candidate.get("guid") or "").strip().strip("{}").lower()
316
+ if guid == profile_id:
317
+ profile = candidate
318
+ break
319
+ if profile is None:
320
+ default_profile = str(settings.get("defaultProfile") or "").strip().strip("{}").lower()
321
+ for candidate in profile_list:
322
+ if not isinstance(candidate, dict):
323
+ continue
324
+ guid = str(candidate.get("guid") or "").strip().strip("{}").lower()
325
+ if guid == default_profile:
326
+ profile = candidate
327
+ break
328
+
329
+ scheme = (profile or {}).get("colorScheme")
330
+ if isinstance(scheme, str) and scheme.strip():
331
+ return scheme.strip()
332
+ scheme = profile_defaults.get("colorScheme")
333
+ if isinstance(scheme, str) and scheme.strip():
334
+ return scheme.strip()
335
+ return "Campbell"
336
+
337
+
338
+ def _theme_from_windows_terminal_settings() -> TerminalTheme | None:
339
+ has_windows_terminal = bool(os.environ.get("WT_SESSION"))
340
+ override = env_get("ALYSIS_WINDOWS_TERMINAL_SETTINGS")
341
+ is_wsl = _is_wsl()
342
+ _theme_debug(f"is_wsl={is_wsl}, WT_SESSION={'present' if has_windows_terminal else 'missing'}")
343
+ if not has_windows_terminal and not override and not is_wsl:
344
+ return None
345
+ try:
346
+ settings_paths = _windows_terminal_settings_paths()
347
+ except OSError as exc:
348
+ _theme_debug(f"settings.json paths failed: {exc}")
349
+ return "dark" if has_windows_terminal else None
350
+ _theme_debug(f"settings.json paths tried: {len(settings_paths)}")
351
+ for settings_path in settings_paths:
352
+ if not _safe_is_file(settings_path):
353
+ continue
354
+ settings = _load_jsonc_file(settings_path)
355
+ if not settings:
356
+ continue
357
+ scheme_name = _windows_terminal_scheme_name(settings)
358
+ if not scheme_name:
359
+ continue
360
+ schemes = settings.get("schemes")
361
+ schemes = schemes if isinstance(schemes, list) else []
362
+ for scheme in schemes:
363
+ if not isinstance(scheme, dict):
364
+ continue
365
+ name = str(scheme.get("name") or "").strip()
366
+ if name.lower() != scheme_name.lower():
367
+ continue
368
+ detected = _theme_from_hex_background(scheme.get("background"))
369
+ if detected:
370
+ _theme_debug(f'active scheme="{scheme_name}" -> {detected}')
371
+ return detected
372
+ detected = _windows_terminal_builtin_scheme_theme(scheme_name)
373
+ if detected:
374
+ _theme_debug(f'active scheme="{scheme_name}" -> {detected}')
375
+ return detected
376
+ _theme_debug(f'active scheme="{scheme_name}" -> none')
377
+ if has_windows_terminal:
378
+ _theme_debug("windows-terminal default -> dark")
379
+ return "dark"
380
+ return None
381
+
382
+
383
+ def detect_terminal_theme_if_available(stream: Any | None = None) -> TerminalTheme | None:
384
+ """Detect the terminal background without guessing when detection fails."""
385
+ for env_name in ("ALYSIS_THEME", "OWL_THEME"):
386
+ raw_value = env_get(env_name)
387
+ requested = _normalize_theme(raw_value)
388
+ _theme_debug(f"env={env_name} -> {requested or 'none'}")
389
+ if requested:
390
+ return requested
391
+
392
+ colorfgbg = os.environ.get("COLORFGBG")
393
+ detected = _theme_from_colorfgbg(colorfgbg)
394
+ _theme_debug(f"COLORFGBG={colorfgbg or 'missing'} -> {detected or 'none'}")
395
+ if detected:
396
+ return detected
397
+
398
+ if os.environ.get("NO_COLOR"):
399
+ _theme_debug("OSC11=skipped (NO_COLOR)")
400
+ elif not _truthy_env("ALYSIS_ENABLE_OSC11"):
401
+ _theme_debug("OSC11=skipped (disabled)")
402
+ else:
403
+ detected = _theme_from_osc11(stream)
404
+ if detected:
405
+ return detected
406
+
407
+ detected = _theme_from_windows_terminal_settings()
408
+ if detected:
409
+ return detected
410
+
411
+ # macOS's global light/dark appearance does not describe a Terminal.app
412
+ # window's active profile. A light desktop can host a dark terminal (and
413
+ # vice versa), so using AppleInterfaceStyle here can select the exact
414
+ # opposite foreground palette. Unknown is safer: callers then inherit the
415
+ # terminal's own foreground and background colours.
416
+ if os.environ.get("TERM_PROGRAM") == "Apple_Terminal":
417
+ _theme_debug("Apple_Terminal profile background unavailable -> none")
418
+ return None
419
+
420
+
421
+ def detect_terminal_theme(stream: Any | None = None) -> TerminalTheme:
422
+ """Detect the host terminal theme, returning neutral when it is unknown."""
423
+ detected = detect_terminal_theme_if_available(stream)
424
+ if detected:
425
+ _theme_debug(f"result={detected}")
426
+ return detected
427
+
428
+ fallback = _fallback_theme()
429
+ _theme_debug(f"result={fallback}")
430
+ return fallback
431
+
432
+
433
+ def _fallback_theme() -> TerminalTheme:
434
+ for env_name in ("ALYSIS_FALLBACK_THEME", "OWL_FALLBACK_THEME"):
435
+ fallback = _normalize_theme(env_get(env_name))
436
+ if fallback:
437
+ return fallback
438
+ return "neutral"
439
+
440
+
441
+ __all__ = [
442
+ "detect_terminal_theme",
443
+ "detect_terminal_theme_if_available",
444
+ "_hex_to_8bit",
445
+ "_load_jsonc_file",
446
+ "_strip_json_comments",
447
+ "_is_wsl",
448
+ "_theme_from_colorfgbg",
449
+ "_theme_from_hex_background",
450
+ "_theme_from_osc11",
451
+ "_theme_from_windows_terminal_settings",
452
+ "_windows_terminal_builtin_scheme_theme",
453
+ "_windows_terminal_scheme_name",
454
+ "_windows_terminal_settings_paths",
455
+ ]
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any
5
+
6
+
7
+ @dataclass(frozen=True, slots=True)
8
+ class StatusEvent:
9
+ mode: str
10
+ model: str
11
+ workspace: str
12
+ session_id: str
13
+ branch: str
14
+ dirty: bool
15
+ stream: bool
16
+ task: str = "-"
17
+
18
+
19
+ @dataclass(frozen=True, slots=True)
20
+ class ToolStartEvent:
21
+ tool_call_id: str
22
+ name: str
23
+ args: dict[str, Any]
24
+ step: int
25
+ subagent_name: str | None = None
26
+ subagent_mode: str | None = None
27
+ nesting_depth: int = 0
28
+
29
+
30
+ @dataclass(frozen=True, slots=True)
31
+ class ToolOutputEvent:
32
+ tool_call_id: str
33
+ name: str
34
+ chunk: str
35
+ subagent_name: str | None = None
36
+ subagent_mode: str | None = None
37
+ nesting_depth: int = 0
38
+
39
+
40
+ @dataclass(frozen=True, slots=True)
41
+ class ToolEndEvent:
42
+ tool_call_id: str
43
+ name: str
44
+ status: str
45
+ elapsed_ms: int
46
+ meta: dict[str, Any] = field(default_factory=dict)
47
+ subagent_name: str | None = None
48
+ subagent_mode: str | None = None
49
+ nesting_depth: int = 0
50
+
51
+
52
+ @dataclass(frozen=True, slots=True)
53
+ class SubagentStartEvent:
54
+ name: str
55
+ mode: str
56
+ subagent_session_id: str | None = None
57
+ # What the subagent is for (the definition's description). Surfaces may show a
58
+ # condensed form so the user knows what agent they just entered.
59
+ description: str = ""
60
+ subagent_run_id: str | None = None
61
+ workspace_view: str = "shared"
62
+ label: str = ""
63
+
64
+
65
+ @dataclass(frozen=True, slots=True)
66
+ class SubagentEndEvent:
67
+ name: str
68
+ mode: str
69
+ status: str
70
+ elapsed_ms: int
71
+ steps_completed: int
72
+ subagent_session_id: str | None = None
73
+ error: str | None = None
74
+ subagent_run_id: str | None = None
75
+ workspace_view: str = "shared"
76
+ label: str = ""
77
+
78
+
79
+ @dataclass(frozen=True, slots=True)
80
+ class PatchEvent:
81
+ files: list[str]
82
+ diff: str
83
+ summary: str = ""
84
+
85
+
86
+ @dataclass(frozen=True, slots=True)
87
+ class ApprovalRequest:
88
+ kind: str
89
+ reason: str
90
+ preview: str
91
+ files: list[str] = field(default_factory=list)
92
+ command: str | None = None
93
+ metadata: dict[str, object] = field(default_factory=dict)
94
+ allow_for_session_scope: dict[str, object] | None = None
95
+
96
+
97
+ @dataclass(frozen=True, slots=True)
98
+ class ApprovalDecision:
99
+ allow: bool
100
+ allow_for_session: bool = False