novacode-cli 1.2.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 (691) hide show
  1. novacode_cli/__init__.py +29 -0
  2. novacode_cli/__main__.py +6 -0
  3. novacode_cli/_lazy_heavy.py +99 -0
  4. novacode_cli/_version.py +3 -0
  5. novacode_cli/agent_stream.py +178 -0
  6. novacode_cli/agents/agent_file.py +250 -0
  7. novacode_cli/agents/agent_mailbox.py +120 -0
  8. novacode_cli/agents/approval_decisions.py +146 -0
  9. novacode_cli/agents/arg_repair.py +196 -0
  10. novacode_cli/agents/async_agents/__init__.py +6 -0
  11. novacode_cli/agents/async_agents/_config.py +213 -0
  12. novacode_cli/agents/async_agents/_mcp_tools.py +192 -0
  13. novacode_cli/agents/async_agents/_specialist.py +84 -0
  14. novacode_cli/agents/async_agents/_test_commands.py +89 -0
  15. novacode_cli/agents/async_agents/_tools.py +432 -0
  16. novacode_cli/agents/async_agents/general_purpose.py +42 -0
  17. novacode_cli/agents/async_agents/langgraph.json +9 -0
  18. novacode_cli/agents/async_agents/research.py +22 -0
  19. novacode_cli/agents/async_context.py +303 -0
  20. novacode_cli/agents/async_on_demand.py +52 -0
  21. novacode_cli/agents/async_task_errors.py +75 -0
  22. novacode_cli/agents/async_workspace.py +27 -0
  23. novacode_cli/agents/attribution.py +165 -0
  24. novacode_cli/agents/browser_mode.py +119 -0
  25. novacode_cli/agents/btw_agent.py +71 -0
  26. novacode_cli/agents/caveman.py +352 -0
  27. novacode_cli/agents/caveman_support.py +370 -0
  28. novacode_cli/agents/code_mode.py +774 -0
  29. novacode_cli/agents/code_runtime.py +160 -0
  30. novacode_cli/agents/context_compaction.py +1339 -0
  31. novacode_cli/agents/core_agent.py +2710 -0
  32. novacode_cli/agents/default_subagents/__init__.py +24 -0
  33. novacode_cli/agents/default_subagents/async_subagents.py +296 -0
  34. novacode_cli/agents/default_subagents/builtin/browser-automation-agent.md +110 -0
  35. novacode_cli/agents/default_subagents/builtin/bug-fix-agent.md +22 -0
  36. novacode_cli/agents/default_subagents/builtin/bug-investigation-agent.md +42 -0
  37. novacode_cli/agents/default_subagents/builtin/code-explorer.md +37 -0
  38. novacode_cli/agents/default_subagents/builtin/code-review-agent.md +33 -0
  39. novacode_cli/agents/default_subagents/builtin/dependency-audit-agent.md +34 -0
  40. novacode_cli/agents/default_subagents/builtin/documentation-update-agent.md +46 -0
  41. novacode_cli/agents/default_subagents/builtin/performance-audit-agent.md +41 -0
  42. novacode_cli/agents/default_subagents/builtin/plan-scout-agent.md +64 -0
  43. novacode_cli/agents/default_subagents/builtin/refactoring-agent.md +35 -0
  44. novacode_cli/agents/default_subagents/builtin/refactoring-specialist-agent.md +175 -0
  45. novacode_cli/agents/default_subagents/builtin/security-audit-agent.md +96 -0
  46. novacode_cli/agents/default_subagents/builtin/test-generation-agent.md +33 -0
  47. novacode_cli/agents/default_subagents/builtin/test-runner-agent.md +55 -0
  48. novacode_cli/agents/default_subagents/prompt.py +88 -0
  49. novacode_cli/agents/default_subagents/subagents.py +138 -0
  50. novacode_cli/agents/dream_agent.py +93 -0
  51. novacode_cli/agents/edit_diagnostics.py +362 -0
  52. novacode_cli/agents/edit_fallback.py +62 -0
  53. novacode_cli/agents/handoff.py +166 -0
  54. novacode_cli/agents/invocation.py +152 -0
  55. novacode_cli/agents/model_budget.py +42 -0
  56. novacode_cli/agents/model_retry.py +113 -0
  57. novacode_cli/agents/model_router.py +420 -0
  58. novacode_cli/agents/openai_decisions.py +186 -0
  59. novacode_cli/agents/plan_agent/__init__.py +12 -0
  60. novacode_cli/agents/plan_agent/plan_agent.py +357 -0
  61. novacode_cli/agents/plan_agent/plan_mode_middleware.py +64 -0
  62. novacode_cli/agents/plan_execution.py +237 -0
  63. novacode_cli/agents/ponytail.py +66 -0
  64. novacode_cli/agents/prime.py +274 -0
  65. novacode_cli/agents/provider_caching.py +99 -0
  66. novacode_cli/agents/server_launcher.py +904 -0
  67. novacode_cli/agents/strict_tools.py +384 -0
  68. novacode_cli/agents/task_discipline.py +294 -0
  69. novacode_cli/agents/tool_call_repair.py +290 -0
  70. novacode_cli/agents/tool_offload.py +291 -0
  71. novacode_cli/agents/tool_search.py +806 -0
  72. novacode_cli/agents/tool_search_variants.py +106 -0
  73. novacode_cli/agents/tool_verdicts.py +1194 -0
  74. novacode_cli/agents/user_async_agents.py +312 -0
  75. novacode_cli/artifacts/__init__.py +10 -0
  76. novacode_cli/artifacts/registry.py +278 -0
  77. novacode_cli/artifacts/server.py +426 -0
  78. novacode_cli/assets/Nova.png +0 -0
  79. novacode_cli/assets/nova-avatar.png +0 -0
  80. novacode_cli/audio/__init__.py +301 -0
  81. novacode_cli/audio/capture.py +137 -0
  82. novacode_cli/audio/downloads.py +273 -0
  83. novacode_cli/audio/pipeline.py +391 -0
  84. novacode_cli/audio/playback.py +87 -0
  85. novacode_cli/audio/providers.py +208 -0
  86. novacode_cli/audio/speakable.py +78 -0
  87. novacode_cli/audio/stt.py +132 -0
  88. novacode_cli/audio/stt_deepgram.py +69 -0
  89. novacode_cli/audio/stt_elevenlabs.py +89 -0
  90. novacode_cli/audio/stt_parakeet.py +94 -0
  91. novacode_cli/audio/stt_whistle.py +61 -0
  92. novacode_cli/audio/summarize.py +92 -0
  93. novacode_cli/audio/tts.py +85 -0
  94. novacode_cli/audio/tts_kokoro.py +73 -0
  95. novacode_cli/audio/tts_orpheus.py +180 -0
  96. novacode_cli/audio/tts_pocket.py +131 -0
  97. novacode_cli/audio/tts_sano.py +69 -0
  98. novacode_cli/audio/vad.py +145 -0
  99. novacode_cli/backends/__init__.py +17 -0
  100. novacode_cli/backends/filesystem.py +894 -0
  101. novacode_cli/backends/native_search.py +92 -0
  102. novacode_cli/bootstrap/__init__.py +9 -0
  103. novacode_cli/bootstrap/env_snapshot.py +240 -0
  104. novacode_cli/bootstrap/steering.py +464 -0
  105. novacode_cli/bootstrap/vision_router.py +604 -0
  106. novacode_cli/brand.py +362 -0
  107. novacode_cli/cli_args.py +718 -0
  108. novacode_cli/commands/__init__.py +237 -0
  109. novacode_cli/commands/agents_commands.py +231 -0
  110. novacode_cli/commands/auth_handler.py +40 -0
  111. novacode_cli/commands/browser_use_handler.py +75 -0
  112. novacode_cli/commands/cache_handler.py +32 -0
  113. novacode_cli/commands/chat_handler.py +1357 -0
  114. novacode_cli/commands/ci_fix.py +171 -0
  115. novacode_cli/commands/claude_plan.py +331 -0
  116. novacode_cli/commands/codex_plan.py +195 -0
  117. novacode_cli/commands/commands.py +1113 -0
  118. novacode_cli/commands/create_handler.py +124 -0
  119. novacode_cli/commands/create_server.py +1887 -0
  120. novacode_cli/commands/cron_handler.py +119 -0
  121. novacode_cli/commands/dream_handler.py +203 -0
  122. novacode_cli/commands/effort_handler.py +65 -0
  123. novacode_cli/commands/evolution_handler.py +214 -0
  124. novacode_cli/commands/file_commands.py +381 -0
  125. novacode_cli/commands/handoff_handler.py +68 -0
  126. novacode_cli/commands/hooks_handler.py +269 -0
  127. novacode_cli/commands/init_handler.py +146 -0
  128. novacode_cli/commands/learning_handler.py +160 -0
  129. novacode_cli/commands/lite_mode_handler.py +76 -0
  130. novacode_cli/commands/log_commands.py +363 -0
  131. novacode_cli/commands/mcp_handler.py +29 -0
  132. novacode_cli/commands/model_handler.py +29 -0
  133. novacode_cli/commands/notifications_handler.py +158 -0
  134. novacode_cli/commands/onboard_handler.py +121 -0
  135. novacode_cli/commands/plan_handler.py +440 -0
  136. novacode_cli/commands/planner_usage.py +250 -0
  137. novacode_cli/commands/plugin_install_handler.py +38 -0
  138. novacode_cli/commands/plugins_handler.py +35 -0
  139. novacode_cli/commands/prime_handler.py +455 -0
  140. novacode_cli/commands/prompt_handler.py +149 -0
  141. novacode_cli/commands/provider_usage.py +160 -0
  142. novacode_cli/commands/ralph_events.py +106 -0
  143. novacode_cli/commands/ralph_handler.py +1293 -0
  144. novacode_cli/commands/refine_handler.py +213 -0
  145. novacode_cli/commands/research_handler.py +202 -0
  146. novacode_cli/commands/rootapp_remote.py +83 -0
  147. novacode_cli/commands/router_handler.py +36 -0
  148. novacode_cli/commands/server_commands.py +249 -0
  149. novacode_cli/commands/session_commands.py +203 -0
  150. novacode_cli/commands/share_handler.py +450 -0
  151. novacode_cli/commands/side_commands.py +366 -0
  152. novacode_cli/commands/skill_invoke.py +420 -0
  153. novacode_cli/commands/skills_commands.py +48 -0
  154. novacode_cli/commands/trace_handler.py +322 -0
  155. novacode_cli/commands/trello_handler.py +226 -0
  156. novacode_cli/commands/trello_remote.py +177 -0
  157. novacode_cli/commands/trello_server.py +1214 -0
  158. novacode_cli/commands/vision_handler.py +127 -0
  159. novacode_cli/commands/voice_handler.py +447 -0
  160. novacode_cli/commands/webhook_handler.py +134 -0
  161. novacode_cli/commands/wiki_commands.py +227 -0
  162. novacode_cli/compaction.py +753 -0
  163. novacode_cli/computation_cache.py +159 -0
  164. novacode_cli/computer/__init__.py +1 -0
  165. novacode_cli/computer/persistent.py +234 -0
  166. novacode_cli/computer/preview.py +253 -0
  167. novacode_cli/computer/runtime.py +474 -0
  168. novacode_cli/computer/windows_console.py +152 -0
  169. novacode_cli/computer/windows_qemu.py +211 -0
  170. novacode_cli/config/browser_mode.py +159 -0
  171. novacode_cli/config/catalog_models.py +95 -0
  172. novacode_cli/config/config.py +1388 -0
  173. novacode_cli/config/credentials.py +540 -0
  174. novacode_cli/config/google_oauth_auth.py +281 -0
  175. novacode_cli/config/model_capabilities.py +343 -0
  176. novacode_cli/config/model_catalog.py +275 -0
  177. novacode_cli/config/model_create.py +1325 -0
  178. novacode_cli/config/model_manager.py +695 -0
  179. novacode_cli/config/nova_config.py +1283 -0
  180. novacode_cli/config/openai_chatgpt_auth.py +384 -0
  181. novacode_cli/config/opencode_gateway.py +25 -0
  182. novacode_cli/config/plan_mode.py +188 -0
  183. novacode_cli/config/provider_auth.py +438 -0
  184. novacode_cli/config/provider_catalog.json +5127 -0
  185. novacode_cli/config/provider_registry.py +38 -0
  186. novacode_cli/config/provider_transports.py +258 -0
  187. novacode_cli/config/role_models.py +175 -0
  188. novacode_cli/context/__init__.py +50 -0
  189. novacode_cli/context/_analysis.py +799 -0
  190. novacode_cli/context/_budget.py +116 -0
  191. novacode_cli/context/_conversation.py +73 -0
  192. novacode_cli/context/_dynamic.py +264 -0
  193. novacode_cli/context/_model_config.py +380 -0
  194. novacode_cli/context/_models_dev.py +99 -0
  195. novacode_cli/context/archives.py +248 -0
  196. novacode_cli/context/estimates.py +65 -0
  197. novacode_cli/context/history.py +17 -0
  198. novacode_cli/context/knowledge_cache.py +292 -0
  199. novacode_cli/context/manager.py +101 -0
  200. novacode_cli/context/observations.py +65 -0
  201. novacode_cli/context/pressure.py +168 -0
  202. novacode_cli/context/provider_accounting.py +109 -0
  203. novacode_cli/context/snapshot.py +493 -0
  204. novacode_cli/context/strategies.py +279 -0
  205. novacode_cli/context/task_progress.py +122 -0
  206. novacode_cli/core/__init__.py +0 -0
  207. novacode_cli/core/agent_loop.py +1821 -0
  208. novacode_cli/core/autonomous_loop.py +277 -0
  209. novacode_cli/core/code_approvals.py +57 -0
  210. novacode_cli/core/input_preparation.py +276 -0
  211. novacode_cli/core/reasoning.py +67 -0
  212. novacode_cli/core/streaming.py +326 -0
  213. novacode_cli/core/subagent_tasks.py +696 -0
  214. novacode_cli/core/subagent_tracking.py +235 -0
  215. novacode_cli/core/tool_results.py +116 -0
  216. novacode_cli/core/verification_loop.py +272 -0
  217. novacode_cli/council.py +595 -0
  218. novacode_cli/council_consensus.py +115 -0
  219. novacode_cli/council_decision.py +157 -0
  220. novacode_cli/council_planner.py +1421 -0
  221. novacode_cli/council_settings.py +208 -0
  222. novacode_cli/council_web_settings.py +41 -0
  223. novacode_cli/council_workspace.py +56 -0
  224. novacode_cli/cowork/__init__.py +10 -0
  225. novacode_cli/cowork/broker_middleware.py +162 -0
  226. novacode_cli/cowork/launcher.py +102 -0
  227. novacode_cli/cowork/policy.py +284 -0
  228. novacode_cli/cowork/ui.py +826 -0
  229. novacode_cli/daemons/__init__.py +1 -0
  230. novacode_cli/daemons/registry.py +342 -0
  231. novacode_cli/desktop_notifications.py +302 -0
  232. novacode_cli/doctor.py +251 -0
  233. novacode_cli/embeddings.py +109 -0
  234. novacode_cli/entrypoint.py +56 -0
  235. novacode_cli/errors/__init__.py +19 -0
  236. novacode_cli/errors/handlers.py +648 -0
  237. novacode_cli/errors/provider_errors.py +249 -0
  238. novacode_cli/errors/taxonomy.py +80 -0
  239. novacode_cli/events.py +179 -0
  240. novacode_cli/file_ops.py +714 -0
  241. novacode_cli/git_safety.py +281 -0
  242. novacode_cli/handoff.py +383 -0
  243. novacode_cli/headless/__init__.py +18 -0
  244. novacode_cli/headless/input.py +58 -0
  245. novacode_cli/headless/output.py +224 -0
  246. novacode_cli/headless/pipe.py +532 -0
  247. novacode_cli/headless/runner.py +461 -0
  248. novacode_cli/hermes/__init__.py +39 -0
  249. novacode_cli/hermes/activation.py +297 -0
  250. novacode_cli/hermes/config.py +129 -0
  251. novacode_cli/hermes/curator.py +199 -0
  252. novacode_cli/hermes/evolution.py +374 -0
  253. novacode_cli/hermes/ledger.py +364 -0
  254. novacode_cli/hermes/memory_tiers.py +969 -0
  255. novacode_cli/hermes/middleware.py +678 -0
  256. novacode_cli/hermes/overview.py +174 -0
  257. novacode_cli/hermes/prompt_evolution.py +503 -0
  258. novacode_cli/hermes/refine_loop.py +643 -0
  259. novacode_cli/hermes/refinement_log.py +190 -0
  260. novacode_cli/hermes/review.py +674 -0
  261. novacode_cli/hermes/skill_debate.py +135 -0
  262. novacode_cli/hermes/skill_discovery.py +450 -0
  263. novacode_cli/hermes/skill_manager.py +335 -0
  264. novacode_cli/hermes/skill_proposals.py +43 -0
  265. novacode_cli/hermes/test_gaming.py +119 -0
  266. novacode_cli/hermes/tracker.py +435 -0
  267. novacode_cli/hermes/tuner.py +206 -0
  268. novacode_cli/hermes/verification_memory.py +134 -0
  269. novacode_cli/hermes/verifier.py +277 -0
  270. novacode_cli/hitl/__init__.py +22 -0
  271. novacode_cli/hitl/interrupts.py +493 -0
  272. novacode_cli/hooks.py +359 -0
  273. novacode_cli/image_utils.py +517 -0
  274. novacode_cli/init/__init__.py +7 -0
  275. novacode_cli/init/events.py +43 -0
  276. novacode_cli/input_utils.py +526 -0
  277. novacode_cli/install_commands.py +87 -0
  278. novacode_cli/integrations/__init__.py +82 -0
  279. novacode_cli/integrations/daytona.py +122 -0
  280. novacode_cli/integrations/docker.py +309 -0
  281. novacode_cli/integrations/host_path.py +111 -0
  282. novacode_cli/integrations/langsmith.py +151 -0
  283. novacode_cli/integrations/modal.py +134 -0
  284. novacode_cli/integrations/runloop.py +130 -0
  285. novacode_cli/integrations/sandbox_factory.py +1388 -0
  286. novacode_cli/integrations/sandbox_registry.py +312 -0
  287. novacode_cli/integrations/workdir_backend.py +589 -0
  288. novacode_cli/main.py +2078 -0
  289. novacode_cli/mcp/__init__.py +73 -0
  290. novacode_cli/mcp/auth.py +189 -0
  291. novacode_cli/mcp/client.py +571 -0
  292. novacode_cli/mcp/code_mode.py +5 -0
  293. novacode_cli/mcp/code_runtime.py +5 -0
  294. novacode_cli/mcp/commands.py +902 -0
  295. novacode_cli/mcp/config.py +406 -0
  296. novacode_cli/mcp/generic.py +128 -0
  297. novacode_cli/mcp/middleware.py +993 -0
  298. novacode_cli/mcp/presets.py +367 -0
  299. novacode_cli/memory/__init__.py +1 -0
  300. novacode_cli/memory/agent_memory.py +1312 -0
  301. novacode_cli/memory/builtin_lessons.py +60 -0
  302. novacode_cli/memory/dream_gates.py +192 -0
  303. novacode_cli/memory/limits.py +59 -0
  304. novacode_cli/memory/parsed_cache.py +106 -0
  305. novacode_cli/memory/recall_stats.py +97 -0
  306. novacode_cli/memory/semantic.py +116 -0
  307. novacode_cli/memory/store.py +335 -0
  308. novacode_cli/memory/wiki.py +274 -0
  309. novacode_cli/migrate.py +185 -0
  310. novacode_cli/onboarding.py +649 -0
  311. novacode_cli/onboarding_check.py +119 -0
  312. novacode_cli/path_approval.py +297 -0
  313. novacode_cli/plan_archive.py +148 -0
  314. novacode_cli/plugins/__init__.py +121 -0
  315. novacode_cli/plugins/claude_plugins.py +538 -0
  316. novacode_cli/plugins/cli.py +168 -0
  317. novacode_cli/plugins/components.py +413 -0
  318. novacode_cli/plugins/hooks.py +356 -0
  319. novacode_cli/plugins/loader.py +317 -0
  320. novacode_cli/plugins/marketplaces.py +199 -0
  321. novacode_cli/plugins/storage.py +70 -0
  322. novacode_cli/prime.py +759 -0
  323. novacode_cli/prime_factory/__init__.py +15 -0
  324. novacode_cli/prime_factory/container.py +198 -0
  325. novacode_cli/prime_factory/controller.py +565 -0
  326. novacode_cli/prime_factory/knowledge.py +261 -0
  327. novacode_cli/prime_factory/publication.py +218 -0
  328. novacode_cli/prime_factory/recovery.py +50 -0
  329. novacode_cli/prime_factory/research.py +370 -0
  330. novacode_cli/prime_factory/runner.py +608 -0
  331. novacode_cli/prime_factory/runtime.py +261 -0
  332. novacode_cli/prime_factory/state.py +201 -0
  333. novacode_cli/prime_factory/store.py +128 -0
  334. novacode_cli/prime_factory/worker.py +129 -0
  335. novacode_cli/prime_factory/workflow.py +899 -0
  336. novacode_cli/prime_factory/workspace.py +317 -0
  337. novacode_cli/prime_memory.py +290 -0
  338. novacode_cli/process_manager.py +585 -0
  339. novacode_cli/project_onboard.py +537 -0
  340. novacode_cli/prompts/System_Prompt_Nova.jinja +23 -0
  341. novacode_cli/prompts/__init__.py +168 -0
  342. novacode_cli/prompts/agent_definitions.jinja +11 -0
  343. novacode_cli/prompts/agent_generation.jinja +125 -0
  344. novacode_cli/prompts/async_agents/general_purpose.jinja +22 -0
  345. novacode_cli/prompts/claude_plan_mode.jinja +12 -0
  346. novacode_cli/prompts/coding_workflow.jinja +18 -0
  347. novacode_cli/prompts/computer_use.jinja +17 -0
  348. novacode_cli/prompts/core_agent_system.jinja +81 -0
  349. novacode_cli/prompts/delegation.jinja +15 -0
  350. novacode_cli/prompts/desktop_power.jinja +4 -0
  351. novacode_cli/prompts/file_paths.jinja +15 -0
  352. novacode_cli/prompts/file_tracker.jinja +23 -0
  353. novacode_cli/prompts/init_agents_md.jinja +56 -0
  354. novacode_cli/prompts/init_exploration.jinja +174 -0
  355. novacode_cli/prompts/init_semantic_orchestrate.jinja +37 -0
  356. novacode_cli/prompts/instruction_scope.jinja +5 -0
  357. novacode_cli/prompts/learnings_extraction.jinja +45 -0
  358. novacode_cli/prompts/longterm_memory.jinja +54 -0
  359. novacode_cli/prompts/mcp.jinja +84 -0
  360. novacode_cli/prompts/memory_consolidation.jinja +40 -0
  361. novacode_cli/prompts/nova_evolution.jinja +73 -0
  362. novacode_cli/prompts/nova_review.jinja +158 -0
  363. novacode_cli/prompts/nova_skill_debate.jinja +36 -0
  364. novacode_cli/prompts/nova_standing_instructions.jinja +26 -0
  365. novacode_cli/prompts/nova_verify.jinja +100 -0
  366. novacode_cli/prompts/onboard_dashboard.jinja +378 -0
  367. novacode_cli/prompts/plan_agent.jinja +87 -0
  368. novacode_cli/prompts/plan_scouts.jinja +5 -0
  369. novacode_cli/prompts/plan_storage.jinja +8 -0
  370. novacode_cli/prompts/planning.jinja +82 -0
  371. novacode_cli/prompts/ponytail/LICENSE +21 -0
  372. novacode_cli/prompts/ponytail/UPSTREAM.json +15 -0
  373. novacode_cli/prompts/ponytail/hooks/ponytail-config.js +175 -0
  374. novacode_cli/prompts/ponytail/hooks/ponytail-instructions.js +98 -0
  375. novacode_cli/prompts/ponytail/skills/ponytail/SKILL.md +52 -0
  376. novacode_cli/prompts/ponytail/skills/ponytail-audit/SKILL.md +103 -0
  377. novacode_cli/prompts/ponytail/skills/ponytail-debt/SKILL.md +44 -0
  378. novacode_cli/prompts/ponytail/skills/ponytail-gain/SKILL.md +52 -0
  379. novacode_cli/prompts/ponytail/skills/ponytail-help/SKILL.md +76 -0
  380. novacode_cli/prompts/ponytail/skills/ponytail-review/SKILL.md +101 -0
  381. novacode_cli/prompts/prompt_evolution.jinja +27 -0
  382. novacode_cli/prompts/ralph_iteration.jinja +75 -0
  383. novacode_cli/prompts/refine_gate.jinja +31 -0
  384. novacode_cli/prompts/refine_plan.jinja +64 -0
  385. novacode_cli/prompts/refine_review.jinja +34 -0
  386. novacode_cli/prompts/research_delivery.jinja +9 -0
  387. novacode_cli/prompts/research_swarm.jinja +130 -0
  388. novacode_cli/prompts/response_style.jinja +5 -0
  389. novacode_cli/prompts/session_summarization.jinja +86 -0
  390. novacode_cli/prompts/skill_creation.jinja +85 -0
  391. novacode_cli/prompts/subagents/fact_checker.jinja +48 -0
  392. novacode_cli/prompts/subagents/financial_analyst.jinja +50 -0
  393. novacode_cli/prompts/subagents/literature_reviewer.jinja +52 -0
  394. novacode_cli/prompts/subagents/market_analyst.jinja +48 -0
  395. novacode_cli/prompts/subagents/research_synthesizer.jinja +57 -0
  396. novacode_cli/prompts/subagents/technical_researcher.jinja +56 -0
  397. novacode_cli/prompts/subagents/web_researcher.jinja +46 -0
  398. novacode_cli/prompts/summarization.jinja +107 -0
  399. novacode_cli/prompts/summarization_answers.jinja +23 -0
  400. novacode_cli/prompts/summarization_questions.jinja +32 -0
  401. novacode_cli/prompts/vision_caption.jinja +21 -0
  402. novacode_cli/prompts/voice_summary.jinja +65 -0
  403. novacode_cli/prompts/wiki_file.jinja +57 -0
  404. novacode_cli/prompts/wiki_ingest.jinja +87 -0
  405. novacode_cli/recovery.py +383 -0
  406. novacode_cli/remote/__init__.py +45 -0
  407. novacode_cli/remote/approvals.py +282 -0
  408. novacode_cli/remote/async_task_clients.py +97 -0
  409. novacode_cli/remote/async_task_watcher.py +240 -0
  410. novacode_cli/remote/bridge.py +905 -0
  411. novacode_cli/remote/command_menu.py +26 -0
  412. novacode_cli/remote/command_ui.py +243 -0
  413. novacode_cli/remote/config.py +199 -0
  414. novacode_cli/remote/discord_bridge.py +530 -0
  415. novacode_cli/remote/discord_format.py +31 -0
  416. novacode_cli/remote/discord_threads.py +225 -0
  417. novacode_cli/remote/images.py +97 -0
  418. novacode_cli/remote/processor.py +601 -0
  419. novacode_cli/remote/rootapp_bot/bot.cjs +16 -0
  420. novacode_cli/remote/rootapp_bot/package-lock.json +2683 -0
  421. novacode_cli/remote/rootapp_bot/package.json +18 -0
  422. novacode_cli/remote/rootapp_bot/transport.cjs +80 -0
  423. novacode_cli/remote/rootapp_bridge.py +370 -0
  424. novacode_cli/remote/rootapp_setup.py +89 -0
  425. novacode_cli/remote/routing.py +103 -0
  426. novacode_cli/remote/scheduler.py +302 -0
  427. novacode_cli/remote/session.py +164 -0
  428. novacode_cli/remote/status.py +411 -0
  429. novacode_cli/remote/streaming.py +188 -0
  430. novacode_cli/remote/telegram_bridge.py +1118 -0
  431. novacode_cli/remote/telegram_format.py +215 -0
  432. novacode_cli/remote/telegram_hub.py +256 -0
  433. novacode_cli/remote/voice_notes.py +120 -0
  434. novacode_cli/remote/webhook_adapters.py +167 -0
  435. novacode_cli/remote/webhook_server.py +154 -0
  436. novacode_cli/rewind.py +150 -0
  437. novacode_cli/rooms/__init__.py +1 -0
  438. novacode_cli/rooms/bridge.py +86 -0
  439. novacode_cli/rooms/cli.py +231 -0
  440. novacode_cli/rooms/nova.py +227 -0
  441. novacode_cli/rooms/runtime.py +299 -0
  442. novacode_cli/rooms/store.py +538 -0
  443. novacode_cli/rooms/workspace.py +94 -0
  444. novacode_cli/security/__init__.py +29 -0
  445. novacode_cli/security/approval_context.py +45 -0
  446. novacode_cli/security/delegated_approval.py +68 -0
  447. novacode_cli/security/local_http.py +85 -0
  448. novacode_cli/security/middleware.py +87 -0
  449. novacode_cli/security/paths.py +35 -0
  450. novacode_cli/security/policy.py +535 -0
  451. novacode_cli/security/policy_writer.py +90 -0
  452. novacode_cli/security/prompt_injection.py +203 -0
  453. novacode_cli/security/remember.py +81 -0
  454. novacode_cli/security/rule_synthesis.py +116 -0
  455. novacode_cli/security/secret_files.py +61 -0
  456. novacode_cli/security/session_allow.py +114 -0
  457. novacode_cli/security/unicode_security.py +516 -0
  458. novacode_cli/security/validator.py +173 -0
  459. novacode_cli/server/__init__.py +9 -0
  460. novacode_cli/server/app.py +632 -0
  461. novacode_cli/server/event_adapter.py +189 -0
  462. novacode_cli/server/session_manager.py +90 -0
  463. novacode_cli/server_main.py +64 -0
  464. novacode_cli/server_runner/dev_server.py +530 -0
  465. novacode_cli/server_runner/test_runner.py +470 -0
  466. novacode_cli/session/__init__.py +1 -0
  467. novacode_cli/session/adapters/__init__.py +240 -0
  468. novacode_cli/session/adapters/claude_code.py +102 -0
  469. novacode_cli/session/adapters/codex.py +77 -0
  470. novacode_cli/session/adapters/harness_native.py +75 -0
  471. novacode_cli/session/checkpoint_coordinator.py +448 -0
  472. novacode_cli/session/context_restore.py +25 -0
  473. novacode_cli/session/history_export.py +228 -0
  474. novacode_cli/session/history_tree.py +174 -0
  475. novacode_cli/session/imported_context.py +267 -0
  476. novacode_cli/session/runtime_identity.py +32 -0
  477. novacode_cli/session/session_persistence.py +1168 -0
  478. novacode_cli/session/session_prompt_builder.py +279 -0
  479. novacode_cli/session/session_restore.py +351 -0
  480. novacode_cli/session/session_summarization.py +20 -0
  481. novacode_cli/session/transcript_journal.py +153 -0
  482. novacode_cli/sessions/__init__.py +11 -0
  483. novacode_cli/sessions/gateway.py +84 -0
  484. novacode_cli/sessions/launch.py +51 -0
  485. novacode_cli/sessions/lease.py +213 -0
  486. novacode_cli/sessions/messaging.py +255 -0
  487. novacode_cli/sessions/protocol.py +216 -0
  488. novacode_cli/sessions/resume.py +31 -0
  489. novacode_cli/sessions/supervisor.py +498 -0
  490. novacode_cli/sessions/tasks.py +73 -0
  491. novacode_cli/sessions/tui_messaging.py +413 -0
  492. novacode_cli/sessions/worker.py +652 -0
  493. novacode_cli/sessions/worktree.py +262 -0
  494. novacode_cli/shell/__init__.py +27 -0
  495. novacode_cli/shell/jobs.py +475 -0
  496. novacode_cli/shell/middleware.py +1568 -0
  497. novacode_cli/shell/os_sandbox.py +205 -0
  498. novacode_cli/shell/output.py +181 -0
  499. novacode_cli/shell/patterns.py +275 -0
  500. novacode_cli/shell/processes.py +87 -0
  501. novacode_cli/shell/utils.py +236 -0
  502. novacode_cli/skills/__init__.py +26 -0
  503. novacode_cli/skills/builtin/handoff/SKILL.md +15 -0
  504. novacode_cli/skills/curation_middleware.py +69 -0
  505. novacode_cli/skills/executable.py +161 -0
  506. novacode_cli/skills/libraries.py +102 -0
  507. novacode_cli/skills/load.py +248 -0
  508. novacode_cli/skills/prune.py +215 -0
  509. novacode_cli/skills/refreshing_middleware.py +896 -0
  510. novacode_cli/skills/retrieval.py +248 -0
  511. novacode_cli/skills/runtime.py +118 -0
  512. novacode_cli/skills/schema.py +254 -0
  513. novacode_cli/skills/skill_creation.py +1549 -0
  514. novacode_cli/skills/skill_lock.py +75 -0
  515. novacode_cli/skills/skill_system_prompt.py +16 -0
  516. novacode_cli/skills/skills_prefs.py +126 -0
  517. novacode_cli/skills/tool_resolver.py +31 -0
  518. novacode_cli/skills/upstream.py +50 -0
  519. novacode_cli/skills/versioning.py +291 -0
  520. novacode_cli/states/Session.py +847 -0
  521. novacode_cli/states/__init__.py +31 -0
  522. novacode_cli/states/slices/__init__.py +17 -0
  523. novacode_cli/states/slices/agent_runtime.py +249 -0
  524. novacode_cli/states/slices/background_tasks.py +21 -0
  525. novacode_cli/states/slices/notifications.py +74 -0
  526. novacode_cli/states/slices/remote_bridge.py +56 -0
  527. novacode_cli/states/slices/ui_settings.py +49 -0
  528. novacode_cli/states/slices/wiki.py +25 -0
  529. novacode_cli/teammates/__init__.py +1 -0
  530. novacode_cli/teammates/controller.py +557 -0
  531. novacode_cli/teammates/graph.py +104 -0
  532. novacode_cli/teammates/registry.py +175 -0
  533. novacode_cli/teammates/service.py +254 -0
  534. novacode_cli/teammates/worker.py +19 -0
  535. novacode_cli/teams/__init__.py +1 -0
  536. novacode_cli/teams/adapters/__init__.py +1 -0
  537. novacode_cli/teams/adapters/container.py +316 -0
  538. novacode_cli/teams/adapters/inprocess.py +206 -0
  539. novacode_cli/teams/adapters/process.py +364 -0
  540. novacode_cli/teams/bootstrap.py +246 -0
  541. novacode_cli/teams/container_git.py +67 -0
  542. novacode_cli/teams/context.py +34 -0
  543. novacode_cli/teams/coordinator.py +815 -0
  544. novacode_cli/teams/gateway.py +200 -0
  545. novacode_cli/teams/host.py +64 -0
  546. novacode_cli/teams/legacy.py +52 -0
  547. novacode_cli/teams/middleware.py +176 -0
  548. novacode_cli/teams/models.py +104 -0
  549. novacode_cli/teams/output.py +47 -0
  550. novacode_cli/teams/protocol.py +50 -0
  551. novacode_cli/teams/recovery.py +80 -0
  552. novacode_cli/teams/scheduler.py +44 -0
  553. novacode_cli/teams/store.py +631 -0
  554. novacode_cli/teams/worker.py +251 -0
  555. novacode_cli/teams/workspace.py +100 -0
  556. novacode_cli/token_utils.py +256 -0
  557. novacode_cli/tools/__init__.py +104 -0
  558. novacode_cli/tools/_shared.py +97 -0
  559. novacode_cli/tools/_types.py +24 -0
  560. novacode_cli/tools/artifact_tools.py +137 -0
  561. novacode_cli/tools/code_search_tools.py +330 -0
  562. novacode_cli/tools/computer_tools.py +77 -0
  563. novacode_cli/tools/cron_tools.py +65 -0
  564. novacode_cli/tools/daemon_tool.py +290 -0
  565. novacode_cli/tools/desktop_tools.py +161 -0
  566. novacode_cli/tools/fetch_tools.py +530 -0
  567. novacode_cli/tools/http_tools.py +279 -0
  568. novacode_cli/tools/inspection_tools.py +107 -0
  569. novacode_cli/tools/job_tools.py +143 -0
  570. novacode_cli/tools/knowledge_tools.py +427 -0
  571. novacode_cli/tools/memory_tools.py +461 -0
  572. novacode_cli/tools/memory_wiki_tools.py +40 -0
  573. novacode_cli/tools/notebook_tools.py +238 -0
  574. novacode_cli/tools/oracle_tool.py +83 -0
  575. novacode_cli/tools/plan_archive_tools.py +80 -0
  576. novacode_cli/tools/plan_mode_tools.py +315 -0
  577. novacode_cli/tools/python_kernel_loop.py +165 -0
  578. novacode_cli/tools/python_kernel_tool.py +222 -0
  579. novacode_cli/tools/reflection_tools.py +34 -0
  580. novacode_cli/tools/scraper_tools.py +377 -0
  581. novacode_cli/tools/skill_tools.py +275 -0
  582. novacode_cli/tools/speak_tool.py +51 -0
  583. novacode_cli/tools/store_memory_tools.py +227 -0
  584. novacode_cli/tools/ui_tools.py +62 -0
  585. novacode_cli/tools/waiter_tools.py +408 -0
  586. novacode_cli/tools/web_tools.py +349 -0
  587. novacode_cli/tools/wiki_tools.py +152 -0
  588. novacode_cli/tools/worktree_tools.py +219 -0
  589. novacode_cli/tracking/__init__.py +10 -0
  590. novacode_cli/tracking/file_tracker.py +826 -0
  591. novacode_cli/tracking/local_metrics.py +170 -0
  592. novacode_cli/tracking/loop_guard.py +507 -0
  593. novacode_cli/tracking/request_metrics.py +60 -0
  594. novacode_cli/tracking/tracing.py +692 -0
  595. novacode_cli/tracking/usage_tree.py +677 -0
  596. novacode_cli/tracking/workspace_anchoring.py +231 -0
  597. novacode_cli/tui/__init__.py +11 -0
  598. novacode_cli/tui/animation_rate.py +9 -0
  599. novacode_cli/tui/animations.py +332 -0
  600. novacode_cli/tui/app.py +19315 -0
  601. novacode_cli/tui/auth_display.py +87 -0
  602. novacode_cli/tui/auth_screens.py +826 -0
  603. novacode_cli/tui/avatar.py +294 -0
  604. novacode_cli/tui/avatar_frames.py +21 -0
  605. novacode_cli/tui/background_tasks.py +35 -0
  606. novacode_cli/tui/browser_settings_screen.py +70 -0
  607. novacode_cli/tui/caveman_screen.py +185 -0
  608. novacode_cli/tui/council_settings_screen.py +182 -0
  609. novacode_cli/tui/council_view.py +535 -0
  610. novacode_cli/tui/decision_settings.py +268 -0
  611. novacode_cli/tui/diff_preview.py +199 -0
  612. novacode_cli/tui/gc_tuning.py +63 -0
  613. novacode_cli/tui/handoff_screen.py +206 -0
  614. novacode_cli/tui/harness.py +244 -0
  615. novacode_cli/tui/history_tree_screen.py +179 -0
  616. novacode_cli/tui/home.py +328 -0
  617. novacode_cli/tui/home_scene.py +94 -0
  618. novacode_cli/tui/icons.py +81 -0
  619. novacode_cli/tui/interface_styles.tcss +327 -0
  620. novacode_cli/tui/matrix3.py +108 -0
  621. novacode_cli/tui/mcp_tools_screen.py +131 -0
  622. novacode_cli/tui/motion.py +178 -0
  623. novacode_cli/tui/output_body.py +136 -0
  624. novacode_cli/tui/output_buffer.py +59 -0
  625. novacode_cli/tui/palette.py +334 -0
  626. novacode_cli/tui/pickers.py +237 -0
  627. novacode_cli/tui/prime_panel.py +506 -0
  628. novacode_cli/tui/provider_signin.py +213 -0
  629. novacode_cli/tui/pty_shell.py +159 -0
  630. novacode_cli/tui/reference_screens.py +444 -0
  631. novacode_cli/tui/resume_picker.py +346 -0
  632. novacode_cli/tui/rooms.py +597 -0
  633. novacode_cli/tui/screens.py +7088 -0
  634. novacode_cli/tui/session_import.py +333 -0
  635. novacode_cli/tui/session_pane.py +242 -0
  636. novacode_cli/tui/session_tab.py +42 -0
  637. novacode_cli/tui/session_transcript.py +118 -0
  638. novacode_cli/tui/shell_output.py +7 -0
  639. novacode_cli/tui/stall_watch.py +174 -0
  640. novacode_cli/tui/statusline.py +40 -0
  641. novacode_cli/tui/statusline_screen.py +91 -0
  642. novacode_cli/tui/teammate_updates.py +162 -0
  643. novacode_cli/tui/teammates.py +548 -0
  644. novacode_cli/tui/terminal.py +289 -0
  645. novacode_cli/tui/terminal_view.py +235 -0
  646. novacode_cli/tui/themes.py +118 -0
  647. novacode_cli/tui/update_notice.py +84 -0
  648. novacode_cli/tui/voice_downloads.py +113 -0
  649. novacode_cli/tui/widgets.py +2038 -0
  650. novacode_cli/tui/windows_input.py +38 -0
  651. novacode_cli/tui/workspace_approval.py +165 -0
  652. novacode_cli/ui/council_web.py +113 -0
  653. novacode_cli/ui/council_workspace.py +72 -0
  654. novacode_cli/ui/cowork_web.py +41 -0
  655. novacode_cli/ui/diff_highlight.py +160 -0
  656. novacode_cli/ui/execution.py +1396 -0
  657. novacode_cli/ui/exit_summary.py +65 -0
  658. novacode_cli/ui/hitl_approval.py +196 -0
  659. novacode_cli/ui/input_preparation.py +2 -0
  660. novacode_cli/ui/interrupt_handlers.py +215 -0
  661. novacode_cli/ui/question_prompt.py +151 -0
  662. novacode_cli/ui/status_phrases.py +157 -0
  663. novacode_cli/ui/stream_preview.py +66 -0
  664. novacode_cli/ui/streaming.py +2 -0
  665. novacode_cli/ui/subagent_tracking.py +2 -0
  666. novacode_cli/ui/ui_elements.py +1585 -0
  667. novacode_cli/ui/web_workspace.py +244 -0
  668. novacode_cli/ui_events.py +299 -0
  669. novacode_cli/update_ui.py +243 -0
  670. novacode_cli/updates.py +489 -0
  671. novacode_cli/utils/backend_patches.py +399 -0
  672. novacode_cli/utils/backend_paths.py +467 -0
  673. novacode_cli/utils/lazy_providers.py +51 -0
  674. novacode_cli/utils/model_info.py +223 -0
  675. novacode_cli/utils/pdf_extraction.py +183 -0
  676. novacode_cli/utils/startup.py +29 -0
  677. novacode_cli/utils/tasks.py +42 -0
  678. novacode_cli/utils/windows.py +9 -0
  679. novacode_cli/vixie/hook_adapter.py +127 -0
  680. novacode_cli/vixie/server.py +375 -0
  681. novacode_cli/wiki/__init__.py +15 -0
  682. novacode_cli/wiki/ask.py +56 -0
  683. novacode_cli/wiki/file.py +71 -0
  684. novacode_cli/wiki/ingest.py +184 -0
  685. novacode_cli/wiki/manager.py +261 -0
  686. novacode_cli-1.2.0.dist-info/METADATA +271 -0
  687. novacode_cli-1.2.0.dist-info/RECORD +691 -0
  688. novacode_cli-1.2.0.dist-info/WHEEL +5 -0
  689. novacode_cli-1.2.0.dist-info/entry_points.txt +2 -0
  690. novacode_cli-1.2.0.dist-info/licenses/LICENSE +21 -0
  691. novacode_cli-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,195 @@
