painapple-code 1.1.2__tar.gz → 1.1.3__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 (515) hide show
  1. {painapple_code-1.1.2 → painapple_code-1.1.3}/CHANGELOG.md +8 -0
  2. {painapple_code-1.1.2/src/painapple_code.egg-info → painapple_code-1.1.3}/PKG-INFO +1 -1
  3. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/security.md +1 -1
  4. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/permissions-and-thinking.md +1 -1
  5. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/providers.md +1 -1
  6. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/_version.py +3 -3
  7. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/__init__.py +1 -0
  8. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/launch.py +14 -2
  9. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/transport.py +97 -0
  10. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/services/agent_session.py +17 -0
  11. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/dist/app.bundle.js +4 -2
  12. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/command-executor.js +17 -3
  13. {painapple_code-1.1.2 → painapple_code-1.1.3/src/painapple_code.egg-info}/PKG-INFO +1 -1
  14. painapple_code-1.1.3/src/painapple_code.egg-info/scm_version.json +8 -0
  15. painapple_code-1.1.2/src/painapple_code.egg-info/scm_version.json +0 -8
  16. {painapple_code-1.1.2 → painapple_code-1.1.3}/.devcontainer/devcontainer.json +0 -0
  17. {painapple_code-1.1.2 → painapple_code-1.1.3}/.dockerignore +0 -0
  18. {painapple_code-1.1.2 → painapple_code-1.1.3}/.gitignore +0 -0
  19. {painapple_code-1.1.2 → painapple_code-1.1.3}/CONTRIBUTING.md +0 -0
  20. {painapple_code-1.1.2 → painapple_code-1.1.3}/Dockerfile +0 -0
  21. {painapple_code-1.1.2 → painapple_code-1.1.3}/LICENSE +0 -0
  22. {painapple_code-1.1.2 → painapple_code-1.1.3}/MANIFEST.in +0 -0
  23. {painapple_code-1.1.2 → painapple_code-1.1.3}/README.dockerhub.md +0 -0
  24. {painapple_code-1.1.2 → painapple_code-1.1.3}/README.md +0 -0
  25. {painapple_code-1.1.2 → painapple_code-1.1.3}/SECURITY.md +0 -0
  26. {painapple_code-1.1.2 → painapple_code-1.1.3}/THIRD_PARTY_NOTICES.md +0 -0
  27. {painapple_code-1.1.2 → painapple_code-1.1.3}/build-frontend.sh +0 -0
  28. {painapple_code-1.1.2 → painapple_code-1.1.3}/docker-compose.yml +0 -0
  29. {painapple_code-1.1.2 → painapple_code-1.1.3}/docker-entrypoint.sh +0 -0
  30. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/annotate-editor.png +0 -0
  31. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/browser-widget.png +0 -0
  32. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/comments-stash.gif +0 -0
  33. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/cost-analytics.png +0 -0
  34. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/favicon.png +0 -0
  35. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/input-autocomplete.gif +0 -0
  36. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/logo.png +0 -0
  37. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/markdown-quick-edit.gif +0 -0
  38. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/overview.png +0 -0
  39. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/prompt-history.png +0 -0
  40. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/quick-switcher.gif +0 -0
  41. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/quick-switcher.png +0 -0
  42. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/settings-appearance.png +0 -0
  43. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/settings-claude.png +0 -0
  44. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/shadow-journal.png +0 -0
  45. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/snippets-picker.png +0 -0
  46. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/terminal.gif +0 -0
  47. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/turn-summary-bar-expanded.png +0 -0
  48. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/turn-summary-bar.png +0 -0
  49. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/welcome-screen.png +0 -0
  50. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/assets/zen-mode.png +0 -0
  51. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/changelog.md +0 -0
  52. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/features.md +0 -0
  53. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/first-run.md +0 -0
  54. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/install-devcontainer.md +0 -0
  55. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/install-docker.md +0 -0
  56. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/install-pip.md +0 -0
  57. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/getting-started/requirements.md +0 -0
  58. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/analytics-and-history.md +0 -0
  59. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/claude-artifacts.md +0 -0
  60. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/customization.md +0 -0
  61. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/files.md +0 -0
  62. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/git-and-diffs.md +0 -0
  63. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/images-and-annotation.md +0 -0
  64. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/input-and-commands.md +0 -0
  65. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/ipad-and-mobile.md +0 -0
  66. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/sessions.md +0 -0
  67. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/shadow-git.md +0 -0
  68. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/stash-and-discussions.md +0 -0
  69. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/terminal.md +0 -0
  70. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/welcome-screen.md +0 -0
  71. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/guides/zen-mode.md +0 -0
  72. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/index.md +0 -0
  73. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/api.md +0 -0
  74. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/commands.md +0 -0
  75. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/data-storage.md +0 -0
  76. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/keyboard-shortcuts.md +0 -0
  77. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/optional-helpers.md +0 -0
  78. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/profiles.md +0 -0
  79. {painapple_code-1.1.2 → painapple_code-1.1.3}/docs-site/reference/server-cli.md +0 -0
  80. {painapple_code-1.1.2 → painapple_code-1.1.3}/mkdocs.yml +0 -0
  81. {painapple_code-1.1.2 → painapple_code-1.1.3}/painapple-docker.sh +0 -0
  82. {painapple_code-1.1.2 → painapple_code-1.1.3}/pyproject.toml +0 -0
  83. {painapple_code-1.1.2 → painapple_code-1.1.3}/requirements-docs.txt +0 -0
  84. {painapple_code-1.1.2 → painapple_code-1.1.3}/requirements.txt +0 -0
  85. {painapple_code-1.1.2 → painapple_code-1.1.3}/setup.cfg +0 -0
  86. {painapple_code-1.1.2 → painapple_code-1.1.3}/setup.py +0 -0
  87. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/__init__.py +0 -0
  88. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/__main__.py +0 -0
  89. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/auth_middleware.py +0 -0
  90. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/__init__.py +0 -0
  91. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/__init__.py +0 -0
  92. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/claude_seed.py +0 -0
  93. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/config.py +0 -0
  94. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/container.py +0 -0
  95. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/launch.py +0 -0
  96. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/deploy/runtime.py +0 -0
  97. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/lifecycle_cmd.py +0 -0
  98. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/list_cmd.py +0 -0
  99. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/manage_cmd.py +0 -0
  100. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/netinfo.py +0 -0
  101. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/profiles.py +0 -0
  102. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/serve_args.py +0 -0
  103. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/serve_config.py +0 -0
  104. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/setup_cmd.py +0 -0
  105. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cli/ui.py +0 -0
  106. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/cost_analytics.py +0 -0
  107. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/data/models.defaults.yaml +0 -0
  108. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/data/models.yaml +0 -0
  109. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/data/presets.defaults.json +0 -0
  110. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/data/strings.yaml +0 -0
  111. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/helpers.py +0 -0
  112. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/paths.py +0 -0
  113. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/prompt_explorer.py +0 -0
  114. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/__init__.py +0 -0
  115. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/base.py +0 -0
  116. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/__init__.py +0 -0
  117. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/capabilities.py +0 -0
  118. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/errors.py +0 -0
  119. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/launch.py +0 -0
  120. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/summary.py +0 -0
  121. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude/translate.py +0 -0
  122. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude_sdk/__init__.py +0 -0
  123. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/claude_sdk/driver.py +0 -0
  124. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex/__init__.py +0 -0
  125. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex/capabilities.py +0 -0
  126. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex/errors.py +0 -0
  127. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex/translate.py +0 -0
  128. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/capabilities.py +0 -0
  129. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/summary.py +0 -0
  130. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/providers/codex_app_server/translate.py +0 -0
  131. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/__init__.py +0 -0
  132. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_agents.py +0 -0
  133. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_app.py +0 -0
  134. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_app_commit_sections.py +0 -0
  135. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_app_config.py +0 -0
  136. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_app_session_prefs.py +0 -0
  137. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_browser.py +0 -0
  138. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_commands.py +0 -0
  139. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_costs.py +0 -0
  140. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_drafts.py +0 -0
  141. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_exec.py +0 -0
  142. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_files.py +0 -0
  143. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_git.py +0 -0
  144. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_logs.py +0 -0
  145. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_plugins.py +0 -0
  146. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_project_config.py +0 -0
  147. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_prompts.py +0 -0
  148. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_providers.py +0 -0
  149. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_search.py +0 -0
  150. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_session_stash.py +0 -0
  151. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_session_welcome.py +0 -0
  152. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_sessions.py +0 -0
  153. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_shadow.py +0 -0
  154. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_shadow_db.py +0 -0
  155. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_shadow_files.py +0 -0
  156. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_shadow_search.py +0 -0
  157. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_skills.py +0 -0
  158. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_tasks.py +0 -0
  159. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_terminal.py +0 -0
  160. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_upload.py +0 -0
  161. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/api_viewer.py +0 -0
  162. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/dependencies.py +0 -0
  163. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/routes/ws_chat.py +0 -0
  164. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/server.py +0 -0
  165. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/server_logging.py +0 -0
  166. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/services/__init__.py +0 -0
  167. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/session_store.py +0 -0
  168. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/session_store_core.py +0 -0
  169. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_db.py +0 -0
  170. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_db_plans.py +0 -0
  171. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_db_queries.py +0 -0
  172. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_db_schema.py +0 -0
  173. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_git.py +0 -0
  174. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_git_frontmatter.py +0 -0
  175. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_git_sections.py +0 -0
  176. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_git_summary.py +0 -0
  177. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/shadow_parser.py +0 -0
  178. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/00-variables.css +0 -0
  179. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/01-base.css +0 -0
  180. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/02-tooltips.css +0 -0
  181. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/09-left-rail.css +0 -0
  182. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/10-header.css +0 -0
  183. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/11-connection-bar.css +0 -0
  184. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/20-messages.css +0 -0
  185. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/21-tool-blocks.css +0 -0
  186. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/22-edit-diff.css +0 -0
  187. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/23-thinking.css +0 -0
  188. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/24-background-tasks.css +0 -0
  189. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/25-context-block.css +0 -0
  190. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/26-session-setup.css +0 -0
  191. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/30-markdown.css +0 -0
  192. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/40-input.css +0 -0
  193. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/41-autocomplete.css +0 -0
  194. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/42-activity-strip.css +0 -0
  195. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/43-file-autocomplete.css +0 -0
  196. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/44-snippets-autocomplete.css +0 -0
  197. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/45-selection-bar.css +0 -0
  198. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/46-keyboard-bar.css +0 -0
  199. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/47-keyboard-longpress.css +0 -0
  200. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/47-token-profile.css +0 -0
  201. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/50-welcome.css +0 -0
  202. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/51-modals.css +0 -0
  203. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/52-utilities.css +0 -0
  204. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/53-image-upload.css +0 -0
  205. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/54-todo-list.css +0 -0
  206. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/55-file-upload.css +0 -0
  207. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/56-chat-navigator.css +0 -0
  208. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/56-permission-card.css +0 -0
  209. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/56-plan-approval.css +0 -0
  210. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/56-question-form.css +0 -0
  211. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/57-swipe-indicator.css +0 -0
  212. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/58-session-families.css +0 -0
  213. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/59-about.css +0 -0
  214. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/61-log-explorer.css +0 -0
  215. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/62-json-tree.css +0 -0
  216. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/62-skills-widget.css +0 -0
  217. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/63-commands-widget.css +0 -0
  218. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/63-plugins-widget.css +0 -0
  219. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/63-terminal.css +0 -0
  220. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/64-search-files-widget.css +0 -0
  221. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/65-snippets-widget.css +0 -0
  222. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/66-active-sessions.css +0 -0
  223. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/66-agents-widget.css +0 -0
  224. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/66-file-explorer-widget.css +0 -0
  225. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/66-git-panel.css +0 -0
  226. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/66-history-explorer.css +0 -0
  227. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/67-diff-viewer.css +0 -0
  228. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/67-editor-view.css +0 -0
  229. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/67-file-preview-widget.css +0 -0
  230. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-browser-widget.css +0 -0
  231. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-compare-wizard.css +0 -0
  232. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-csv-preview.css +0 -0
  233. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-diff-preview.css +0 -0
  234. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-helpers-install-widget.css +0 -0
  235. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-image-annotate.css +0 -0
  236. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-terminal-view.css +0 -0
  237. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/68-uploads-widget.css +0 -0
  238. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/69-cost-analytics.css +0 -0
  239. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/70-config-panel.css +0 -0
  240. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/70-excalidraw.css +0 -0
  241. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/70-prompt-explorer.css +0 -0
  242. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/71-chart.css +0 -0
  243. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/72-discussion-sidebar.css +0 -0
  244. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/74-debug-logs.css +0 -0
  245. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/80-open-dialog.css +0 -0
  246. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/80-quick-switcher.css +0 -0
  247. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/80-widget-system.css +0 -0
  248. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/81-quick-actions.css +0 -0
  249. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/82-context-popover.css +0 -0
  250. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/83-context-menu.css +0 -0
  251. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/85-lazy-loading.css +0 -0
  252. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/86-zen-mode.css +0 -0
  253. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/87-grid-switcher.css +0 -0
  254. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/css/login.css +0 -0
  255. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/feature-triage.html +0 -0
  256. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/apple-touch-icon.png +0 -0
  257. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/favicon-32.png +0 -0
  258. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/favicon.ico +0 -0
  259. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-128.png +0 -0
  260. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-144.png +0 -0
  261. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-152.png +0 -0
  262. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-180.png +0 -0
  263. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-192.png +0 -0
  264. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-384.png +0 -0
  265. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-512.png +0 -0
  266. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-72.png +0 -0
  267. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/icons/icon-96.png +0 -0
  268. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/action-delegate.js +0 -0
  269. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/activity-strip.js +0 -0
  270. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/context-menus.js +0 -0
  271. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/file-preview.js +0 -0
  272. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/init-ui.js +0 -0
  273. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/input-events.js +0 -0
  274. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/input-resize.js +0 -0
  275. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/message-actions.js +0 -0
  276. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/panels.js +0 -0
  277. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/rendering-delegators.js +0 -0
  278. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/server-loading.js +0 -0
  279. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/session-ops.js +0 -0
  280. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/session-switch.js +0 -0
  281. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/settings-helpers.js +0 -0
  282. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app/startup-welcome.js +0 -0
  283. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app-context.js +0 -0
  284. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/app.js +0 -0
  285. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/auth-fetch.js +0 -0
  286. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/background-tasks.js +0 -0
  287. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/boot.js +0 -0
  288. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/caret-position.js +0 -0
  289. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/chat-navigator.js +0 -0
  290. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/chat-search.js +0 -0
  291. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/command-store.js +0 -0
  292. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/components.js +0 -0
  293. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/config.js +0 -0
  294. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/context-menu.js +0 -0
  295. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/controllers/chat-controller.js +0 -0
  296. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/controllers/dialog-controller.js +0 -0
  297. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/controllers/tab-controller.js +0 -0
  298. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/controllers/thinking-controller.js +0 -0
  299. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/diff-utils.js +0 -0
  300. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/drafts-pill.js +0 -0
  301. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/editor-view.js +0 -0
  302. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/effort-settings.js +0 -0
  303. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/feature-triage.js +0 -0
  304. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/file-autocomplete.js +0 -0
  305. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/file-tabs.js +0 -0
  306. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/gestures.js +0 -0
  307. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/grid-switcher.js +0 -0
  308. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/input-handler.js +0 -0
  309. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/keyboard-bar.js +0 -0
  310. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/layout-switcher.js +0 -0
  311. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/linkify-utils.js +0 -0
  312. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/login.js +0 -0
  313. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/open-dialog.js +0 -0
  314. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/orphan-terminals.js +0 -0
  315. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/path-utils.js +0 -0
  316. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/perf-marks.js +0 -0
  317. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/permission-settings.js +0 -0
  318. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/pointer-input.js +0 -0
  319. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/json-tree-menu.js +0 -0
  320. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/json-tree-toolbar.js +0 -0
  321. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/json-tree.js +0 -0
  322. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-breadcrumb.js +0 -0
  323. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-edit.js +0 -0
  324. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-events.js +0 -0
  325. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-history.js +0 -0
  326. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-inline-edit.js +0 -0
  327. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-poll.js +0 -0
  328. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-render.js +0 -0
  329. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-search.js +0 -0
  330. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-state.js +0 -0
  331. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview/preview-utils.js +0 -0
  332. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/chart-plugin.js +0 -0
  333. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/csv-plugin.js +0 -0
  334. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/diff-plugin.js +0 -0
  335. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/excalidraw-plugin.js +0 -0
  336. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/html-plugin.js +0 -0
  337. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/image-plugin.js +0 -0
  338. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/index.js +0 -0
  339. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/json-plugin.js +0 -0
  340. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/jsonl-plugin.js +0 -0
  341. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/markdown-plugin.js +0 -0
  342. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/panzoom-plugin.js +0 -0
  343. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/preview-plugins/plugin-helpers.js +0 -0
  344. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/project-color-picker.js +0 -0
  345. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/project-colors.js +0 -0
  346. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/prompt-favorites.js +0 -0
  347. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-actions-menu.js +0 -0
  348. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-actions-registry.js +0 -0
  349. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/controller.js +0 -0
  350. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/fuzzy-scorer.js +0 -0
  351. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/index.js +0 -0
  352. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/base-provider.js +0 -0
  353. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/command-provider.js +0 -0
  354. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/file-provider.js +0 -0
  355. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/panel-provider.js +0 -0
  356. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/project-provider.js +0 -0
  357. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/read-files-provider.js +0 -0
  358. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/providers/skills-provider.js +0 -0
  359. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/registry.js +0 -0
  360. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/ui/item.js +0 -0
  361. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/quick-switcher/ui/picker.js +0 -0
  362. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/recent-opens.js +0 -0
  363. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/scroll-manager.js +0 -0
  364. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/scroll-state-machine.js +0 -0
  365. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/selection/action-bar.js +0 -0
  366. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/selection/index.js +0 -0
  367. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/selection/selection-handler.js +0 -0
  368. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/selection/state.js +0 -0
  369. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/agent-progress.js +0 -0
  370. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/handle-agent-message.js +0 -0
  371. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/handle-message.js +0 -0
  372. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/interactive.js +0 -0
  373. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/message-store.js +0 -0
  374. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/messages.js +0 -0
  375. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/persistence.js +0 -0
  376. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/restore.js +0 -0
  377. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session/sync.js +0 -0
  378. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session-container-pool.js +0 -0
  379. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session-setup-panel.js +0 -0
  380. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/session.js +0 -0
  381. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/shortcut-hints.js +0 -0
  382. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/shortcuts.js +0 -0
  383. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/skills-autocomplete.js +0 -0
  384. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/snippets-autocomplete.js +0 -0
  385. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/stash-refs-view.js +0 -0
  386. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/stash-ui.js +0 -0
  387. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/stash.js +0 -0
  388. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/status-bar.js +0 -0
  389. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/token-profile.js +0 -0
  390. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/tool-renderer-blocks.js +0 -0
  391. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/tool-renderer-thinking.js +0 -0
  392. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/tool-renderer.js +0 -0
  393. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/tooltips.js +0 -0
  394. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/upload-manager.js +0 -0
  395. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/utils.js +0 -0
  396. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/api.js +0 -0
  397. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/cards.js +0 -0
  398. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/context-menu.js +0 -0
  399. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/families.js +0 -0
  400. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/preview.js +0 -0
  401. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome/state.js +0 -0
  402. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/welcome.js +0 -0
  403. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/base-widget.js +0 -0
  404. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/device-manager.js +0 -0
  405. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/event-bus.js +0 -0
  406. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/icons.js +0 -0
  407. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/index.js +0 -0
  408. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/init.js +0 -0
  409. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/bottom-sheet.js +0 -0
  410. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/floating.js +0 -0
  411. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/index.js +0 -0
  412. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/modal.js +0 -0
  413. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/sidebar.js +0 -0
  414. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/tab.js +0 -0
  415. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/types/top-sheet.js +0 -0
  416. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widget-system/widget-manager.js +0 -0
  417. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/about-widget.js +0 -0
  418. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/active-sessions-widget.js +0 -0
  419. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/agents-widget.js +0 -0
  420. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/browser-widget.js +0 -0
  421. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/commands-widget.js +0 -0
  422. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/commit-sections.js +0 -0
  423. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/dir-autocomplete.js +0 -0
  424. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/gestures.js +0 -0
  425. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/models-tab.js +0 -0
  426. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/quick-actions-tab.js +0 -0
  427. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/shortcut-editor.js +0 -0
  428. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/state.js +0 -0
  429. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config/system-controls.js +0 -0
  430. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/config-widget.js +0 -0
  431. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/cost-analytics-widget.js +0 -0
  432. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/debug-widget.js +0 -0
  433. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/diff-viewer-widget.js +0 -0
  434. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/discussion-widget.js +0 -0
  435. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/file-explorer-widget.js +0 -0
  436. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/file-preview-widget.js +0 -0
  437. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/git-widget.js +0 -0
  438. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/helpers-install-widget.js +0 -0
  439. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/history-explorer-widget.js +0 -0
  440. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/image-annotate-widget.js +0 -0
  441. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/image-preview-widget.js +0 -0
  442. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/index.js +0 -0
  443. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/log-explorer-widget.js +0 -0
  444. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/plugins-widget.js +0 -0
  445. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/prompt-explorer-widget.js +0 -0
  446. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/search-files-widget.js +0 -0
  447. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/skills-widget.js +0 -0
  448. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/snippets-widget.js +0 -0
  449. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/sub-agents-widget.js +0 -0
  450. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/tasks-widget.js +0 -0
  451. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/connection.js +0 -0
  452. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/gestures.js +0 -0
  453. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/init.js +0 -0
  454. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/link-providers.js +0 -0
  455. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/osc52.js +0 -0
  456. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/render.js +0 -0
  457. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/size.js +0 -0
  458. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/state.js +0 -0
  459. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal/wrap-utils.js +0 -0
  460. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/terminal-widget.js +0 -0
  461. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/uploads-widget.js +0 -0
  462. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/js/widgets/zen-widget.js +0 -0
  463. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/login.html +0 -0
  464. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/manifest.json +0 -0
  465. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/sw.js +0 -0
  466. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/LICENSES.txt +0 -0
  467. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/README.md +0 -0
  468. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/codemirror.js +0 -0
  469. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/codemirror.js.LEGAL.txt +0 -0
  470. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/github-markdown-dark.min.css +0 -0
  471. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight-github-dark.min.css +0 -0
  472. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight-lang-dockerfile.min.js +0 -0
  473. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight-lang-nginx.min.js +0 -0
  474. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight-lang-properties.min.js +0 -0
  475. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight-lang-scala.min.js +0 -0
  476. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/highlight.min.js +0 -0
  477. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/marked.min.js +0 -0
  478. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/purify.min.js +0 -0
  479. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/xterm-addon-fit.js +0 -0
  480. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/xterm.css +0 -0
  481. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/vendor/xterm.js +0 -0
  482. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/static/web-client.html +0 -0
  483. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/subprocess_registry.py +0 -0
  484. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tls_cert.py +0 -0
  485. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/agents/shadow-git-helper.md +0 -0
  486. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/excalidraw-to-svg.js +0 -0
  487. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/install-helpers.sh +0 -0
  488. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/shadow-git +0 -0
  489. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/shadow-query +0 -0
  490. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/term-bin/pbcopy +0 -0
  491. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/tools/vegalite-to-svg.js +0 -0
  492. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/turn_query.py +0 -0
  493. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/turn_tracker.py +0 -0
  494. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/__init__.py +0 -0
  495. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/agent_cli.py +0 -0
  496. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/bash_file_ops.py +0 -0
  497. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/chart.py +0 -0
  498. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/excalidraw.py +0 -0
  499. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/file_lock.py +0 -0
  500. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/file_paths.py +0 -0
  501. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/generate_icons.py +0 -0
  502. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/proc.py +0 -0
  503. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/pty_backend.py +0 -0
  504. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/pty_posix.py +0 -0
  505. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/pty_windows.py +0 -0
  506. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/utils/token_profiles.py +0 -0
  507. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/viewer_templates.py +0 -0
  508. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code/welcome_search.py +0 -0
  509. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/SOURCES.txt +0 -0
  510. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/dependency_links.txt +0 -0
  511. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/entry_points.txt +0 -0
  512. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/requires.txt +0 -0
  513. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/scm_file_list.json +0 -0
  514. {painapple_code-1.1.2 → painapple_code-1.1.3}/src/painapple_code.egg-info/top_level.txt +0 -0
  515. {painapple_code-1.1.2 → painapple_code-1.1.3}/start.sh +0 -0
