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,1763 @@
1
+ /**
2
+ * Widget System - Base styles for all widget types
3
+ *
4
+ * Numbering: 80-xx for widget system
5
+ * - 80: Base widget styles
6
+ * - 81: Bottom sheet specific
7
+ * - 82: Sidebar specific
8
+ * - 83: Floating specific
9
+ * - 84: Tab specific
10
+ * - 85: Modal specific
11
+ */
12
+
13
+ /* ============================================
14
+ CSS Variables for Widget System
15
+ ============================================ */
16
+
17
+ :root {
18
+ /* Widget dimensions */
19
+ --widget-bottom-sheet-half: 45vh;
20
+ --widget-bottom-sheet-full: 85vh;
21
+ --widget-sidebar-width: 280px;
22
+ --widget-floating-min-width: 200px;
23
+ --widget-floating-min-height: 150px;
24
+
25
+ /* Widget z-index layers (above old panels: terminal 900, log-explorer 999, modals 1000) */
26
+ --z-widget-base: 1100;
27
+ --z-widget-sidebar: 1200;
28
+ --z-widget-bottom-sheet: 1300;
29
+ --z-widget-top-sheet: 1350;
30
+ --z-widget-floating: 1500;
31
+ --z-widget-modal-backdrop: 1600;
32
+ --z-widget-modal: 1650;
33
+
34
+ /* Widget transitions */
35
+ --widget-transition-fast: 150ms ease;
36
+ --widget-transition-normal: 250ms ease;
37
+ --widget-transition-slow: 350ms ease;
38
+
39
+ /* Widget header */
40
+ --widget-header-height: var(--layout-widget-header-height);
41
+ --widget-header-bg: var(--surface-secondary, #1a1a1a);
42
+ --widget-header-border: var(--border-color, #333);
43
+
44
+ /* Widget content */
45
+ --widget-bg: var(--surface-primary, #0d0d0d);
46
+ --widget-border-radius: var(--radius-lg);
47
+ --widget-shadow: 0 -4px 20px rgba(0, 0, 0, 0.4);
48
+ }
49
+
50
+ /* ============================================
51
+ Base Widget Container
52
+ ============================================ */
53
+
54
+ .widget {
55
+ position: fixed;
56
+ display: flex;
57
+ flex-direction: column;
58
+ background: var(--widget-bg);
59
+ overflow: hidden;
60
+ transition:
61
+ transform var(--widget-transition-normal),
62
+ height var(--widget-transition-normal),
63
+ width var(--widget-transition-normal),
64
+ opacity var(--widget-transition-fast);
65
+ }
66
+
67
+ .widget-dragging,
68
+ .widget-resizing {
69
+ transition: none !important;
70
+ user-select: none;
71
+ }
72
+
73
+ .widget-loading {
74
+ opacity: 0.7;
75
+ pointer-events: none;
76
+ }
77
+
78
+ .widget-error {
79
+ border-color: var(--accent-red, #ef4444) !important;
80
+ }
81
+
82
+ /* ============================================
83
+ Widget Header
84
+ ============================================ */
85
+
86
+ .widget-header {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: var(--sp-8);
90
+ height: var(--widget-header-height);
91
+ padding: 0 var(--sp-12);
92
+ background: var(--widget-header-bg);
93
+ border-bottom: 1px solid var(--widget-header-border);
94
+ flex-shrink: 0;
95
+ cursor: pointer;
96
+ user-select: none;
97
+ }
98
+
99
+ .widget-drag-handle {
100
+ position: absolute;
101
+ top: 6px;
102
+ left: 50%;
103
+ transform: translateX(-50%);
104
+ width: 36px;
105
+ height: 4px;
106
+ background: var(--text-muted, #666);
107
+ border-radius: var(--radius-xs);
108
+ opacity: 0.5;
109
+ transition: opacity var(--widget-transition-fast), transform var(--widget-transition-fast);
110
+ }
111
+
112
+ .widget-header:hover .widget-drag-handle {
113
+ opacity: 0.8;
114
+ }
115
+
116
+ /* Touch-friendly drag handle - larger touch target and more visible */
117
+ @media (hover: none) and (pointer: coarse) {
118
+ .widget-drag-handle {
119
+ width: 48px;
120
+ height: 5px;
121
+ opacity: 0.7;
122
+ /* Larger touch target with padding */
123
+ padding: var(--sp-12) var(--sp-24);
124
+ margin: -12px -24px;
125
+ background-clip: content-box;
126
+ }
127
+
128
+ /* Visual feedback when dragging */
129
+ .widget-dragging .widget-drag-handle {
130
+ opacity: 1;
131
+ transform: translateX(-50%) scaleX(1.2);
132
+ }
133
+ }
134
+
135
+ .widget-title-icon {
136
+ display: flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ width: 18px;
140
+ height: 18px;
141
+ color: var(--accent);
142
+ }
143
+
144
+ .widget-title-icon svg {
145
+ width: 100%;
146
+ height: 100%;
147
+ }
148
+
149
+ .widget-title {
150
+ font-weight: 500;
151
+ font-size: var(--font-size-base);
152
+ color: var(--text-primary, #fff);
153
+ }
154
+
155
+ .widget-summary {
156
+ font-size: var(--font-size-xs);
157
+ color: var(--text-muted, #888);
158
+ margin-left: 4px;
159
+ }
160
+
161
+ .widget-header-spacer {
162
+ flex: 1;
163
+ }
164
+
165
+ .widget-actions {
166
+ display: flex;
167
+ align-items: center;
168
+ gap: var(--sp-4);
169
+ }
170
+
171
+ .widget-header-btn {
172
+ position: relative;
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ width: var(--layout-btn-sm);
177
+ height: var(--layout-btn-sm);
178
+ padding: 0;
179
+ border: none;
180
+ border-radius: var(--radius-md);
181
+ background: transparent;
182
+ color: var(--text-secondary, #aaa);
183
+ cursor: pointer;
184
+ transition: all var(--widget-transition-fast);
185
+ }
186
+
187
+ .widget-header-btn:hover {
188
+ background: var(--surface-hover, #333);
189
+ color: var(--text-primary, #fff);
190
+ }
191
+
192
+ .widget-header-btn.is-active {
193
+ background: var(--accent-muted, rgba(var(--accent-rgb), 0.2));
194
+ color: var(--accent);
195
+ }
196
+
197
+ .widget-header-btn svg {
198
+ width: 16px;
199
+ height: 16px;
200
+ }
201
+
202
+ .widget-close:hover {
203
+ background: var(--accent-red, #ef4444);
204
+ color: white;
205
+ }
206
+
207
+ .widget-transform-btn {
208
+ opacity: 0.6;
209
+ }
210
+
211
+ .widget-transform-btn:hover {
212
+ opacity: 1;
213
+ }
214
+
215
+ /* ============================================
216
+ Widget Content
217
+ ============================================ */
218
+
219
+ .widget-content-wrapper {
220
+ flex: 1;
221
+ display: flex;
222
+ flex-direction: column;
223
+ overflow: hidden;
224
+ min-height: 0;
225
+ /* iPadOS: overflow:hidden creates an invisible scroll port that captures touch events.
226
+ Let both directions pass through to child scroll containers. */
227
+ touch-action: pan-x pan-y;
228
+ }
229
+
230
+ .widget-content {
231
+ flex: 1;
232
+ overflow: auto;
233
+ -webkit-overflow-scrolling: touch;
234
+ overscroll-behavior: contain;
235
+ }
236
+
237
+ /* ============================================
238
+ Bottom Sheet Widget
239
+ ============================================ */
240
+
241
+ /* Backdrop for bottom sheet - tappable to dismiss */
242
+ .widget-bottom-sheet-backdrop {
243
+ position: fixed;
244
+ inset: 0;
245
+ background: rgba(0, 0, 0, 0.4);
246
+ opacity: 0;
247
+ pointer-events: none;
248
+ transition: opacity var(--widget-transition-normal);
249
+ z-index: calc(var(--z-widget-bottom-sheet) - 1);
250
+ -webkit-tap-highlight-color: transparent;
251
+ }
252
+
253
+ .widget-bottom-sheet-backdrop.visible {
254
+ opacity: 1;
255
+ pointer-events: auto;
256
+ }
257
+
258
+ /* Tap feedback */
259
+ .widget-bottom-sheet-backdrop:active {
260
+ background: rgba(0, 0, 0, 0.5);
261
+ }
262
+
263
+ .widget-bottom-sheet {
264
+ bottom: 0;
265
+ left: 0;
266
+ right: 0;
267
+ height: var(--widget-height, 0);
268
+ border-radius: var(--widget-border-radius) var(--widget-border-radius) 0 0;
269
+ box-shadow: var(--widget-shadow);
270
+ transform: translateY(100%);
271
+ z-index: var(--z-widget-bottom-sheet);
272
+ }
273
+
274
+ .widget-bottom-sheet.widget-collapsed {
275
+ transform: translateY(100%);
276
+ pointer-events: none;
277
+ }
278
+
279
+ .widget-bottom-sheet.widget-half,
280
+ .widget-bottom-sheet.widget-full {
281
+ transform: translateY(0);
282
+ pointer-events: auto;
283
+ }
284
+
285
+ /* ============================================
286
+ Top Sheet Widget
287
+ ============================================ */
288
+
289
+ .widget-top-sheet {
290
+ top: 0;
291
+ left: 0;
292
+ right: 0;
293
+ height: var(--widget-height, 0);
294
+ border-radius: 0 0 var(--widget-border-radius) var(--widget-border-radius);
295
+ box-shadow: var(--widget-shadow);
296
+ transform: translateY(-100%);
297
+ z-index: var(--z-widget-top-sheet);
298
+ }
299
+
300
+ .widget-top-sheet.widget-collapsed {
301
+ transform: translateY(-100%);
302
+ pointer-events: none;
303
+ }
304
+
305
+ .widget-top-sheet.widget-half,
306
+ .widget-top-sheet.widget-full {
307
+ transform: translateY(0);
308
+ pointer-events: auto;
309
+ }
310
+
311
+ /* Top sheet drag handle at bottom (moved from header to widget container in JS) */
312
+ .widget-top-sheet > .widget-drag-handle {
313
+ position: static;
314
+ transform: none;
315
+ width: 100%;
316
+ height: auto;
317
+ padding: var(--sp-8) 0;
318
+ margin: 0;
319
+ flex-shrink: 0;
320
+ display: flex;
321
+ justify-content: center;
322
+ background: transparent;
323
+ border-top: 1px solid var(--border-primary);
324
+ border-bottom: none;
325
+ border-radius: 0;
326
+ cursor: ns-resize;
327
+ opacity: 0.7;
328
+ }
329
+
330
+ .widget-top-sheet > .widget-drag-handle::after {
331
+ content: '';
332
+ width: 48px;
333
+ height: 5px;
334
+ background: var(--text-muted, #666);
335
+ border-radius: var(--radius-sm);
336
+ }
337
+
338
+ /* Top sheet header adjustments */
339
+ .widget-top-sheet .widget-header {
340
+ border-bottom: 1px solid var(--border-primary);
341
+ }
342
+
343
+ /* ============================================
344
+ Sidebar Widget
345
+ ============================================ */
346
+
347
+ .widget-sidebar-left,
348
+ .widget-sidebar-right {
349
+ top: var(--header-height, 48px);
350
+ bottom: 0;
351
+ width: var(--widget-width, var(--widget-sidebar-width));
352
+ border-radius: 0;
353
+ z-index: var(--z-widget-sidebar);
354
+ }
355
+
356
+ .widget-sidebar-left {
357
+ left: 0;
358
+ transform: translateX(-100%);
359
+ border-right: 1px solid var(--widget-header-border);
360
+ }
361
+
362
+ .widget-sidebar-right {
363
+ right: 0;
364
+ transform: translateX(100%);
365
+ border-left: 1px solid var(--widget-header-border);
366
+ }
367
+
368
+ .widget-sidebar-left.widget-open,
369
+ .widget-sidebar-left.widget-visible,
370
+ .widget-sidebar-right.widget-open,
371
+ .widget-sidebar-right.widget-visible {
372
+ transform: translateX(0);
373
+ }
374
+
375
+ .widget-sidebar-left.widget-collapsed,
376
+ .widget-sidebar-right.widget-collapsed {
377
+ pointer-events: none;
378
+ }
379
+
380
+ /* Sidebar resize handle */
381
+ .widget-sidebar-left .widget-resize-handle.widget-resize-right,
382
+ .widget-sidebar-right .widget-resize-handle.widget-resize-left {
383
+ position: absolute;
384
+ top: 0;
385
+ bottom: 0;
386
+ width: 6px;
387
+ cursor: ew-resize;
388
+ background: transparent;
389
+ transition: background var(--widget-transition-fast);
390
+ }
391
+
392
+ .widget-sidebar-left .widget-resize-handle.widget-resize-right {
393
+ right: 0;
394
+ }
395
+
396
+ .widget-sidebar-right .widget-resize-handle.widget-resize-left {
397
+ left: 0;
398
+ }
399
+
400
+ .widget-resize-handle:hover {
401
+ background: var(--accent);
402
+ opacity: 0.3;
403
+ }
404
+
405
+ /* ============================================
406
+ Floating Widget
407
+ ============================================ */
408
+
409
+ .widget-floating,
410
+ .widget-floating-window {
411
+ /* Belt-and-braces fallback: JS sets --widget-x/--widget-y on init, where
412
+ the real default spawn is computed (top of the screen, just right of the
413
+ chat column). Here we can only approximate it with the right edge. */
414
+ left: var(--widget-x, calc(100vw - var(--widget-width, 700px) - 20px));
415
+ top: var(--widget-y, 60px);
416
+ width: var(--widget-width, 700px);
417
+ height: var(--widget-height, 500px);
418
+ min-width: var(--widget-floating-min-width);
419
+ min-height: var(--widget-floating-min-height);
420
+ border-radius: var(--widget-border-radius);
421
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
422
+ border: 1px solid var(--widget-header-border);
423
+ outline: none;
424
+ z-index: var(--z-widget-floating);
425
+ /* Override base overflow:hidden to allow resize handles to extend outside */
426
+ overflow: visible;
427
+ }
428
+
429
+ .widget-floating.widget-hidden,
430
+ .widget-floating.widget-collapsed {
431
+ opacity: 0;
432
+ pointer-events: none;
433
+ transform: scale(0.95);
434
+ /* visibility:hidden is the real fix for the "scroll dies in the area
435
+ a floating widget used to occupy" bug. CSS `pointer-events:none`
436
+ on a parent does NOT cascade through iframes in WebKit/iPadOS — a
437
+ collapsed widget with an iframe (browser, HTML preview) silently
438
+ captures wheel/touch events at the chat behind, even after we set
439
+ opacity:0. `visibility:hidden` IS inherited, applies to iframes,
440
+ and removes them from hit-testing in every engine.
441
+
442
+ The transition-delay on `visibility` matches the opacity fade so
443
+ the close animation plays first, THEN visibility snaps to hidden.
444
+ Without the delay it would disappear instantly. */
445
+ visibility: hidden;
446
+ transition: opacity var(--widget-transition-fast),
447
+ transform var(--widget-transition-fast),
448
+ visibility 0s var(--widget-transition-fast);
449
+ }
450
+
451
+ /* Defense-in-depth cascade for engines that DO honour pointer-events
452
+ on iframes — costs nothing if visibility:hidden already did the job. */
453
+ .widget-floating.widget-hidden *,
454
+ .widget-floating.widget-collapsed * {
455
+ pointer-events: none;
456
+ }
457
+
458
+ .widget-floating.widget-visible {
459
+ visibility: visible;
460
+ opacity: 1;
461
+ pointer-events: auto;
462
+ transform: scale(1);
463
+ /* No delay on the show side — visibility flips to visible immediately
464
+ so the opacity 0→1 fade is actually painted. */
465
+ transition: opacity var(--widget-transition-fast),
466
+ transform var(--widget-transition-fast),
467
+ visibility 0s 0s;
468
+ }
469
+
470
+ .widget-floating.widget-maximized {
471
+ left: 0 !important;
472
+ top: 0 !important;
473
+ width: 100vw !important;
474
+ height: 100vh !important;
475
+ border-radius: 0;
476
+ }
477
+
478
+ /* Floating header is draggable */
479
+ .widget-floating .widget-header {
480
+ cursor: move;
481
+ }
482
+
483
+ .widget-floating .widget-drag-handle {
484
+ display: none; /* No handle bar for floating */
485
+ }
486
+
487
+ /* Floating resize handles */
488
+ .widget-floating .widget-resize-handle,
489
+ .widget-floating-window .widget-resize-handle {
490
+ position: absolute;
491
+ background: transparent;
492
+ z-index: 10;
493
+ transition: background 0.15s ease;
494
+ }
495
+
496
+ /* Show visual feedback on hover - subtle highlight */
497
+ .widget-floating .widget-resize-handle:hover,
498
+ .widget-floating-window .widget-resize-handle:hover {
499
+ background: rgba(99, 102, 241, 0.3);
500
+ }
501
+
502
+ .widget-floating .widget-resize-handle:active,
503
+ .widget-floating-window .widget-resize-handle:active {
504
+ background: rgba(99, 102, 241, 0.5);
505
+ }
506
+
507
+ .widget-floating .widget-resize-n,
508
+ .widget-floating .widget-resize-s,
509
+ .widget-floating-window .widget-resize-n,
510
+ .widget-floating-window .widget-resize-s {
511
+ left: 10px;
512
+ right: 10px;
513
+ height: 8px;
514
+ cursor: ns-resize;
515
+ }
516
+
517
+ .widget-floating .widget-resize-n,
518
+ .widget-floating-window .widget-resize-n { top: -2px; }
519
+ .widget-floating .widget-resize-s,
520
+ .widget-floating-window .widget-resize-s { bottom: -2px; }
521
+
522
+ .widget-floating .widget-resize-e,
523
+ .widget-floating .widget-resize-w,
524
+ .widget-floating-window .widget-resize-e,
525
+ .widget-floating-window .widget-resize-w {
526
+ top: 10px;
527
+ bottom: 10px;
528
+ width: 8px;
529
+ cursor: ew-resize;
530
+ }
531
+
532
+ .widget-floating .widget-resize-e,
533
+ .widget-floating-window .widget-resize-e { right: -2px; }
534
+ .widget-floating .widget-resize-w,
535
+ .widget-floating-window .widget-resize-w { left: -2px; }
536
+
537
+ .widget-floating .widget-resize-ne,
538
+ .widget-floating .widget-resize-nw,
539
+ .widget-floating .widget-resize-se,
540
+ .widget-floating .widget-resize-sw,
541
+ .widget-floating-window .widget-resize-ne,
542
+ .widget-floating-window .widget-resize-nw,
543
+ .widget-floating-window .widget-resize-se,
544
+ .widget-floating-window .widget-resize-sw {
545
+ width: 16px;
546
+ height: 16px;
547
+ }
548
+
549
+ .widget-floating .widget-resize-ne,
550
+ .widget-floating-window .widget-resize-ne { top: -4px; right: -4px; cursor: nesw-resize; }
551
+ .widget-floating .widget-resize-nw,
552
+ .widget-floating-window .widget-resize-nw { top: -4px; left: -4px; cursor: nwse-resize; }
553
+ .widget-floating .widget-resize-se,
554
+ .widget-floating-window .widget-resize-se { bottom: -4px; right: -4px; cursor: nwse-resize; }
555
+ .widget-floating .widget-resize-sw,
556
+ .widget-floating-window .widget-resize-sw { bottom: -4px; left: -4px; cursor: nesw-resize; }
557
+
558
+ /* Visual corner indicators (resize grip) */
559
+ .widget-floating .widget-resize-se::after,
560
+ .widget-floating .widget-resize-sw::after,
561
+ .widget-floating-window .widget-resize-se::after,
562
+ .widget-floating-window .widget-resize-sw::after {
563
+ content: '';
564
+ position: absolute;
565
+ bottom: 6px;
566
+ width: 8px;
567
+ height: 2px;
568
+ background: var(--text-muted, #666);
569
+ border-radius: 1px; /* fixed: half-height of the 2px dash */
570
+ opacity: 0.4;
571
+ transition: opacity 0.15s;
572
+ }
573
+
574
+ .widget-floating .widget-resize-se::after,
575
+ .widget-floating-window .widget-resize-se::after { right: 6px; }
576
+ .widget-floating .widget-resize-sw::after,
577
+ .widget-floating-window .widget-resize-sw::after { left: 6px; }
578
+
579
+ .widget-floating .widget-resize-se:hover::after,
580
+ .widget-floating .widget-resize-sw:hover::after,
581
+ .widget-floating-window .widget-resize-se:hover::after,
582
+ .widget-floating-window .widget-resize-sw:hover::after {
583
+ opacity: 0.8;
584
+ }
585
+
586
+ /* Stacked lines for corner grip effect */
587
+ .widget-floating .widget-resize-se::before,
588
+ .widget-floating .widget-resize-sw::before,
589
+ .widget-floating-window .widget-resize-se::before,
590
+ .widget-floating-window .widget-resize-sw::before {
591
+ content: '';
592
+ position: absolute;
593
+ bottom: 10px;
594
+ width: 5px;
595
+ height: 2px;
596
+ background: var(--text-muted, #666);
597
+ border-radius: 1px; /* fixed: half-height of the 2px dash */
598
+ opacity: 0.3;
599
+ transition: opacity 0.15s;
600
+ }
601
+
602
+ .widget-floating .widget-resize-se::before,
603
+ .widget-floating-window .widget-resize-se::before { right: 6px; }
604
+ .widget-floating .widget-resize-sw::before,
605
+ .widget-floating-window .widget-resize-sw::before { left: 6px; }
606
+
607
+ .widget-floating .widget-resize-se:hover::before,
608
+ .widget-floating .widget-resize-sw:hover::before,
609
+ .widget-floating-window .widget-resize-se:hover::before,
610
+ .widget-floating-window .widget-resize-sw:hover::before {
611
+ opacity: 0.6;
612
+ }
613
+
614
+ /* Snap preview overlays */
615
+ .widget-snap-preview-left::before,
616
+ .widget-snap-preview-right::before,
617
+ .widget-snap-preview-top::before,
618
+ .widget-snap-preview-bottom::before {
619
+ content: '';
620
+ position: fixed;
621
+ background: var(--accent);
622
+ opacity: 0.15;
623
+ z-index: calc(var(--z-widget-floating) - 1);
624
+ pointer-events: none;
625
+ transition: all var(--widget-transition-fast);
626
+ }
627
+
628
+ .widget-snap-preview-left::before {
629
+ left: 0;
630
+ top: 0;
631
+ width: 50%;
632
+ height: 100%;
633
+ }
634
+
635
+ .widget-snap-preview-right::before {
636
+ right: 0;
637
+ top: 0;
638
+ width: 50%;
639
+ height: 100%;
640
+ }
641
+
642
+ .widget-snap-preview-top::before {
643
+ left: 0;
644
+ top: 0;
645
+ width: 100%;
646
+ height: 100%;
647
+ }
648
+
649
+ .widget-snap-preview-bottom::before {
650
+ left: 0;
651
+ bottom: 0;
652
+ width: 100%;
653
+ height: 50%;
654
+ }
655
+
656
+ /* ============================================
657
+ Tab Widget (fullscreen view)
658
+ ============================================ */
659
+
660
+ /* Container for tab view - fullscreen overlay */
661
+ .widget.widget-tab-view {
662
+ position: fixed;
663
+ inset: 0;
664
+ width: 100%;
665
+ max-width: none;
666
+ height: 100%;
667
+ border-radius: 0;
668
+ z-index: var(--z-widget-modal);
669
+ display: none;
670
+ flex-direction: column;
671
+ background: var(--widget-bg);
672
+ }
673
+
674
+ .widget.widget-tab-view.widget-active,
675
+ .widget.widget-tab-view.widget-tab-visible {
676
+ display: flex;
677
+ }
678
+
679
+ /* Show header for standalone tab views (with back button) */
680
+ .widget.widget-tab-view .widget-header {
681
+ display: flex;
682
+ background: var(--widget-header-bg);
683
+ border-bottom: 1px solid var(--widget-header-border);
684
+ }
685
+
686
+ /* Tab bar button element (NOT the container) */
687
+ .widget-tab-btn {
688
+ display: flex;
689
+ align-items: center;
690
+ gap: var(--sp-6);
691
+ padding: var(--sp-6) var(--sp-12);
692
+ background: transparent;
693
+ border-radius: var(--radius-sm) var(--radius-sm) 0 0;
694
+ cursor: pointer;
695
+ user-select: none;
696
+ transition: all var(--widget-transition-fast);
697
+ max-width: 180px;
698
+ }
699
+
700
+ .widget-tab-btn:hover {
701
+ background: var(--surface-hover, #333);
702
+ }
703
+
704
+ .widget-tab-btn.widget-tab-active {
705
+ background: var(--surface-primary, #0d0d0d);
706
+ }
707
+
708
+ .widget-tab-btn .widget-tab-icon {
709
+ display: flex;
710
+ width: 14px;
711
+ height: 14px;
712
+ color: var(--text-muted, #888);
713
+ }
714
+
715
+ .widget-tab-btn .widget-tab-icon svg {
716
+ width: 100%;
717
+ height: 100%;
718
+ }
719
+
720
+ .widget-tab-btn .widget-tab-title {
721
+ font-size: var(--font-size-sm);
722
+ color: var(--text-secondary, #aaa);
723
+ white-space: nowrap;
724
+ overflow: hidden;
725
+ text-overflow: ellipsis;
726
+ }
727
+
728
+ .widget-tab-btn.widget-tab-active .widget-tab-title {
729
+ color: var(--text-primary, #fff);
730
+ }
731
+
732
+ .widget-tab-btn .widget-tab-close {
733
+ display: flex;
734
+ align-items: center;
735
+ justify-content: center;
736
+ width: 16px;
737
+ height: 16px;
738
+ padding: 0;
739
+ border: none;
740
+ border-radius: var(--radius-sm);
741
+ background: transparent;
742
+ color: var(--text-muted, #888);
743
+ font-size: var(--font-size-md);
744
+ line-height: 1;
745
+ cursor: pointer;
746
+ opacity: 0;
747
+ transition: all var(--widget-transition-fast);
748
+ }
749
+
750
+ .widget-tab-btn:hover .widget-tab-close {
751
+ opacity: 1;
752
+ }
753
+
754
+ .widget-tab-btn .widget-tab-close:hover {
755
+ background: var(--accent-red, #ef4444);
756
+ color: white;
757
+ }
758
+
759
+ .widget-tab-btn.widget-tab-dirty .widget-tab-title::after {
760
+ content: ' •';
761
+ color: var(--accent-orange, #f59e0b);
762
+ }
763
+
764
+ /* ============================================
765
+ Modal Widget
766
+ ============================================ */
767
+
768
+ .widget-modal-backdrop {
769
+ position: fixed;
770
+ inset: 0;
771
+ background: rgba(0, 0, 0, 0.6);
772
+ backdrop-filter: blur(2px);
773
+ opacity: 0;
774
+ pointer-events: none;
775
+ /* See the .widget-modal-dialog note below — a closed backdrop is a
776
+ full-viewport fixed box, so it needs visibility:hidden for the same
777
+ reason the dialog does. */
778
+ visibility: hidden;
779
+ transition: opacity var(--widget-transition-normal),
780
+ visibility 0s var(--widget-transition-normal);
781
+ z-index: var(--z-widget-modal-backdrop);
782
+ }
783
+
784
+ .widget-modal-backdrop-visible {
785
+ opacity: 1;
786
+ pointer-events: auto;
787
+ visibility: visible;
788
+ transition: opacity var(--widget-transition-normal),
789
+ visibility 0s 0s;
790
+ }
791
+
792
+ .widget-modal-dialog {
793
+ position: fixed;
794
+ top: 50%;
795
+ left: 50%;
796
+ transform: translate(-50%, -50%) scale(0.95);
797
+ width: var(--widget-width, auto);
798
+ max-width: var(--widget-max-width, 90vw);
799
+ max-height: var(--widget-max-height, 90vh);
800
+ border-radius: var(--widget-border-radius);
801
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
802
+ opacity: 0;
803
+ pointer-events: none;
804
+
805
+ /* visibility:hidden is load-bearing — same bug .widget-floating documents
806
+ above, and modals are the worse case: a closed modal is never removed
807
+ from the DOM and stays laid out at up to 95vw x 95vh dead-centre, so it
808
+ blankets nearly the whole viewport. `opacity:0` + `pointer-events:none`
809
+ is not enough on WebKit/iPadOS, where the inherited pointer-events does
810
+ not reliably suppress hit-testing (it never cascades into iframes at
811
+ all). The symptom: right-clicking a .turn-file-pill in the chat behind
812
+ a closed image gallery hit the GALLERY's capture-phase contextmenu
813
+ listener instead, serving the image menu for the last-viewed image, and
814
+ hover/tooltips died anywhere the ghost overlapped. `visibility` IS
815
+ inherited and removes the subtree from hit-testing in every engine.
816
+
817
+ The 0s delay matches the fade so the close animation still plays before
818
+ visibility snaps to hidden; the visible rule flips it back with no
819
+ delay so the 0->1 fade is actually painted. Note this replaces the old
820
+ `transition: all` — it must be an explicit property list for the
821
+ visibility delay to be expressible. */
822
+ visibility: hidden;
823
+ transition: opacity var(--widget-transition-normal),
824
+ transform var(--widget-transition-normal),
825
+ visibility 0s var(--widget-transition-normal);
826
+ z-index: var(--z-widget-modal);
827
+ }
828
+
829
+ .widget-modal-dialog.widget-visible {
830
+ transform: translate(-50%, -50%) scale(1);
831
+ opacity: 1;
832
+ pointer-events: auto;
833
+ visibility: visible;
834
+ transition: opacity var(--widget-transition-normal),
835
+ transform var(--widget-transition-normal),
836
+ visibility 0s 0s;
837
+ }
838
+
839
+ /* Defense-in-depth cascade, mirroring the .widget-floating rule above —
840
+ costs nothing if visibility:hidden already did the job. */
841
+ .widget-modal-dialog:not(.widget-visible) * {
842
+ pointer-events: none;
843
+ }
844
+
845
+ .widget-modal-dialog .widget-drag-handle {
846
+ display: none;
847
+ }
848
+
849
+ /* Prevent body scroll when modal is open */
850
+ body.widget-modal-open {
851
+ overflow: hidden;
852
+ }
853
+
854
+ /* ============================================
855
+ Responsive Adjustments
856
+ ============================================ */
857
+
858
+ @media (max-width: 768px) {
859
+ :root {
860
+ --widget-sidebar-width: 100vw;
861
+ --widget-bottom-sheet-half: 50vh;
862
+ --widget-bottom-sheet-full: 90vh;
863
+ }
864
+
865
+ .widget-floating {
866
+ /* On mobile, floating widgets become bottom sheets */
867
+ left: 0 !important;
868
+ right: 0 !important;
869
+ bottom: 0 !important;
870
+ top: auto !important;
871
+ width: 100% !important;
872
+ max-height: 80vh;
873
+ border-radius: var(--widget-border-radius) var(--widget-border-radius) 0 0;
874
+ }
875
+
876
+ .widget-floating .widget-resize-handle {
877
+ display: none;
878
+ }
879
+ }
880
+
881
+ /* ============================================
882
+ Widget Content Helpers
883
+ ============================================ */
884
+
885
+ /* Loading indicator */
886
+ .widget-loading-indicator {
887
+ display: flex;
888
+ align-items: center;
889
+ justify-content: center;
890
+ padding: var(--sp-48) var(--sp-16);
891
+ color: var(--text-muted, #888);
892
+ font-size: var(--font-size-md);
893
+ }
894
+
895
+ /* Empty state */
896
+ .widget-empty-message {
897
+ display: flex;
898
+ align-items: center;
899
+ justify-content: center;
900
+ padding: var(--sp-48) var(--sp-16);
901
+ color: var(--text-muted, #888);
902
+ text-align: center;
903
+ font-size: var(--font-size-md);
904
+ }
905
+
906
+ /* Error message */
907
+ .widget-error-message {
908
+ display: flex;
909
+ align-items: center;
910
+ justify-content: center;
911
+ padding: var(--sp-48) var(--sp-16);
912
+ color: var(--accent-red, #ef4444);
913
+ text-align: center;
914
+ font-size: var(--font-size-md);
915
+ }
916
+
917
+ /* ============================================
918
+ Changes Widget Content Styling
919
+ ============================================ */
920
+
921
+ /* Override widget content padding for changes list
922
+ NOTE: Use [data-widget-id] attr selector — widget DOM IDs are session-scoped
923
+ (e.g. widget-changes-sess_xxx), so #widget-changes never matches. */
924
+ [data-widget-id="changes"] .widget-content {
925
+ padding: 0;
926
+ }
927
+
928
+ [data-widget-id="changes"] .changes-list {
929
+ padding: var(--sp-12);
930
+ }
931
+
932
+ /* ============================================
933
+ Widget Tab View (in app's main content area)
934
+ ============================================ */
935
+
936
+ /* Widget views - uses .view class pattern like session/editor/terminal views */
937
+ #widget-views.view {
938
+ flex-direction: column;
939
+ overflow: hidden;
940
+ }
941
+
942
+ /* Individual widget tab content */
943
+ .widget-tab-content {
944
+ display: none;
945
+ flex: 1;
946
+ flex-direction: column;
947
+ overflow: hidden;
948
+ min-height: 0;
949
+ padding: 0;
950
+ }
951
+
952
+ .widget-tab-content.active {
953
+ display: flex;
954
+ }
955
+
956
+ /* Terminal in tab needs bottom padding for iPad rounded corners / safe area */
957
+ .widget-tab-content[data-widget-id="terminal"] {
958
+ padding-bottom: max(12px, env(safe-area-inset-bottom, 12px));
959
+ background: #1a1a2e;
960
+ }
961
+
962
+ /* Widget icon in tab bar */
963
+ .tab-widget .widget-icon {
964
+ display: flex;
965
+ align-items: center;
966
+ justify-content: center;
967
+ width: 16px;
968
+ height: 16px;
969
+ }
970
+
971
+ .tab-widget .widget-icon svg {
972
+ width: 14px;
973
+ height: 14px;
974
+ }
975
+
976
+ /* Widget tab styling (matches file/terminal tabs) */
977
+ .tab-widget {
978
+ background: var(--tab-bg, transparent);
979
+ }
980
+
981
+ .tab-widget.active {
982
+ background: var(--tab-active-bg, #1a1a1a);
983
+ }
984
+
985
+ /* ============================================
986
+ Git Widget - Specific Styles
987
+ ============================================ */
988
+
989
+ /* Git widget header summary - branch and badges */
990
+ [data-widget-id="git"] .widget-summary {
991
+ display: flex;
992
+ align-items: center;
993
+ gap: var(--sp-6);
994
+ flex-wrap: nowrap;
995
+ overflow: hidden;
996
+ }
997
+
998
+ .git-summary-branch {
999
+ font-family: var(--font-mono);
1000
+ font-size: var(--font-size-xs);
1001
+ font-weight: 500;
1002
+ color: var(--accent);
1003
+ background: rgba(var(--accent-rgb), 0.15);
1004
+ padding: 2px var(--sp-8);
1005
+ border-radius: var(--radius-sm);
1006
+ white-space: nowrap;
1007
+ max-width: 100px;
1008
+ overflow: hidden;
1009
+ text-overflow: ellipsis;
1010
+ }
1011
+
1012
+ .git-summary-sync {
1013
+ font-family: var(--font-mono);
1014
+ font-size: var(--font-size-xs);
1015
+ font-weight: 600;
1016
+ padding: 2px var(--sp-4);
1017
+ border-radius: var(--radius-sm);
1018
+ }
1019
+
1020
+ .git-summary-sync.ahead {
1021
+ color: var(--accent-green, #22c55e);
1022
+ }
1023
+
1024
+ .git-summary-sync.behind {
1025
+ color: var(--accent-red, #ef4444);
1026
+ }
1027
+
1028
+ .git-summary-badge {
1029
+ display: inline-flex;
1030
+ align-items: center;
1031
+ justify-content: center;
1032
+ min-width: 18px;
1033
+ height: 18px;
1034
+ padding: 0 var(--sp-5);
1035
+ font-family: var(--font-mono);
1036
+ font-size: 10px;
1037
+ font-weight: 600;
1038
+ border-radius: var(--radius-sm);
1039
+ cursor: default;
1040
+ }
1041
+
1042
+ .git-summary-badge.staged {
1043
+ background: rgba(34, 197, 94, 0.2);
1044
+ color: var(--accent-green, #22c55e);
1045
+ }
1046
+
1047
+ .git-summary-badge.modified {
1048
+ background: rgba(245, 158, 11, 0.2);
1049
+ color: var(--accent-orange, #f59e0b);
1050
+ }
1051
+
1052
+ .git-summary-badge.untracked {
1053
+ background: rgba(156, 163, 175, 0.2);
1054
+ color: var(--text-muted, #888);
1055
+ }
1056
+
1057
+ .git-summary-badge.clean {
1058
+ background: rgba(34, 197, 94, 0.2);
1059
+ color: var(--accent-green, #22c55e);
1060
+ }
1061
+
1062
+ /* Git widget content area */
1063
+ [data-widget-id="git"] .widget-content {
1064
+ padding: 0;
1065
+ }
1066
+
1067
+ [data-widget-id="git"] .git-content {
1068
+ padding: var(--sp-12);
1069
+ }
1070
+
1071
+ /* File item - two-line layout for better readability */
1072
+ [data-widget-id="git"] .git-file-item {
1073
+ display: flex;
1074
+ align-items: center;
1075
+ padding: var(--sp-10) var(--sp-12);
1076
+ gap: var(--sp-10);
1077
+ background: var(--bg-secondary, #1a1a1a);
1078
+ border-radius: var(--radius-md);
1079
+ margin-bottom: var(--sp-4);
1080
+ cursor: pointer;
1081
+ transition: background 0.15s ease;
1082
+ }
1083
+
1084
+ [data-widget-id="git"] .git-file-item:hover {
1085
+ background: var(--bg-tertiary, #262626);
1086
+ }
1087
+
1088
+ [data-widget-id="git"] .git-file-item[data-no-diff="true"] {
1089
+ cursor: default;
1090
+ opacity: 0.7;
1091
+ }
1092
+
1093
+ /* Status badge */
1094
+ [data-widget-id="git"] .git-file-status {
1095
+ flex-shrink: 0;
1096
+ width: 22px;
1097
+ height: 22px;
1098
+ display: flex;
1099
+ align-items: center;
1100
+ justify-content: center;
1101
+ font-family: var(--font-mono);
1102
+ font-size: var(--font-size-xs);
1103
+ font-weight: 700;
1104
+ border-radius: var(--radius-sm);
1105
+ background: rgba(255, 255, 255, 0.05);
1106
+ }
1107
+
1108
+ /* File path - show full path with ellipsis in middle */
1109
+ [data-widget-id="git"] .git-file-path {
1110
+ flex: 1;
1111
+ min-width: 0;
1112
+ font-family: var(--font-mono);
1113
+ font-size: var(--font-size-sm);
1114
+ color: var(--text-secondary, #aaa);
1115
+ white-space: nowrap;
1116
+ overflow: hidden;
1117
+ text-overflow: ellipsis;
1118
+ /* Show end of path (filename) when truncating */
1119
+ direction: rtl;
1120
+ text-align: left;
1121
+ }
1122
+
1123
+ [data-widget-id="git"] .git-file-path::before {
1124
+ content: '\200E'; /* LTR mark to fix display */
1125
+ }
1126
+
1127
+ /* Chevron */
1128
+ [data-widget-id="git"] .git-file-chevron {
1129
+ flex-shrink: 0;
1130
+ width: 16px;
1131
+ height: 16px;
1132
+ color: var(--text-muted, #666);
1133
+ opacity: 0.5;
1134
+ transition: opacity 0.15s;
1135
+ }
1136
+
1137
+ [data-widget-id="git"] .git-file-chevron svg {
1138
+ width: 100%;
1139
+ height: 100%;
1140
+ }
1141
+
1142
+ [data-widget-id="git"] .git-file-item:hover .git-file-chevron {
1143
+ opacity: 1;
1144
+ }
1145
+
1146
+ /* Section headers */
1147
+ [data-widget-id="git"] .git-section {
1148
+ margin-bottom: var(--sp-16);
1149
+ }
1150
+
1151
+ [data-widget-id="git"] .git-section-header {
1152
+ display: flex;
1153
+ align-items: center;
1154
+ gap: var(--sp-8);
1155
+ padding: var(--sp-8) var(--sp-4);
1156
+ font-size: var(--font-size-xs);
1157
+ font-weight: 600;
1158
+ color: var(--text-muted, #888);
1159
+ text-transform: uppercase;
1160
+ letter-spacing: 0.5px;
1161
+ }
1162
+
1163
+ [data-widget-id="git"] .git-section-staged .git-section-header {
1164
+ color: var(--accent-green, #22c55e);
1165
+ }
1166
+
1167
+ [data-widget-id="git"] .git-section-modified .git-section-header {
1168
+ color: var(--accent-orange, #f59e0b);
1169
+ }
1170
+
1171
+ [data-widget-id="git"] .git-section-untracked .git-section-header {
1172
+ color: var(--text-muted, #888);
1173
+ }
1174
+
1175
+ [data-widget-id="git"] .git-section-count {
1176
+ display: inline-flex;
1177
+ align-items: center;
1178
+ justify-content: center;
1179
+ min-width: 20px;
1180
+ height: 20px;
1181
+ padding: 0 var(--sp-6);
1182
+ background: rgba(255, 255, 255, 0.1);
1183
+ border-radius: var(--radius-sm);
1184
+ font-size: var(--font-size-xs);
1185
+ font-weight: 500;
1186
+ color: var(--text-secondary, #aaa);
1187
+ }
1188
+
1189
+ /* Empty and loading states */
1190
+ [data-widget-id="git"] .git-loading,
1191
+ [data-widget-id="git"] .git-empty,
1192
+ [data-widget-id="git"] .git-error {
1193
+ display: flex;
1194
+ align-items: center;
1195
+ justify-content: center;
1196
+ padding: var(--sp-48) var(--sp-16);
1197
+ color: var(--text-muted, #888);
1198
+ text-align: center;
1199
+ font-size: var(--font-size-base);
1200
+ }
1201
+
1202
+ [data-widget-id="git"] .git-error {
1203
+ color: var(--accent-red, #ef4444);
1204
+ }
1205
+
1206
+ /* Diff view styles */
1207
+ [data-widget-id="git"] .git-diff-view,
1208
+ [data-widget-id="git"] .git-history-view,
1209
+ [data-widget-id="git"] .git-commit-detail {
1210
+ display: flex;
1211
+ flex-direction: column;
1212
+ height: 100%;
1213
+ }
1214
+
1215
+ [data-widget-id="git"] .git-diff-header,
1216
+ [data-widget-id="git"] .git-history-header,
1217
+ [data-widget-id="git"] .git-commit-detail-header {
1218
+ display: flex;
1219
+ align-items: center;
1220
+ gap: var(--sp-8);
1221
+ padding: var(--sp-8) var(--sp-12);
1222
+ background: var(--bg-secondary, #1a1a1a);
1223
+ border-bottom: 1px solid var(--border-primary, #333);
1224
+ flex-shrink: 0;
1225
+ }
1226
+
1227
+ [data-widget-id="git"] .git-back-btn {
1228
+ display: flex;
1229
+ align-items: center;
1230
+ justify-content: center;
1231
+ width: var(--layout-btn-sm);
1232
+ height: var(--layout-btn-sm);
1233
+ border: none;
1234
+ border-radius: var(--radius-md);
1235
+ background: transparent;
1236
+ color: var(--text-secondary, #aaa);
1237
+ cursor: pointer;
1238
+ transition: all 0.15s;
1239
+ }
1240
+
1241
+ [data-widget-id="git"] .git-back-btn:hover {
1242
+ background: var(--bg-hover, #333);
1243
+ color: var(--text-primary, #fff);
1244
+ }
1245
+
1246
+ [data-widget-id="git"] .git-back-btn svg {
1247
+ width: 16px;
1248
+ height: 16px;
1249
+ }
1250
+
1251
+ [data-widget-id="git"] .git-diff-title,
1252
+ [data-widget-id="git"] .git-history-title {
1253
+ font-weight: 500;
1254
+ font-size: var(--font-size-base);
1255
+ color: var(--text-primary, #fff);
1256
+ font-family: var(--font-mono);
1257
+ }
1258
+
1259
+ [data-widget-id="git"] .git-diff-staged {
1260
+ font-size: 10px;
1261
+ padding: var(--sp-2) var(--sp-6);
1262
+ border-radius: var(--radius-sm);
1263
+ background: rgba(34, 197, 94, 0.15);
1264
+ color: var(--accent-green, #22c55e);
1265
+ text-transform: uppercase;
1266
+ font-weight: 600;
1267
+ }
1268
+
1269
+ [data-widget-id="git"] .git-diff-stats {
1270
+ margin-left: auto;
1271
+ font-size: var(--font-size-sm);
1272
+ display: flex;
1273
+ gap: var(--sp-8);
1274
+ }
1275
+
1276
+ [data-widget-id="git"] .git-diff-stats .added { color: var(--accent-green, #22c55e); }
1277
+ [data-widget-id="git"] .git-diff-stats .removed { color: var(--accent-red, #ef4444); }
1278
+
1279
+ [data-widget-id="git"] .git-diff-container {
1280
+ flex: 1;
1281
+ overflow: auto;
1282
+ padding: var(--sp-8);
1283
+ }
1284
+
1285
+ [data-widget-id="git"] .git-no-diff {
1286
+ padding: var(--sp-24);
1287
+ text-align: center;
1288
+ color: var(--text-muted, #888);
1289
+ font-size: var(--font-size-base);
1290
+ }
1291
+
1292
+ /* Diff hunks */
1293
+ [data-widget-id="git"] .git-hunk {
1294
+ margin-bottom: var(--sp-12);
1295
+ border-radius: var(--radius-md);
1296
+ overflow: hidden;
1297
+ background: var(--bg-secondary, #1a1a1a);
1298
+ border: 1px solid var(--border-primary, #333);
1299
+ }
1300
+
1301
+ [data-widget-id="git"] .git-hunk-header {
1302
+ font-family: var(--font-mono);
1303
+ font-size: var(--font-size-xs);
1304
+ color: var(--accent);
1305
+ background: rgba(var(--accent-rgb), 0.1);
1306
+ padding: var(--sp-6) var(--sp-12);
1307
+ border-bottom: 1px solid var(--border-primary, #333);
1308
+ }
1309
+
1310
+ [data-widget-id="git"] .git-hunk-lines {
1311
+ font-family: var(--font-mono);
1312
+ font-size: var(--font-size-sm);
1313
+ line-height: 1.5;
1314
+ }
1315
+
1316
+ [data-widget-id="git"] .git-diff-line {
1317
+ padding: 2px var(--sp-12);
1318
+ white-space: pre-wrap;
1319
+ word-break: break-all;
1320
+ }
1321
+
1322
+ [data-widget-id="git"] .git-diff-line.added {
1323
+ background: rgba(34, 197, 94, 0.12);
1324
+ color: var(--accent-green, #22c55e);
1325
+ }
1326
+
1327
+ [data-widget-id="git"] .git-diff-line.removed {
1328
+ background: rgba(239, 68, 68, 0.12);
1329
+ color: var(--accent-red, #ef4444);
1330
+ }
1331
+
1332
+ [data-widget-id="git"] .git-diff-line.context {
1333
+ color: var(--text-muted, #888);
1334
+ }
1335
+
1336
+ /* History view - commit list */
1337
+ [data-widget-id="git"] .git-commit-list {
1338
+ flex: 1;
1339
+ overflow-y: auto;
1340
+ padding: var(--sp-8);
1341
+ }
1342
+
1343
+ [data-widget-id="git"] .git-commit-item {
1344
+ display: flex;
1345
+ align-items: center;
1346
+ gap: var(--sp-12);
1347
+ padding: var(--sp-12);
1348
+ background: var(--bg-secondary, #1a1a1a);
1349
+ border-radius: var(--radius-md);
1350
+ margin-bottom: var(--sp-4);
1351
+ cursor: pointer;
1352
+ transition: background 0.15s;
1353
+ }
1354
+
1355
+ [data-widget-id="git"] .git-commit-item:hover {
1356
+ background: var(--bg-tertiary, #262626);
1357
+ }
1358
+
1359
+ [data-widget-id="git"] .git-commit-hash {
1360
+ flex-shrink: 0;
1361
+ font-family: var(--font-mono);
1362
+ font-size: var(--font-size-xs);
1363
+ color: var(--accent-orange, #f59e0b);
1364
+ background: rgba(245, 158, 11, 0.1);
1365
+ padding: var(--sp-3) var(--sp-8);
1366
+ border-radius: var(--radius-sm);
1367
+ }
1368
+
1369
+ [data-widget-id="git"] .git-commit-info {
1370
+ flex: 1;
1371
+ min-width: 0;
1372
+ }
1373
+
1374
+ [data-widget-id="git"] .git-commit-subject {
1375
+ font-size: var(--font-size-base);
1376
+ color: var(--text-primary, #fff);
1377
+ white-space: nowrap;
1378
+ overflow: hidden;
1379
+ text-overflow: ellipsis;
1380
+ margin-bottom: 2px;
1381
+ }
1382
+
1383
+ [data-widget-id="git"] .git-commit-meta {
1384
+ font-size: var(--font-size-xs);
1385
+ color: var(--text-muted, #888);
1386
+ display: flex;
1387
+ gap: var(--sp-12);
1388
+ }
1389
+
1390
+ [data-widget-id="git"] .git-commit-chevron {
1391
+ flex-shrink: 0;
1392
+ width: 16px;
1393
+ height: 16px;
1394
+ color: var(--text-muted, #666);
1395
+ opacity: 0.5;
1396
+ }
1397
+
1398
+ [data-widget-id="git"] .git-commit-chevron svg {
1399
+ width: 100%;
1400
+ height: 100%;
1401
+ }
1402
+
1403
+ [data-widget-id="git"] .git-commit-item:hover .git-commit-chevron {
1404
+ opacity: 1;
1405
+ }
1406
+
1407
+ [data-widget-id="git"] .git-load-more {
1408
+ width: 100%;
1409
+ padding: var(--sp-12);
1410
+ margin-top: var(--sp-8);
1411
+ border: 1px dashed var(--border-primary, #333);
1412
+ background: transparent;
1413
+ color: var(--text-secondary, #aaa);
1414
+ border-radius: var(--radius-md);
1415
+ cursor: pointer;
1416
+ font-size: var(--font-size-base);
1417
+ transition: all 0.15s;
1418
+ }
1419
+
1420
+ [data-widget-id="git"] .git-load-more:hover {
1421
+ background: var(--bg-secondary, #1a1a1a);
1422
+ border-style: solid;
1423
+ }
1424
+
1425
+ /* Commit detail view */
1426
+ [data-widget-id="git"] .git-commit-detail-hash {
1427
+ font-family: var(--font-mono);
1428
+ font-size: var(--font-size-sm);
1429
+ color: var(--accent-orange, #f59e0b);
1430
+ }
1431
+
1432
+ [data-widget-id="git"] .git-commit-detail-info {
1433
+ padding: var(--sp-16);
1434
+ border-bottom: 1px solid var(--border-primary, #333);
1435
+ }
1436
+
1437
+ [data-widget-id="git"] .git-commit-detail-subject {
1438
+ font-size: var(--font-size-content);
1439
+ font-weight: 500;
1440
+ color: var(--text-primary, #fff);
1441
+ margin-bottom: 4px;
1442
+ }
1443
+
1444
+ [data-widget-id="git"] .git-commit-detail-body {
1445
+ font-size: var(--font-size-base);
1446
+ color: var(--text-secondary, #aaa);
1447
+ margin: var(--sp-8) 0;
1448
+ white-space: pre-wrap;
1449
+ line-height: 1.5;
1450
+ }
1451
+
1452
+ [data-widget-id="git"] .git-commit-detail-meta {
1453
+ font-size: var(--font-size-sm);
1454
+ color: var(--text-muted, #888);
1455
+ display: flex;
1456
+ gap: var(--sp-16);
1457
+ }
1458
+
1459
+ [data-widget-id="git"] .git-commit-files-header {
1460
+ display: flex;
1461
+ align-items: center;
1462
+ justify-content: space-between;
1463
+ padding: var(--sp-10) var(--sp-16);
1464
+ background: var(--bg-tertiary, #262626);
1465
+ font-size: var(--font-size-sm);
1466
+ color: var(--text-secondary, #aaa);
1467
+ }
1468
+
1469
+ [data-widget-id="git"] .git-commit-stats {
1470
+ display: flex;
1471
+ gap: var(--sp-8);
1472
+ }
1473
+
1474
+ [data-widget-id="git"] .git-commit-stats .added { color: var(--accent-green, #22c55e); }
1475
+ [data-widget-id="git"] .git-commit-stats .removed { color: var(--accent-red, #ef4444); }
1476
+
1477
+ [data-widget-id="git"] .git-commit-files {
1478
+ padding: var(--sp-8) var(--sp-16);
1479
+ border-bottom: 1px solid var(--border-primary, #333);
1480
+ max-height: 150px;
1481
+ overflow-y: auto;
1482
+ }
1483
+
1484
+ [data-widget-id="git"] .git-commit-file {
1485
+ display: flex;
1486
+ align-items: center;
1487
+ justify-content: space-between;
1488
+ padding: var(--sp-6) 0;
1489
+ font-size: var(--font-size-sm);
1490
+ cursor: pointer;
1491
+ transition: color 0.15s;
1492
+ }
1493
+
1494
+ [data-widget-id="git"] .git-commit-file:hover {
1495
+ color: var(--accent);
1496
+ }
1497
+
1498
+ [data-widget-id="git"] .git-commit-file-path {
1499
+ font-family: var(--font-mono);
1500
+ color: var(--text-secondary, #aaa);
1501
+ white-space: nowrap;
1502
+ overflow: hidden;
1503
+ text-overflow: ellipsis;
1504
+ }
1505
+
1506
+ [data-widget-id="git"] .git-commit-file:hover .git-commit-file-path {
1507
+ color: var(--accent);
1508
+ }
1509
+
1510
+ [data-widget-id="git"] .git-commit-file-stats {
1511
+ font-family: var(--font-mono);
1512
+ font-size: var(--font-size-xs);
1513
+ flex-shrink: 0;
1514
+ margin-left: var(--sp-12);
1515
+ }
1516
+
1517
+ [data-widget-id="git"] .git-commit-file-stats .added { color: var(--accent-green, #22c55e); }
1518
+ [data-widget-id="git"] .git-commit-file-stats .removed { color: var(--accent-red, #ef4444); }
1519
+
1520
+ [data-widget-id="git"] .git-commit-diffs {
1521
+ flex: 1;
1522
+ overflow-y: auto;
1523
+ padding: var(--sp-8);
1524
+ }
1525
+
1526
+ [data-widget-id="git"] .git-commit-diff-file {
1527
+ margin-bottom: var(--sp-16);
1528
+ }
1529
+
1530
+ [data-widget-id="git"] .git-commit-diff-file-header {
1531
+ font-family: var(--font-mono);
1532
+ font-size: var(--font-size-sm);
1533
+ color: var(--text-primary, #fff);
1534
+ background: var(--bg-tertiary, #262626);
1535
+ padding: var(--sp-8) var(--sp-12);
1536
+ border-radius: var(--radius-md) var(--radius-md) 0 0;
1537
+ border: 1px solid var(--border-primary, #333);
1538
+ border-bottom: none;
1539
+ }
1540
+
1541
+ /* ============================================
1542
+ Terminal Widget Styles
1543
+ ============================================ */
1544
+
1545
+ [data-widget-id="terminal"] {
1546
+ /* Match terminal bg so no dark strip bleeds between content border-radius and widget border */
1547
+ background: #1a1a2e;
1548
+ }
1549
+
1550
+ [data-widget-id="terminal"] .widget-content {
1551
+ background: #1a1a2e;
1552
+ padding: 0;
1553
+ overflow: hidden; /* xterm.js handles its own scrolling — auto lets fitAddon overshoot by half a row */
1554
+ }
1555
+
1556
+ .terminal-widget-body {
1557
+ display: flex;
1558
+ flex-direction: column;
1559
+ height: 100%;
1560
+ background: #1a1a2e;
1561
+ position: relative;
1562
+ }
1563
+
1564
+ .terminal-widget-xterm {
1565
+ flex: 1;
1566
+ padding: var(--sp-8);
1567
+ box-sizing: content-box; /* fitAddon.fit() reads getComputedStyle().height — must exclude padding */
1568
+ overflow: hidden;
1569
+ min-height: 0;
1570
+ touch-action: none; /* Prevent browser scroll — xterm.js handles touch internally */
1571
+ -webkit-touch-callout: none; /* Prevent native iOS long-press callout on links */
1572
+ }
1573
+
1574
+ /* Override xterm defaults */
1575
+ .terminal-widget-xterm .xterm {
1576
+ padding: 0;
1577
+ height: 100% !important;
1578
+ max-height: 100% !important;
1579
+ }
1580
+
1581
+ .terminal-widget-xterm .xterm-viewport {
1582
+ background: #1a1a2e !important;
1583
+ max-height: 100% !important;
1584
+ }
1585
+
1586
+ .terminal-widget-xterm .xterm-screen {
1587
+ max-height: 100% !important;
1588
+ }
1589
+
1590
+ /* Hide native OS caret on iPad/iOS - xterm.js has its own cursor */
1591
+ .terminal-widget-xterm .xterm-helper-textarea {
1592
+ caret-color: transparent !important;
1593
+ opacity: 0 !important;
1594
+ }
1595
+
1596
+ .terminal-widget-loading {
1597
+ position: absolute;
1598
+ inset: 0;
1599
+ display: flex;
1600
+ align-items: center;
1601
+ justify-content: center;
1602
+ color: var(--text-muted, #888);
1603
+ font-size: var(--font-size-md);
1604
+ background: #1a1a2e;
1605
+ z-index: 10;
1606
+ }
1607
+
1608
+ .terminal-widget-loading[hidden] {
1609
+ display: none;
1610
+ }
1611
+
1612
+ /* Terminal status in header */
1613
+ .terminal-widget-status {
1614
+ font-size: var(--font-size-xs);
1615
+ font-weight: 400;
1616
+ padding: 2px var(--sp-6);
1617
+ border-radius: var(--radius-sm);
1618
+ background: var(--bg-tertiary, #262626);
1619
+ }
1620
+
1621
+ .terminal-widget-status:empty {
1622
+ display: none;
1623
+ }
1624
+
1625
+ .terminal-widget-status.status-connecting {
1626
+ color: var(--accent-orange, #f59e0b);
1627
+ }
1628
+
1629
+ .terminal-widget-status.status-connected {
1630
+ display: none;
1631
+ }
1632
+
1633
+ .terminal-widget-status.status-disconnected {
1634
+ color: var(--accent-red, #ef4444);
1635
+ background: rgba(239, 68, 68, 0.1);
1636
+ }
1637
+
1638
+ .terminal-widget-status.status-error {
1639
+ color: var(--accent-red, #ef4444);
1640
+ background: rgba(239, 68, 68, 0.1);
1641
+ }
1642
+
1643
+ .terminal-widget-status.status-exited {
1644
+ color: var(--text-muted, #888);
1645
+ }
1646
+
1647
+ /* Terminal widget specific header actions */
1648
+ [data-widget-id="terminal"] .widget-action[title="Kill Terminal"]:hover {
1649
+ color: var(--accent-red, #ef4444);
1650
+ }
1651
+
1652
+ [data-widget-id="terminal"] .widget-action[title="Open in Tab"]:hover {
1653
+ color: var(--accent);
1654
+ }
1655
+
1656
+ /* Floating terminal specific styles - larger default size */
1657
+ [data-widget-id="terminal"].widget-floating {
1658
+ /* Use CSS variables for width/height so resize handles work */
1659
+ /* Default values are set here, FloatingWidget updates --widget-width/height on resize */
1660
+ --widget-width: 900px;
1661
+ --widget-height: 500px;
1662
+ min-width: 400px;
1663
+ min-height: 250px;
1664
+ }
1665
+
1666
+ [data-widget-id="terminal"].widget-floating .widget-content {
1667
+ border-radius: 0 0 var(--widget-border-radius) var(--widget-border-radius);
1668
+ }
1669
+
1670
+ /* Bottom sheet terminal - compact header */
1671
+ [data-widget-id="terminal"].widget-bottom-sheet .widget-header,
1672
+ [data-widget-id="terminal"].widget-top-sheet .widget-header {
1673
+ padding: 0 var(--sp-8);
1674
+ height: 36px;
1675
+ }
1676
+
1677
+ /* ============================================
1678
+ Visibility Scope Selector
1679
+ ============================================ */
1680
+
1681
+ /* Scope button - eye icon with colored dot indicator */
1682
+ .widget-scope-btn {
1683
+ position: relative;
1684
+ }
1685
+
1686
+ .widget-scope-dot {
1687
+ position: absolute;
1688
+ bottom: 3px;
1689
+ right: 3px;
1690
+ width: 7px;
1691
+ height: 7px;
1692
+ border-radius: 50%;
1693
+ border: 1.5px solid var(--widget-bg, #1a1a1a);
1694
+ pointer-events: none;
1695
+ }
1696
+
1697
+ /* Scope dropdown popup */
1698
+ .widget-scope-dropdown {
1699
+ position: absolute;
1700
+ top: 100%;
1701
+ right: 0;
1702
+ margin-top: 4px;
1703
+ min-width: 200px;
1704
+ background: var(--surface-raised, #2a2a2a);
1705
+ border: 1px solid var(--border-subtle, #444);
1706
+ border-radius: var(--radius-md);
1707
+ padding: var(--sp-4);
1708
+ z-index: var(--z-always-top, 4000);
1709
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
1710
+ }
1711
+
1712
+ /* Individual scope option */
1713
+ .widget-scope-option {
1714
+ display: flex;
1715
+ align-items: center;
1716
+ gap: var(--sp-10);
1717
+ padding: var(--sp-5) var(--sp-8);
1718
+ line-height: var(--layout-menu-line-height);
1719
+ border-radius: var(--radius-md);
1720
+ cursor: pointer;
1721
+ transition: background 0.15s;
1722
+ }
1723
+
1724
+ .widget-scope-option:hover {
1725
+ background: var(--surface-hover, #333);
1726
+ }
1727
+
1728
+ .widget-scope-option.active {
1729
+ background: var(--surface-hover, #333);
1730
+ }
1731
+
1732
+ .widget-scope-option.active .widget-scope-option-label {
1733
+ color: var(--text-primary, #fff);
1734
+ }
1735
+
1736
+ /* Colored dot in option row */
1737
+ .widget-scope-option-dot {
1738
+ flex-shrink: 0;
1739
+ width: 10px;
1740
+ height: 10px;
1741
+ border-radius: 50%;
1742
+ }
1743
+
1744
+ /* Text column */
1745
+ .widget-scope-option-text {
1746
+ display: flex;
1747
+ flex-direction: column;
1748
+ gap: 1px;
1749
+ min-width: 0;
1750
+ }
1751
+
1752
+ .widget-scope-option-label {
1753
+ font-size: var(--font-size-base);
1754
+ font-weight: 500;
1755
+ color: var(--text-secondary, #aaa);
1756
+ white-space: nowrap;
1757
+ }
1758
+
1759
+ .widget-scope-option-desc {
1760
+ font-size: var(--font-size-xs);
1761
+ color: var(--text-tertiary, #666);
1762
+ white-space: nowrap;
1763
+ }