painapple-code 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. painapple_code/__init__.py +30 -0
  2. painapple_code/__main__.py +18 -0
  3. painapple_code/_version.py +24 -0
  4. painapple_code/auth_middleware.py +930 -0
  5. painapple_code/cli/__init__.py +204 -0
  6. painapple_code/cli/deploy/__init__.py +15 -0
  7. painapple_code/cli/deploy/claude_seed.py +41 -0
  8. painapple_code/cli/deploy/config.py +260 -0
  9. painapple_code/cli/deploy/container.py +715 -0
  10. painapple_code/cli/deploy/launch.py +163 -0
  11. painapple_code/cli/deploy/runtime.py +223 -0
  12. painapple_code/cli/lifecycle_cmd.py +443 -0
  13. painapple_code/cli/list_cmd.py +572 -0
  14. painapple_code/cli/manage_cmd.py +670 -0
  15. painapple_code/cli/netinfo.py +125 -0
  16. painapple_code/cli/profiles.py +390 -0
  17. painapple_code/cli/serve_args.py +163 -0
  18. painapple_code/cli/serve_config.py +256 -0
  19. painapple_code/cli/setup_cmd.py +664 -0
  20. painapple_code/cli/ui.py +438 -0
  21. painapple_code/cost_analytics.py +879 -0
  22. painapple_code/data/models.defaults.yaml +18 -0
  23. painapple_code/data/models.yaml +18 -0
  24. painapple_code/data/presets.defaults.json +32 -0
  25. painapple_code/data/strings.yaml +2269 -0
  26. painapple_code/helpers.py +406 -0
  27. painapple_code/paths.py +1514 -0
  28. painapple_code/prompt_explorer.py +984 -0
  29. painapple_code/providers/__init__.py +224 -0
  30. painapple_code/providers/base.py +710 -0
  31. painapple_code/providers/claude/__init__.py +74 -0
  32. painapple_code/providers/claude/capabilities.py +218 -0
  33. painapple_code/providers/claude/errors.py +79 -0
  34. painapple_code/providers/claude/launch.py +50 -0
  35. painapple_code/providers/claude/summary.py +89 -0
  36. painapple_code/providers/claude/translate.py +74 -0
  37. painapple_code/providers/claude_sdk/__init__.py +139 -0
  38. painapple_code/providers/claude_sdk/driver.py +412 -0
  39. painapple_code/providers/codex/__init__.py +87 -0
  40. painapple_code/providers/codex/capabilities.py +321 -0
  41. painapple_code/providers/codex/errors.py +70 -0
  42. painapple_code/providers/codex/launch.py +142 -0
  43. painapple_code/providers/codex/summary.py +196 -0
  44. painapple_code/providers/codex/translate.py +204 -0
  45. painapple_code/providers/codex_app_server/__init__.py +100 -0
  46. painapple_code/providers/codex_app_server/capabilities.py +41 -0
  47. painapple_code/providers/codex_app_server/launch.py +202 -0
  48. painapple_code/providers/codex_app_server/summary.py +291 -0
  49. painapple_code/providers/codex_app_server/translate.py +263 -0
  50. painapple_code/providers/codex_app_server/transport.py +238 -0
  51. painapple_code/routes/__init__.py +0 -0
  52. painapple_code/routes/api_agents.py +441 -0
  53. painapple_code/routes/api_app.py +368 -0
  54. painapple_code/routes/api_app_commit_sections.py +127 -0
  55. painapple_code/routes/api_app_config.py +997 -0
  56. painapple_code/routes/api_app_session_prefs.py +217 -0
  57. painapple_code/routes/api_browser.py +690 -0
  58. painapple_code/routes/api_commands.py +374 -0
  59. painapple_code/routes/api_costs.py +128 -0
  60. painapple_code/routes/api_drafts.py +139 -0
  61. painapple_code/routes/api_exec.py +149 -0
  62. painapple_code/routes/api_files.py +542 -0
  63. painapple_code/routes/api_git.py +657 -0
  64. painapple_code/routes/api_logs.py +649 -0
  65. painapple_code/routes/api_plugins.py +275 -0
  66. painapple_code/routes/api_project_config.py +418 -0
  67. painapple_code/routes/api_prompts.py +231 -0
  68. painapple_code/routes/api_providers.py +53 -0
  69. painapple_code/routes/api_search.py +411 -0
  70. painapple_code/routes/api_session_stash.py +234 -0
  71. painapple_code/routes/api_session_welcome.py +151 -0
  72. painapple_code/routes/api_sessions.py +742 -0
  73. painapple_code/routes/api_shadow.py +323 -0
  74. painapple_code/routes/api_shadow_db.py +512 -0
  75. painapple_code/routes/api_shadow_files.py +332 -0
  76. painapple_code/routes/api_shadow_search.py +476 -0
  77. painapple_code/routes/api_skills.py +610 -0
  78. painapple_code/routes/api_tasks.py +147 -0
  79. painapple_code/routes/api_terminal.py +540 -0
  80. painapple_code/routes/api_upload.py +293 -0
  81. painapple_code/routes/api_viewer.py +229 -0
  82. painapple_code/routes/dependencies.py +109 -0
  83. painapple_code/routes/ws_chat.py +837 -0
  84. painapple_code/server.py +2208 -0
  85. painapple_code/server_logging.py +263 -0
  86. painapple_code/services/__init__.py +0 -0
  87. painapple_code/services/agent_session.py +2738 -0
  88. painapple_code/session_store.py +253 -0
  89. painapple_code/session_store_core.py +879 -0
  90. painapple_code/shadow_db.py +830 -0
  91. painapple_code/shadow_db_plans.py +369 -0
  92. painapple_code/shadow_db_queries.py +595 -0
  93. painapple_code/shadow_db_schema.py +676 -0
  94. painapple_code/shadow_git.py +1296 -0
  95. painapple_code/shadow_git_frontmatter.py +314 -0
  96. painapple_code/shadow_git_sections.py +520 -0
  97. painapple_code/shadow_git_summary.py +462 -0
  98. painapple_code/shadow_parser.py +560 -0
  99. painapple_code/static/css/00-variables.css +276 -0
  100. painapple_code/static/css/01-base.css +245 -0
  101. painapple_code/static/css/02-tooltips.css +36 -0
  102. painapple_code/static/css/09-left-rail.css +448 -0
  103. painapple_code/static/css/10-header.css +777 -0
  104. painapple_code/static/css/11-connection-bar.css +120 -0
  105. painapple_code/static/css/20-messages.css +750 -0
  106. painapple_code/static/css/21-tool-blocks.css +2340 -0
  107. painapple_code/static/css/22-edit-diff.css +619 -0
  108. painapple_code/static/css/23-thinking.css +1584 -0
  109. painapple_code/static/css/24-background-tasks.css +359 -0
  110. painapple_code/static/css/25-context-block.css +252 -0
  111. painapple_code/static/css/26-session-setup.css +144 -0
  112. painapple_code/static/css/30-markdown.css +854 -0
  113. painapple_code/static/css/40-input.css +2418 -0
  114. painapple_code/static/css/41-autocomplete.css +127 -0
  115. painapple_code/static/css/42-activity-strip.css +97 -0
  116. painapple_code/static/css/43-file-autocomplete.css +121 -0
  117. painapple_code/static/css/44-snippets-autocomplete.css +224 -0
  118. painapple_code/static/css/45-selection-bar.css +433 -0
  119. painapple_code/static/css/46-keyboard-bar.css +119 -0
  120. painapple_code/static/css/47-keyboard-longpress.css +116 -0
  121. painapple_code/static/css/47-token-profile.css +106 -0
  122. painapple_code/static/css/50-welcome.css +3095 -0
  123. painapple_code/static/css/51-modals.css +301 -0
  124. painapple_code/static/css/52-utilities.css +77 -0
  125. painapple_code/static/css/53-image-upload.css +456 -0
  126. painapple_code/static/css/54-todo-list.css +102 -0
  127. painapple_code/static/css/55-file-upload.css +113 -0
  128. painapple_code/static/css/56-chat-navigator.css +218 -0
  129. painapple_code/static/css/56-permission-card.css +332 -0
  130. painapple_code/static/css/56-plan-approval.css +204 -0
  131. painapple_code/static/css/56-question-form.css +602 -0
  132. painapple_code/static/css/57-swipe-indicator.css +95 -0
  133. painapple_code/static/css/58-session-families.css +627 -0
  134. painapple_code/static/css/59-about.css +196 -0
  135. painapple_code/static/css/61-log-explorer.css +723 -0
  136. painapple_code/static/css/62-json-tree.css +489 -0
  137. painapple_code/static/css/62-skills-widget.css +650 -0
  138. painapple_code/static/css/63-commands-widget.css +30 -0
  139. painapple_code/static/css/63-plugins-widget.css +174 -0
  140. painapple_code/static/css/63-terminal.css +516 -0
  141. painapple_code/static/css/64-search-files-widget.css +448 -0
  142. painapple_code/static/css/65-snippets-widget.css +426 -0
  143. painapple_code/static/css/66-active-sessions.css +979 -0
  144. painapple_code/static/css/66-agents-widget.css +265 -0
  145. painapple_code/static/css/66-file-explorer-widget.css +855 -0
  146. painapple_code/static/css/66-git-panel.css +791 -0
  147. painapple_code/static/css/66-history-explorer.css +1496 -0
  148. painapple_code/static/css/67-diff-viewer.css +602 -0
  149. painapple_code/static/css/67-editor-view.css +748 -0
  150. painapple_code/static/css/67-file-preview-widget.css +1873 -0
  151. painapple_code/static/css/68-browser-widget.css +337 -0
  152. painapple_code/static/css/68-compare-wizard.css +355 -0
  153. painapple_code/static/css/68-csv-preview.css +106 -0
  154. painapple_code/static/css/68-diff-preview.css +103 -0
  155. painapple_code/static/css/68-helpers-install-widget.css +491 -0
  156. painapple_code/static/css/68-image-annotate.css +346 -0
  157. painapple_code/static/css/68-terminal-view.css +98 -0
  158. painapple_code/static/css/68-uploads-widget.css +229 -0
  159. painapple_code/static/css/69-cost-analytics.css +537 -0
  160. painapple_code/static/css/70-config-panel.css +3736 -0
  161. painapple_code/static/css/70-excalidraw.css +136 -0
  162. painapple_code/static/css/70-prompt-explorer.css +890 -0
  163. painapple_code/static/css/71-chart.css +111 -0
  164. painapple_code/static/css/72-discussion-sidebar.css +678 -0
  165. painapple_code/static/css/74-debug-logs.css +656 -0
  166. painapple_code/static/css/80-open-dialog.css +146 -0
  167. painapple_code/static/css/80-quick-switcher.css +383 -0
  168. painapple_code/static/css/80-widget-system.css +1763 -0
  169. painapple_code/static/css/81-quick-actions.css +1020 -0
  170. painapple_code/static/css/82-context-popover.css +1233 -0
  171. painapple_code/static/css/83-context-menu.css +339 -0
  172. painapple_code/static/css/85-lazy-loading.css +102 -0
  173. painapple_code/static/css/86-zen-mode.css +708 -0
  174. painapple_code/static/css/87-grid-switcher.css +346 -0
  175. painapple_code/static/css/login.css +198 -0
  176. painapple_code/static/dist/app.bundle.js +7177 -0
  177. painapple_code/static/feature-triage.html +446 -0
  178. painapple_code/static/icons/apple-touch-icon.png +0 -0
  179. painapple_code/static/icons/favicon-32.png +0 -0
  180. painapple_code/static/icons/favicon.ico +0 -0
  181. painapple_code/static/icons/icon-128.png +0 -0
  182. painapple_code/static/icons/icon-144.png +0 -0
  183. painapple_code/static/icons/icon-152.png +0 -0
  184. painapple_code/static/icons/icon-180.png +0 -0
  185. painapple_code/static/icons/icon-192.png +0 -0
  186. painapple_code/static/icons/icon-384.png +0 -0
  187. painapple_code/static/icons/icon-512.png +0 -0
  188. painapple_code/static/icons/icon-72.png +0 -0
  189. painapple_code/static/icons/icon-96.png +0 -0
  190. painapple_code/static/js/action-delegate.js +187 -0
  191. painapple_code/static/js/activity-strip.js +193 -0
  192. painapple_code/static/js/app/context-menus.js +619 -0
  193. painapple_code/static/js/app/file-preview.js +163 -0
  194. painapple_code/static/js/app/init-ui.js +574 -0
  195. painapple_code/static/js/app/input-events.js +561 -0
  196. painapple_code/static/js/app/input-resize.js +313 -0
  197. painapple_code/static/js/app/message-actions.js +419 -0
  198. painapple_code/static/js/app/panels.js +210 -0
  199. painapple_code/static/js/app/rendering-delegators.js +246 -0
  200. painapple_code/static/js/app/server-loading.js +365 -0
  201. painapple_code/static/js/app/session-ops.js +287 -0
  202. painapple_code/static/js/app/session-switch.js +443 -0
  203. painapple_code/static/js/app/settings-helpers.js +280 -0
  204. painapple_code/static/js/app/startup-welcome.js +290 -0
  205. painapple_code/static/js/app-context.js +157 -0
  206. painapple_code/static/js/app.js +2134 -0
  207. painapple_code/static/js/auth-fetch.js +46 -0
  208. painapple_code/static/js/background-tasks.js +274 -0
  209. painapple_code/static/js/boot.js +73 -0
  210. painapple_code/static/js/caret-position.js +171 -0
  211. painapple_code/static/js/chat-navigator.js +710 -0
  212. painapple_code/static/js/chat-search.js +323 -0
  213. painapple_code/static/js/command-executor.js +176 -0
  214. painapple_code/static/js/command-store.js +497 -0
  215. painapple_code/static/js/components.js +1414 -0
  216. painapple_code/static/js/config.js +218 -0
  217. painapple_code/static/js/context-menu.js +740 -0
  218. painapple_code/static/js/controllers/chat-controller.js +4252 -0
  219. painapple_code/static/js/controllers/dialog-controller.js +217 -0
  220. painapple_code/static/js/controllers/tab-controller.js +1828 -0
  221. painapple_code/static/js/controllers/thinking-controller.js +915 -0
  222. painapple_code/static/js/diff-utils.js +486 -0
  223. painapple_code/static/js/drafts-pill.js +95 -0
  224. painapple_code/static/js/editor-view.js +815 -0
  225. painapple_code/static/js/effort-settings.js +430 -0
  226. painapple_code/static/js/feature-triage.js +811 -0
  227. painapple_code/static/js/file-autocomplete.js +516 -0
  228. painapple_code/static/js/file-tabs.js +123 -0
  229. painapple_code/static/js/gestures.js +448 -0
  230. painapple_code/static/js/grid-switcher.js +334 -0
  231. painapple_code/static/js/input-handler.js +1472 -0
  232. painapple_code/static/js/keyboard-bar.js +495 -0
  233. painapple_code/static/js/layout-switcher.js +109 -0
  234. painapple_code/static/js/linkify-utils.js +200 -0
  235. painapple_code/static/js/login.js +141 -0
  236. painapple_code/static/js/open-dialog.js +879 -0
  237. painapple_code/static/js/orphan-terminals.js +373 -0
  238. painapple_code/static/js/path-utils.js +179 -0
  239. painapple_code/static/js/perf-marks.js +102 -0
  240. painapple_code/static/js/permission-settings.js +475 -0
  241. painapple_code/static/js/pointer-input.js +59 -0
  242. painapple_code/static/js/preview/json-tree-menu.js +226 -0
  243. painapple_code/static/js/preview/json-tree-toolbar.js +291 -0
  244. painapple_code/static/js/preview/json-tree.js +457 -0
  245. painapple_code/static/js/preview/preview-breadcrumb.js +387 -0
  246. painapple_code/static/js/preview/preview-edit.js +367 -0
  247. painapple_code/static/js/preview/preview-events.js +361 -0
  248. painapple_code/static/js/preview/preview-history.js +567 -0
  249. painapple_code/static/js/preview/preview-inline-edit.js +869 -0
  250. painapple_code/static/js/preview/preview-poll.js +108 -0
  251. painapple_code/static/js/preview/preview-render.js +572 -0
  252. painapple_code/static/js/preview/preview-search.js +421 -0
  253. painapple_code/static/js/preview/preview-state.js +256 -0
  254. painapple_code/static/js/preview/preview-utils.js +251 -0
  255. painapple_code/static/js/preview-plugins/chart-plugin.js +22 -0
  256. painapple_code/static/js/preview-plugins/csv-plugin.js +188 -0
  257. painapple_code/static/js/preview-plugins/diff-plugin.js +258 -0
  258. painapple_code/static/js/preview-plugins/excalidraw-plugin.js +25 -0
  259. painapple_code/static/js/preview-plugins/html-plugin.js +104 -0
  260. painapple_code/static/js/preview-plugins/image-plugin.js +20 -0
  261. painapple_code/static/js/preview-plugins/index.js +34 -0
  262. painapple_code/static/js/preview-plugins/json-plugin.js +99 -0
  263. painapple_code/static/js/preview-plugins/jsonl-plugin.js +152 -0
  264. painapple_code/static/js/preview-plugins/markdown-plugin.js +266 -0
  265. painapple_code/static/js/preview-plugins/panzoom-plugin.js +63 -0
  266. painapple_code/static/js/preview-plugins/plugin-helpers.js +282 -0
  267. painapple_code/static/js/project-color-picker.js +110 -0
  268. painapple_code/static/js/project-colors.js +163 -0
  269. painapple_code/static/js/prompt-favorites.js +187 -0
  270. painapple_code/static/js/quick-actions-menu.js +1736 -0
  271. painapple_code/static/js/quick-actions-registry.js +1239 -0
  272. painapple_code/static/js/quick-switcher/controller.js +294 -0
  273. painapple_code/static/js/quick-switcher/fuzzy-scorer.js +123 -0
  274. painapple_code/static/js/quick-switcher/index.js +30 -0
  275. painapple_code/static/js/quick-switcher/providers/base-provider.js +51 -0
  276. painapple_code/static/js/quick-switcher/providers/command-provider.js +56 -0
  277. painapple_code/static/js/quick-switcher/providers/file-provider.js +291 -0
  278. painapple_code/static/js/quick-switcher/providers/panel-provider.js +132 -0
  279. painapple_code/static/js/quick-switcher/providers/project-provider.js +361 -0
  280. painapple_code/static/js/quick-switcher/providers/read-files-provider.js +104 -0
  281. painapple_code/static/js/quick-switcher/providers/skills-provider.js +129 -0
  282. painapple_code/static/js/quick-switcher/registry.js +69 -0
  283. painapple_code/static/js/quick-switcher/ui/item.js +54 -0
  284. painapple_code/static/js/quick-switcher/ui/picker.js +464 -0
  285. painapple_code/static/js/recent-opens.js +40 -0
  286. painapple_code/static/js/scroll-manager.js +530 -0
  287. painapple_code/static/js/scroll-state-machine.js +359 -0
  288. painapple_code/static/js/selection/action-bar.js +793 -0
  289. painapple_code/static/js/selection/index.js +15 -0
  290. painapple_code/static/js/selection/selection-handler.js +877 -0
  291. painapple_code/static/js/selection/state.js +181 -0
  292. painapple_code/static/js/session/agent-progress.js +202 -0
  293. painapple_code/static/js/session/handle-agent-message.js +481 -0
  294. painapple_code/static/js/session/handle-message.js +550 -0
  295. painapple_code/static/js/session/interactive.js +587 -0
  296. painapple_code/static/js/session/message-store.js +271 -0
  297. painapple_code/static/js/session/messages.js +253 -0
  298. painapple_code/static/js/session/persistence.js +179 -0
  299. painapple_code/static/js/session/restore.js +136 -0
  300. painapple_code/static/js/session/sync.js +333 -0
  301. painapple_code/static/js/session-container-pool.js +371 -0
  302. painapple_code/static/js/session-setup-panel.js +274 -0
  303. painapple_code/static/js/session.js +1047 -0
  304. painapple_code/static/js/shortcut-hints.js +272 -0
  305. painapple_code/static/js/shortcuts.js +1146 -0
  306. painapple_code/static/js/skills-autocomplete.js +262 -0
  307. painapple_code/static/js/snippets-autocomplete.js +738 -0
  308. painapple_code/static/js/stash-refs-view.js +83 -0
  309. painapple_code/static/js/stash-ui.js +768 -0
  310. painapple_code/static/js/stash.js +785 -0
  311. painapple_code/static/js/status-bar.js +1184 -0
  312. painapple_code/static/js/token-profile.js +274 -0
  313. painapple_code/static/js/tool-renderer-blocks.js +1626 -0
  314. painapple_code/static/js/tool-renderer-thinking.js +813 -0
  315. painapple_code/static/js/tool-renderer.js +1500 -0
  316. painapple_code/static/js/tooltips.js +197 -0
  317. painapple_code/static/js/upload-manager.js +1019 -0
  318. painapple_code/static/js/utils.js +521 -0
  319. painapple_code/static/js/welcome/api.js +363 -0
  320. painapple_code/static/js/welcome/cards.js +626 -0
  321. painapple_code/static/js/welcome/context-menu.js +585 -0
  322. painapple_code/static/js/welcome/families.js +801 -0
  323. painapple_code/static/js/welcome/preview.js +234 -0
  324. painapple_code/static/js/welcome/state.js +129 -0
  325. painapple_code/static/js/welcome.js +1874 -0
  326. painapple_code/static/js/widget-system/base-widget.js +717 -0
  327. painapple_code/static/js/widget-system/device-manager.js +178 -0
  328. painapple_code/static/js/widget-system/event-bus.js +152 -0
  329. painapple_code/static/js/widget-system/icons.js +120 -0
  330. painapple_code/static/js/widget-system/index.js +49 -0
  331. painapple_code/static/js/widget-system/init.js +54 -0
  332. painapple_code/static/js/widget-system/types/bottom-sheet.js +307 -0
  333. painapple_code/static/js/widget-system/types/floating.js +915 -0
  334. painapple_code/static/js/widget-system/types/index.js +40 -0
  335. painapple_code/static/js/widget-system/types/modal.js +147 -0
  336. painapple_code/static/js/widget-system/types/sidebar.js +158 -0
  337. painapple_code/static/js/widget-system/types/tab.js +146 -0
  338. painapple_code/static/js/widget-system/types/top-sheet.js +203 -0
  339. painapple_code/static/js/widget-system/widget-manager.js +1187 -0
  340. painapple_code/static/js/widgets/about-widget.js +260 -0
  341. painapple_code/static/js/widgets/active-sessions-widget.js +760 -0
  342. painapple_code/static/js/widgets/agents-widget.js +897 -0
  343. painapple_code/static/js/widgets/browser-widget.js +579 -0
  344. painapple_code/static/js/widgets/commands-widget.js +694 -0
  345. painapple_code/static/js/widgets/config/commit-sections.js +449 -0
  346. painapple_code/static/js/widgets/config/dir-autocomplete.js +224 -0
  347. painapple_code/static/js/widgets/config/gestures.js +161 -0
  348. painapple_code/static/js/widgets/config/models-tab.js +988 -0
  349. painapple_code/static/js/widgets/config/quick-actions-tab.js +882 -0
  350. painapple_code/static/js/widgets/config/shortcut-editor.js +587 -0
  351. painapple_code/static/js/widgets/config/state.js +517 -0
  352. painapple_code/static/js/widgets/config/system-controls.js +90 -0
  353. painapple_code/static/js/widgets/config-widget.js +1535 -0
  354. painapple_code/static/js/widgets/cost-analytics-widget.js +621 -0
  355. painapple_code/static/js/widgets/debug-widget.js +693 -0
  356. painapple_code/static/js/widgets/diff-viewer-widget.js +1420 -0
  357. painapple_code/static/js/widgets/discussion-widget.js +1107 -0
  358. painapple_code/static/js/widgets/file-explorer-widget.js +2166 -0
  359. painapple_code/static/js/widgets/file-preview-widget.js +861 -0
  360. painapple_code/static/js/widgets/git-widget.js +794 -0
  361. painapple_code/static/js/widgets/helpers-install-widget.js +720 -0
  362. painapple_code/static/js/widgets/history-explorer-widget.js +1804 -0
  363. painapple_code/static/js/widgets/image-annotate-widget.js +951 -0
  364. painapple_code/static/js/widgets/image-preview-widget.js +692 -0
  365. painapple_code/static/js/widgets/index.js +176 -0
  366. painapple_code/static/js/widgets/log-explorer-widget.js +1057 -0
  367. painapple_code/static/js/widgets/plugins-widget.js +305 -0
  368. painapple_code/static/js/widgets/prompt-explorer-widget.js +1119 -0
  369. painapple_code/static/js/widgets/search-files-widget.js +529 -0
  370. painapple_code/static/js/widgets/skills-widget.js +843 -0
  371. painapple_code/static/js/widgets/snippets-widget.js +479 -0
  372. painapple_code/static/js/widgets/sub-agents-widget.js +333 -0
  373. painapple_code/static/js/widgets/tasks-widget.js +379 -0
  374. painapple_code/static/js/widgets/terminal/connection.js +283 -0
  375. painapple_code/static/js/widgets/terminal/gestures.js +357 -0
  376. painapple_code/static/js/widgets/terminal/init.js +642 -0
  377. painapple_code/static/js/widgets/terminal/link-providers.js +532 -0
  378. painapple_code/static/js/widgets/terminal/osc52.js +213 -0
  379. painapple_code/static/js/widgets/terminal/render.js +159 -0
  380. painapple_code/static/js/widgets/terminal/size.js +54 -0
  381. painapple_code/static/js/widgets/terminal/state.js +211 -0
  382. painapple_code/static/js/widgets/terminal/wrap-utils.js +101 -0
  383. painapple_code/static/js/widgets/terminal-widget.js +793 -0
  384. painapple_code/static/js/widgets/uploads-widget.js +461 -0
  385. painapple_code/static/js/widgets/zen-widget.js +1001 -0
  386. painapple_code/static/login.html +51 -0
  387. painapple_code/static/manifest.json +73 -0
  388. painapple_code/static/sw.js +293 -0
  389. painapple_code/static/vendor/LICENSES.txt +769 -0
  390. painapple_code/static/vendor/README.md +103 -0
  391. painapple_code/static/vendor/codemirror.js +35 -0
  392. painapple_code/static/vendor/codemirror.js.LEGAL.txt +304 -0
  393. painapple_code/static/vendor/github-markdown-dark.min.css +1124 -0
  394. painapple_code/static/vendor/highlight-github-dark.min.css +10 -0
  395. painapple_code/static/vendor/highlight-lang-dockerfile.min.js +8 -0
  396. painapple_code/static/vendor/highlight-lang-nginx.min.js +21 -0
  397. painapple_code/static/vendor/highlight-lang-properties.min.js +10 -0
  398. painapple_code/static/vendor/highlight-lang-scala.min.js +28 -0
  399. painapple_code/static/vendor/highlight.min.js +1213 -0
  400. painapple_code/static/vendor/marked.min.js +6 -0
  401. painapple_code/static/vendor/purify.min.js +3 -0
  402. painapple_code/static/vendor/xterm-addon-fit.js +2 -0
  403. painapple_code/static/vendor/xterm.css +209 -0
  404. painapple_code/static/vendor/xterm.js +2 -0
  405. painapple_code/static/web-client.html +635 -0
  406. painapple_code/subprocess_registry.py +535 -0
  407. painapple_code/tls_cert.py +79 -0
  408. painapple_code/tools/agents/shadow-git-helper.md +400 -0
  409. painapple_code/tools/excalidraw-to-svg.js +143 -0
  410. painapple_code/tools/install-helpers.sh +148 -0
  411. painapple_code/tools/shadow-git +320 -0
  412. painapple_code/tools/shadow-query +120 -0
  413. painapple_code/tools/vegalite-to-svg.js +79 -0
  414. painapple_code/turn_query.py +766 -0
  415. painapple_code/turn_tracker.py +221 -0
  416. painapple_code/utils/__init__.py +0 -0
  417. painapple_code/utils/agent_cli.py +306 -0
  418. painapple_code/utils/chart.py +103 -0
  419. painapple_code/utils/excalidraw.py +107 -0
  420. painapple_code/utils/file_lock.py +162 -0
  421. painapple_code/utils/file_paths.py +648 -0
  422. painapple_code/utils/generate_icons.py +251 -0
  423. painapple_code/utils/proc.py +205 -0
  424. painapple_code/utils/pty_backend.py +59 -0
  425. painapple_code/utils/pty_posix.py +160 -0
  426. painapple_code/utils/pty_windows.py +245 -0
  427. painapple_code/utils/token_profiles.py +91 -0
  428. painapple_code/viewer_templates.py +657 -0
  429. painapple_code/welcome_search.py +879 -0
  430. painapple_code-1.0.0.dist-info/METADATA +292 -0
  431. painapple_code-1.0.0.dist-info/RECORD +436 -0
  432. painapple_code-1.0.0.dist-info/WHEEL +5 -0
  433. painapple_code-1.0.0.dist-info/entry_points.txt +2 -0
  434. painapple_code-1.0.0.dist-info/licenses/LICENSE +661 -0
  435. painapple_code-1.0.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +261 -0
  436. painapple_code-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,448 @@