@@ -2,6 +2,14 @@
2
2
 
3
3
  Notable changes are documented here per release. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [SemVer](https://semver.org/), and the git tag is the single source of truth for the version (the PyPI wheel, the Docker image tag, and `__version__` all derive from it).
4
4
 
5
+ ## 1.1.3 — 2026-10-01
6
+
7
+ ### Fixed
8
+
9
+ - Codex sessions now ask for MCP tool approvals with the same in-chat permission card Claude sessions use — Allow / Deny, plus "always allow" for this session or for good. Previously Codex rejected every MCP tool call that needed approval (anything not marked read-only).
10
+ - Switching a Codex session's permission mode (e.g. to Full access, the equivalent of `codex --yolo`) now takes effect for the existing conversation; before, a resumed Codex thread kept the sandbox it was started with, even across server restarts.
11
+ - Failed `!` bang commands show the stderr explaining the failure instead of a bare "Exit code: N", and output written to both stdout and stderr is no longer cut down to stdout.
12
+
5
13
  ## 1.1.2 — 2026-09-30
6
14
 
7
15
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: painapple-code
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Self-hosted remote UI for Claude Code that journals every turn - background AI summaries become shadow-git commits and a queryable DuckDB history
5
5
  Author-email: Michał Booth-Wrotkowski <michal@boothw.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -21,7 +21,7 @@ The modes available on the default provider (set per session via the button next
21
21
  | **Auto** | `auto` | Claude's AI classifier gates each tool call |
22
22
  | **YOLO** | `bypassPermissions` | Full access |
23
23
 
24
- Three caveats. First, the approval cards only protect you while you're the one clicking them — in **YOLO** and **Auto** nothing asks, and those are the modes that give Claude the most freedom. Second, the cards exist only on the Claude provider: Codex enforces its own sandbox tiers instead. Third — and this is the point of this whole section — the boundary that actually holds is the one *below* the agent: the OS user, the container, the VM. A permission mode is the agent cooperating, not a sandbox. See the [permissions guide](../guides/permissions-and-thinking.md) for the full story.
24
+ Three caveats. First, the approval cards only protect you while you're the one clicking them — in **YOLO** and **Auto** nothing asks, and those are the modes that give Claude the most freedom. Second, on the Codex provider the cards cover only MCP tool calls (Codex asks before running an MCP tool that isn't marked read-only); everything else is governed by Codex's own sandbox tiers. Third — and this is the point of this whole section — the boundary that actually holds is the one *below* the agent: the OS user, the container, the VM. A permission mode is the agent cooperating, not a sandbox. See the [permissions guide](../guides/permissions-and-thinking.md) for the full story.
25
25
 
26
26
  ## Terminal
27
27
 
@@ -28,7 +28,7 @@ The **"always allow"** options on a card are the CLI's own "don't ask again" sug
28
28
  The default mode is **Ask** — reads run freely, but every edit and command waits for your approval on a card. Prefer **Accept Edits** to wave edits through and only get carded for commands, **YOLO** or **Auto** to let Claude just work, or **Don't Ask** to auto-deny anything your allow rules don't already cover. **Plan** stays read-only.
29
29
 
30
30
  !!! note "Other providers"
31
- Sessions can also run on OpenAI Codex — see [AI providers](providers.md) for picking one per session (or pinning a server-wide default with `--default-provider`). The same pass-through applies: Codex doesn't use these modes at all, so the button maps to the Codex CLI's own **sandbox tiers** (Read-only / Workspace write / Full access), enforced by Codex.
31
+ Sessions can also run on OpenAI Codex — see [AI providers](providers.md) for picking one per session (or pinning a server-wide default with `--default-provider`). The same pass-through applies: Codex doesn't use these modes at all, so the button maps to the Codex CLI's own **sandbox tiers** (Read-only / Workspace write / Full access), enforced by Codex. One thing still asks: before running an MCP tool that isn't marked read-only, Codex requests approval, and that shows up as the same in-chat card (with "always allow" for this session or for good). **Full access** behaves like `codex --yolo` and runs MCP tools without asking.
32
32
 
33
33
  !!! note "Auto mode is a research preview"
34
34
  Auto is the CLI's `--permission-mode auto`, where a classifier model on Claude Code's side gates each call. It needs a recent CLI and model (Sonnet 4.6+/Opus 4.6+ on the Anthropic API; Team/Enterprise plans need an org owner to enable it). Also, headless auto sessions abort after 3 consecutive classifier blocks (or 20 total) — if Claude keeps getting blocked, the turn ends rather than looping.
@@ -33,7 +33,7 @@ The **default provider** for new sessions is set with the **Make default** butto
33
33
  Each provider self-describes its capabilities, and the UI follows:
34
34
 
35
35
  - **Models** — the model picker shows the *active provider's* catalog. Claude's comes from the server's editable `models.yaml`; Codex's mirrors the Codex CLI's own model list (so it updates when Codex does). Per-provider default models are configured in Settings → Providers.
36
- - **Permission modes** — the Claude provider speaks Claude's modes (Plan / Ask / Don't Ask / Accept Edits / Auto / YOLO — see [Permission modes](permissions-and-thinking.md)); the Codex provider maps to Codex **sandbox tiers**: Read-only, Workspace write, and Full access.
36
+ - **Permission modes** — the Claude provider speaks Claude's modes (Plan / Ask / Don't Ask / Accept Edits / Auto / YOLO — see [Permission modes](permissions-and-thinking.md)); the Codex provider maps to Codex **sandbox tiers**: Read-only, Workspace write, and Full access. Codex's MCP tool approvals render as the same in-chat permission cards; Full access skips them, like `codex --yolo`.
37
37
  - **Effort** — the effort gauge renders each provider's own scale. Claude has five levels (low → max); Codex levels come from its model catalog and can reach `xhigh` / `ultra` on recent models, with the picker narrowing to what the selected model supports.
