codex-partner 0.0.4__tar.gz → 0.0.6__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.4 → codex_partner-0.0.6}/PKG-INFO +57 -5
  2. {codex_partner-0.0.4 → codex_partner-0.0.6}/README.md +53 -4
  3. {codex_partner-0.0.4 → codex_partner-0.0.6}/app.py +151 -18
  4. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/__init__.py +1 -1
  5. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/activity_graph.py +2 -1
  6. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/app_server.py +4 -1
  7. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/database.py +5 -4
  8. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/discovery.py +4 -2
  9. codex_partner-0.0.6/codex_partner/platform_support.py +74 -0
  10. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/ssh_auth.py +6 -1
  11. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/PKG-INFO +57 -5
  12. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/SOURCES.txt +2 -0
  13. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/requires.txt +3 -0
  14. {codex_partner-0.0.4 → codex_partner-0.0.6}/pyproject.toml +4 -1
  15. codex_partner-0.0.6/tests/test_platform_support.py +62 -0
  16. {codex_partner-0.0.4 → codex_partner-0.0.6}/tests/test_running_state.py +53 -28
  17. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/__main__.py +0 -0
  18. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/cli.py +0 -0
  19. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/commands.py +0 -0
  20. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner/schemas.py +0 -0
  21. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/dependency_links.txt +0 -0
  22. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/entry_points.txt +0 -0
  23. {codex_partner-0.0.4 → codex_partner-0.0.6}/codex_partner.egg-info/top_level.txt +0 -0
  24. {codex_partner-0.0.4 → codex_partner-0.0.6}/setup.cfg +0 -0
  25. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/__init__.py +0 -0
  26. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/app.js +0 -0
  27. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/chat-worker.js +0 -0
  28. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/conversation.js +0 -0
  29. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/core.js +0 -0
  30. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/default-user-avatar.webp +0 -0
  31. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/editor.js +0 -0
  32. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/exploration-tree.js +0 -0
  33. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/history-pagination.js +0 -0
  34. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/index.html +0 -0
  35. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/mascot-dance.css +0 -0
  36. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/mascot-dance.js +0 -0
  37. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/settings.js +0 -0
  38. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/styles.css +0 -0
  39. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/LICENSE +0 -0
  40. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/ace.js +0 -0
  41. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/ext-modelist.js +0 -0
  42. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-abap.js +0 -0
  43. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-abc.js +0 -0
  44. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-actionscript.js +0 -0
  45. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ada.js +0 -0
  46. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-alda.js +0 -0
  47. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-apache_conf.js +0 -0
  48. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-apex.js +0 -0
  49. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-applescript.js +0 -0
  50. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-aql.js +0 -0
  51. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-asciidoc.js +0 -0
  52. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-asl.js +0 -0
  53. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-assembly_arm32.js +0 -0
  54. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-assembly_x86.js +0 -0
  55. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-astro.js +0 -0
  56. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-autohotkey.js +0 -0
  57. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-basic.js +0 -0
  58. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-batchfile.js +0 -0
  59. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-bibtex.js +0 -0
  60. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-c9search.js +0 -0
  61. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-c_cpp.js +0 -0
  62. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-cedar.js +0 -0
  63. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-cedarschema.js +0 -0
  64. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-cirru.js +0 -0
  65. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-clojure.js +0 -0
  66. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-clue.js +0 -0
  67. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-cobol.js +0 -0
  68. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-coffee.js +0 -0
  69. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-coldfusion.js +0 -0
  70. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-crystal.js +0 -0
  71. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csharp.js +0 -0
  72. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csound_document.js +0 -0
  73. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csound_orchestra.js +0 -0
  74. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csound_score.js +0 -0
  75. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csp.js +0 -0
  76. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-css.js +0 -0
  77. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-csv.js +0 -0
  78. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-curly.js +0 -0
  79. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-cuttlefish.js +0 -0
  80. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-d.js +0 -0
  81. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-dart.js +0 -0
  82. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-diff.js +0 -0
  83. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-django.js +0 -0
  84. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-dockerfile.js +0 -0
  85. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-dot.js +0 -0
  86. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-drools.js +0 -0
  87. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-edifact.js +0 -0
  88. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-eiffel.js +0 -0
  89. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ejs.js +0 -0
  90. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-elixir.js +0 -0
  91. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-elm.js +0 -0
  92. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-erlang.js +0 -0
  93. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-flix.js +0 -0
  94. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-forth.js +0 -0
  95. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-fortran.js +0 -0
  96. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-fsharp.js +0 -0
  97. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-fsl.js +0 -0
  98. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ftl.js +0 -0
  99. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-gcode.js +0 -0
  100. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-gherkin.js +0 -0
  101. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-gitignore.js +0 -0
  102. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-glsl.js +0 -0
  103. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-gobstones.js +0 -0
  104. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-golang.js +0 -0
  105. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-graphqlschema.js +0 -0
  106. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-groovy.js +0 -0
  107. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-groq.js +0 -0
  108. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-haml.js +0 -0
  109. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-handlebars.js +0 -0
  110. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-haskell.js +0 -0
  111. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-haskell_cabal.js +0 -0
  112. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-haxe.js +0 -0
  113. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-hjson.js +0 -0
  114. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-html.js +0 -0
  115. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-html_elixir.js +0 -0
  116. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-html_ruby.js +0 -0
  117. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ini.js +0 -0
  118. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-io.js +0 -0
  119. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ion.js +0 -0
  120. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jack.js +0 -0
  121. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jade.js +0 -0
  122. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-java.js +0 -0
  123. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-javascript.js +0 -0
  124. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jexl.js +0 -0
  125. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-json.js +0 -0
  126. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-json5.js +0 -0
  127. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jsoniq.js +0 -0
  128. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jsp.js +0 -0
  129. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jssm.js +0 -0
  130. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-jsx.js +0 -0
  131. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-julia.js +0 -0
  132. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-kotlin.js +0 -0
  133. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-latex.js +0 -0
  134. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-latte.js +0 -0
  135. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-less.js +0 -0
  136. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-liquid.js +0 -0
  137. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-lisp.js +0 -0
  138. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-livescript.js +0 -0
  139. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-logiql.js +0 -0
  140. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-logtalk.js +0 -0
  141. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-lsl.js +0 -0
  142. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-lua.js +0 -0
  143. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-luapage.js +0 -0
  144. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-lucene.js +0 -0
  145. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-makefile.js +0 -0
  146. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mariadb.js +0 -0
  147. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-markdown.js +0 -0
  148. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mask.js +0 -0
  149. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-matlab.js +0 -0
  150. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-maze.js +0 -0
  151. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mediawiki.js +0 -0
  152. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mel.js +0 -0
  153. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mips.js +0 -0
  154. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mixal.js +0 -0
  155. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mushcode.js +0 -0
  156. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-mysql.js +0 -0
  157. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nasal.js +0 -0
  158. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nginx.js +0 -0
  159. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nim.js +0 -0
  160. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nix.js +0 -0
  161. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nsis.js +0 -0
  162. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-nunjucks.js +0 -0
  163. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-objectivec.js +0 -0
  164. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ocaml.js +0 -0
  165. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-odin.js +0 -0
  166. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-partiql.js +0 -0
  167. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-pascal.js +0 -0
  168. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-perl.js +0 -0
  169. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-pgsql.js +0 -0
  170. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-php.js +0 -0
  171. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-php_laravel_blade.js +0 -0
  172. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-pig.js +0 -0
  173. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-plain_text.js +0 -0
  174. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-plsql.js +0 -0
  175. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-powershell.js +0 -0
  176. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-praat.js +0 -0
  177. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-prisma.js +0 -0
  178. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-prolog.js +0 -0
  179. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-properties.js +0 -0
  180. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-protobuf.js +0 -0
  181. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-prql.js +0 -0
  182. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-puppet.js +0 -0
  183. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-python.js +0 -0
  184. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-qml.js +0 -0
  185. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-r.js +0 -0
  186. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-raku.js +0 -0
  187. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-razor.js +0 -0
  188. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-rdoc.js +0 -0
  189. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-red.js +0 -0
  190. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-redshift.js +0 -0
  191. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-rhtml.js +0 -0
  192. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-robot.js +0 -0
  193. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-rst.js +0 -0
  194. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-ruby.js +0 -0
  195. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-rust.js +0 -0
  196. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sac.js +0 -0
  197. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sass.js +0 -0
  198. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-scad.js +0 -0
  199. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-scala.js +0 -0
  200. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-scheme.js +0 -0
  201. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-scrypt.js +0 -0
  202. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-scss.js +0 -0
  203. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sh.js +0 -0
  204. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sjs.js +0 -0
  205. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-slim.js +0 -0
  206. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-smarty.js +0 -0
  207. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-smithy.js +0 -0
  208. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-snippets.js +0 -0
  209. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-soy_template.js +0 -0
  210. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-space.js +0 -0
  211. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sparql.js +0 -0
  212. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sql.js +0 -0
  213. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-sqlserver.js +0 -0
  214. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-stylus.js +0 -0
  215. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-svg.js +0 -0
  216. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-swift.js +0 -0
  217. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-tcl.js +0 -0
  218. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-terraform.js +0 -0
  219. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-tex.js +0 -0
  220. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-text.js +0 -0
  221. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-textile.js +0 -0
  222. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-toml.js +0 -0
  223. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-tsv.js +0 -0
  224. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-tsx.js +0 -0
  225. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-turtle.js +0 -0
  226. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-twig.js +0 -0
  227. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-typescript.js +0 -0
  228. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-vala.js +0 -0
  229. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-vbscript.js +0 -0
  230. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-velocity.js +0 -0
  231. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-verilog.js +0 -0
  232. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-vhdl.js +0 -0
  233. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-visualforce.js +0 -0
  234. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-vue.js +0 -0
  235. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-wollok.js +0 -0
  236. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-xml.js +0 -0
  237. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-xquery.js +0 -0
  238. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-yaml.js +0 -0
  239. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-zeek.js +0 -0
  240. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/mode-zig.js +0 -0
  241. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/ace/theme-tomorrow_night_eighties.js +0 -0
  242. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/i18next/LICENSE +0 -0
  243. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/i18next/i18next.min.js +0 -0
  244. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/LICENSE +0 -0
  245. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  246. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  247. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  248. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  249. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  250. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  251. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  252. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  253. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  254. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  255. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  256. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  257. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  258. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  259. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  260. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  261. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  262. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  263. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  264. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  265. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  266. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  267. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  268. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  269. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  270. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  271. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  272. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  273. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  274. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  275. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  276. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  277. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  278. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  279. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  280. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  281. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  282. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  283. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  284. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  285. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  286. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  287. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  288. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  289. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  290. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  291. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  292. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  293. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  294. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  295. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  296. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  297. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  298. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  299. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  300. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  301. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  302. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  303. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  304. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  305. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/katex.min.css +0 -0
  306. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/katex/katex.min.js +0 -0
  307. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/markdown-it/LICENSE +0 -0
  308. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/markdown-it/markdown-it.min.js +0 -0
  309. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/markdown-it-texmath/LICENSE +0 -0
  310. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/markdown-it-texmath/texmath.js +0 -0
  311. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/toastui-editor/LICENSE +0 -0
  312. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/toastui-editor/toastui-editor-dark.css +0 -0
  313. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/toastui-editor/toastui-editor.css +0 -0
  314. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/toastui-editor/toastui-editor.js +0 -0
  315. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/toastui-editor/zh-cn.js +0 -0
  316. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/LICENSE +0 -0
  317. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/fit.LICENSE +0 -0
  318. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/fit.js +0 -0
  319. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/unicode11.LICENSE +0 -0
  320. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/unicode11.js +0 -0
  321. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/web-links.LICENSE +0 -0
  322. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/addons/web-links.js +0 -0
  323. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/xterm.css +0 -0
  324. {codex_partner-0.0.4 → codex_partner-0.0.6}/static/vendor/xterm/xterm.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-partner