1
+ /**
2
+ * Gesture Handler for Tab Navigation
3
+ *
4
+ * Intercepts two-finger trackpad swipes and touch gestures
5
+ * to enable tab switching instead of browser back/forward navigation.
6
+ *
7
+ * Works best in PWA standalone mode where browser navigation is disabled.
8
+ */
9
+
10
+ /**
11
+ * GestureManager - Handles swipe gestures for tab navigation
12
+ */
13
+ export class GestureManager {
14
+ constructor(app) {
15
+ this.app = app;
16
+
17
+ // Wheel gesture state (trackpad two-finger swipe)
18
+ this.wheelAccumulator = 0;
19
+ this.wheelTimeout = null;
20
+ this.wheelCooldown = false;
21
+
22
+ // Touch gesture state
23
+ this.touchStartX = 0;
24
+ this.touchStartY = 0;
25
+ this.touchStartTime = 0;
26
+ this.touchCooldown = false;
27
+ this.isSwiping = false;
28
+ this.swipeIndicator = null;
29
+
30
+ // Configuration
31
+ this.config = {
32
+ // Wheel settings
33
+ wheelThreshold: 120, // Accumulated deltaX to trigger (px)
34
+ wheelResetDelay: 150, // Reset accumulator after this delay (ms)
35
+ wheelCooldownTime: 400, // Cooldown between triggers (ms)
36
+
37
+ // Touch settings
38
+ touchThreshold: 130, // Minimum swipe distance (px) - ~17% of iPad portrait
39
+ touchMaxTime: 500, // Maximum swipe duration (ms)
40
+ touchAngleThreshold: 2.0, // Horizontal must be 2x vertical
41
+ touchCooldownTime: 400, // Cooldown between triggers (ms)
42
+
43
+ // Edge swipe detection (for non-PWA mode)
44
+ edgeZone: 30, // Edge zone width (px)
45
+ };
46
+
47
+ this.init();
48
+ }
49
+
50
+ init() {
51
+ // Wheel events for trackpad
52
+ document.addEventListener('wheel', (e) => this.handleWheel(e), { passive: false });
53
+
54
+ // Touch events for mobile/tablet
55
+ // Using passive: false to allow preventDefault() for blocking browser back/forward gestures
56
+ // This is necessary because iOS Safari interprets edge swipes as navigation
57
+ document.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });
58
+ document.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });
59
+ document.addEventListener('touchend', (e) => this.handleTouchEnd(e), { passive: false });
60
+ document.addEventListener('touchcancel', (e) => this.handleTouchCancel(e), { passive: true });
61
+
62
+ // Create swipe indicator element
63
+ this.createSwipeIndicator();
64
+
65
+ // History API trap (fallback for any navigation that slips through)
66
+ this.setupHistoryTrap();
67
+ }
68
+
69
+ /**
70
+ * Handle wheel events (trackpad two-finger swipe)
71
+ */
72
+ handleWheel(e) {
73
+ // Skip if in terminal (has its own scrolling)
74
+ const inTerminal = e.target.closest('.terminal-container, .xterm');
75
+
76
+ // Skip if inside a floating widget (widgets contain their own scroll)
77
+ const inWidget = e.target.closest('.widget-floating');
78
+
79
+ // Skip if target has horizontal scroll
80
+ const hasScroll = this.hasHorizontalScroll(e.target);
81
+
82
+ // Check for any horizontal component (even small)
83
+ // iPadOS trackpad back/forward gesture starts with small deltaX values
84
+ const hasHorizontalComponent = Math.abs(e.deltaX) > 0;
85
+ // Only treat horizontal as the *primary* axis when it dominates.
86
+ // Many mice/trackpads emit a tiny incidental deltaX on a pure vertical
87
+ // scroll — blocking the whole event on that would kill chat scroll on
88
+ // any message that has no horizontally-scrolling descendant (the
89
+ // ancestor check above only saves us when a <pre> or table is nearby).
90
+ // iPadOS back/forward edge swipes are intrinsically horizontal, so
91
+ // they still satisfy |deltaX| > |deltaY| and remain blocked.
92
+ const isHorizontalDominant = Math.abs(e.deltaX) > Math.abs(e.deltaY);
93
+
94
+ // Prevent browser back/forward only for primarily-horizontal wheel
95
+ // movement (except in terminal, horizontally scrollable areas, or
96
+ // floating widgets). Must happen early before the browser can
97
+ // interpret it as navigation.
98
+ if (hasHorizontalComponent && isHorizontalDominant && !inTerminal && !hasScroll && !inWidget) {
99
+ e.preventDefault();
100
+ }
101
+
102
+ // Only care about significant horizontal movement for tab switching
103
+ const isHorizontal = Math.abs(e.deltaX) > Math.abs(e.deltaY) && Math.abs(e.deltaX) > 5;
104
+
105
+ // Now apply filtering for tab switch logic
106
+ if (this.wheelCooldown) return;
107
+ if (inTerminal) return;
108
+ if (inWidget) return;
109
+ if (hasScroll) return;
110
+ if (!isHorizontal) return;
111
+
112
+ // Accumulate horizontal movement
113
+ this.wheelAccumulator += e.deltaX;
114
+
115
+ // Clear existing timeout
116
+ if (this.wheelTimeout) {
117
+ clearTimeout(this.wheelTimeout);
118
+ }
119
+
120
+ // Check if threshold exceeded
121
+ if (Math.abs(this.wheelAccumulator) >= this.config.wheelThreshold) {
122
+ const direction = this.wheelAccumulator > 0 ? 1 : -1; // 1 = next, -1 = prev
123
+ this.triggerTabSwitch(direction, 'wheel');
124
+
125
+ // Reset and set cooldown
126
+ this.wheelAccumulator = 0;
127
+ this.wheelCooldown = true;
128
+ setTimeout(() => {
129
+ this.wheelCooldown = false;
130
+ }, this.config.wheelCooldownTime);
131
+ }
132
+
133
+ // Reset accumulator after delay (gesture ended)
134
+ this.wheelTimeout = setTimeout(() => {
135
+ this.wheelAccumulator = 0;
136
+ }, this.config.wheelResetDelay);
137
+ }
138
+
139
+ /**
140
+ * Handle touch start
141
+ */
142
+ handleTouchStart(e) {
143
+ if (e.touches.length !== 1) return; // Single finger only
144
+
145
+ // Skip if starting inside a floating overlay (widget, modal, dialog)
146
+ if (this.isInsideOverlay(e.target)) return;
147
+
148
+ this.touchStartX = e.touches[0].clientX;
149
+ this.touchStartY = e.touches[0].clientY;
150
+ this.touchStartTime = Date.now();
151
+ }
152
+
153
+ /**
154
+ * Handle touch end
155
+ */
156
+ handleTouchEnd(e) {
157
+ // Skip if cooldown active
158
+ if (this.touchCooldown) return;
159
+
160
+ // Skip if no start recorded
161
+ if (!this.touchStartTime) return;
162
+
163
+ const touch = e.changedTouches[0];
164
+ const deltaX = touch.clientX - this.touchStartX;
165
+ const deltaY = touch.clientY - this.touchStartY;
166
+ const deltaTime = Date.now() - this.touchStartTime;
167
+
168
+ // Reset start
169
+ this.touchStartTime = 0;
170
+
171
+ // Skip if too slow
172
+ if (deltaTime > this.config.touchMaxTime) return;
173
+
174
+ // Skip if not enough horizontal movement
175
+ if (Math.abs(deltaX) < this.config.touchThreshold) return;
176
+
177
+ // Skip if not primarily horizontal
178
+ if (Math.abs(deltaX) < Math.abs(deltaY) * this.config.touchAngleThreshold) return;
179
+
180
+ // Skip if in terminal
181
+ if (e.target.closest('.terminal-container, .xterm')) return;
182
+
183
+ // Skip if target has horizontal scroll
184
+ if (this.hasHorizontalScroll(e.target)) return;
185
+
186
+ // Skip if text is being selected (user is dragging to select, not swiping)
187
+ const selection = window.getSelection();
188
+ if (selection && selection.toString().trim().length > 0) {
189
+ return;
190
+ }
191
+
192
+ // Determine direction: swipe left (deltaX < 0) = next, swipe right (deltaX > 0) = prev
193
+ const direction = deltaX < 0 ? 1 : -1;
194
+
195
+ // Prevent synthetic click from this touch sequence (stops iOS keyboard popup)
196
+ e.preventDefault();
197
+
198
+ // Flash indicator to show threshold was reached
199
+ this.flashIndicator(direction);
200
+
201
+ this.triggerTabSwitch(direction, 'touch');
202
+
203
+ // Set cooldown
204
+ this.touchCooldown = true;
205
+ setTimeout(() => {
206
+ this.touchCooldown = false;
207
+ }, this.config.touchCooldownTime);
208
+
209
+ // Reset swipe state
210
+ this.isSwiping = false;
211
+ this.hideIndicator();
212
+ }
213
+
214
+ /**
215
+ * Handle touch cancel (e.g., interrupted by system gesture)
216
+ */
217
+ handleTouchCancel(e) {
218
+ this.touchStartTime = 0;
219
+ this.isSwiping = false;
220
+ this.hideIndicator();
221
+ }
222
+
223
+ /**
224
+ * Handle touch move - track swipe progress for visual feedback
225
+ * Also prevents browser back/forward gestures when horizontal swipe detected
226
+ */
227
+ handleTouchMove(e) {
228
+ // Skip if no start recorded or cooldown active
229
+ if (!this.touchStartTime || this.touchCooldown) return;
230
+ if (e.touches.length !== 1) return;
231
+
232
+ const touch = e.touches[0];
233
+ const deltaX = touch.clientX - this.touchStartX;
234
+ const deltaY = touch.clientY - this.touchStartY;
235
+ const deltaTime = Date.now() - this.touchStartTime;
236
+
237
+ // Skip if too slow already
238
+ if (deltaTime > this.config.touchMaxTime) {
239
+ this.hideIndicator();
240
+ return;
241
+ }
242
+
243
+ // Check if this looks like a horizontal swipe
244
+ const absX = Math.abs(deltaX);
245
+ const absY = Math.abs(deltaY);
246
+
247
+ // Require some minimum movement before showing indicator
248
+ if (absX < 20) {
249
+ if (this.isSwiping) {
250
+ this.hideIndicator();
251
+ this.isSwiping = false;
252
+ }
253
+ return;
254
+ }
255
+
256
+ // Must be primarily horizontal
257
+ if (absX < absY * this.config.touchAngleThreshold) {
258
+ if (this.isSwiping) {
259
+ this.hideIndicator();
260
+ this.isSwiping = false;
261
+ }
262
+ return;
263
+ }
264
+
265
+ // Skip if in terminal or scrollable area
266
+ if (e.target.closest('.terminal-container, .xterm')) return;
267
+ if (this.hasHorizontalScroll(e.target)) return;
268
+
269
+ // PREVENT browser back/forward navigation for horizontal swipes
270
+ // This is critical for iOS Safari which interprets edge swipes as navigation
271
+ e.preventDefault();
272
+
273
+ // We're swiping! Show indicator
274
+ this.isSwiping = true;
275
+ const progress = Math.min(absX / this.config.touchThreshold, 1);
276
+ const direction = deltaX < 0 ? 1 : -1; // 1 = next (swipe left), -1 = prev (swipe right)
277
+ this.updateIndicator(progress, direction);
278
+ }
279
+
280
+ /**
281
+ * Create the swipe indicator element
282
+ */
283
+ createSwipeIndicator() {
284
+ this.swipeIndicator = document.createElement('div');
285
+ this.swipeIndicator.className = 'swipe-indicator';
286
+ this.swipeIndicator.innerHTML = `
287
+ <div class="swipe-indicator-bar"></div>
288
+ <div class="swipe-indicator-label"></div>
289
+ `;
290
+ document.body.appendChild(this.swipeIndicator);
291
+ }
292
+
293
+ /**
294
+ * Update indicator progress and direction
295
+ * @param {number} progress - 0 to 1
296
+ * @param {number} direction - 1 for next, -1 for prev
297
+ */
298
+ updateIndicator(progress, direction) {
299
+ if (!this.swipeIndicator) return;
300
+
301
+ const bar = this.swipeIndicator.querySelector('.swipe-indicator-bar');
302
+ const label = this.swipeIndicator.querySelector('.swipe-indicator-label');
303
+
304
+ // Show indicator
305
+ this.swipeIndicator.classList.add('visible');
306
+
307
+ // Set direction class
308
+ this.swipeIndicator.classList.toggle('direction-next', direction === 1);
309
+ this.swipeIndicator.classList.toggle('direction-prev', direction === -1);
310
+
311
+ // Update progress (bar width)
312
+ const percent = Math.round(progress * 100);
313
+ bar.style.width = `${percent}%`;
314
+
315
+ // Threshold reached state
316
+ const thresholdReached = progress >= 1;
317
+ this.swipeIndicator.classList.toggle('threshold-reached', thresholdReached);
318
+
319
+ // Update label
320
+ if (thresholdReached) {
321
+ label.textContent = direction === 1 ? 'Next tab →' : '← Prev tab';
322
+ } else {
323
+ label.textContent = `${percent}%`;
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Flash indicator to confirm tab switch
329
+ */
330
+ flashIndicator(direction) {
331
+ if (!this.swipeIndicator) return;
332
+
333
+ this.swipeIndicator.classList.add('visible', 'flash');
334
+ this.swipeIndicator.classList.toggle('direction-next', direction === 1);
335
+ this.swipeIndicator.classList.toggle('direction-prev', direction === -1);
336
+
337
+ const bar = this.swipeIndicator.querySelector('.swipe-indicator-bar');
338
+ bar.style.width = '100%';
339
+
340
+ const label = this.swipeIndicator.querySelector('.swipe-indicator-label');
341
+ label.textContent = direction === 1 ? 'Next tab →' : '← Prev tab';
342
+
343
+ // Remove flash after animation
344
+ setTimeout(() => {
345
+ this.swipeIndicator.classList.remove('flash');
346
+ this.hideIndicator();
347
+ }, 300);
348
+ }
349
+
350
+ /**
351
+ * Hide the indicator
352
+ */
353
+ hideIndicator() {
354
+ if (!this.swipeIndicator) return;
355
+ this.swipeIndicator.classList.remove('visible', 'threshold-reached', 'direction-next', 'direction-prev');
356
+
357
+ const bar = this.swipeIndicator.querySelector('.swipe-indicator-bar');
358
+ if (bar) bar.style.width = '0%';
359
+ }
360
+
361
+ /**
362
+ * Check if element is inside a floating overlay (widget, modal, dialog)
363
+ * These should not trigger swipe-to-switch-tab gestures
364
+ */
365
+ isInsideOverlay(element) {
366
+ // Selectors for floating UI elements that should block swipe gestures
367
+ const overlaySelectors = [
368
+ '.widget', // All widgets (floating, bottom-sheet, modal, sidebar)
369
+ '.modal', // Legacy modals
370
+ '#modal-overlay', // Modal overlay
371
+ '.prompt-dialog', // Prompt dialogs
372
+ '.prompt-dialog-overlay',
373
+ '.context-menu', // Context menus
374
+ '.tabs-overview-dropdown', // Tab overview dropdown
375
+ ];
376
+
377
+ return element.closest(overlaySelectors.join(', ')) !== null;
378
+ }
379
+
380
+ /**
381
+ * Check if element or ancestors have horizontal scroll
382
+ */
383
+ hasHorizontalScroll(element) {
384
+ let el = element;
385
+ while (el && el !== document.body) {
386
+ if (el.scrollWidth > el.clientWidth) {
387
+ const style = window.getComputedStyle(el);
388
+ const overflow = style.overflowX;
389
+ if (overflow === 'auto' || overflow === 'scroll') {
390
+ return true;
391
+ }
392
+ }
393
+ el = el.parentElement;
394
+ }
395
+ return false;
396
+ }
397
+
398
+ /**
399
+ * Trigger tab switch
400
+ */
401
+ triggerTabSwitch(direction, source) {
402
+ // direction: 1 = next, -1 = prev
403
+ if (typeof this.app?.cycleTab === 'function') {
404
+ // Temporarily suppress focus on the message input to prevent
405
+ // iOS keyboard popup during gesture-based tab switch.
406
+ // Covers ALL focus paths (click handlers, reconnect, rAF callbacks).
407
+ const input = this.app.els?.messageInput;
408
+ if (input && !input._originalFocus) {
409
+ input._originalFocus = input.focus;
410
+ input.focus = () => {};
411
+ setTimeout(() => {
412
+ if (input._originalFocus) {
413
+ input.focus = input._originalFocus;
414
+ delete input._originalFocus;
415
+ }
416
+ }, 300);
417
+ }
418
+
419
+ this.app.cycleTab(direction);
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Setup History API trap to catch any navigation that slips through
425
+ */
426
+ setupHistoryTrap() {
427
+ // Push initial state so there's something to "go back to"
428
+ history.pushState({ gesture: true }, '', location.href);
429
+
430
+ // Catch popstate (back/forward navigation)
431
+ window.addEventListener('popstate', (e) => {
432
+ // Re-push to prevent actual navigation
433
+ history.pushState({ gesture: true }, '', location.href);
434
+
435
+ // Note: We don't trigger tab switch here because we don't know
436
+ // the direction of the navigation attempt. The wheel/touch handlers
437
+ // should catch the gesture before it becomes a popstate.
438
+ });
439
+ }
440
+
441
+ /**
442
+ * Check if running in PWA standalone mode
443
+ */
444
+ isPWAStandalone() {
445
+ return window.matchMedia('(display-mode: standalone)').matches ||
446
+ window.navigator.standalone === true;
447
+ }
448
+ }