38
38
  - **Cost** — Codex reports tokens only, no dollar figure, so the `$` cost readouts hide on Codex sessions and the turn bar shows token counts.
39
39
  - **Continue in the CLI** — the **Continue in CLI** quick action is provider-aware: a Claude session gives you `claude -r <id>`, a Codex session `codex exec resume <id>`.
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.1.2'
22
- __version_tuple__ = version_tuple = (1, 1, 2)
21
+ __version__ = version = '1.1.3'
22
+ __version_tuple__ = version_tuple = (1, 1, 3)
23
23
 
24
- __commit_id__ = commit_id = 'g2fe4788'
24
+ __commit_id__ = commit_id = 'g0c414ec'
@@ -88,6 +88,7 @@ class CodexAppServerProvider(
88
88
  persistent_process=True, # one app-server process, many turns
89
89
  forward_plain_stderr=False, # app-server logs human progress to stderr
90
90
  transport="jsonrpc", # the session layer drives a transport driver
91
+ interactive_permissions=True, # MCP tool approvals → permission card
91
92
  )
92
93
 
93
94
  def make_transport(self, process, opts, session):
@@ -74,8 +74,20 @@ class _LaunchMixin:
74
74
  return params
75
75
 
76
76
  def thread_resume_params(self, opts: LaunchOptions, thread_id: str, cwd: str) -> dict:
77
- """Params for `thread/resume` (continue an existing thread by id)."""
78
- params: dict = {"threadId": thread_id, "cwd": cwd}
77
+ """Params for `thread/resume` (continue an existing thread by id).
78
+
79
+ Sandbox/approval MUST ride along: without them the app-server keeps the
80
+ thread's ORIGINAL sandbox from its rollout, so a mode change (which
81
+ respawns + resumes) never took effect — a thread started in
82
+ workspace-write still gated MCP tools after switching to
83
+ danger-full-access (codex --yolo), even across restarts.
84
+ """
85
+ params: dict = {
86
+ "threadId": thread_id,
87
+ "cwd": cwd,
88
+ "sandbox": _SANDBOX_BY_MODE.get(opts.permission_mode or "", _DEFAULT_SANDBOX),
89
+ "approvalPolicy": "never",
90
+ }
79
91
  model = self._wire_model(opts.model)
80
92
  if model:
81
93
  params["model"] = model
@@ -21,6 +21,7 @@ from __future__ import annotations
21
21
  import asyncio
22
22
  import json
23
23
  import logging
24
+ import re
24
25
 
25
26
  from painapple_code.session_store import SessionStore
26
27
 
@@ -44,6 +45,21 @@ _APPROVAL_DENY = {
44
45
  }
45
46
 
46
47
 
