codex-partner 0.0.6__tar.gz → 0.0.7__tar.gz

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 (324) hide show
  1. {codex_partner-0.0.6 → codex_partner-0.0.7}/PKG-INFO +4 -3
  2. {codex_partner-0.0.6 → codex_partner-0.0.7}/README.md +3 -2
  3. {codex_partner-0.0.6 → codex_partner-0.0.7}/app.py +71 -4
  4. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/__init__.py +1 -1
  5. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/schemas.py +1 -0
  6. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/PKG-INFO +4 -3
  7. {codex_partner-0.0.6 → codex_partner-0.0.7}/pyproject.toml +1 -1
  8. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/app.js +27 -4
  9. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/core.js +16 -5
  10. {codex_partner-0.0.6 → codex_partner-0.0.7}/tests/test_running_state.py +83 -4
  11. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/__main__.py +0 -0
  12. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/activity_graph.py +0 -0
  13. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/app_server.py +0 -0
  14. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/cli.py +0 -0
  15. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/commands.py +0 -0
  16. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/database.py +0 -0
  17. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/discovery.py +0 -0
  18. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/platform_support.py +0 -0
  19. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner/ssh_auth.py +0 -0
  20. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/SOURCES.txt +0 -0
  21. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/dependency_links.txt +0 -0
  22. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/entry_points.txt +0 -0
  23. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/requires.txt +0 -0
  24. {codex_partner-0.0.6 → codex_partner-0.0.7}/codex_partner.egg-info/top_level.txt +0 -0
  25. {codex_partner-0.0.6 → codex_partner-0.0.7}/setup.cfg +0 -0
  26. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/__init__.py +0 -0
  27. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/chat-worker.js +0 -0
  28. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/conversation.js +0 -0
  29. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/default-user-avatar.webp +0 -0
  30. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/editor.js +0 -0
  31. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/exploration-tree.js +0 -0
  32. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/history-pagination.js +0 -0
  33. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/index.html +0 -0
  34. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/mascot-dance.css +0 -0
  35. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/mascot-dance.js +0 -0
  36. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/settings.js +0 -0
  37. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/styles.css +0 -0
  38. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/LICENSE +0 -0
  39. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/ace.js +0 -0
  40. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/ext-modelist.js +0 -0
  41. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-abap.js +0 -0
  42. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-abc.js +0 -0
  43. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-actionscript.js +0 -0
  44. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ada.js +0 -0
  45. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-alda.js +0 -0
  46. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-apache_conf.js +0 -0
  47. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-apex.js +0 -0
  48. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-applescript.js +0 -0
  49. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-aql.js +0 -0
  50. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-asciidoc.js +0 -0
  51. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-asl.js +0 -0
  52. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-assembly_arm32.js +0 -0
  53. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-assembly_x86.js +0 -0
  54. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-astro.js +0 -0
  55. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-autohotkey.js +0 -0
  56. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-basic.js +0 -0
  57. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-batchfile.js +0 -0
  58. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-bibtex.js +0 -0
  59. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-c9search.js +0 -0
  60. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-c_cpp.js +0 -0
  61. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-cedar.js +0 -0
  62. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-cedarschema.js +0 -0
  63. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-cirru.js +0 -0
  64. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-clojure.js +0 -0
  65. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-clue.js +0 -0
  66. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-cobol.js +0 -0
  67. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-coffee.js +0 -0
  68. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-coldfusion.js +0 -0
  69. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-crystal.js +0 -0
  70. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csharp.js +0 -0
  71. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csound_document.js +0 -0
  72. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csound_orchestra.js +0 -0
  73. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csound_score.js +0 -0
  74. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csp.js +0 -0
  75. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-css.js +0 -0
  76. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-csv.js +0 -0
  77. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-curly.js +0 -0
  78. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-cuttlefish.js +0 -0
  79. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-d.js +0 -0
  80. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-dart.js +0 -0
  81. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-diff.js +0 -0
  82. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-django.js +0 -0
  83. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-dockerfile.js +0 -0
  84. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-dot.js +0 -0
  85. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-drools.js +0 -0
  86. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-edifact.js +0 -0
  87. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-eiffel.js +0 -0
  88. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ejs.js +0 -0
  89. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-elixir.js +0 -0
  90. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-elm.js +0 -0
  91. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-erlang.js +0 -0
  92. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-flix.js +0 -0
  93. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-forth.js +0 -0
  94. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-fortran.js +0 -0
  95. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-fsharp.js +0 -0
  96. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-fsl.js +0 -0
  97. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ftl.js +0 -0
  98. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-gcode.js +0 -0
  99. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-gherkin.js +0 -0
  100. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-gitignore.js +0 -0
  101. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-glsl.js +0 -0
  102. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-gobstones.js +0 -0
  103. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-golang.js +0 -0
  104. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-graphqlschema.js +0 -0
  105. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-groovy.js +0 -0
  106. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-groq.js +0 -0
  107. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-haml.js +0 -0
  108. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-handlebars.js +0 -0
  109. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-haskell.js +0 -0
  110. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-haskell_cabal.js +0 -0
  111. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-haxe.js +0 -0
  112. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-hjson.js +0 -0
  113. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-html.js +0 -0
  114. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-html_elixir.js +0 -0
  115. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-html_ruby.js +0 -0
  116. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ini.js +0 -0
  117. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-io.js +0 -0
  118. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ion.js +0 -0
  119. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jack.js +0 -0
  120. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jade.js +0 -0
  121. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-java.js +0 -0
  122. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-javascript.js +0 -0
  123. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jexl.js +0 -0
  124. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-json.js +0 -0
  125. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-json5.js +0 -0
  126. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jsoniq.js +0 -0
  127. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jsp.js +0 -0
  128. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jssm.js +0 -0
  129. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-jsx.js +0 -0
  130. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-julia.js +0 -0
  131. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-kotlin.js +0 -0
  132. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-latex.js +0 -0
  133. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-latte.js +0 -0
  134. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-less.js +0 -0
  135. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-liquid.js +0 -0
  136. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-lisp.js +0 -0
  137. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-livescript.js +0 -0
  138. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-logiql.js +0 -0
  139. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-logtalk.js +0 -0
  140. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-lsl.js +0 -0
  141. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-lua.js +0 -0
  142. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-luapage.js +0 -0
  143. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-lucene.js +0 -0
  144. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-makefile.js +0 -0
  145. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mariadb.js +0 -0
  146. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-markdown.js +0 -0
  147. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mask.js +0 -0
  148. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-matlab.js +0 -0
  149. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-maze.js +0 -0
  150. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mediawiki.js +0 -0
  151. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mel.js +0 -0
  152. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mips.js +0 -0
  153. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mixal.js +0 -0
  154. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mushcode.js +0 -0
  155. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-mysql.js +0 -0
  156. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nasal.js +0 -0
  157. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nginx.js +0 -0
  158. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nim.js +0 -0
  159. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nix.js +0 -0
  160. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nsis.js +0 -0
  161. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-nunjucks.js +0 -0
  162. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-objectivec.js +0 -0
  163. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ocaml.js +0 -0
  164. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-odin.js +0 -0
  165. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-partiql.js +0 -0
  166. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-pascal.js +0 -0
  167. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-perl.js +0 -0
  168. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-pgsql.js +0 -0
  169. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-php.js +0 -0
  170. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-php_laravel_blade.js +0 -0
  171. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-pig.js +0 -0
  172. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-plain_text.js +0 -0
  173. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-plsql.js +0 -0
  174. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-powershell.js +0 -0
  175. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-praat.js +0 -0
  176. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-prisma.js +0 -0
  177. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-prolog.js +0 -0
  178. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-properties.js +0 -0
  179. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-protobuf.js +0 -0
  180. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-prql.js +0 -0
  181. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-puppet.js +0 -0
  182. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-python.js +0 -0
  183. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-qml.js +0 -0
  184. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-r.js +0 -0
  185. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-raku.js +0 -0
  186. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-razor.js +0 -0
  187. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-rdoc.js +0 -0
  188. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-red.js +0 -0
  189. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-redshift.js +0 -0
  190. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-rhtml.js +0 -0
  191. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-robot.js +0 -0
  192. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-rst.js +0 -0
  193. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-ruby.js +0 -0
  194. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-rust.js +0 -0
  195. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sac.js +0 -0
  196. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sass.js +0 -0
  197. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-scad.js +0 -0
  198. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-scala.js +0 -0
  199. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-scheme.js +0 -0
  200. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-scrypt.js +0 -0
  201. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-scss.js +0 -0
  202. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sh.js +0 -0
  203. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sjs.js +0 -0
  204. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-slim.js +0 -0
  205. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-smarty.js +0 -0
  206. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-smithy.js +0 -0
  207. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-snippets.js +0 -0
  208. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-soy_template.js +0 -0
  209. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-space.js +0 -0
  210. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sparql.js +0 -0
  211. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sql.js +0 -0
  212. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-sqlserver.js +0 -0
  213. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-stylus.js +0 -0
  214. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-svg.js +0 -0
  215. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-swift.js +0 -0
  216. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-tcl.js +0 -0
  217. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-terraform.js +0 -0
  218. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-tex.js +0 -0
  219. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-text.js +0 -0
  220. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-textile.js +0 -0
  221. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-toml.js +0 -0
  222. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-tsv.js +0 -0
  223. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-tsx.js +0 -0
  224. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-turtle.js +0 -0
  225. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-twig.js +0 -0
  226. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-typescript.js +0 -0
  227. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-vala.js +0 -0
  228. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-vbscript.js +0 -0
  229. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-velocity.js +0 -0
  230. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-verilog.js +0 -0
  231. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-vhdl.js +0 -0
  232. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-visualforce.js +0 -0
  233. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-vue.js +0 -0
  234. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-wollok.js +0 -0
  235. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-xml.js +0 -0
  236. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-xquery.js +0 -0
  237. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-yaml.js +0 -0
  238. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-zeek.js +0 -0
  239. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/mode-zig.js +0 -0
  240. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/ace/theme-tomorrow_night_eighties.js +0 -0
  241. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/i18next/LICENSE +0 -0
  242. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/i18next/i18next.min.js +0 -0
  243. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/LICENSE +0 -0
  244. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  245. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  246. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  247. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  248. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  249. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  250. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  251. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  252. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  253. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  254. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  255. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  256. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  257. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  258. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  259. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  260. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  261. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  262. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  263. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  264. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  265. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  266. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  267. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  268. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  269. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  270. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  271. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  272. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  273. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  274. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  275. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  276. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  277. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  278. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  279. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  280. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  281. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  282. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  283. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  284. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  285. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  286. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  287. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  288. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  289. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  290. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  291. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  292. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  293. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  294. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  295. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  296. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  297. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  298. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  299. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  300. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  301. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  302. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  303. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  304. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/katex.min.css +0 -0
  305. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/katex/katex.min.js +0 -0
  306. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/markdown-it/LICENSE +0 -0
  307. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/markdown-it/markdown-it.min.js +0 -0
  308. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/markdown-it-texmath/LICENSE +0 -0
  309. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/markdown-it-texmath/texmath.js +0 -0
  310. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/toastui-editor/LICENSE +0 -0
  311. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/toastui-editor/toastui-editor-dark.css +0 -0
  312. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/toastui-editor/toastui-editor.css +0 -0
  313. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/toastui-editor/toastui-editor.js +0 -0
  314. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/toastui-editor/zh-cn.js +0 -0
  315. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/LICENSE +0 -0
  316. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/fit.LICENSE +0 -0
  317. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/fit.js +0 -0
  318. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/unicode11.LICENSE +0 -0
  319. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/unicode11.js +0 -0
  320. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/web-links.LICENSE +0 -0
  321. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/addons/web-links.js +0 -0
  322. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/xterm.css +0 -0
  323. {codex_partner-0.0.6 → codex_partner-0.0.7}/static/vendor/xterm/xterm.js +0 -0
  324. {codex_partner-0.0.6 → codex_partner-0.0.7}/tests/test_platform_support.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-partner
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: A self-hosted web interface for managing persistent Codex tasks.
5
5
  Project-URL: Homepage, https://github.com/froststeam/Codex-Partner