3
- Version: 0.0.4
3
+ Version: 0.0.6
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
@@ -9,6 +9,8 @@ Keywords: codex,agent,task-management,self-hosted
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Environment :: Web Environment
11
11
  Classifier: Framework :: FastAPI
12
+ Classifier: Operating System :: MacOS
13
+ Classifier: Operating System :: Microsoft :: Windows
12
14
  Classifier: Operating System :: POSIX :: Linux
13
15
  Classifier: Programming Language :: Python :: 3
14
16
  Classifier: Programming Language :: Python :: 3 :: Only
@@ -20,6 +22,7 @@ Requires-Dist: uvicorn[standard]>=0.27
20
22
  Requires-Dist: tomli>=2.0; python_version < "3.11"
21
23
  Requires-Dist: PyYAML>=6.0
22
24
  Requires-Dist: pexpect>=4.8; platform_system != "Windows"
25
+ Requires-Dist: pywinpty>=2.0.13; platform_system == "Windows"
23
26
  Requires-Dist: python-dotenv>=1.0
24
27
  Requires-Dist: Pillow>=10.0
25
28
 
@@ -46,6 +49,18 @@ Codex Partner is a self-hosted control panel for long-running Codex work. It kee
46
49
  - Codex memories, Skills, archive, recycle bin, and SSH workspace support