48
+ # MCP tool approvals. Codex asks before running an MCP tool that isn't
49
+ # annotated read-only — even under `approvalPolicy="never"`, which only governs
50
+ # shell/patch escalations — by sending an `mcpServer/elicitation/request` whose
51
+ # `_meta.codex_approval_kind` is "mcp_tool_call". An unanswered/errored request
52
+ # makes codex reject the call ("user rejected MCP tool call"), so these are
53
+ # round-tripped to the client's permission card instead. `_meta.persist` lists
54
+ # the remember-scopes codex will honour ("session", "always"); echoing one back
55
+ # in the accept response's `_meta.persist` stops it asking again.
56
+ _MCP_APPROVAL_KIND = "mcp_tool_call"
57
+ _MCP_TOOL_RE = re.compile(r'run tool "([^"]+)"')
58
+ # codex persist scope → the permission card's suggestion `destination`
59
+ # (reusing the addRules row shape the Claude card already renders/labels).
60
+ _PERSIST_DESTINATION = {"session": "session", "always": "userSettings"}
61
+
62
+
47
63
  def _client_version() -> str:
48
64
  try:
49
65
  from painapple_code import __version__
@@ -66,6 +82,12 @@ class JsonRpcTransport:
66
82
  self._thread_id = None # codex thread id (== session.session_id)
67
83
  self._active_turn_id = None # in-flight turn id (turn/interrupt needs it)
68
84
  self._send_lock = asyncio.Lock() # serialize handshake/thread/turn sends
85
+ # Set by the session layer: async callable(permission_request dict) that
86
+ # surfaces an approval card to the client. None → approvals are declined.
87
+ self.on_permission_request = None
88
+ # permission request_id → (JSON-RPC request id, [persist scope per
89
+ # suggestion index]) for approvals awaiting the user's decision.
90
+ self._pending_approvals: dict = {}
69
91
 
70
92
  # --- low-level JSON-RPC I/O ------------------------------------------
71
93
 
@@ -133,6 +155,13 @@ class JsonRpcTransport:
133
155
  self._active_turn_id = turn["id"]
134
156
  elif method == "turn/completed":
135
157
  self._active_turn_id = None
158
+ elif method == "serverRequest/resolved":
159
+ # Codex settled a request itself (turn interrupted / thread closed)
160
+ # — retire any approval card still waiting on it.
161
+ rid = (native.get("params") or {}).get("requestId")
162
+ request_id = f"codex-mcp-{rid}"
163
+ if request_id in self._pending_approvals:
164
+ asyncio.create_task(self._expire_approval(request_id))
136
165
  return True # notification → translate
137
166
 
138
167
  async def initialize(self) -> None:
@@ -226,6 +255,9 @@ class JsonRpcTransport:
226
255
  async def _answer_server_request(self, native: dict) -> None:
227
256
  method = native.get("method", "")
228
257
  rid = native.get("id")
258
+ if method == "mcpServer/elicitation/request":
259
+ await self._handle_elicitation(rid, native.get("params") or {})
260
+ return
229
261
  deny = _APPROVAL_DENY.get(method)
230
262
  if deny is not None:
231
263
  await self._write({"jsonrpc": "2.0", "id": rid, "result": deny})
@@ -236,3 +268,68 @@ class JsonRpcTransport:
236
268
  "jsonrpc": "2.0", "id": rid,
237
269
  "error": {"code": -32601, "message": f"{method} not handled"},
238
270
  })
271
+
272
+ # --- MCP tool approvals ------------------------------------------------
273
+
274
+ async def _handle_elicitation(self, rid, params: dict) -> None:
275
+ """Surface an MCP tool approval as a permission card.
276
+
277
+ Only codex's own tool-call approvals are routed to the user. A genuine
278
+ MCP-server elicitation (a form/URL the server wants filled in) has no
279
+ UI here yet, so it's declined — explicitly, so codex doesn't hang.
280
+ """
281
+ meta = params.get("_meta") or {}
282
+ if (meta.get("codex_approval_kind") != _MCP_APPROVAL_KIND
283
+ or self.on_permission_request is None):
284
+ logger.info(f"codex elicitation from {params.get('serverName')!r} "
285
+ f"declined (kind={meta.get('codex_approval_kind')!r})")
286
+ await self._write({"jsonrpc": "2.0", "id": rid,
287
+ "result": {"action": "decline", "content": None}})
288
+ return
289
+
290
+ server = params.get("serverName") or "mcp"
291
+ message = params.get("message") or ""
292
+ m = _MCP_TOOL_RE.search(message)
293
+ tool_name = f"mcp__{server}__{m.group(1)}" if m else f"mcp__{server}"
294
+ persist = [p for p in (meta.get("persist") or []) if p in _PERSIST_DESTINATION]
295
+ request_id = f"codex-mcp-{rid}"
296
+ self._pending_approvals[request_id] = (rid, persist)
297
+ tool_input = meta.get("tool_params")
298
+ await self.on_permission_request({
299
+ "type": "permission_request",
300
+ "request_id": request_id,
301
+ "tool_name": tool_name,
302
+ "input": tool_input if isinstance(tool_input, dict) else {},
303
+ "description": message or None,
304
+ "suggestions": [
305
+ {"type": "addRules", "rules": [{"tool_name": tool_name}],
306
+ "destination": _PERSIST_DESTINATION[p]}
307
+ for p in persist
308
+ ],
309
+ })
310
+
311
+ async def _expire_approval(self, request_id: str) -> None:
312
+ self._pending_approvals.pop(request_id, None)
313
+ self.session._pending_permission_requests.pop(request_id, None)
314
+ # ok=False → the client marks the card expired (same as a dead process).
315
+ await self.session.safe_send({"type": "permission_resolved",
316
+ "request_id": request_id, "ok": False})
317
+
318
+ def owns_permission(self, request_id) -> bool:
319
+ return request_id in self._pending_approvals
320
+
321
+ async def respond_permission(self, request_id: str, data: dict) -> bool:
322
+ """Answer a pending MCP approval with the user's decision."""
323
+ entry = self._pending_approvals.pop(request_id, None)
324
+ if entry is None:
325
+ return False
326
+ rid, persist = entry
327
+ if data.get("behavior") == "allow":
328
+ result: dict = {"action": "accept", "content": None}
329
+ idx = data.get("suggestion_index")
330
+ if isinstance(idx, int) and 0 <= idx < len(persist):
331
+ result["_meta"] = {"persist": persist[idx]}
332
+ else:
333
+ result = {"action": "decline", "content": None}
334
+ await self._write({"jsonrpc": "2.0", "id": rid, "result": result})
335
+ return True
@@ -866,6 +866,11 @@ class AgentManager:
866
866
  session.process, launch_opts, session
867
867
  )
868
868
  if session._transport is not None:
869
+ if hasattr(session._transport, "on_permission_request"):
870
+ # Transport-native approvals (Codex MCP tool calls)
871
+ # ride the same permission-card flow as claude-sdk.
872
+ session._transport.on_permission_request = (
873
+ lambda msg, _s=session: self._handle_permission_request(_s, msg))
869
874
  await session._transport.initialize()
870
875
 
871
876
  return True
@@ -2486,6 +2491,18 @@ class AgentManager:
2486
2491
  return False
2487
2492
  if not session.process or not session.is_running:
2488
2493
  return False
2494
+ transport = session._transport
2495
+ if transport is not None and getattr(transport, "owns_permission", lambda _r: False)(request_id):
2496
+ # JSON-RPC transport answers its own server request (Codex MCP
2497
+ # approval) — nothing goes to stdin as a line frame.
2498
+ try:
2499
+ ok = await transport.respond_permission(request_id, data)
2500
+ except Exception as e:
2501
+ logger.error(f"Error sending transport permission response: {e}")
2502
+ return False
2503
+ session._pending_permission_requests.pop(request_id, None)
2504
+ session.touch()
2505
+ return ok
2489
2506
  request = session._pending_permission_requests[request_id]