6
6
  Project-URL: Repository, https://github.com/froststeam/Codex-Partner.git
@@ -48,6 +48,7 @@ Codex Partner is a self-hosted control panel for long-running Codex work. It kee
48
48
  - Model and API provider management with health checks and failover
49
49
  - Codex memories, Skills, archive, recycle bin, and SSH workspace support
50
50
  - Default YOLO mode for newly created sessions
51
+ - Safe terminal-to-web takeover: normal web sends ask before stopping a terminal turn; `Alt+Enter` keeps the message queued without interruption
51
52
 
52
53
  ## Platform support
53
54
 
@@ -126,7 +127,7 @@ py -m codex_partner
126
127
  ## Docker
127
128
 
128
129
  ```bash
129
- docker build -t codex-partner:0.0.6 .
130
+ docker build -t codex-partner:0.0.7 .
130
131
  docker run -d --name codex-partner \
131
132
  -p 8787:8787 \
132
133
  --add-host=host.docker.internal:host-gateway \
@@ -135,7 +136,7 @@ docker run -d --name codex-partner \
135
136
  -v codex-partner-data:/var/lib/codex-partner \
136
137
  -v codex-home:/home/codex/.codex \
137
138
  -v codex-workspace:/workspace \
138
- codex-partner:0.0.6
139
+ codex-partner:0.0.7
139
140
  docker exec -it codex-partner codex login
140
141
  ```