1
+ """/codex-plan: OpenAI Codex plans headless; Nova approves and implements.
2
+
3
+ Each turn runs ``codex exec --json`` in the project with a read-only sandbox
4
+ (Codex has no plan mode; read-only is what keeps it to planning) and reads its
5
+ JSONL events. Codex cannot write a plan file read-only, so the plan is its final
6
+ message, ending in ``PLAN_READY``; questions are a final message without it.
7
+ Answers and refinements resume the same thread with ``codex exec resume``.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import contextlib
14
+ import json
15
+ import re
16
+ import shutil
17
+ from collections.abc import Callable
18
+ from pathlib import Path
19
+
20
+ from novacode_cli.commands.claude_plan import (
21
+ PLAN_READY,
22
+ QUESTIONS_PROTOCOL,
23
+ REVIEW_INSTRUCTIONS,
24
+ PlanTurn,
25
+ cli_env,
26
+ needs_login,
27
+ parse_questions,
28
+ )
29
+
30
+ NAME = "Codex"
31
+ COMMAND = "/codex-plan"
32
+ DOCS_URL = "https://github.com/openai/codex"
33
+ COLOR = "#10a37f"
34
+ INSTALL_LABEL = "npm install -g @openai/codex"
35
+ LOGIN_HINT = (
36
+ "Log in once: run `codex login` in a terminal (or set OPENAI_API_KEY), "
37
+ "then run /codex-plan again."
38
+ )
39
+
40
+ INSTRUCTIONS = f"""\
41
+ You are planning for another coding agent (Nova), which will implement your plan.
42
+ Do not modify any files: explore the repository read-only as much as you need.
43
+ The user answers only between your turns.
44
+ {QUESTIONS_PROTOCOL}
45
+ - When the plan is complete, reply with the full plan in markdown: context, the
46
+ concrete steps with the files to change, and how to verify. End the reply
47
+ with a line containing only {PLAN_READY}.
48
+
49
+ Task:
50
+ """
51
+ REVIEW_COMMAND = "/codex-review"
52
+ #: The read-only sandbox already keeps the reviewer from editing.
53
+ REVIEW_ARGS = {"instructions": REVIEW_INSTRUCTIONS + "\nWhat to review:\n"}
54
+
55
+
56
+ def executable() -> str | None:
57
+ """The ``codex`` CLI, if installed."""
58
+ return shutil.which("codex")
59
+
60
+
61
+ def install_command() -> list[str]:
62
+ """Codex's npm package (needs Node.js)."""
63
+ npm = shutil.which("npm") or "npm"
64
+ return [npm, "install", "-g", "@openai/codex"]
65
+
66
+
67
+ async def install(on_line: Callable[[str], None]) -> bool:
68
+ """Install with npm, streaming its output; True when ``codex`` is then found."""
69
+ if shutil.which("npm") is None:
70
+ on_line("npm is not installed: install Node.js (https://nodejs.org), then retry.")
71
+ return False
72
+ try:
73
+ process = await asyncio.create_subprocess_exec(
74
+ *install_command(),
75
+ stdin=asyncio.subprocess.DEVNULL,
76
+ stdout=asyncio.subprocess.PIPE,
77
+ stderr=asyncio.subprocess.STDOUT,
78
+ )
79
+ except OSError as exc:
80
+ on_line(f"Could not start the installer: {exc}")
81
+ return False
82
+ assert process.stdout is not None
83
+ async for raw in process.stdout:
84
+ line = raw.decode(errors="replace").rstrip()
85
+ if line:
86
+ on_line(line)
87
+ await process.wait()
88
+ return executable() is not None
89
+
90
+
91
+ _SHELL_WRAPPER = re.compile(r'^"?[^"]*?(?:pwsh|powershell|bash|sh)(?:\.exe)?"?\s+(?:-NoProfile\s+)?-(?:Command|c|lc)\s+', re.I)
92
+
93
+
94
+ def _brief(command: str) -> str:
95
+ """``"C:\\...\\pwsh.exe" -Command 'Get-Content app.py'`` -> ``$ Get-Content app.py``."""
96
+ inner = _SHELL_WRAPPER.sub("", command).strip().strip("'\"")
97
+ return "$ " + " ".join(inner.split())[:90]
98
+
99
+
100
+ #: Nova's exported OpenAI settings (see ``claude_plan.ANTHROPIC_VARS``): a
101
+ #: custom base URL from Nova's model settings would send Codex elsewhere.
102
+ OPENAI_VARS = ("OPENAI_API_KEY", "OPENAI_BASE_URL", "CODEX_API_KEY")
103
+
104
+
105
+ async def run_turn(
106
+ prompt: str,
107
+ cwd: Path,
108
+ *,
109
+ session_id: str | None = None,
110
+ on_step: Callable[[str], None] | None = None,
111
+ on_session: Callable[[str], None] | None = None,
112
+ instructions: str = INSTRUCTIONS,
113
+ ) -> PlanTurn:
114
+ """Run one headless planning turn; ``on_step`` receives each command Codex runs.
115
+
116
+ Runs on the user's own ``codex login``. Only when there is none, and Nova
117
+ has an OpenAI key, is the turn retried with that key.
118
+ """
119
+ env, has_key = cli_env(OPENAI_VARS)
120
+ extra = {"on_session": on_session, "instructions": instructions}
121
+ turn = await _run(prompt, cwd, session_id=session_id, on_step=on_step, env=env, **extra)
122
+ if turn.error and has_key and needs_login(turn.error):
123
+ turn = await _run(
124
+ prompt, cwd, session_id=session_id, on_step=on_step, **extra,
125
+ env=cli_env(OPENAI_VARS, keep=True)[0],
126
+ )
127
+ if turn.error and needs_login(turn.error):
128
+ turn.error = f"Codex is not logged in. {LOGIN_HINT}\n({turn.error[:200]})"
129
+ return turn
130
+
131
+
132
+ async def _run(
133
+ prompt: str,
134
+ cwd: Path,
135
+ *,
136
+ session_id: str | None,
137
+ on_step: Callable[[str], None] | None,
138
+ env: dict[str, str],
139
+ on_session: Callable[[str], None] | None = None,
140
+ instructions: str = INSTRUCTIONS,
141
+ ) -> PlanTurn:
142
+ exe = executable()
143
+ if exe is None:
144
+ return PlanTurn(error="Codex is not installed (no `codex` found).")
145
+ common = ["--json", "--skip-git-repo-check", "-c", 'sandbox_mode="read-only"']
146
+ if session_id:
147
+ command = [exe, "exec", "resume", session_id, *common, prompt]
148
+ else:
149
+ command = [exe, "exec", *common, instructions + prompt]
150
+ process = await asyncio.create_subprocess_exec(
151
+ *command,
152
+ cwd=str(cwd),
153
+ env=env,
154
+ stdin=asyncio.subprocess.DEVNULL, # else it waits for piped input
155
+ stdout=asyncio.subprocess.PIPE,
156
+ stderr=asyncio.subprocess.PIPE,
157
+ limit=16 * 1024 * 1024,
158
+ )
159
+ turn = PlanTurn(session_id=session_id)
160
+ try:
161
+ assert process.stdout is not None
162
+ async for raw in process.stdout:
163
+ try:
164
+ event = json.loads(raw)
165
+ except ValueError:
166
+ continue
167
+ kind = event.get("type")
168
+ item = event.get("item") or {}
169
+ if kind == "thread.started":
170
+ turn.session_id = event.get("thread_id") or turn.session_id
171
+ if turn.session_id and on_session is not None:
172
+ on_session(turn.session_id) # known now, so an interrupted run can resume
173
+ elif kind == "item.started" and item.get("type") == "command_execution":
174
+ if on_step is not None:
175
+ on_step(_brief(str(item.get("command") or "")))
176
+ elif kind == "item.completed" and item.get("type") == "agent_message":
177
+ turn.text = str(item.get("text") or "") # the last one is the reply
178
+ elif kind in ("turn.failed", "error"):
179
+ error = event.get("error") or {}
180
+ turn.error = str(error.get("message") if isinstance(error, dict) else error) or str(
181
+ event.get("message") or "Codex failed"
182
+ )
183
+ await process.wait()
184
+ except asyncio.CancelledError:
185
+ with contextlib.suppress(ProcessLookupError):
186
+ process.kill()
187
+ raise
188
+ if process.returncode and not turn.error:
189
+ stderr = (await process.stderr.read()).decode(errors="replace") if process.stderr else ""
190
+ turn.error = stderr.strip()[-600:] or f"codex exited with {process.returncode}"
191
+ if PLAN_READY in turn.text:
192
+ turn.text = turn.plan = turn.text.replace(PLAN_READY, "").strip()
193
+ else:
194
+ turn.text, turn.questions = parse_questions(turn.text)
195
+ return turn