2490
2507
  frame = {
2491
2508
  "type": "permission_response",
@@ -7032,8 +7032,10 @@ ${m?`<div class="${b}">${w}</div>`:'<div class="tool-output" style="color: var(-
7032
7032
  </svg>
7033
7033
  </span>
7034
7034
  </div>
7035
- `}renderTabs(){let e=this.getAllTabs().map(s=>s.data?s.type==="session"?this._renderSessionTab(s.data):this._renderWidgetTab(s.data):"").join("");this._saveTabOrder(),this.els.tabs.innerHTML=e,this._installTabDelegation(),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.updateOverflowIndicator(),this.scrollActiveTabIntoView()})})}_installTabDelegation(){if(this._tabDelegationInstalled)return;this._tabDelegationInstalled=!0;let e=this.els.tabs,s=document.querySelector(".header-overview-btn");s&&s.addEventListener("click",m=>{m.stopPropagation(),this.toggleTabsOverview(s)});let i=this.els.tabsViewport||e.parentElement;i?.querySelector(".tabs-overflow-left")?.addEventListener("click",m=>{m.stopPropagation(),e.scrollBy({left:-e.clientWidth*.8,behavior:"smooth"})}),i?.querySelector(".tabs-overflow-right")?.addEventListener("click",m=>{m.stopPropagation(),e.scrollBy({left:e.clientWidth*.8,behavior:"smooth"})}),e.addEventListener("click",m=>{if(this._suppressClickUntil){let k=Date.now()<this._suppressClickUntil;if(this._suppressClickUntil=0,k){m.stopPropagation();return}}let v=m.target.closest(".tab");if(!v)return;let w=v.dataset.type,b=v.dataset.id,_=m.target.closest(".tab-pin-btn");if(_){m.stopPropagation(),this.toggleTabPin(_.dataset.unpinKind,_.dataset.unpin,!1);return}if(m.target.closest(".close-btn")){let k=m.target.closest(".close-btn").dataset.close;if(w==="session"){let $=this.sessionManager.get(k);$&&this.ctx._app.closeSession($)}else w==="widget"&&this.closeWidgetTab(k)}else if(w==="session"){let k=this.sessionManager.get(b);k&&this.switchToSession(k)}else w==="widget"&&this.switchToWidgetTab(b)}),this._installMouseDrag(e);let n=null,o=null,a=null,r=!1,c=!1,d=0,p=l(()=>{o&&(document.removeEventListener("click",o,{capture:!0}),o=null)},"removeClickBlocker"),h=l(()=>{o=l(m=>{m.preventDefault(),m.stopPropagation(),m.stopImmediatePropagation(),p()},"clickBlocker"),document.addEventListener("click",o,{capture:!0,once:!0})},"installClickBlocker"),f=l(()=>{n&&(clearTimeout(n),n=null),a?.classList.remove("dragging"),a=null,r=!1,c=!1},"resetTouchDrag");e.addEventListener("touchstart",m=>{let v=m.target.closest(".tab");v&&(p(),a=v,r=!1,c=!1,d=m.touches[0].clientX,n=setTimeout(()=>{n=null,r=!0,v.classList.add("dragging")},400))},{passive:!0}),e.addEventListener("touchmove",m=>{if(r&&a){m.preventDefault(),c=!0,this._dragReposition(e,a,m.touches[0].clientX);return}n&&(clearTimeout(n),n=null)},{passive:!1}),e.addEventListener("touchend",m=>{let v=a,w=r,b=c;if(f(),!(!v||!w))if(m.preventDefault(),m.stopPropagation(),h(),setTimeout(p,400),b)this.applyDomOrder();else{let _=v.getBoundingClientRect(),k=this.ctx._app.buildTabContextMenu(v);k.length>0&&this.ctx._app.contextMenu.show(d,_.bottom+4,k)}},{passive:!1}),e.addEventListener("touchcancel",()=>{f()},{passive:!0}),e.addEventListener("scroll",()=>{this.updateOverflowIndicator()})}_installMouseDrag(e){let s=null,i=!1,n=0,o=0,a=l(c=>{if(s){if(!i){if(Math.abs(c.clientX-n)<6&&Math.abs(c.clientY-o)<6)return;i=!0,s.classList.add("dragging"),e.classList.add("tabs-drag-active")}this._dragReposition(e,s,c.clientX)}},"onMove"),r=l(()=>{document.removeEventListener("pointermove",a),document.removeEventListener("pointerup",r),document.removeEventListener("pointercancel",r),i&&s&&(s.classList.remove("dragging"),e.classList.remove("tabs-drag-active"),this._suppressClickUntil=Date.now()+150,this.applyDomOrder()),s=null,i=!1},"onUp");e.addEventListener("pointerdown",c=>{if(c.pointerType==="touch"||c.button!==0)return;let d=c.target.closest(".tab");!d||c.target.closest(".close-btn")||(s=d,i=!1,n=c.clientX,o=c.clientY,document.addEventListener("pointermove",a),document.addEventListener("pointerup",r),document.addEventListener("pointercancel",r))})}updateOverflowIndicator(){let e=this.els.tabs;if(!e)return;let s=this.els.tabsViewport||e.parentElement,i=s?.querySelector(".tabs-overflow-left"),n=s?.querySelector(".tabs-overflow-right");if(!i&&!n)return;let o=e.querySelectorAll(".tab"),a=e.scrollWidth-e.clientWidth>1;if(o.length===0||!a){i&&(i.style.display="none"),n&&(n.style.display="none");return}let r=e.getBoundingClientRect(),c=0,d=0;o.forEach(p=>{let h=p.getBoundingClientRect();h.right<r.left+20&&c++,h.left>r.right-20&&d++}),i&&(c>0?(i.textContent=`+${c}`,i.style.display="flex"):i.style.display="none"),n&&(d>0?(n.textContent=`+${d}`,n.style.display="flex"):n.style.display="none")}closeActiveTab(){this.activeMode==="widget"&&this.activeWidgetTabId&&this.closeWidgetTab(this.activeWidgetTabId)}};G();V();yl();var cu=class{static{l(this,"CommandExecutor")}constructor(e){this.ctx=e}get app(){return this.ctx._app}get activeSession(){return this.ctx.session}handleSlashCommand(e){let s=e.split(" "),i=s[0],n=s.slice(1).join(" "),o=ji.find(p=>p.cmd===i);if(o&&this.app[o.action]){o.hasArgs?this.app[o.action](n):this.app[o.action]();return}let a=Ri(),r=this.activeSession?.cwd||this.app.cwd||null,c=a.getCommand(i,r);if(c){this.executeCustomCommand(c,n);return}this.app.autocomplete?.agentCommands?.find(p=>p.cmd===i)||i.startsWith("/")?this.app.sendMessage(e):this.activeSession?.addSystemLog(`Unknown command: ${e}`)}async executeCustomCommand(e,s){let i=Ri(),n={input:s,cwd:this.activeSession?.cwd||this.app.cwd||"",session:this.activeSession?.id||""};if(e.type===ze.PROMPT){let o=i.expandVariables(e.prompt,n);this.app.sendMessage(o)}else if(e.type===ze.SHELL){let o=i.expandVariables(e.shell,n);await this.executeShellCommand(o)}}async executeShellCommand(e,s={}){let{saveToRecent:i=!1,toolType:n="shell"}=s;if(!e.trim()||!this.activeSession)return;let o=this.activeSession.cwd||".";if(i){let r=ue.get("recent-shell",[]).filter(c=>c!==e);r.unshift(e),ue.set("recent-shell",r.slice(0,10))}try{let a=await fetch(`${S.API_BASE}/api/exec`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({command:e,cwd:o})}),r=await a.json();if(!a.ok){this.activeSession.addSystemLog(`Error: ${r.detail}`,"error");return}let c=(r.stdout||r.stderr||"(no output)").trim();if(this.activeSession.addMessage({role:"tool",toolType:n,toolName:"Shell",toolInput:{command:e},toolOutput:c.slice(0,3e3)+(c.length>3e3?`
7036
- ...(truncated)`:""),toolError:r.exit_code!==0?`Exit code: ${r.exit_code}`:null}),this.activeSession.pendingBangOutputs||(this.activeSession.pendingBangOutputs=[]),this.activeSession.pendingBangOutputs.push({command:e,output:c.slice(0,3e3),exitCode:r.exit_code}),n==="bang"){let d=this.activeSession.pendingBangOutputs.length,p=this.app.els?.messageInput;p&&(p.placeholder=`${d} command${d>1?"s":""} buffered. Type message and press Enter...`)}}catch(a){console.error("Shell execution error:",a),this.activeSession.addSystemLog(`Failed to execute: ${a.message}`,"error")}}async handleBangCommand(e){let s=e.slice(1).trim();s&&this.activeSession&&await this.executeShellCommand(s,{saveToRecent:!0,toolType:"bang"})}};N();G();V();$e();var dm=class{static{l(this,"OrphanTerminalsManager")}constructor(){this.btn=null,this.badge=null,this.dropdown=null,this.list=null,this.bulkActions=null,this.orphans=[],this.isOpen=!1}init(){this.btn=document.getElementById("orphan-terminals-btn"),this.badge=document.getElementById("orphan-badge"),this.dropdown=document.getElementById("orphan-dropdown"),this.list=document.getElementById("orphan-list"),this.bulkActions=document.getElementById("orphan-bulk-actions");let e=document.getElementById("orphan-refresh-btn"),s=document.getElementById("orphan-tab-all-btn"),i=document.getElementById("orphan-kill-all-btn");if(!this.btn||!this.dropdown){console.warn("Orphan terminals UI elements not found");return}this.btn.addEventListener("click",n=>{n.target.closest(".orphan-terminals-dropdown")||this.toggle()}),e&&e.addEventListener("click",n=>{n.stopPropagation(),this.refresh()}),s&&s.addEventListener("click",n=>{n.stopPropagation(),this.tabAll()}),i&&i.addEventListener("click",n=>{n.stopPropagation(),this.killAll()}),document.addEventListener("click",n=>{this.isOpen&&!this.btn.contains(n.target)&&this.close()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&this.isOpen&&this.close()}),this.refresh(),setInterval(()=>this.refreshBadge(),3e4)}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.dropdown.classList.add("visible"),this.refresh()}close(){this.isOpen=!1,this.dropdown.classList.remove("visible")}async refresh(){try{let e=await this.fetchOrphans();this.orphans=e,this.updateBadge(),this.renderList()}catch(e){console.error("Failed to fetch orphaned terminals:",e),this.list.innerHTML=`<div class="orphan-dropdown-empty">${u.orphan_terminals.failed_load}</div>`}}async refreshBadge(){try{let e=await this.fetchOrphans();this.orphans=e,this.updateBadge()}catch{}}async fetchOrphans(){let e=await fetch(`${S.API_BASE}/api/terminals`);if(!e.ok)throw new Error(`HTTP ${e.status}`);let i=(await e.json()).terminals||[],n=this.getConnectedSessionIds();return i.filter(o=>!n.has(o.session))}getConnectedSessionIds(){let e=new Set,s=Ae.getTabIds();for(let i of s){let n=Ae.getTabState(i);n?.sessionId&&e.add(n.sessionId)}return e}updateBadge(){let e=this.orphans.filter(s=>s.alive).length;this.badge&&(this.badge.textContent=e>0?e:"",this.badge.dataset.count=e),this.bulkActions&&(this.bulkActions.style.display=this.orphans.length>0?"flex":"none")}renderList(){if(this.list){if(this.orphans.length===0){this.list.innerHTML=`<div class="orphan-dropdown-empty">${u.orphan_terminals.empty}</div>`;return}this.list.innerHTML=this.orphans.map(e=>`
7035
+ `}renderTabs(){let e=this.getAllTabs().map(s=>s.data?s.type==="session"?this._renderSessionTab(s.data):this._renderWidgetTab(s.data):"").join("");this._saveTabOrder(),this.els.tabs.innerHTML=e,this._installTabDelegation(),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.updateOverflowIndicator(),this.scrollActiveTabIntoView()})})}_installTabDelegation(){if(this._tabDelegationInstalled)return;this._tabDelegationInstalled=!0;let e=this.els.tabs,s=document.querySelector(".header-overview-btn");s&&s.addEventListener("click",m=>{m.stopPropagation(),this.toggleTabsOverview(s)});let i=this.els.tabsViewport||e.parentElement;i?.querySelector(".tabs-overflow-left")?.addEventListener("click",m=>{m.stopPropagation(),e.scrollBy({left:-e.clientWidth*.8,behavior:"smooth"})}),i?.querySelector(".tabs-overflow-right")?.addEventListener("click",m=>{m.stopPropagation(),e.scrollBy({left:e.clientWidth*.8,behavior:"smooth"})}),e.addEventListener("click",m=>{if(this._suppressClickUntil){let k=Date.now()<this._suppressClickUntil;if(this._suppressClickUntil=0,k){m.stopPropagation();return}}let v=m.target.closest(".tab");if(!v)return;let w=v.dataset.type,b=v.dataset.id,_=m.target.closest(".tab-pin-btn");if(_){m.stopPropagation(),this.toggleTabPin(_.dataset.unpinKind,_.dataset.unpin,!1);return}if(m.target.closest(".close-btn")){let k=m.target.closest(".close-btn").dataset.close;if(w==="session"){let $=this.sessionManager.get(k);$&&this.ctx._app.closeSession($)}else w==="widget"&&this.closeWidgetTab(k)}else if(w==="session"){let k=this.sessionManager.get(b);k&&this.switchToSession(k)}else w==="widget"&&this.switchToWidgetTab(b)}),this._installMouseDrag(e);let n=null,o=null,a=null,r=!1,c=!1,d=0,p=l(()=>{o&&(document.removeEventListener("click",o,{capture:!0}),o=null)},"removeClickBlocker"),h=l(()=>{o=l(m=>{m.preventDefault(),m.stopPropagation(),m.stopImmediatePropagation(),p()},"clickBlocker"),document.addEventListener("click",o,{capture:!0,once:!0})},"installClickBlocker"),f=l(()=>{n&&(clearTimeout(n),n=null),a?.classList.remove("dragging"),a=null,r=!1,c=!1},"resetTouchDrag");e.addEventListener("touchstart",m=>{let v=m.target.closest(".tab");v&&(p(),a=v,r=!1,c=!1,d=m.touches[0].clientX,n=setTimeout(()=>{n=null,r=!0,v.classList.add("dragging")},400))},{passive:!0}),e.addEventListener("touchmove",m=>{if(r&&a){m.preventDefault(),c=!0,this._dragReposition(e,a,m.touches[0].clientX);return}n&&(clearTimeout(n),n=null)},{passive:!1}),e.addEventListener("touchend",m=>{let v=a,w=r,b=c;if(f(),!(!v||!w))if(m.preventDefault(),m.stopPropagation(),h(),setTimeout(p,400),b)this.applyDomOrder();else{let _=v.getBoundingClientRect(),k=this.ctx._app.buildTabContextMenu(v);k.length>0&&this.ctx._app.contextMenu.show(d,_.bottom+4,k)}},{passive:!1}),e.addEventListener("touchcancel",()=>{f()},{passive:!0}),e.addEventListener("scroll",()=>{this.updateOverflowIndicator()})}_installMouseDrag(e){let s=null,i=!1,n=0,o=0,a=l(c=>{if(s){if(!i){if(Math.abs(c.clientX-n)<6&&Math.abs(c.clientY-o)<6)return;i=!0,s.classList.add("dragging"),e.classList.add("tabs-drag-active")}this._dragReposition(e,s,c.clientX)}},"onMove"),r=l(()=>{document.removeEventListener("pointermove",a),document.removeEventListener("pointerup",r),document.removeEventListener("pointercancel",r),i&&s&&(s.classList.remove("dragging"),e.classList.remove("tabs-drag-active"),this._suppressClickUntil=Date.now()+150,this.applyDomOrder()),s=null,i=!1},"onUp");e.addEventListener("pointerdown",c=>{if(c.pointerType==="touch"||c.button!==0)return;let d=c.target.closest(".tab");!d||c.target.closest(".close-btn")||(s=d,i=!1,n=c.clientX,o=c.clientY,document.addEventListener("pointermove",a),document.addEventListener("pointerup",r),document.addEventListener("pointercancel",r))})}updateOverflowIndicator(){let e=this.els.tabs;if(!e)return;let s=this.els.tabsViewport||e.parentElement,i=s?.querySelector(".tabs-overflow-left"),n=s?.querySelector(".tabs-overflow-right");if(!i&&!n)return;let o=e.querySelectorAll(".tab"),a=e.scrollWidth-e.clientWidth>1;if(o.length===0||!a){i&&(i.style.display="none"),n&&(n.style.display="none");return}let r=e.getBoundingClientRect(),c=0,d=0;o.forEach(p=>{let h=p.getBoundingClientRect();h.right<r.left+20&&c++,h.left>r.right-20&&d++}),i&&(c>0?(i.textContent=`+${c}`,i.style.display="flex"):i.style.display="none"),n&&(d>0?(n.textContent=`+${d}`,n.style.display="flex"):n.style.display="none")}closeActiveTab(){this.activeMode==="widget"&&this.activeWidgetTabId&&this.closeWidgetTab(this.activeWidgetTabId)}};G();V();yl();var cu=class{static{l(this,"CommandExecutor")}constructor(e){this.ctx=e}get app(){return this.ctx._app}get activeSession(){return this.ctx.session}handleSlashCommand(e){let s=e.split(" "),i=s[0],n=s.slice(1).join(" "),o=ji.find(p=>p.cmd===i);if(o&&this.app[o.action]){o.hasArgs?this.app[o.action](n):this.app[o.action]();return}let a=Ri(),r=this.activeSession?.cwd||this.app.cwd||null,c=a.getCommand(i,r);if(c){this.executeCustomCommand(c,n);return}this.app.autocomplete?.agentCommands?.find(p=>p.cmd===i)||i.startsWith("/")?this.app.sendMessage(e):this.activeSession?.addSystemLog(`Unknown command: ${e}`)}async executeCustomCommand(e,s){let i=Ri(),n={input:s,cwd:this.activeSession?.cwd||this.app.cwd||"",session:this.activeSession?.id||""};if(e.type===ze.PROMPT){let o=i.expandVariables(e.prompt,n);this.app.sendMessage(o)}else if(e.type===ze.SHELL){let o=i.expandVariables(e.shell,n);await this.executeShellCommand(o)}}async executeShellCommand(e,s={}){let{saveToRecent:i=!1,toolType:n="shell"}=s;if(!e.trim()||!this.activeSession)return;let o=this.activeSession.cwd||".";if(i){let r=ue.get("recent-shell",[]).filter(c=>c!==e);r.unshift(e),ue.set("recent-shell",r.slice(0,10))}try{let a=await fetch(`${S.API_BASE}/api/exec`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({command:e,cwd:o})}),r=await a.json();if(!a.ok){this.activeSession.addSystemLog(`Error: ${r.detail}`,"error");return}let c=[r.stdout,r.stderr].map(f=>(f||"").replace(/\s+$/,"")).filter(Boolean).join(`
7036
+ `),d=c||"(no output)",p=d.slice(0,3e3)+(d.length>3e3?`
7037
+ ...(truncated)`:""),h=r.exit_code!==0;if(this.activeSession.addMessage({role:"tool",toolType:n,toolName:"Shell",toolInput:{command:e},toolOutput:p,toolError:h?`${c?p+`
7038
+ `:""}Exit code: ${r.exit_code}`:null}),this.activeSession.pendingBangOutputs||(this.activeSession.pendingBangOutputs=[]),this.activeSession.pendingBangOutputs.push({command:e,output:d.slice(0,3e3),exitCode:r.exit_code}),n==="bang"){let f=this.activeSession.pendingBangOutputs.length,m=this.app.els?.messageInput;m&&(m.placeholder=`${f} command${f>1?"s":""} buffered. Type message and press Enter...`)}}catch(a){console.error("Shell execution error:",a),this.activeSession.addSystemLog(`Failed to execute: ${a.message}`,"error")}}async handleBangCommand(e){let s=e.slice(1).trim();s&&this.activeSession&&await this.executeShellCommand(s,{saveToRecent:!0,toolType:"bang"})}};N();G();V();$e();var dm=class{static{l(this,"OrphanTerminalsManager")}constructor(){this.btn=null,this.badge=null,this.dropdown=null,this.list=null,this.bulkActions=null,this.orphans=[],this.isOpen=!1}init(){this.btn=document.getElementById("orphan-terminals-btn"),this.badge=document.getElementById("orphan-badge"),this.dropdown=document.getElementById("orphan-dropdown"),this.list=document.getElementById("orphan-list"),this.bulkActions=document.getElementById("orphan-bulk-actions");let e=document.getElementById("orphan-refresh-btn"),s=document.getElementById("orphan-tab-all-btn"),i=document.getElementById("orphan-kill-all-btn");if(!this.btn||!this.dropdown){console.warn("Orphan terminals UI elements not found");return}this.btn.addEventListener("click",n=>{n.target.closest(".orphan-terminals-dropdown")||this.toggle()}),e&&e.addEventListener("click",n=>{n.stopPropagation(),this.refresh()}),s&&s.addEventListener("click",n=>{n.stopPropagation(),this.tabAll()}),i&&i.addEventListener("click",n=>{n.stopPropagation(),this.killAll()}),document.addEventListener("click",n=>{this.isOpen&&!this.btn.contains(n.target)&&this.close()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&this.isOpen&&this.close()}),this.refresh(),setInterval(()=>this.refreshBadge(),3e4)}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.dropdown.classList.add("visible"),this.refresh()}close(){this.isOpen=!1,this.dropdown.classList.remove("visible")}async refresh(){try{let e=await this.fetchOrphans();this.orphans=e,this.updateBadge(),this.renderList()}catch(e){console.error("Failed to fetch orphaned terminals:",e),this.list.innerHTML=`<div class="orphan-dropdown-empty">${u.orphan_terminals.failed_load}</div>`}}async refreshBadge(){try{let e=await this.fetchOrphans();this.orphans=e,this.updateBadge()}catch{}}async fetchOrphans(){let e=await fetch(`${S.API_BASE}/api/terminals`);if(!e.ok)throw new Error(`HTTP ${e.status}`);let i=(await e.json()).terminals||[],n=this.getConnectedSessionIds();return i.filter(o=>!n.has(o.session))}getConnectedSessionIds(){let e=new Set,s=Ae.getTabIds();for(let i of s){let n=Ae.getTabState(i);n?.sessionId&&e.add(n.sessionId)}return e}updateBadge(){let e=this.orphans.filter(s=>s.alive).length;this.badge&&(this.badge.textContent=e>0?e:"",this.badge.dataset.count=e),this.bulkActions&&(this.bulkActions.style.display=this.orphans.length>0?"flex":"none")}renderList(){if(this.list){if(this.orphans.length===0){this.list.innerHTML=`<div class="orphan-dropdown-empty">${u.orphan_terminals.empty}</div>`;return}this.list.innerHTML=this.orphans.map(e=>`
7037
7039
  <div class="orphan-terminal-item" data-session="${g(e.session)}">
7038
7040
  <div class="orphan-terminal-info">
7039
7041
  <span class="orphan-terminal-pid">PID ${e.pid||"?"}</span>
@@ -124,14 +124,28 @@ export class CommandExecutor {
124
124
  }
125
125
 
126
126
  // Show output in UI as a tool block
127
- const output = (data.stdout || data.stderr || '(no output)').trim();
127
+ // Both streams, not `stdout || stderr` — a command that writes to
128
+ // both (progress on stderr, result on stdout) lost its stderr.
129
+ const combined = [data.stdout, data.stderr]
130
+ .map(s => (s || '').replace(/\s+$/, ''))
131
+ .filter(Boolean)
132
+ .join('\n');
133
+ const output = combined || '(no output)';
134
+ const shown = output.slice(0, 3000) + (output.length > 3000 ? '\n...(truncated)' : '');
135
+ // The Bash renderer shows toolError INSTEAD of toolOutput on error
136
+ // (Claude's Bash tool puts the full failure text there), so the
137
+ // output must ride in toolError too — a bare "Exit code: N" hid
138
+ // the stderr that explains the failure.
139
+ const failed = data.exit_code !== 0;
128
140
  this.activeSession.addMessage({
129
141
  role: 'tool',
130
142
  toolType: toolType,
131
143
  toolName: 'Shell',
132
144
  toolInput: { command: shellCmd },
133
- toolOutput: output.slice(0, 3000) + (output.length > 3000 ? '\n...(truncated)' : ''),
134
- toolError: data.exit_code !== 0 ? `Exit code: ${data.exit_code}` : null
145
+ toolOutput: shown,
146
+ toolError: failed
147
+ ? `${combined ? shown + '\n' : ''}Exit code: ${data.exit_code}`
148
+ : null
135
149
  });
136
150
 
137
151
  // Add to pending outputs for next Claude message
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: painapple-code
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Self-hosted remote UI for Claude Code that journals every turn - background AI summaries become shadow-git commits and a queryable DuckDB history
5
5
  Author-email: Michał Booth-Wrotkowski <michal@boothw.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.1.3",
3
+ "distance": 0,
4
+ "node": "g0c414ec",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-01"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.1.2",
3
- "distance": 0,
4
- "node": "g2fe4788",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-09-30"
8
- }
File without changes
File without changes
File without changes
File without changes