141
142
 
@@ -20,6 +20,7 @@ Codex Partner is a self-hosted control panel for long-running Codex work. It kee
20
20
  - Model and API provider management with health checks and failover
21
21
  - Codex memories, Skills, archive, recycle bin, and SSH workspace support
22
22
  - Default YOLO mode for newly created sessions
23
+ - Safe terminal-to-web takeover: normal web sends ask before stopping a terminal turn; `Alt+Enter` keeps the message queued without interruption
23
24
 
24
25
  ## Platform support
25
26
 
@@ -98,7 +99,7 @@ py -m codex_partner
98
99
  ## Docker
99
100
 
100
101
  ```bash
101
- docker build -t codex-partner:0.0.6 .
102
+ docker build -t codex-partner:0.0.7 .
102
103
  docker run -d --name codex-partner \
103
104
  -p 8787:8787 \
104
105
  --add-host=host.docker.internal:host-gateway \
@@ -107,7 +108,7 @@ docker run -d --name codex-partner \
107
108
  -v codex-partner-data:/var/lib/codex-partner \
108
109
  -v codex-home:/home/codex/.codex \
109
110
  -v codex-workspace:/workspace \
110
- codex-partner:0.0.6
111
+ codex-partner:0.0.7
111
112
  docker exec -it codex-partner codex login
112
113
  ```