47
50
  - Default YOLO mode for newly created sessions
48
51
 
52
+ ## Platform support
53
+
54
+ Codex Partner runs natively on Linux, macOS, and Windows with Python 3.10 or newer.
55
+
56
+ | Platform | Codex sessions | Workspace tools | Browser terminal | Background service |
57
+ | --- | --- | --- | --- | --- |
58
+ | Linux | Yes | Yes | POSIX PTY | systemd user service |
59
+ | macOS | Yes | Yes | zsh/bash PTY | Run directly or use launchd |
60
+ | Windows 10/11 | Yes | Yes | PowerShell through ConPTY | Run directly or use Task Scheduler |
61
+
62
+ Windows terminal support uses `pywinpty`, which is installed automatically. Key-based remote SSH works when the OpenSSH client is installed. Browser password prompts for remote SSH are not available on native Windows; configure an SSH key first.
63
+
49
64
  ## Install
50
65
 
51
66
  Requires Python 3.10+ and an authenticated [Codex CLI](https://github.com/openai/codex).
@@ -69,12 +84,49 @@ codex-partner
69
84
 
70
85
  Open <http://127.0.0.1:8787>.
71
86
 
72
- For access from other devices, set `CODEX_DASHBOARD_HOST=0.0.0.0`. Codex Partner signs browsers in with a username and password accepted by this server's SSH service; the password is verified by OpenSSH and is never stored. Put HTTPS in front of the service before entering an SSH password over an untrusted network.
87
+ Linux keeps SSH browser authentication enabled by default. macOS and Windows default to unauthenticated loopback access because desktop installations normally do not run an SSH server. For access from other devices, set `CODEX_DASHBOARD_HOST=0.0.0.0`, configure `CODEX_DASHBOARD_AUTH=ssh`, and put HTTPS in front of the service. When authentication is handled by a reverse proxy, explicitly set `CODEX_DASHBOARD_AUTH=none`; Codex Partner rejects a non-loopback bind with an implicit unauthenticated default.
88
+
89
+ ### macOS
90
+
91
+ Install Python and Node.js with Homebrew if they are not already available, then install and authenticate Codex:
92
+
93
+ ```bash
94
+ brew install python node
95
+ npm install --global @openai/codex
96
+ codex login
97
+ python3 -m pip install --user --upgrade codex-partner
98
+ python3 -m codex_partner
99
+ ```
100
+
101
+ Open <http://127.0.0.1:8787>. Application data defaults to `~/Library/Application Support/CodexPartner`; native Codex state remains in `~/.codex`.
102
+
103
+ ### Windows
104
+
105
+ Run these commands in PowerShell. Install Python and Node.js first if they are not already available:
106
+
107
+ ```powershell
108
+ winget install --id Python.Python.3.12 -e
109
+ winget install --id OpenJS.NodeJS.LTS -e
110
+ npm install --global @openai/codex
111
+ codex login
112
+ py -m pip install --user --upgrade codex-partner
113
+ py -m codex_partner
114
+ ```
115
+
116
+ Open <http://127.0.0.1:8787>. Application data defaults to `%LOCALAPPDATA%\CodexPartner`; native Codex state remains in `%USERPROFILE%\.codex`. If `codex` is not found after installing Node.js, close and reopen PowerShell so its `PATH` is refreshed.
117
+
118
+ For local desktop use, keep the default `127.0.0.1` bind address. To set options for one PowerShell session:
119
+
120
+ ```powershell
121
+ $env:CODEX_DASHBOARD_PORT = "8787"
122
+ $env:CODEX_DASHBOARD_AUTH = "none"
123
+ py -m codex_partner
124
+ ```
73
125
 
74
126
  ## Docker
75
127
 
76
128
  ```bash
77
- docker build -t codex-partner:0.0.4 .
129
+ docker build -t codex-partner:0.0.6 .
78
130
  docker run -d --name codex-partner \
79
131
  -p 8787:8787 \
80
132
  --add-host=host.docker.internal:host-gateway \
@@ -83,11 +135,11 @@ docker run -d --name codex-partner \
83
135
  -v codex-partner-data:/var/lib/codex-partner \
84
136
  -v codex-home:/home/codex/.codex \
85
137
  -v codex-workspace:/workspace \
86
- codex-partner:0.0.4
138
+ codex-partner:0.0.6
87
139
  docker exec -it codex-partner codex login
88
140
  ```
89
141
 
90
- ## systemd
142
+ ## Linux systemd
91
143
 
92
144
  After completing the source installation above, stop the foreground process and install the user service:
93
145
 
@@ -21,6 +21,18 @@ Codex Partner is a self-hosted control panel for long-running Codex work. It kee
21
21
  - Codex memories, Skills, archive, recycle bin, and SSH workspace support
22
22
  - Default YOLO mode for newly created sessions
23
23
 
24
+ ## Platform support
25
+
26
+ Codex Partner runs natively on Linux, macOS, and Windows with Python 3.10 or newer.
27
+
28
+ | Platform | Codex sessions | Workspace tools | Browser terminal | Background service |
29
+ | --- | --- | --- | --- | --- |
30
+ | Linux | Yes | Yes | POSIX PTY | systemd user service |
31
+ | macOS | Yes | Yes | zsh/bash PTY | Run directly or use launchd |
32
+ | Windows 10/11 | Yes | Yes | PowerShell through ConPTY | Run directly or use Task Scheduler |
33
+
34
+ Windows terminal support uses `pywinpty`, which is installed automatically. Key-based remote SSH works when the OpenSSH client is installed. Browser password prompts for remote SSH are not available on native Windows; configure an SSH key first.
35
+
24
36
  ## Install
25
37
 
26
38
  Requires Python 3.10+ and an authenticated [Codex CLI](https://github.com/openai/codex).
@@ -44,12 +56,49 @@ codex-partner
44
56
 
45
57
  Open <http://127.0.0.1:8787>.
46
58
 
47
- For access from other devices, set `CODEX_DASHBOARD_HOST=0.0.0.0`. Codex Partner signs browsers in with a username and password accepted by this server's SSH service; the password is verified by OpenSSH and is never stored. Put HTTPS in front of the service before entering an SSH password over an untrusted network.
59
+ Linux keeps SSH browser authentication enabled by default. macOS and Windows default to unauthenticated loopback access because desktop installations normally do not run an SSH server. For access from other devices, set `CODEX_DASHBOARD_HOST=0.0.0.0`, configure `CODEX_DASHBOARD_AUTH=ssh`, and put HTTPS in front of the service. When authentication is handled by a reverse proxy, explicitly set `CODEX_DASHBOARD_AUTH=none`; Codex Partner rejects a non-loopback bind with an implicit unauthenticated default.
60
+
61
+ ### macOS
62
+
63
+ Install Python and Node.js with Homebrew if they are not already available, then install and authenticate Codex:
64
+
65
+ ```bash
66
+ brew install python node
67
+ npm install --global @openai/codex
68
+ codex login
69
+ python3 -m pip install --user --upgrade codex-partner
70
+ python3 -m codex_partner
71
+ ```
72
+
73
+ Open <http://127.0.0.1:8787>. Application data defaults to `~/Library/Application Support/CodexPartner`; native Codex state remains in `~/.codex`.
74
+
75
+ ### Windows
76
+
77
+ Run these commands in PowerShell. Install Python and Node.js first if they are not already available:
78
+
79
+ ```powershell
80
+ winget install --id Python.Python.3.12 -e
81
+ winget install --id OpenJS.NodeJS.LTS -e
82
+ npm install --global @openai/codex
83
+ codex login
84
+ py -m pip install --user --upgrade codex-partner
85
+ py -m codex_partner
86
+ ```
87
+
88
+ Open <http://127.0.0.1:8787>. Application data defaults to `%LOCALAPPDATA%\CodexPartner`; native Codex state remains in `%USERPROFILE%\.codex`. If `codex` is not found after installing Node.js, close and reopen PowerShell so its `PATH` is refreshed.
89
+
90
+ For local desktop use, keep the default `127.0.0.1` bind address. To set options for one PowerShell session:
91
+
92
+ ```powershell
93
+ $env:CODEX_DASHBOARD_PORT = "8787"
94
+ $env:CODEX_DASHBOARD_AUTH = "none"
95
+ py -m codex_partner
96
+ ```
48
97
 
49
98
  ## Docker
50
99
 
51
100
  ```bash
52
- docker build -t codex-partner:0.0.4 .
101
+ docker build -t codex-partner:0.0.6 .
53
102
  docker run -d --name codex-partner \
54
103
  -p 8787:8787 \
55
104
  --add-host=host.docker.internal:host-gateway \
@@ -58,11 +107,11 @@ docker run -d --name codex-partner \
58
107
  -v codex-partner-data:/var/lib/codex-partner \
59
108
  -v codex-home:/home/codex/.codex \
60
109
  -v codex-workspace:/workspace \
61
- codex-partner:0.0.4
110
+ codex-partner:0.0.6
62
111
  docker exec -it codex-partner codex login
63
112
  ```
64
113
 
65
- ## systemd
114
+ ## Linux systemd
66
115
 
67
116
  After completing the source installation above, stop the foreground process and install the user service:
68
117
 
@@ -7,7 +7,6 @@ import binascii
7
7
  import codecs
8
8
  import errno
9
9
  import getpass
10
- import fcntl
11
10
  import glob
12
11
  import hashlib
13
12
  import io
@@ -16,7 +15,6 @@ import json
16
15
  import mimetypes
17
16
  import os
18
17
  import posixpath
19
- import pty
20
18
  import platform
21
19
  import re
22
20
  import signal
@@ -27,7 +25,6 @@ import sqlite3
27
25
  import socket
28
26
  import struct
29
27
  import subprocess
30
- import termios
31
28
  import time
32
29
  import uuid
33
30
  import urllib.error
@@ -43,7 +40,20 @@ from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
43
40
  from starlette.middleware.gzip import GZipMiddleware
44
41
  from dotenv import load_dotenv
45
42
  import yaml
46
- import pexpect
43
+ try:
44
+ import fcntl
45
+ import pty
46
+ import termios
47
+ except ImportError: # Native Windows has no POSIX PTY APIs.
48
+ fcntl = pty = termios = None
49
+ try:
50
+ import pexpect
51
+ except ImportError: # Password-driven SSH prompts are optional on Windows.
52
+ pexpect = None
53
+ try:
54
+ from winpty import PtyProcess as WindowsPtyProcess
55
+ except ImportError: # Installed through the Windows-only pywinpty dependency.
56
+ WindowsPtyProcess = None
47
57
  from PIL import Image, ImageOps, ImageSequence, UnidentifiedImageError
48
58
 
49
59
  from codex_partner import APP_NAME, APP_VERSION
@@ -59,6 +69,14 @@ from codex_partner.discovery import (
59
69
  official_candidates,
60
70
  vscode_candidates,
61
71
  )
72
+ from codex_partner.platform_support import (
73
+ IS_WINDOWS,
74
+ default_auth_mode,
75
+ default_data_dir,
76
+ local_shell_command,
77
+ prepare_subprocess_command,
78
+ validate_bind_auth,
79
+ )
62
80
  from codex_partner.schemas import (
63
81
  ApprovalResolveIn,
64
82
  AvatarIn,
@@ -91,12 +109,12 @@ except ModuleNotFoundError: # Python 3.10
91
109
  ROOT = Path(__file__).resolve().parent
92
110
  load_dotenv(ROOT / ".env", override=False)
93
111
  STATIC = ROOT / "static"
94
- DATA_DIR = Path(os.getenv("CODEX_DASHBOARD_DATA", str(ROOT / "data")))
112
+ DATA_DIR = default_data_dir(ROOT)
95
113
  DATA_DIR.mkdir(parents=True, exist_ok=True)
96
114
  DB_PATH = DATA_DIR / "dashboard.sqlite3"
97
115
  CODEX_HOME = Path(os.getenv("CODEX_HOME", str(Path.home() / ".codex"))).expanduser().resolve()
98
116
  CODEX_MEMORY_DIR = CODEX_HOME / "memories"
99
- AUTH_MODE = os.getenv("CODEX_DASHBOARD_AUTH", "ssh").strip().lower()
117
+ AUTH_MODE = os.getenv("CODEX_DASHBOARD_AUTH", default_auth_mode()).strip().lower()
100
118
  if AUTH_MODE not in {"ssh", "none"}:
101
119
  raise RuntimeError("CODEX_DASHBOARD_AUTH must be 'ssh' or 'none'")
102
120
  AUTH_COOKIE = "codex_partner_session"
@@ -128,6 +146,7 @@ def configured_port(name: str, default: int) -> int:
128
146
 
129
147
 
130
148
  DASHBOARD_HOST = os.getenv("CODEX_DASHBOARD_HOST", "127.0.0.1").strip() or "127.0.0.1"
149
+ validate_bind_auth(DASHBOARD_HOST, AUTH_MODE, "CODEX_DASHBOARD_AUTH" in os.environ)
131
150
  DASHBOARD_PORT = configured_port("CODEX_DASHBOARD_PORT", 8787)
132
151
  AUTH_SSH_PORT = configured_port("CODEX_DASHBOARD_AUTH_SSH_PORT", 22)
133
152
  SSH_BIN = shutil.which("ssh") or "ssh"
@@ -135,7 +154,12 @@ SSH_CONFIG = Path.home() / ".ssh/config"
135
154
  SSH_FIXED_HOST = os.getenv("CODEX_DASHBOARD_SSH_HOST", "").strip()
136
155
  SSH_FIXED_USER = os.getenv("CODEX_DASHBOARD_SSH_USER", "").strip()
137
156
  SSH_FIXED_PORT = configured_port("CODEX_DASHBOARD_SSH_PORT", 22)
138
- SSH_RUNTIME_DIR = Path(os.getenv("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")) / "codex-dashboard-ssh"
157
+ if os.getenv("XDG_RUNTIME_DIR"):
158
+ SSH_RUNTIME_DIR = Path(os.environ["XDG_RUNTIME_DIR"]) / "codex-dashboard-ssh"
159
+ elif hasattr(os, "getuid") and platform.system() == "Linux":
160
+ SSH_RUNTIME_DIR = Path(f"/run/user/{os.getuid()}") / "codex-dashboard-ssh"
161
+ else:
162
+ SSH_RUNTIME_DIR = DATA_DIR / "ssh-runtime"
139
163
  try:
140
164
  SSH_RUNTIME_DIR.mkdir(parents=True, exist_ok=True, mode=0o700)
141
165
  SSH_RUNTIME_DIR.chmod(0o700)
@@ -207,7 +231,7 @@ def codex_management_snapshot() -> dict[str, Any]:
207
231
  if CODEX_AVAILABLE:
208
232
  try:
209
233
  result = subprocess.run(
210
- [CODEX_BIN, "--version"],
234
+ prepare_subprocess_command([CODEX_BIN, "--version"]),
211
235
  stdin=subprocess.DEVNULL,
212
236
  stdout=subprocess.PIPE,
213
237
  stderr=subprocess.STDOUT,
@@ -1154,8 +1178,23 @@ def rollout_writer_pids(path: str, refresh: bool = False) -> set[int]:
1154
1178
  try:
1155
1179
  processes = os.scandir("/proc")
1156
1180
  except OSError:
1181
+ lsof = shutil.which("lsof")
1182
+ if lsof:
1183
+ try:
1184
+ result = subprocess.run(
1185
+ [lsof, "-t", "--", target],
1186
+ capture_output=True,
1187
+ text=True,
1188
+ encoding="utf-8",
1189
+ errors="replace",
1190
+ timeout=2,
1191
+ check=False,
1192
+ )
1193
+ writers = {int(value) for value in result.stdout.splitlines() if value.isdigit()}
1194
+ except (OSError, subprocess.SubprocessError, ValueError):
1195
+ pass
1157
1196
  rollout_writer_cache[target] = (stamp, writers)
1158
- return writers
1197
+ return set(writers)
1159
1198
  with processes:
1160
1199
  for process in processes:
1161
1200
  if not process.name.isdigit():
@@ -1826,7 +1865,7 @@ def ssh_config_aliases(path: Path = SSH_CONFIG, seen: Optional[set[Path]] = None
1826
1865
  return []
1827
1866
  for line in lines:
1828
1867
  try:
1829
- parts = shlex.split(line, comments=True, posix=True)
1868
+ parts = shlex.split(line, comments=True, posix=not IS_WINDOWS)
1830
1869
  except ValueError:
1831
1870
  continue
1832
1871
  if not parts:
@@ -1995,6 +2034,8 @@ exit 1
1995
2034
 
1996
2035
 
1997
2036
  def password_ssh_connect(host: str, password: str) -> tuple[bool, str]:
2037
+ if pexpect is None:
2038
+ return False, "SSH password authentication is unavailable on this platform"
1998
2039
  args = [
1999
2040
  *ssh_options(host, batch=False),
2000
2041
  "-o", "ConnectTimeout=10",
@@ -3613,7 +3654,7 @@ def appserver_turn_inputs(task: dict, message: str) -> list[dict[str, Any]]:
3613
3654
  continue
3614
3655
  seen.add((kind, path))
3615
3656
  if kind == "mention":
3616
- inputs.append({"type": "mention", "name": PurePosixPath(path).name, "path": path})
3657
+ inputs.append({"type": "mention", "name": Path(path).name, "path": path})
3617
3658
  else:
3618
3659
  item: dict[str, Any] = {"type": kind, "path": path}
3619
3660
  if kind == "localImage":
@@ -3867,6 +3908,13 @@ async def close_terminal_session(terminal_id: str) -> None:
3867
3908
  if not session:
3868
3909
  return
3869
3910
  session["closed"] = True
3911
+ windows_pty = session.get("windows_pty")
3912
+ if windows_pty is not None:
3913
+ try:
3914
+ await asyncio.to_thread(lambda: windows_pty.close(force=True))
3915
+ except Exception:
3916
+ pass
3917
+ return
3870
3918
  fd, pid = session.get("fd"), session.get("pid")
3871
3919
  loop = session.get("loop")
3872
3920
  if loop and fd is not None:
@@ -3905,6 +3953,81 @@ def set_terminal_size(fd: int, cols: int, rows: int) -> None:
3905
3953
  fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0))
3906
3954
 
3907
3955
 
3956
+ async def windows_terminal_socket(websocket: WebSocket, task_id: str, cwd: str, ssh_host: str) -> None:
3957
+ if WindowsPtyProcess is None:
3958
+ await websocket.send_json({"type": "error", "message": "Windows terminal support requires pywinpty"})
3959
+ await websocket.close(code=1011)
3960
+ return
3961
+ env = os.environ.copy()
3962
+ env.update({"TERM": "xterm-256color", "COLORTERM": "truecolor"})
3963
+ if ssh_host:
3964
+ remote_command = f"cd -- {shlex.quote(cwd)} && exec \"${{SHELL:-/bin/sh}}\" -il"
3965
+ command = [*ssh_options(ssh_host, batch=True, tty=True), ssh_destination(ssh_host), remote_command]
3966
+ shell_label = f"ssh:{ssh_host}"
3967
+ else:
3968
+ command, shell_label = local_shell_command()
3969
+ try:
3970
+ spawn_cwd = cwd if not ssh_host else str(DEFAULT_WORKSPACE)
3971
+ process = await asyncio.to_thread(WindowsPtyProcess.spawn, command, cwd=spawn_cwd, env=env)
3972
+ except Exception as exc:
3973
+ await websocket.send_json({"type": "error", "message": f"terminal start failed: {exc}"})
3974
+ await websocket.close(code=1011)
3975
+ return
3976
+
3977
+ terminal_id = str(uuid.uuid4())
3978
+ session = {"windows_pty": process, "task_id": task_id, "closed": False}
3979
+ terminal_sessions[terminal_id] = session
3980
+ await websocket.send_json({"type": "ready", "terminal_id": terminal_id, "cwd": cwd, "shell": shell_label})
3981
+
3982
+ async def pump_output() -> None:
3983
+ while not session["closed"]:
3984
+ try:
3985
+ data = await asyncio.to_thread(process.read, 65536)
3986
+ except (EOFError, OSError):
3987
+ data = ""
3988
+ if data:
3989
+ await websocket.send_json({"type": "output", "data": data})
3990
+ continue
3991
+ await websocket.send_json({"type": "exit", "code": getattr(process, "exitstatus", None)})
3992
+ return
3993
+
3994
+ async def receive_input() -> None:
3995
+ while True:
3996
+ incoming = await websocket.receive_json()
3997
+ kind = incoming.get("type")
3998
+ if kind == "input":
3999
+ value = incoming.get("data", incoming.get("input", ""))
4000
+ if isinstance(value, str) and value:
4001
+ await asyncio.to_thread(process.write, value)
4002
+ elif kind == "resize":
4003
+ try:
4004
+ cols = max(20, min(int(incoming.get("cols", 120)), 400))
4005
+ rows = max(4, min(int(incoming.get("rows", 32)), 160))
4006
+ await asyncio.to_thread(process.setwinsize, rows, cols)
4007
+ except (OSError, ValueError, TypeError):
4008
+ continue
4009
+ elif kind == "ping":
4010
+ await websocket.send_json({"type": "pong"})
4011
+ elif kind == "close":
4012
+ return
4013
+
4014
+ pump_task = asyncio.create_task(pump_output())
4015
+ receive_task = asyncio.create_task(receive_input())
4016
+ try:
4017
+ _done, pending = await asyncio.wait({pump_task, receive_task}, return_when=asyncio.FIRST_COMPLETED)
4018
+ for waiter in pending:
4019
+ waiter.cancel()
4020
+ await asyncio.gather(*pending, return_exceptions=True)
4021
+ except WebSocketDisconnect:
4022
+ pass
4023
+ finally:
4024
+ for waiter in (pump_task, receive_task):
4025
+ if not waiter.done():
4026
+ waiter.cancel()
4027
+ await asyncio.gather(pump_task, receive_task, return_exceptions=True)
4028
+ await close_terminal_session(terminal_id)
4029
+
4030
+
3908
4031
  @app.websocket("/ws/terminal/{task_id}")
3909
4032
  async def terminal_socket(websocket: WebSocket, task_id: str):
3910
4033
  if not websocket_auth_session(websocket):
@@ -3921,11 +4044,17 @@ async def terminal_socket(websocket: WebSocket, task_id: str):
3921
4044
  await websocket.close(code=4428, reason="SSH login required")
3922
4045
  return
3923
4046
  await websocket.accept()
3924
- terminal_id = str(uuid.uuid4())
3925
4047
  cwd = task["workspace"] if ssh_host else (task["workspace"] if Path(task["workspace"]).is_dir() else str(DEFAULT_WORKSPACE))
3926
- shell = f"ssh:{ssh_host}" if ssh_host else os.environ.get("SHELL", "/bin/bash")
3927
- if not ssh_host and not Path(shell).is_file():
3928
- shell = "/bin/bash"
4048
+ if IS_WINDOWS:
4049
+ await windows_terminal_socket(websocket, task_id, cwd, ssh_host)
4050
+ return
4051
+ terminal_id = str(uuid.uuid4())
4052
+ shell_command, local_shell = local_shell_command()
4053
+ shell = f"ssh:{ssh_host}" if ssh_host else local_shell
4054
+ if pty is None or fcntl is None or termios is None:
4055
+ await websocket.send_json({"type": "error", "message": "PTY support is unavailable on this platform"})
4056
+ await websocket.close(code=1011)
4057
+ return
3929
4058
  pid, fd = pty.fork()
3930
4059
  if pid == 0:
3931
4060
  try:
@@ -3937,7 +4066,7 @@ async def terminal_socket(websocket: WebSocket, task_id: str):
3937
4066
  os.execvpe(command[0], command, env)
3938
4067
  else:
3939
4068
  os.chdir(cwd)
3940
- os.execvpe(shell, [shell, "-i"], env)
4069
+ os.execvpe(shell_command[0], shell_command, env)
3941
4070
  except Exception as exc:
3942
4071
  os.write(2, f"terminal start failed: {exc}\n".encode())
3943
4072
  os._exit(127)
@@ -4473,7 +4602,7 @@ async def install_codex(force: bool = False, _: Any = Depends(auth)):
4473
4602
  env["PATH"] = os.pathsep.join((str(Path(npm).parent), str(extra_bin), env.get("PATH", "")))
4474
4603
  try:
4475
4604
  process = await asyncio.create_subprocess_exec(
4476
- *command,
4605
+ *prepare_subprocess_command(command),
4477
4606
  stdout=asyncio.subprocess.PIPE,
4478
4607
  stderr=asyncio.subprocess.STDOUT,
4479
4608
  env=env,
@@ -5655,6 +5784,8 @@ async def supervise(task: dict, session_id: str, providers: list[Optional[dict]]
5655
5784
  cwd = None
5656
5785
  env.pop("OPENAI_API_KEY", None)
5657
5786
  env.pop("OPENAI_BASE_URL", None)
5787
+ else:
5788
+ spawn_cmd = prepare_subprocess_command(spawn_cmd)
5658
5789
  process = await asyncio.create_subprocess_exec(*spawn_cmd, cwd=cwd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, env=env)
5659
5790
  async with running_lock:
5660
5791
  running[task_id] = process
@@ -6249,7 +6380,7 @@ def git_diff_summary(task: dict) -> str:
6249
6380
  sections = []
6250
6381
  for index, command in enumerate(commands):
6251
6382
  try:
6252
- completed = ssh_capture(task["ssh_host"], shlex.join(command), 12) if task.get("ssh_host") else subprocess.run(command, capture_output=True, text=True, timeout=8, check=False)
6383
+ completed = ssh_capture(task["ssh_host"], shlex.join(command), 12) if task.get("ssh_host") else subprocess.run(prepare_subprocess_command(command), capture_output=True, text=True, timeout=8, check=False)
6253
6384
  except (OSError, subprocess.TimeoutExpired) as exc:
6254
6385
  return f"无法读取 Git 变更:{exc}"
6255
6386
  output = (completed.stdout or completed.stderr).strip()
@@ -6805,6 +6936,8 @@ async def supervise_operation(task: dict, session_id: str, cmd: list[str]) -> No
6805
6936
  connection = await require_ssh_connection(task["ssh_host"], codex=True)
6806
6937
  spawn_cmd = [*ssh_options(task["ssh_host"], batch=True), ssh_destination(task["ssh_host"]), shlex.join([connection["codex_bin"], *cmd[1:]])]
6807
6938
  cwd = None
6939
+ else:
6940
+ spawn_cmd = prepare_subprocess_command(spawn_cmd)
6808
6941
  process = await asyncio.create_subprocess_exec(*spawn_cmd, cwd=cwd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, env=os.environ.copy())
6809
6942
  async with running_lock:
6810
6943
  running[task_id] = process
@@ -1,4 +1,4 @@
1
1
  """Codex Partner application package."""
2
2
 
3
3
  APP_NAME = "Codex Partner"
4
- APP_VERSION = "0.0.4"
4
+ APP_VERSION = "0.0.6"
@@ -132,7 +132,8 @@ def event_key(event: dict[str, Any]) -> str:
132
132
  for key in ("type", "turn_id", "turnId", "item_id", "id", "status", "phase")
133
133
  )
134
134
  body = payload.get("text") or payload.get("command") or payload.get("tool") or ""
135
- return f"live:{fingerprint(f'{event.get("ts", "")}:{identity}:{body}') }"
135
+ source = f"{event.get('ts', '')}:{identity}:{body}"
136
+ return f"live:{fingerprint(source)}"
136
137
 
137
138
 
138
139
  def semantic_event(event: dict[str, Any]) -> bool:
@@ -4,6 +4,8 @@ import asyncio
4
4
  import json
5
5
  from typing import Any, Awaitable, Callable, Optional
6
6
 
7
+ from .platform_support import prepare_subprocess_command
8
+
7
9
 
8
10
  NotificationHandler = Callable[[str, dict], Awaitable[None]]
9
11
 
@@ -55,8 +57,9 @@ class AppServerClient:
55
57
  await asyncio.wait_for(self.process.wait(), 1)
56
58
  except Exception:
57
59
  pass
60
+ command = prepare_subprocess_command(self.command)
58
61
  self.process = await asyncio.create_subprocess_exec(
59
- *self.command,
62
+ *command,
60
63
  stdin=asyncio.subprocess.PIPE,
61
64
  stdout=asyncio.subprocess.PIPE,
62
65
  stderr=asyncio.subprocess.DEVNULL,
@@ -2,6 +2,7 @@
2
2
 
3
3
  import sqlite3
4
4
  import threading
5
+ from contextlib import closing
5
6
  from pathlib import Path
6
7
  from typing import Callable, Optional
7
8
 
@@ -27,7 +28,7 @@ class Database:
27
28
  return connection
28
29
 
29
30
  def initialize(self) -> None:
30
- with self.lock, self.connect() as connection:
31
+ with self.lock, closing(self.connect()) as connection:
31
32
  connection.executescript(
32
33
  """
33
34
  CREATE TABLE IF NOT EXISTS tasks (
@@ -262,15 +263,15 @@ class Database:
262
263
  )
263
264
 
264
265
  def one(self, sql: str, args: tuple = ()) -> Optional[dict]:
265
- with self.lock, self.connect() as connection:
266
+ with self.lock, closing(self.connect()) as connection:
266
267
  row = connection.execute(sql, args).fetchone()
267
268
  return dict(row) if row else None
268
269
 
269
270
  def all(self, sql: str, args: tuple = ()) -> list[dict]:
270
- with self.lock, self.connect() as connection:
271
+ with self.lock, closing(self.connect()) as connection:
271
272
  return [dict(row) for row in connection.execute(sql, args).fetchall()]
272
273
 
273
274
  def execute(self, sql: str, args: tuple = ()) -> None:
274
- with self.lock, self.connect() as connection:
275
+ with self.lock, closing(self.connect()) as connection:
275
276
  connection.execute(sql, args)
276
277
  connection.commit()
@@ -8,6 +8,8 @@ import subprocess
8
8
  from pathlib import Path
9
9
  from typing import Callable, Optional
10
10
 
11
+ from .platform_support import prepare_subprocess_command
12
+
11
13
 
12
14
  def executable_works(candidate: str) -> bool:
13
15
  path = Path(candidate).expanduser()
@@ -15,7 +17,7 @@ def executable_works(candidate: str) -> bool:
15
17
  return False
16
18
  try:
17
19
  result = subprocess.run(
18
- [str(path), "--version"],
20
+ prepare_subprocess_command([str(path), "--version"]),
19
21
  stdin=subprocess.DEVNULL,
20
22
  stdout=subprocess.DEVNULL,
21
23
  stderr=subprocess.DEVNULL,
@@ -122,7 +124,7 @@ def install_plan(system: str, npm: str, package: str) -> dict:
122
124
  if not supported:
123
125
  reason = f"暂不支持在 {system} 上自动安装 Codex"
124
126
  elif not npm:
125
- reason = "未找到 npm;请先安装 Node.js LTS(Windows 建议在 WSL 中运行 Codex Partner),然后重试"
127
+ reason = "未找到 npm;请先安装 Node.js LTS,然后重试"
126
128
  else:
127
129
  reason = ""
128
130
  display = subprocess.list2cmdline(command) if os.name == "nt" else shlex.join(command)