113
114
 
@@ -1271,11 +1271,13 @@ def interrupt_rollout_writers(path: str) -> set[int]:
1271
1271
  writers = native_rollout_writer_pids(path, refresh=True)
1272
1272
  for pid in writers:
1273
1273
  try:
1274
- command = Path(f"/proc/{pid}/cmdline").read_bytes().replace(b"\0", b" ")
1275
- if b"app-server" in command:
1276
- continue
1274
+ command_path = Path(f"/proc/{pid}/cmdline")
1275
+ if command_path.is_file():
1276
+ command = command_path.read_bytes().replace(b"\0", b" ")
1277
+ if b"app-server" in command:
1278
+ continue
1277
1279
  os.kill(pid, signal.SIGINT)
1278
- except OSError:
1280
+ except (OSError, ValueError):
1279
1281
  continue
1280
1282
  return writers
1281
1283
 
@@ -4305,6 +4307,61 @@ async def enqueue_task_message(task_id: str, body: str, client_message_id: Optio
4305
4307
  return db.one("SELECT * FROM task_messages WHERE id=?", (message_id,)) or {"id": message_id, "status": "queued"}
4306
4308
 
4307
4309
 
4310
+ async def terminal_turn_active(task_id: str) -> bool:
4311
+ """Refresh and report a terminal-owned turn without confusing dashboard work."""
4312
+ await refresh_live_external_turn(task_id)
4313
+ return bool(refresh_external_primary(task_id)) and not dashboard_owns_task(task_id)
4314
+
4315
+
4316
+ async def interrupt_browser_terminal(task_id: str) -> None:
4317
+ """Send Ctrl+C to the foreground process in every matching browser terminal."""
4318
+ matching = [session for session in terminal_sessions.values() if session.get("task_id") == task_id and not session.get("closed")]
4319
+ for session in matching:
4320
+ try:
4321
+ if process := session.get("windows_pty"):
4322
+ await asyncio.to_thread(process.write, "\x03")
4323
+ elif session.get("fd") is not None:
4324
+ os.write(session["fd"], b"\x03")
4325
+ except (EOFError, OSError):
4326
+ continue
4327
+
4328
+
4329
+ async def stop_terminal_for_web_takeover(task_id: str) -> bool:
4330
+ """Stop terminal-owned turns without letting Goal auto-resume race the web message."""
4331
+ await refresh_live_external_turn(task_id)
4332
+ tracked = list((external_turn_sets.get(task_id) or {}).values())
4333
+ if not tracked:
4334
+ return False
4335
+ await interrupt_browser_terminal(task_id)
4336
+ paths = {str(turn.get("path") or "") for turn in tracked} - {""}
4337
+ for path in paths:
4338
+ await asyncio.to_thread(interrupt_rollout_writers, path)
4339
+ clear_external_turns(task_id)
4340
+ stamp = now()
4341
+ for external in tracked:
4342
+ session_id = str(external.get("session_id") or "")
4343
+ if not session_id:
4344
+ continue
4345
+ db.execute(
4346
+ "UPDATE sessions SET status='stopped',finished_at=COALESCE(finished_at,?),exit_code=COALESCE(exit_code,130),summary='Terminal turn stopped for web takeover' WHERE id=?",
4347
+ (stamp, session_id),
4348
+ )
4349
+ payload = {"type": "turn_aborted", "status": "stopped", "reason": "Web session took over the terminal turn"}
4350
+ db.execute(
4351
+ "INSERT INTO events (session_id,ts,stream,payload) VALUES (?,?,?,?)",
4352
+ (session_id, stamp, "rollout", json.dumps(payload, ensure_ascii=False)),
4353
+ )
4354
+ await broadcast_task(task_id, {"type": "event", "session_id": session_id, "stream": "rollout", "payload": payload, "ts": stamp})
4355
+ db.execute(
4356
+ "UPDATE tasks SET status='stopped',active_session_id=NULL,execution_source='',execution_turn_id='',run_mode='',last_error='',updated_at=? WHERE id=?",
4357
+ (stamp, task_id),
4358
+ )
4359
+ result = task_or_404(task_id)
4360
+ await broadcast_task(task_id, {"type": "task_status", "task": result, "source": {"kind": "web_takeover"}})
4361
+ await broadcast_overview(task_id, {"kind": "web_takeover"})
4362
+ return True
4363
+
4364
+
4308
4365
  def command_event_session(task: dict) -> str:
4309
4366
  if task.get("active_session_id") and db.one("SELECT id FROM sessions WHERE id=?", (task["active_session_id"],)):
4310
4367
  return task["active_session_id"]
@@ -5933,6 +5990,16 @@ async def clear_task_messages(task_id: str, _: Any = Depends(auth)):
5933
5990
 
5934
5991
  @app.post("/api/tasks/{task_id}/messages")
5935
5992
  async def post_task_message(task_id: str, payload: TaskMessageIn, _: Any = Depends(auth)):
5993
+ if payload.delivery != "queue" and await terminal_turn_active(task_id):
5994
+ if not payload.takeover_terminal:
5995
+ raise HTTPException(
5996
+ 409,
5997
+ detail={
5998
+ "code": "terminal_turn_active",
5999
+ "message": "Codex 正在终端中运行。是否停止终端 turn 并由网页接管?",
6000
+ },
6001
+ )
6002
+ await stop_terminal_for_web_takeover(task_id)
5936
6003
  return await enqueue_task_message(task_id, payload.message, payload.client_message_id, payload.delivery)
5937
6004
 
5938
6005
 
@@ -1,4 +1,4 @@
1
1
  """Codex Partner application package."""
2
2
 
3
3
  APP_NAME = "Codex Partner"
4
- APP_VERSION = "0.0.6"
4
+ APP_VERSION = "0.0.7"
@@ -121,6 +121,7 @@ class TaskMessageIn(BaseModel):
121
121
  message: str = Field(min_length=1, max_length=20000)
122
122
  client_message_id: Optional[str] = None
123
123
  delivery: Literal["auto", "queue"] = "auto"
124
+ takeover_terminal: bool = False
124
125
 
125
126
 
126
127
  class TaskMessagePatch(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-partner
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: A self-hosted web interface for managing persistent Codex tasks.
5
5
  Project-URL: Homepage, https://github.com/froststeam/Codex-Partner
6
6
  Project-URL: Repository, https://github.com/froststeam/Codex-Partner.git
@@ -48,6 +48,7 @@ Codex Partner is a self-hosted control panel for long-running Codex work. It kee
48
48
  - Model and API provider management with health checks and failover
49
49
  - Codex memories, Skills, archive, recycle bin, and SSH workspace support
50
50
  - Default YOLO mode for newly created sessions
51
+ - Safe terminal-to-web takeover: normal web sends ask before stopping a terminal turn; `Alt+Enter` keeps the message queued without interruption
51
52
 
52
53
  ## Platform support
53
54
 
@@ -126,7 +127,7 @@ py -m codex_partner
126
127
  ## Docker
127
128
 
128
129
  ```bash
129
- docker build -t codex-partner:0.0.6 .
130
+ docker build -t codex-partner:0.0.7 .
130
131
  docker run -d --name codex-partner \
131
132
  -p 8787:8787 \
132
133
  --add-host=host.docker.internal:host-gateway \
@@ -135,7 +136,7 @@ docker run -d --name codex-partner \
135
136
  -v codex-partner-data:/var/lib/codex-partner \
136
137
  -v codex-home:/home/codex/.codex \
137
138
  -v codex-workspace:/workspace \
138
- codex-partner:0.0.6
139
+ codex-partner:0.0.7
139
140
  docker exec -it codex-partner codex login
140
141
  ```
141
142
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codex-partner"
7
- version = "0.0.6"
7
+ version = "0.0.7"
8
8
  description = "A self-hosted web interface for managing persistent Codex tasks."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -270,6 +270,8 @@ async function submitMessage(mode = "codex") {
270
270
  } catch (error) { input.value = message; resizeComposerInput(input); renderCommandPalette(); toast(error.message); }
271
271
  return;
272
272
  }
273
+ const draftMessage = message;
274
+ const draftAttachments = [...pendingAttachments];
273
275
  if (pendingAttachments.length) {
274
276
  message += pendingAttachments.map((file, index) => {
275
277
  const prefix = message || index ? "\n\n" : "";
@@ -277,15 +279,36 @@ async function submitMessage(mode = "codex") {
277
279
  return `${prefix}[${uiLabel("attachments")}:${file.name}]\n\n\`\`\`\n${file.content}\n\`\`\``;
278
280
  }).join("");
279
281
  }
280
- // Enter never interrupts an active turn. The server owns the durable FIFO
281
- // and dispatches this message as a new turn once the current owner exits.
282
+ let takeoverTerminal = false;
283
+ const terminalActive = Boolean(state.selectedTask?.external_running) && state.selectedTask?.execution_source === "terminal";
284
+ if (mode === "codex" && terminalActive) {
285
+ takeoverTerminal = await appConfirm(uiLabel("terminalTakeoverConfirm"), { danger: true, confirmLabel: uiLabel("terminalTakeoverAction") });
286
+ if (!takeoverTerminal) return;
287
+ }
288
+ // Dashboard-owned turns stay FIFO. A terminal-owned turn requires an
289
+ // explicit takeover confirmation; Alt+Enter always remains queue-only.
282
290
  const clientMessageId = crypto.randomUUID ? crypto.randomUUID() : String(Date.now());
283
- const delivery = mode === "queue" || activeTurn ? "queue" : "auto";
291
+ const delivery = mode === "queue" || (activeTurn && !takeoverTerminal) ? "queue" : "auto";
284
292
  const optimisticStatus = delivery === "queue" ? "queued" : "sending";
285
293
  const optimistic = { id: clientMessageId, body: message, status: optimisticStatus, created_at: new Date().toISOString(), _optimistic: true };
286
294
  upsertTaskMessage(optimistic); state.historyIndex = -1; input.value = ""; resizeComposerInput(input); pendingAttachments = []; $("#composer-context").textContent = ""; $("#attach-file").value = ""; $("#command-palette").hidden = true; renderGoalBar(); scheduleRenderChat(); input.focus();
287
295
  try {
288
- const delivered = await api(`/tasks/${taskId}/messages`, { method: "POST", body: JSON.stringify({ message, client_message_id: clientMessageId, delivery }) });
296
+ let delivered;
297
+ try {
298
+ delivered = await api(`/tasks/${taskId}/messages`, { method: "POST", body: JSON.stringify({ message, client_message_id: clientMessageId, delivery, takeover_terminal: takeoverTerminal }) });
299
+ } catch (error) {
300
+ if (mode !== "codex" || error.code !== "terminal_turn_active" || takeoverTerminal) throw error;
301
+ const confirmed = await appConfirm(uiLabel("terminalTakeoverConfirm"), { danger: true, confirmLabel: uiLabel("terminalTakeoverAction") });
302
+ if (!confirmed) {
303
+ if (state.selectedId === taskId) {
304
+ removeTaskMessage(clientMessageId); input.value = draftMessage; pendingAttachments = draftAttachments;
305
+ resizeComposerInput(input); renderComposerAttachments(); renderGoalBar(); scheduleRenderChat(); input.focus();
306
+ }
307
+ return;
308
+ }
309
+ takeoverTerminal = true;
310
+ delivered = await api(`/tasks/${taskId}/messages`, { method: "POST", body: JSON.stringify({ message, client_message_id: clientMessageId, delivery: "auto", takeover_terminal: true }) });
311
+ }
289
312
  if (state.selectedId === taskId) { upsertTaskMessage(delivered); renderQueuedMessages(); refreshComposerHistory(); renderGoalBar(); scheduleRenderChat(); }
290
313
  if (activeTurn && delivered.status === "queued") toast(uiLabel("queuedAfterTurn"));
291
314
  } catch (error) {
@@ -371,6 +371,8 @@ const UI_LABELS = {
371
371
  approvalSubmit: { zh: "提交选择", en: "Submit", fr: "Envoyer", ja: "送信", ko: "제출" },
372
372
  approvalResolved: { zh: "授权选择已执行", en: "Approval choice applied", fr: "Choix appliqué", ja: "承認を反映しました", ko: "승인 선택을 적용했습니다" },
373
373
  queuedAfterTurn: { zh: "已加入队列,当前 turn 结束后自动发射", en: "Queued and will run after the current turn", fr: "Ajouté à la file et exécuté après le tour actuel", ja: "キューに追加し、現在のターン完了後に自動実行します", ko: "대기열에 추가되었으며 현재 turn 종료 후 자동 실행됩니다" },
374
+ terminalTakeoverConfirm: { zh: "Codex 正在终端中运行。停止终端 turn,并由网页发送这条消息?", en: "Codex is running in a terminal. Stop that turn and send this message from the web?", fr: "Codex s’exécute dans un terminal. Arrêter ce tour et envoyer ce message depuis le Web ?", ja: "Codex はターミナルで実行中です。ターミナルのターンを停止し、このメッセージを Web から送信しますか?", ko: "Codex가 터미널에서 실행 중입니다. 터미널 turn을 중지하고 웹에서 이 메시지를 보낼까요?" },
375
+ terminalTakeoverAction: { zh: "停止终端并发送", en: "Stop terminal and send", fr: "Arrêter et envoyer", ja: "停止して送信", ko: "터미널 중지 후 전송" },
374
376
  clearQueue: { zh: "清空所有排队消息", en: "Clear all queued messages", fr: "Vider tous les messages en attente", ja: "待機メッセージをすべて消去", ko: "대기 메시지 모두 지우기" },
375
377
  dispatchNow: { zh: "立即执行这条消息", en: "Run this message now", fr: "Exécuter ce message maintenant", ja: "このメッセージを今すぐ実行", ko: "이 메시지 지금 실행" },
376
378
  editQueuedAction: { zh: "编辑排队消息", en: "Edit queued message", fr: "Modifier le message en attente", ja: "待機メッセージを編集", ko: "대기 메시지 편집" },
@@ -677,18 +679,27 @@ async function api(path, options = {}, canPrompt = true) {
677
679
  if (response.status === 401 && canPrompt) {
678
680
  if (await requestSSHLogin()) return api(path, options, false);
679
681
  }
680
- if (!response.ok) throw Error(await responseErrorMessage(response));
682
+ if (!response.ok) {
683
+ const detail = await responseErrorDetail(response);
684
+ const error = Error(detail.message);
685
+ error.code = detail.code || "";
686
+ error.detail = detail.detail;
687
+ throw error;
688
+ }
681
689
  return response.json();
682
690
  }
683
- async function responseErrorMessage(response) {
691
+ async function responseErrorDetail(response) {
684
692
  const text = await response.text().catch(() => "");
685
693
  try {
686
694
  const payload = JSON.parse(text);
687
- if (payload?.detail) return String(payload.detail);
695
+ if (payload?.detail && typeof payload.detail === "object") return { message: String(payload.detail.message || response.statusText || "Request failed"), code: String(payload.detail.code || ""), detail: payload.detail };
696
+ if (payload?.detail) return { message: String(payload.detail), code: "", detail: payload.detail };
688
697
  } catch (_) { /* Non-JSON server and proxy errors are expected here. */ }
689
698
  const plain = text.trim();
690
- if (plain && !plain.startsWith("<") && plain.length <= 500) return plain;
691
- return `${response.status} ${response.statusText || "Request failed"}`.trim();
699
+ return { message: plain && !plain.startsWith("<") && plain.length <= 500 ? plain : `${response.status} ${response.statusText || "Request failed"}`.trim(), code: "", detail: null };
700
+ }
701
+ async function responseErrorMessage(response) {
702
+ return (await responseErrorDetail(response)).message;
692
703
  }
693
704
  function toast(message) { const node = $("#toast"); node.textContent = message; node.classList.add("show"); setTimeout(() => node.classList.remove("show"), 2600); }
694
705
  async function copyText(value) {
@@ -1646,6 +1646,83 @@ process.stdout.write(JSON.stringify(browserMessages));
1646
1646
 
1647
1647
  asyncio.run(exercise())
1648
1648
 
1649
+ def test_terminal_message_requires_takeover_confirmation_before_queueing(self):
1650
+ task_id = "terminal-confirm-thread"
1651
+ self.make_task(task_id, "running")
1652
+ self.app.register_external_turn(task_id, {"turn_id": "terminal-turn", "path": "/tmp/terminal-turn.jsonl"})
1653
+ try:
1654
+ with mock.patch.object(self.app, "refresh_live_external_turn", new=mock.AsyncMock(return_value=False)):
1655
+ with self.assertRaises(self.app.HTTPException) as raised:
1656
+ asyncio.run(self.app.post_task_message(
1657
+ task_id,
1658
+ self.app.TaskMessageIn(message="take over", client_message_id="terminal-confirm-message"),
1659
+ None,
1660
+ ))
1661
+ self.assertEqual(409, raised.exception.status_code)
1662
+ self.assertEqual("terminal_turn_active", raised.exception.detail["code"])
1663
+ self.assertIsNone(self.app.db.one("SELECT id FROM task_messages WHERE id='terminal-confirm-message'"))
1664
+ finally:
1665
+ self.app.clear_external_turns(task_id)
1666
+ self.app.db.execute("DELETE FROM tasks WHERE id=?", (task_id,))
1667
+
1668
+ def test_confirmed_terminal_takeover_stops_terminal_then_queues_message(self):
1669
+ task_id = "terminal-takeover-thread"
1670
+ self.make_task(task_id, "running")
1671
+ self.app.register_external_turn(task_id, {"turn_id": "terminal-turn", "path": "/tmp/terminal-turn.jsonl"})
1672
+ try:
1673
+ with mock.patch.object(self.app, "refresh_live_external_turn", new=mock.AsyncMock(return_value=False)), \
1674
+ mock.patch.object(self.app, "stop_terminal_for_web_takeover", new=mock.AsyncMock(return_value=True)) as stop, \
1675
+ mock.patch.object(self.app, "schedule_task_drain") as drain:
1676
+ result = asyncio.run(self.app.post_task_message(
1677
+ task_id,
1678
+ self.app.TaskMessageIn(
1679
+ message="take over",
1680
+ client_message_id="terminal-takeover-message",
1681
+ takeover_terminal=True,
1682
+ ),
1683
+ None,
1684
+ ))
1685
+ stop.assert_awaited_once_with(task_id)
1686
+ drain.assert_called_once_with(task_id)
1687
+ self.assertEqual("queued", result["status"])
1688
+ finally:
1689
+ self.app.clear_external_turns(task_id)
1690
+ self.app.db.execute("DELETE FROM task_messages WHERE task_id=?", (task_id,))
1691
+ self.app.db.execute("DELETE FROM tasks WHERE id=?", (task_id,))
1692
+
1693
+ def test_terminal_takeover_clears_external_owner_without_auto_resume_race(self):
1694
+ task_id = "terminal-takeover-stop-thread"
1695
+ session_id = "external-terminal-takeover-session"
1696
+ self.make_task(task_id, "running")
1697
+ self.app.db.execute(
1698
+ "INSERT INTO sessions (id,task_id,status,attempt,command,started_at,codex_session_id) VALUES (?,?,?,?,?,?,?)",
1699
+ (session_id, task_id, "running", 1, "codex resume", self.app.now(), task_id),
1700
+ )
1701
+ self.app.register_external_turn(task_id, {
1702
+ "turn_id": "terminal-turn",
1703
+ "session_id": session_id,
1704
+ "path": "/tmp/terminal-takeover.jsonl",
1705
+ "started_at": self.app.now(),
1706
+ })
1707
+ try:
1708
+ with mock.patch.object(self.app, "refresh_live_external_turn", new=mock.AsyncMock(return_value=False)), \
1709
+ mock.patch.object(self.app, "interrupt_browser_terminal", new=mock.AsyncMock()) as browser_interrupt, \
1710
+ mock.patch.object(self.app, "interrupt_rollout_writers", return_value={900}) as writer_interrupt, \
1711
+ mock.patch.object(self.app, "schedule_task_drain") as drain:
1712
+ stopped = asyncio.run(self.app.stop_terminal_for_web_takeover(task_id))
1713
+ self.assertTrue(stopped)
1714
+ browser_interrupt.assert_awaited_once_with(task_id)
1715
+ writer_interrupt.assert_called_once_with("/tmp/terminal-takeover.jsonl")
1716
+ drain.assert_not_called()
1717
+ self.assertNotIn(task_id, self.app.external_turns)
1718
+ self.assertEqual("stopped", self.app.task_or_404(task_id)["status"])
1719
+ self.assertEqual("stopped", self.app.db.one("SELECT status FROM sessions WHERE id=?", (session_id,))["status"])
1720
+ event = self.app.db.one("SELECT payload FROM events WHERE session_id=? ORDER BY id DESC LIMIT 1", (session_id,))
1721
+ self.assertEqual("turn_aborted", json.loads(event["payload"])["type"])
1722
+ finally:
1723
+ self.app.clear_external_turns(task_id)
1724
+ self.app.db.execute("DELETE FROM tasks WHERE id=?", (task_id,))
1725
+
1649
1726
  def test_binary_dump_is_rejected_before_queueing(self):
1650
1727
  task_id = "binary-dump-thread"
1651
1728
  self.make_task(task_id, "available")
@@ -2885,7 +2962,7 @@ process.stdout.write(JSON.stringify(browserMessages));
2885
2962
  self.assertNotIn('id="stop-generation"', html)
2886
2963
  self.assertIn('$("#composer-model-select")', conversation_js)
2887
2964
  self.assertIn('当前 API ·', (static / "core.js").read_text(encoding="utf-8"))
2888
- self.assertIn('const delivery = mode === "queue" || activeTurn ? "queue" : "auto"', app_js)
2965
+ self.assertIn('const delivery = mode === "queue" || (activeTurn && !takeoverTerminal) ? "queue" : "auto"', app_js)
2889
2966
  self.assertIn('function toggleGoalRun()', app_js)
2890
2967
  self.assertIn('id="composer-model-select"', html)
2891
2968
  self.assertIn('id="composer-effort-select"', html)
@@ -3104,15 +3181,17 @@ process.stdout.write(JSON.stringify(browserMessages));
3104
3181
  static = Path(__file__).resolve().parents[1] / "static"
3105
3182
  app_js = (static / "app.js").read_text(encoding="utf-8")
3106
3183
  conversation_js = (static / "conversation.js").read_text(encoding="utf-8")
3184
+ core_js = (static / "core.js").read_text(encoding="utf-8")
3107
3185
  self.assertIn("button.dataset.queueDispatch", app_js)
3108
3186
  self.assertIn('button.dataset.dispatching === "1"', app_js)
3109
3187
  self.assertIn("result.dispatch_error", app_js)
3110
- self.assertIn('const delivery = mode === "queue" || activeTurn ? "queue" : "auto"', app_js)
3188
+ self.assertIn('const delivery = mode === "queue" || (activeTurn && !takeoverTerminal) ? "queue" : "auto"', app_js)
3111
3189
  self.assertIn('toast(uiLabel("queuedAfterTurn"))', app_js)
3112
- self.assertNotIn('if (mode === "codex" && activeTurn)', app_js)
3190
+ self.assertIn('uiLabel("terminalTakeoverConfirm")', app_js)
3191
+ self.assertIn('takeover_terminal: true', app_js)
3192
+ self.assertIn('error.code = detail.code', core_js)
3113
3193
  self.assertIn("data-queue-dispatch", conversation_js)
3114
3194
  self.assertIn("queued-error", conversation_js)
3115
- core_js = (static / "core.js").read_text(encoding="utf-8")
3116
3195
  self.assertIn("function taskIsRunningGroup", core_js)
3117
3196
  self.assertIn('["running", "retrying", "queued"].includes', core_js)
3118
3197
  self.assertIn("taskSortName(a).localeCompare", core_js)
File without changes