@hienlh/ppm 0.19.11 → 0.20.0

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 (536) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/CLAUDE.md +8 -1
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/http-api.md +4 -1
  5. package/dist/web/assets/accounts-settings-section-BQyru31C.js +1 -0
  6. package/dist/web/assets/{ai-resource-editor-iMqzzz5c.js → ai-resource-editor-BgYIPGVP.js} +1 -1
  7. package/dist/web/assets/{ai-settings-section-B-1z-PRb.js → ai-settings-section-Cywmtnps.js} +1 -1
  8. package/dist/web/assets/ai-settings-section-iBRCQvBR.js +1 -0
  9. package/dist/web/assets/{angular-html-C8nsn2VC.js → angular-html-BtJLNcMw.js} +1 -1
  10. package/dist/web/assets/{angular-ts-Caw9nRCH.js → angular-ts-CQiu5F_W.js} +1 -1
  11. package/dist/web/assets/api-client-QfreGirP.js +1 -0
  12. package/dist/web/assets/api-settings-D18Q4Ocp.js +1 -0
  13. package/dist/web/assets/{api-themes-BoOJPqwM.js → api-themes-sSv-6OLk.js} +1 -1
  14. package/dist/web/assets/{apl-Dhu1LORF.js → apl-CKZvgs-w.js} +1 -1
  15. package/dist/web/assets/{appearance-settings-section-2XZgB0mV.js → appearance-settings-section-mhu9T6Fk.js} +1 -1
  16. package/dist/web/assets/architecture-PBZL5I3N-DfR8k8Bc.js +1 -0
  17. package/dist/web/assets/{astro-DwkX9sLZ.js → astro-D0b8ssLD.js} +1 -1
  18. package/dist/web/assets/{audio-preview-CkGZO8Uy.js → audio-preview-B4E5_7TW.js} +1 -1
  19. package/dist/web/assets/{blade-D1fC9Osx.js → blade-DOIpINLw.js} +1 -1
  20. package/dist/web/assets/{bsl-pur-PRip.js → bsl-CJ7_JlQ8.js} +1 -1
  21. package/dist/web/assets/{button-2WCAS8dI.js → button-DX32ffge.js} +1 -1
  22. package/dist/web/assets/{cairo-DDJs9amR.js → cairo-5CpV2T1P.js} +1 -1
  23. package/dist/web/assets/chat-tab-Bs9OD6ss.js +15 -0
  24. package/dist/web/assets/{cobol-Bo0usdoM.js → cobol-BreMVrtc.js} +1 -1
  25. package/dist/web/assets/code-editor-Cv_pzHo7.js +7 -0
  26. package/dist/web/assets/{coffee-DBBsbX1e.js → coffee-D7DoKh5b.js} +1 -1
  27. package/dist/web/assets/{conflict-editor-BpdoTEfv.js → conflict-editor-BnWaMSEa.js} +1 -1
  28. package/dist/web/assets/{context-menu-C13b1uT3.js → context-menu-CJL8L98s.js} +1 -1
  29. package/dist/web/assets/{cpp-6CTO78A-.js → cpp-BnWeWAoE.js} +1 -1
  30. package/dist/web/assets/{crystal-DAlvpAP7.js → crystal-D2pJbFUn.js} +1 -1
  31. package/dist/web/assets/{csv-preview-C3DoHISX.js → csv-preview-DG4YAabr.js} +1 -1
  32. package/dist/web/assets/{data-grid-overlay-editor-iRrpAV0e.js → data-grid-overlay-editor-CbBkhhJa.js} +1 -1
  33. package/dist/web/assets/{database-viewer-CxZ2fdcd.js → database-viewer-B-wA2qT-.js} +1 -1
  34. package/dist/web/assets/diff-viewer-DRtzdfXk.js +4 -0
  35. package/dist/web/assets/{docx-preview-Bgw838ry.js → docx-preview-Xy7SZ7Vf.js} +1 -1
  36. package/dist/web/assets/{edge-D0tZrpC7.js → edge-aqGMtbY3.js} +1 -1
  37. package/dist/web/assets/{edit-diff-preview-DUgmjNre.js → edit-diff-preview-6tzdk7Pn.js} +1 -1
  38. package/dist/web/assets/{elixir-C1E6-o4G.js → elixir-CsYMBLc5.js} +1 -1
  39. package/dist/web/assets/{elm-BKyTfeQX.js → elm-BU8C2gFp.js} +1 -1
  40. package/dist/web/assets/{erb-Cdnr4BMI.js → erb-Z_E49ab8.js} +1 -1
  41. package/dist/web/assets/{erlang-N1237mFq.js → erlang-BRqOjXH9.js} +1 -1
  42. package/dist/web/assets/{esm-ClNnmD9t.js → esm-B-vXxHUd.js} +1 -1
  43. package/dist/web/assets/{explorer-body-Bpe6UX0b.js → explorer-body-uh8oJp6J.js} +2 -2
  44. package/dist/web/assets/explorer-window-content-DLn_4egF.js +1 -0
  45. package/dist/web/assets/{extension-manager-section-D_rKLp-o.js → extension-manager-section-C_ZGYvWf.js} +1 -1
  46. package/dist/web/assets/{extension-webview-kEtrZoRZ.js → extension-webview-DbFWxJpj.js} +1 -1
  47. package/dist/web/assets/{files-settings-section-B0wLfQ9S.js → files-settings-section-BrUbJglA.js} +1 -1
  48. package/dist/web/assets/{fortran-fixed-form-D_f9tVv0.js → fortran-fixed-form-CWbxmDGR.js} +1 -1
  49. package/dist/web/assets/{fsharp-DEJmdhc2.js → fsharp-DKMYbq6I.js} +1 -1
  50. package/dist/web/assets/{gdresource-Dmmrx2gP.js → gdresource-B3yFau4V.js} +1 -1
  51. package/dist/web/assets/{general-settings-section-DZ3xpgwh.js → general-settings-section-B9ZPZVso.js} +1 -1
  52. package/dist/web/assets/{git-commit-qwJ867ig.js → git-commit-BW0p3Ekk.js} +1 -1
  53. package/dist/web/assets/{git-log-panel-BNicD2In.js → git-log-panel-C0jnhmgC.js} +1 -1
  54. package/dist/web/assets/{git-rebase-Dkv8Zw86.js → git-rebase-DrvmQCS7.js} +1 -1
  55. package/dist/web/assets/gitGraph-HDMCJU4V-CPd78aaT.js +1 -0
  56. package/dist/web/assets/{glide-data-grid-CdK5dW5L.js → glide-data-grid-CZVKIum-.js} +6 -6
  57. package/dist/web/assets/{glimmer-js-CcrXn8lQ.js → glimmer-js-BY1XApJJ.js} +1 -1
  58. package/dist/web/assets/{glimmer-ts-CLab3lU7.js → glimmer-ts-DPZtxF8N.js} +1 -1
  59. package/dist/web/assets/{glsl-DXhkG9dU.js → glsl-DZ8G_Hvf.js} +1 -1
  60. package/dist/web/assets/{graphql-Cuqsx8r3.js → graphql-Ck06uCZy.js} +1 -1
  61. package/dist/web/assets/group-chat-tab-DnPtmbPc.js +1 -0
  62. package/dist/web/assets/{hack-C_CBVdBc.js → hack-pLogDwAs.js} +1 -1
  63. package/dist/web/assets/{haml-CBWfzZpv.js → haml-CBqeCQ2A.js} +1 -1
  64. package/dist/web/assets/{handlebars-4e8OR-VI.js → handlebars-B66JmVtp.js} +1 -1
  65. package/dist/web/assets/{html-C5X4urn_.js → html-Dk4wmfwC.js} +1 -1
  66. package/dist/web/assets/{html-derivative-nH-jXfsL.js → html-derivative-CJWqfN51.js} +1 -1
  67. package/dist/web/assets/{http-CQgaG7eu.js → http-CexhotTh.js} +1 -1
  68. package/dist/web/assets/{hurl-B8gidJhu.js → hurl-BScKFk3Z.js} +1 -1
  69. package/dist/web/assets/{hxml-BAK94GX8.js → hxml-DAle7vtu.js} +1 -1
  70. package/dist/web/assets/{image-preview-1kGj4W9R.js → image-preview-fuU4h2nr.js} +1 -1
  71. package/dist/web/assets/index-CHQAPZIX.js +52 -0
  72. package/dist/web/assets/index-CoaVwAF6.css +2 -0
  73. package/dist/web/assets/info-3K5VOQVL-BciNds6R.js +1 -0
  74. package/dist/web/assets/{jinja-BuAjvj8M.js → jinja-yHpyD80t.js} +1 -1
  75. package/dist/web/assets/{jira-watcher-section-DL_boZNh.js → jira-watcher-section-Bjldyhru.js} +1 -1
  76. package/dist/web/assets/{jison-Dhhs26-L.js → jison-BY6WLJVu.js} +1 -1
  77. package/dist/web/assets/{julia-gZavIyll.js → julia-Dd_iYQDT.js} +1 -1
  78. package/dist/web/assets/{just-DDHrFReO.js → just-BTuUKpxF.js} +1 -1
  79. package/dist/web/assets/keybindings-store-DBVXZKp8.js +1 -0
  80. package/dist/web/assets/{keyboard-shortcuts-section-DzQzV49E.js → keyboard-shortcuts-section-D7jaCPrv.js} +1 -1
  81. package/dist/web/assets/{latex-BdGZa8ov.js → latex-Dt3OUlMZ.js} +1 -1
  82. package/dist/web/assets/{liquid-urFfd9Fr.js → liquid-BxPJU2ix.js} +1 -1
  83. package/dist/web/assets/{lua-CcS6tnB5.js → lua-DEGIvn7d.js} +1 -1
  84. package/dist/web/assets/{markdown-renderer-BfoCOrL8.js → markdown-renderer-B4B5oxQS.js} +3 -3
  85. package/dist/web/assets/markdown-renderer-DwHh-jd_.js +1 -0
  86. package/dist/web/assets/{marko-CSQqk4oG.js → marko-BDxwBJur.js} +1 -1
  87. package/dist/web/assets/{mdc-CYIe80m_.js → mdc-B8aXPTg7.js} +1 -1
  88. package/dist/web/assets/{media-url-DBmHJRft.js → media-url-BMeBaB0q.js} +1 -1
  89. package/dist/web/assets/{mobile-bottom-sheet-B3uDlD79.js → mobile-bottom-sheet-CmySDB6I.js} +1 -1
  90. package/dist/web/assets/mobile-explorer-sheet-JJxZYWkV.js +1 -0
  91. package/dist/web/assets/{nextflow-C-W8vX8I.js → nextflow-DBVZnnT_.js} +1 -1
  92. package/dist/web/assets/{nginx-COGi5you.js → nginx-Crpyd-Do.js} +1 -1
  93. package/dist/web/assets/{nim-CPitYGel.js → nim-BSqTBYDj.js} +1 -1
  94. package/dist/web/assets/notification-store-CCWNUHsS.js +1 -0
  95. package/dist/web/assets/{notifications-settings-section-BXCaGBVc.js → notifications-settings-section-DbbX7-Qp.js} +1 -1
  96. package/dist/web/assets/{number-overlay-editor-C_eD-Bdr.js → number-overlay-editor-DRjTIcPH.js} +1 -1
  97. package/dist/web/assets/{overview-panel-Cm2HRtEz.js → overview-panel-DiiA3B_Z.js} +1 -1
  98. package/dist/web/assets/packet-RMMSAZCW-ClD3l2Bs.js +1 -0
  99. package/dist/web/assets/{panel-store-BRrnDO_i.js → panel-store-BmdcSBNb.js} +1 -1
  100. package/dist/web/assets/{pdf-preview-DbRFOtQD.js → pdf-preview-DxNjWa1v.js} +1 -1
  101. package/dist/web/assets/{perl-B0yW3hbb.js → perl-BU0kbB-K.js} +1 -1
  102. package/dist/web/assets/{php-BNMYN5Jp.js → php-D9n1ikHN.js} +1 -1
  103. package/dist/web/assets/pie-UPGHQEXC-PU6kD0rW.js +1 -0
  104. package/dist/web/assets/{postgres-viewer-BrQRqTso.js → postgres-viewer-BScvk5ev.js} +3 -3
  105. package/dist/web/assets/{ppmbot-settings-section-BEV23_SM.js → ppmbot-settings-section-jFA9Ncgo.js} +1 -1
  106. package/dist/web/assets/{process-table-CG8d5eXs.js → process-table-BexeYWQm.js} +1 -1
  107. package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-wWZ6bjwq.js} +1 -1
  108. package/dist/web/assets/{proxy-settings-section-Cw0Wtsv0.js → proxy-settings-section-C_seKq56.js} +1 -1
  109. package/dist/web/assets/{pug-CP5fxsxD.js → pug-BOpaczDr.js} +1 -1
  110. package/dist/web/assets/{qml-CHGpQosY.js → qml-B-cQXhrg.js} +1 -1
  111. package/dist/web/assets/{query-audit-section-50B7mQal.js → query-audit-section-BWXJmPDV.js} +1 -1
  112. package/dist/web/assets/radar-KQ55EAFF-4LzjL0Zt.js +1 -0
  113. package/dist/web/assets/{razor-Cfe0AYo4.js → razor-DFB0pNCh.js} +1 -1
  114. package/dist/web/assets/remote-desktop-mobile-sheet-B--PeL5i.js +2 -0
  115. package/dist/web/assets/{remote-desktop-mobile-view-DPF_b_jd.js → remote-desktop-mobile-view-jgn8nmQa.js} +1 -1
  116. package/dist/web/assets/{remote-desktop-readiness-gate-J7E6355i.js → remote-desktop-readiness-gate-CjDth-W_.js} +1 -1
  117. package/dist/web/assets/{remote-desktop-window-content-0xsAifZH.js → remote-desktop-window-content-CrHAUA03.js} +1 -1
  118. package/dist/web/assets/{rst-DxSSGshb.js → rst-DAXedsgm.js} +1 -1
  119. package/dist/web/assets/{ruby-rbK5SsJa.js → ruby-BCO4polC.js} +1 -1
  120. package/dist/web/assets/{run-in-terminal-DHAvC1AG.js → run-in-terminal-wHKwAnWP.js} +1 -1
  121. package/dist/web/assets/{sas-DDM28fbb.js → sas-DfB5dcFC.js} +1 -1
  122. package/dist/web/assets/schedules-settings-section-DMFn3mYL.js +1 -0
  123. package/dist/web/assets/{scss-TDl-6ro4.js → scss-BknIVgn7.js} +1 -1
  124. package/dist/web/assets/{send-to-chat-BOyUWNKw.js → send-to-chat-BI7-fFpG.js} +1 -1
  125. package/dist/web/assets/{separator-BzGoTlR7.js → separator-W_hJcXPk.js} +1 -1
  126. package/dist/web/assets/{settings-body-CUTsPLea.js → settings-body-Dz2vPTEP.js} +2 -2
  127. package/dist/web/assets/settings-store-CzLnTR8p.js +2 -0
  128. package/dist/web/assets/settings-tab-B5QbsvS4.js +1 -0
  129. package/dist/web/assets/settings-window-content-iM2bPoX5.js +1 -0
  130. package/dist/web/assets/{shaderlab-CCvmDgGS.js → shaderlab-CPu31TpY.js} +1 -1
  131. package/dist/web/assets/{shellsession-BzKS9yKh.js → shellsession-CFX4c_TM.js} +1 -1
  132. package/dist/web/assets/{soy-QfO35nDh.js → soy-rz9hilgm.js} +1 -1
  133. package/dist/web/assets/{sparql-D29RDfp2.js → sparql-Bo8ZDeqE.js} +1 -1
  134. package/dist/web/assets/{sql-query-editor-CwOcDbp4.js → sql-query-editor-C0mGgLfX.js} +1 -1
  135. package/dist/web/assets/{sqlite-viewer-DYdcqZv1.js → sqlite-viewer-Bs3RKf1X.js} +1 -1
  136. package/dist/web/assets/{stata-Be6j_SNv.js → stata-B5J-QMyE.js} +1 -1
  137. package/dist/web/assets/{streaming-store-9_9j70zt.js → streaming-store-9XVmAMfV.js} +1 -1
  138. package/dist/web/assets/{surrealql-CykFjgNG.js → surrealql-Caw1ADnG.js} +1 -1
  139. package/dist/web/assets/{svelte-CdBF8z4-.js → svelte-D3oMVcxz.js} +1 -1
  140. package/dist/web/assets/{system-monitor-body-CugdEvdh.js → system-monitor-body-DvUmEdNe.js} +2 -2
  141. package/dist/web/assets/system-monitor-tab-CHZ5F_ZE.js +1 -0
  142. package/dist/web/assets/{system-monitor-window-content-CJfcQqc2.js → system-monitor-window-content-DjzqoeCN.js} +1 -1
  143. package/dist/web/assets/{tab-host-window-content-5Ga7BheG.js → tab-host-window-content-DKeAr5mD.js} +1 -1
  144. package/dist/web/assets/{tab-store-PZsP5ZwG.js → tab-store-1xYJb0gM.js} +1 -1
  145. package/dist/web/assets/team-member-sheet-Cl9ZB3dl.js +2 -0
  146. package/dist/web/assets/team-member-window-content-DfP7WdFD.js +1 -0
  147. package/dist/web/assets/{templ-BVHE2CNb.js → templ-BAdNyIOL.js} +1 -1
  148. package/dist/web/assets/{terminal-tab-CkxJIjii.js → terminal-tab-J1Fqa_rm.js} +2 -2
  149. package/dist/web/assets/{tex-C8XwrbBw.js → tex-IQ8mELOR.js} +1 -1
  150. package/dist/web/assets/tool-cards-DQghSuKX.js +9 -0
  151. package/dist/web/assets/treemap-KZPCXAKY-DiumLNMg.js +1 -0
  152. package/dist/web/assets/{ts-tags-BIHk5AM0.js → ts-tags-D1DDO2jl.js} +1 -1
  153. package/dist/web/assets/{twig-YcE6Q2Ox.js → twig-C8Fd5RvV.js} +1 -1
  154. package/dist/web/assets/use-accounts-data-KWcMgRlc.js +1 -0
  155. package/dist/web/assets/{use-blob-url-De-ZtcpX.js → use-blob-url-CrwoZJUJ.js} +1 -1
  156. package/dist/web/assets/use-inline-blame-C1G-_NjC.js +8 -0
  157. package/dist/web/assets/{use-monaco-theme-DOhDvEKJ.js → use-monaco-theme-aa4-wjKQ.js} +1 -1
  158. package/dist/web/assets/{use-open-team-member-DWhhWdmJ.js → use-open-team-member-CSUU7Z8N.js} +1 -1
  159. package/dist/web/assets/{use-remote-desktop-display-choice-B3VIBQxC.js → use-remote-desktop-display-choice-B-TpQ-Ua.js} +1 -1
  160. package/dist/web/assets/{use-websocket-D9MsDysx.js → use-websocket-BBslmv3D.js} +1 -1
  161. package/dist/web/assets/{vendor-mermaid-CKKtYuTV.js → vendor-mermaid-CfY1-PkA.js} +1 -1
  162. package/dist/web/assets/{video-preview-VL2Br0YM.js → video-preview-Bd0lcK3d.js} +1 -1
  163. package/dist/web/assets/{vue-q7m01V0h.js → vue-EvccXlkP.js} +1 -1
  164. package/dist/web/assets/{vue-html-D1y9feOj.js → vue-html-Dg0xUJCh.js} +1 -1
  165. package/dist/web/assets/{vue-vine-DrIGs03v.js → vue-vine-BdrMg72k.js} +1 -1
  166. package/dist/web/assets/{window-pip-registry-CSLhJfpL.js → window-pip-registry-CrCYYTTf.js} +1 -1
  167. package/dist/web/assets/{window-store-DGKf9rPG.js → window-store-D0HbQ1pM.js} +1 -1
  168. package/dist/web/assets/ws-auth-D111jj32.js +1 -0
  169. package/dist/web/assets/{xml-oyvc1920.js → xml-MmDclzxK.js} +1 -1
  170. package/dist/web/assets/{xsl-BbIGdNPF.js → xsl-DQEFs6Dd.js} +1 -1
  171. package/dist/web/index.html +23 -23
  172. package/dist/web/sw.js +1 -1
  173. package/docs/extension-development-guide.md +47 -0
  174. package/docs/project-roadmap.md +3 -1
  175. package/package.json +2 -2
  176. package/packages/ext-git-graph/package.json +23 -5
  177. package/packages/ext-git-graph/src/blame-parser.test.ts +154 -0
  178. package/packages/ext-git-graph/src/blame-parser.ts +148 -0
  179. package/packages/ext-git-graph/src/blame-view.ts +389 -0
  180. package/packages/ext-git-graph/src/commit-search.test.ts +118 -0
  181. package/packages/ext-git-graph/src/commit-search.ts +102 -0
  182. package/packages/ext-git-graph/src/compare-args.test.ts +111 -0
  183. package/packages/ext-git-graph/src/compare-args.ts +109 -0
  184. package/packages/ext-git-graph/src/compare-view.ts +343 -0
  185. package/packages/ext-git-graph/src/extension-integration.test.ts +6 -3
  186. package/packages/ext-git-graph/src/extension.ts +202 -249
  187. package/packages/ext-git-graph/src/file-history-parser.test.ts +102 -0
  188. package/packages/ext-git-graph/src/file-history-parser.ts +89 -0
  189. package/packages/ext-git-graph/src/file-history-view.ts +386 -0
  190. package/packages/ext-git-graph/src/git-exec.ts +122 -0
  191. package/packages/ext-git-graph/src/git-state.ts +81 -0
  192. package/packages/ext-git-graph/src/panel-nav.ts +65 -0
  193. package/packages/ext-git-graph/src/panel-registry.ts +72 -0
  194. package/packages/ext-git-graph/src/ppm-api.ts +48 -0
  195. package/packages/ext-git-graph/src/rebase-todo.test.ts +196 -0
  196. package/packages/ext-git-graph/src/rebase-todo.ts +119 -0
  197. package/packages/ext-git-graph/src/rebase-view.ts +483 -0
  198. package/packages/ext-git-graph/src/reflog-parser.test.ts +93 -0
  199. package/packages/ext-git-graph/src/reflog-parser.ts +86 -0
  200. package/packages/ext-git-graph/src/reflog-view.ts +375 -0
  201. package/packages/ext-git-graph/src/register-view-command.ts +47 -0
  202. package/packages/ext-git-graph/src/submodule-parser.test.ts +79 -0
  203. package/packages/ext-git-graph/src/submodule-parser.ts +77 -0
  204. package/packages/ext-git-graph/src/types.ts +10 -1
  205. package/packages/ext-git-graph/src/webview-html.ts +438 -3
  206. package/packages/ext-git-graph/src/webview-shell.ts +236 -0
  207. package/src/providers/claude-agent-sdk.ts +7 -0
  208. package/src/providers/codex-app-server/codex-provider.ts +89 -1
  209. package/src/server/index.ts +1 -1
  210. package/src/server/routes/accounts.ts +25 -1
  211. package/src/server/routes/chat.ts +29 -1
  212. package/src/server/routes/codex-accounts.ts +41 -1
  213. package/src/server/routes/git.ts +97 -0
  214. package/src/server/routes/settings.ts +1 -0
  215. package/src/server/routes/teams.ts +14 -3
  216. package/src/services/account-selector.service.ts +125 -20
  217. package/src/services/account.service.ts +176 -54
  218. package/src/services/autostart-generator.ts +12 -1
  219. package/src/services/codex-account.service.ts +87 -13
  220. package/src/services/db.service.ts +58 -3
  221. package/src/services/extension.service.ts +55 -5
  222. package/src/services/git-blame/blame-porcelain.ts +89 -0
  223. package/src/services/git-blame/git-blame.service.ts +90 -0
  224. package/src/services/git-hunks/git-hunks.service.ts +264 -0
  225. package/src/services/git-hunks/unified-diff.ts +359 -0
  226. package/src/services/picked-account-binding.ts +57 -0
  227. package/src/services/team-member-activity/member-transcript-tail.ts +64 -0
  228. package/src/shared/blame.ts +79 -0
  229. package/src/web/components/chat/chat-history-bar.tsx +35 -6
  230. package/src/web/components/chat/chat-tab.tsx +120 -3
  231. package/src/web/components/chat/codex-usage-panel.tsx +148 -14
  232. package/src/web/components/chat/team-member-window-content.tsx +8 -39
  233. package/src/web/components/chat/usage-badge.tsx +176 -52
  234. package/src/web/components/editor/code-editor.tsx +33 -1
  235. package/src/web/components/editor/diff-viewer.tsx +83 -8
  236. package/src/web/components/editor/editor-toolbar.tsx +25 -1
  237. package/src/web/components/git/git-status-panel.tsx +46 -0
  238. package/src/web/components/git/hunk-selection.ts +132 -0
  239. package/src/web/components/git/hunk-stage-dialog.tsx +419 -0
  240. package/src/web/components/settings/accounts/account-bucket-row.tsx +19 -3
  241. package/src/web/components/settings/accounts/account-card.tsx +153 -33
  242. package/src/web/components/settings/accounts/account-hint.tsx +33 -0
  243. package/src/web/components/settings/accounts/account-usage-format.ts +26 -0
  244. package/src/web/components/settings/accounts/codex-accounts-section.tsx +24 -9
  245. package/src/web/components/settings/accounts/codex-usage-rows.tsx +2 -2
  246. package/src/web/components/settings/accounts/use-accounts-data.ts +32 -2
  247. package/src/web/components/settings/accounts/use-codex-accounts.ts +24 -2
  248. package/src/web/hooks/use-chat.ts +27 -0
  249. package/src/web/hooks/use-inline-blame.ts +175 -0
  250. package/src/web/hooks/use-member-transcript-tail.ts +95 -0
  251. package/src/web/hooks/use-usage.ts +3 -3
  252. package/src/web/lib/api-settings.ts +24 -0
  253. package/src/web/stores/settings-store.ts +12 -0
  254. package/dist/web/assets/accounts-settings-section-C1YP1iCb.js +0 -1
  255. package/dist/web/assets/ai-settings-section-BJPgHUqk.js +0 -1
  256. package/dist/web/assets/api-client-BogqsFna.js +0 -1
  257. package/dist/web/assets/api-settings-BVfemzZW.js +0 -1
  258. package/dist/web/assets/architecture-PBZL5I3N-BZBxtErN.js +0 -1
  259. package/dist/web/assets/chat-tab-Bn4vZVZJ.js +0 -15
  260. package/dist/web/assets/code-editor-DN5GJXT3.js +0 -7
  261. package/dist/web/assets/diff-viewer-DxzD_YSO.js +0 -4
  262. package/dist/web/assets/explorer-window-content-DixZaLLP.js +0 -1
  263. package/dist/web/assets/gitGraph-HDMCJU4V-BHxJbXfV.js +0 -1
  264. package/dist/web/assets/group-chat-tab-D-HXdnoU.js +0 -1
  265. package/dist/web/assets/index-DdMq4zqb.js +0 -52
  266. package/dist/web/assets/index-N-pnuwFP.css +0 -2
  267. package/dist/web/assets/info-3K5VOQVL-DI4p3vbH.js +0 -1
  268. package/dist/web/assets/keybindings-store-DQkz4a35.js +0 -1
  269. package/dist/web/assets/markdown-renderer-C35QMvZp.js +0 -1
  270. package/dist/web/assets/mobile-explorer-sheet-ZHfT5IN3.js +0 -1
  271. package/dist/web/assets/notification-store-J1yP_Ebb.js +0 -1
  272. package/dist/web/assets/packet-RMMSAZCW-YNQWTi_-.js +0 -1
  273. package/dist/web/assets/pie-UPGHQEXC-E3Wiw76n.js +0 -1
  274. package/dist/web/assets/radar-KQ55EAFF-BPQJUKON.js +0 -1
  275. package/dist/web/assets/remote-desktop-mobile-sheet-DhcAyXE5.js +0 -2
  276. package/dist/web/assets/schedules-settings-section-BFzMEPTd.js +0 -1
  277. package/dist/web/assets/settings-store-DWUx3865.js +0 -2
  278. package/dist/web/assets/settings-tab-DVV26vPK.js +0 -1
  279. package/dist/web/assets/settings-window-content-z64J3tfm.js +0 -1
  280. package/dist/web/assets/system-monitor-tab-jnPQtmvK.js +0 -1
  281. package/dist/web/assets/team-member-sheet-8FDCVZMG.js +0 -2
  282. package/dist/web/assets/team-member-window-content-0JRiWRdG.js +0 -1
  283. package/dist/web/assets/tool-cards-DuTlfeWN.js +0 -9
  284. package/dist/web/assets/treemap-KZPCXAKY-C2CvKBQR.js +0 -1
  285. package/dist/web/assets/use-accounts-data--pdg01TI.js +0 -1
  286. package/dist/web/assets/ws-auth-ZSZkAT6p.js +0 -1
  287. /package/dist/web/assets/{abap-Cq9nYQyd.js → abap-D-o-bvtI.js} +0 -0
  288. /package/dist/web/assets/{actionscript-3-DL8rUIy0.js → actionscript-3-D2tIzAm8.js} +0 -0
  289. /package/dist/web/assets/{ada-BY8TLuhY.js → ada-DxatBcxS.js} +0 -0
  290. /package/dist/web/assets/{andromeeda-CyVfHsS0.js → andromeeda-D0LK9YJ3.js} +0 -0
  291. /package/dist/web/assets/{apache-DTQUy73x.js → apache-B7uMPNiW.js} +0 -0
  292. /package/dist/web/assets/{apex-CiSZngrZ.js → apex-B7GiXrAr.js} +0 -0
  293. /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-CEYCBt_0.js} +0 -0
  294. /package/dist/web/assets/{applescript-CzuRDd3h.js → applescript-D_SIFkKe.js} +0 -0
  295. /package/dist/web/assets/{apply-theme-r8tKDrCR.js → apply-theme-BVXAUYoN.js} +0 -0
  296. /package/dist/web/assets/{ara-CSFV93kR.js → ara-C3iECgdg.js} +0 -0
  297. /package/dist/web/assets/{asciidoc-hOQNnXhz.js → asciidoc-gc8z_MMY.js} +0 -0
  298. /package/dist/web/assets/{asm-DdG53NGR.js → asm-27qeoPOI.js} +0 -0
  299. /package/dist/web/assets/{aurora-x-DJ7ORZG6.js → aurora-x-C5J9fWe1.js} +0 -0
  300. /package/dist/web/assets/{awk-B3FFpX_J.js → awk-B7GBzF92.js} +0 -0
  301. /package/dist/web/assets/{ayu-dark-D_P1CfTe.js → ayu-dark-XlnQhuLL.js} +0 -0
  302. /package/dist/web/assets/{ayu-light-Cz3YLUqH.js → ayu-light-DKLLilkU.js} +0 -0
  303. /package/dist/web/assets/{ayu-mirage-JcMq5tgJ.js → ayu-mirage-Dv-XOprJ.js} +0 -0
  304. /package/dist/web/assets/{ballerina-7Hs4Rfpk.js → ballerina-DACRT-sT.js} +0 -0
  305. /package/dist/web/assets/{bat-COgQdnFA.js → bat-BlQCq2XE.js} +0 -0
  306. /package/dist/web/assets/{beancount-BJ3CutBG.js → beancount-DYDztRI0.js} +0 -0
  307. /package/dist/web/assets/{berry-D7so2Cui.js → berry-BE5YKqvx.js} +0 -0
  308. /package/dist/web/assets/{bibtex-Ct3acHa1.js → bibtex-CAm7mgEm.js} +0 -0
  309. /package/dist/web/assets/{bicep-jXDwCQcm.js → bicep-BKgAbfVa.js} +0 -0
  310. /package/dist/web/assets/{bird2-CjLD2cna.js → bird2-yrBNbW1G.js} +0 -0
  311. /package/dist/web/assets/{c-CdgZojnL.js → c-txZFr4RM.js} +0 -0
  312. /package/dist/web/assets/{c3-DtpZYego.js → c3-D_DrzBUd.js} +0 -0
  313. /package/dist/web/assets/{cadence-CPLkixoh.js → cadence-CUFCEgG9.js} +0 -0
  314. /package/dist/web/assets/{can-open-in-ppm-BntPywsy.js → can-open-in-ppm-_yqa69dV.js} +0 -0
  315. /package/dist/web/assets/{catppuccin-frappe-Xt0_qJa9.js → catppuccin-frappe-Dn32MuhA.js} +0 -0
  316. /package/dist/web/assets/{catppuccin-latte-CJnbLec5.js → catppuccin-latte-Dewo7yDf.js} +0 -0
  317. /package/dist/web/assets/{catppuccin-macchiato-BPHP1wYB.js → catppuccin-macchiato-D8WOWZeo.js} +0 -0
  318. /package/dist/web/assets/{catppuccin-mocha-ssWJodGc.js → catppuccin-mocha-b0md48XM.js} +0 -0
  319. /package/dist/web/assets/{clarity-DB0408F6.js → clarity-Ct3UqLBj.js} +0 -0
  320. /package/dist/web/assets/{clojure-dpRPlAO4.js → clojure-CwP5aPEo.js} +0 -0
  321. /package/dist/web/assets/{cmake-r2VkeX9y.js → cmake-D5RF49e5.js} +0 -0
  322. /package/dist/web/assets/{codeowners-v5nQqHiB.js → codeowners-Cl5897L_.js} +0 -0
  323. /package/dist/web/assets/{codeql-BSSEhKRR.js → codeql-BKh1RCg0.js} +0 -0
  324. /package/dist/web/assets/{common-lisp-BXb2MMMA.js → common-lisp-BhHuD6t0.js} +0 -0
  325. /package/dist/web/assets/{coq-BjBNi73X.js → coq-Dco3qwD8.js} +0 -0
  326. /package/dist/web/assets/{csharp-CdPjZRbV.js → csharp-Dpjw9ZA9.js} +0 -0
  327. /package/dist/web/assets/{css-BuxbQOHL.js → css-CPe4cabH.js} +0 -0
  328. /package/dist/web/assets/{csv-Dj-eoZwH.js → csv-BAcTN8Kt.js} +0 -0
  329. /package/dist/web/assets/{csv-parser-CBbALsFU.js → csv-parser-DbxGKdMG.js} +0 -0
  330. /package/dist/web/assets/{cue-Dz73VksN.js → cue-Cr6y60TA.js} +0 -0
  331. /package/dist/web/assets/{cypher-CkVkDywZ.js → cypher-DWtqXXFP.js} +0 -0
  332. /package/dist/web/assets/{d-oU51Pbpf.js → d-BASiTZk4.js} +0 -0
  333. /package/dist/web/assets/{dark-plus-DcwvjjfO.js → dark-plus-56kmnrcl.js} +0 -0
  334. /package/dist/web/assets/{dart-DGvu8mcX.js → dart-C5mZnjoE.js} +0 -0
  335. /package/dist/web/assets/{data-grid-types-B6kUrF-M.js → data-grid-types-DeY60CLU.js} +0 -0
  336. /package/dist/web/assets/{dax-BmbjKQ90.js → dax-B4I2e7d8.js} +0 -0
  337. /package/dist/web/assets/{desktop-IRBSiFfh.js → desktop-DekGg0BT.js} +0 -0
  338. /package/dist/web/assets/{diff-Bdik2JR8.js → diff-CWnJBd73.js} +0 -0
  339. /package/dist/web/assets/{dist-Bv4zQpS1.js → dist-B0J2eYBz.js} +0 -0
  340. /package/dist/web/assets/{dist-C8YPBIOb.js → dist-BKOM_AoT.js} +0 -0
  341. /package/dist/web/assets/{docker-Bgdl0H8I.js → docker-DevchDxK.js} +0 -0
  342. /package/dist/web/assets/{dotenv-COe5NdnA.js → dotenv-DCvtdaGJ.js} +0 -0
  343. /package/dist/web/assets/{dracula-DjURaSAa.js → dracula-8U6Vkk3l.js} +0 -0
  344. /package/dist/web/assets/{dracula-soft-Do7d0bo-.js → dracula-soft-Bfeew5Wg.js} +0 -0
  345. /package/dist/web/assets/{dream-maker-DYwQvJIj.js → dream-maker-DDTJVuoy.js} +0 -0
  346. /package/dist/web/assets/{emacs-lisp-BXjlHyDW.js → emacs-lisp-CEHJqI4m.js} +0 -0
  347. /package/dist/web/assets/{everforest-dark-h8Q2loiX.js → everforest-dark-CHHLt7cq.js} +0 -0
  348. /package/dist/web/assets/{everforest-light-CdsJiL-9.js → everforest-light-TcTbK1sM.js} +0 -0
  349. /package/dist/web/assets/{fennel-D0CBtOvY.js → fennel-Bh4vsA1A.js} +0 -0
  350. /package/dist/web/assets/{fish-DzayfrMj.js → fish-D0T0fILG.js} +0 -0
  351. /package/dist/web/assets/{fluent-CatjkUfx.js → fluent-CgXDXdyy.js} +0 -0
  352. /package/dist/web/assets/{format-bytes-BulRSULX.js → format-bytes-Bc6SqF7M.js} +0 -0
  353. /package/dist/web/assets/{fortran-free-form-DM04ud0b.js → fortran-free-form-CUg3Xhz4.js} +0 -0
  354. /package/dist/web/assets/{gdscript-BLN5iZwf.js → gdscript-Cx056p_k.js} +0 -0
  355. /package/dist/web/assets/{gdshader-BK-1iZQs.js → gdshader-Dj1qP4I5.js} +0 -0
  356. /package/dist/web/assets/{genie-BGPOFWDN.js → genie-SBt15wn7.js} +0 -0
  357. /package/dist/web/assets/{gherkin-CdVOJ_JY.js → gherkin-bTJiHIrB.js} +0 -0
  358. /package/dist/web/assets/{github-dark-B_xW8TaY.js → github-dark-BOPhyugs.js} +0 -0
  359. /package/dist/web/assets/{github-dark-default-h_iKq7CX.js → github-dark-default-Cktqe6NF.js} +0 -0
  360. /package/dist/web/assets/{github-dark-dimmed-nKDYE62T.js → github-dark-dimmed-CeWfII_B.js} +0 -0
  361. /package/dist/web/assets/{github-dark-high-contrast-l8I771QT.js → github-dark-high-contrast-CTx8LpdV.js} +0 -0
  362. /package/dist/web/assets/{github-light-DNhjkg8Z.js → github-light-DVsO5Un1.js} +0 -0
  363. /package/dist/web/assets/{github-light-default-DQ06uS3g.js → github-light-default-BiyPxicr.js} +0 -0
  364. /package/dist/web/assets/{github-light-high-contrast-qc2sZCVN.js → github-light-high-contrast-BPlnke0a.js} +0 -0
  365. /package/dist/web/assets/{gleam-DPPatkNH.js → gleam-CWSxvD0C.js} +0 -0
  366. /package/dist/web/assets/{gn-BnzGQTy5.js → gn-D7NUVJuv.js} +0 -0
  367. /package/dist/web/assets/{gnuplot-Ct1leoo3.js → gnuplot-c5uXmJKc.js} +0 -0
  368. /package/dist/web/assets/{go-qysCdbrn.js → go-CRsHi4Cw.js} +0 -0
  369. /package/dist/web/assets/{groovy-BkWIdrRQ.js → groovy-DpV0RA5r.js} +0 -0
  370. /package/dist/web/assets/{gruvbox-dark-hard-L6Iiybbl.js → gruvbox-dark-hard-DD9fguUN.js} +0 -0
  371. /package/dist/web/assets/{gruvbox-dark-medium-DbD3yl0b.js → gruvbox-dark-medium-BvcwpYJ-.js} +0 -0
  372. /package/dist/web/assets/{gruvbox-dark-soft-Ban2cHK3.js → gruvbox-dark-soft-48dCxX9M.js} +0 -0
  373. /package/dist/web/assets/{gruvbox-light-hard-CK_SjS3e.js → gruvbox-light-hard-CjJ994Ip.js} +0 -0
  374. /package/dist/web/assets/{gruvbox-light-medium-Bjgvhc2w.js → gruvbox-light-medium-DQJQZ_rV.js} +0 -0
  375. /package/dist/web/assets/{gruvbox-light-soft-EWnyYGUu.js → gruvbox-light-soft-AqsC9mKw.js} +0 -0
  376. /package/dist/web/assets/{haskell-rT1N9nYr.js → haskell-B5V7yvmh.js} +0 -0
  377. /package/dist/web/assets/{haxe-Bbc91axo.js → haxe-LWTKfPKr.js} +0 -0
  378. /package/dist/web/assets/{hcl-D-3qJA4v.js → hcl-QmNZdAtI.js} +0 -0
  379. /package/dist/web/assets/{hjson-DWtewcyQ.js → hjson-CboJsAzK.js} +0 -0
  380. /package/dist/web/assets/{hlsl-C7t6hCrO.js → hlsl-Bd-DO_WL.js} +0 -0
  381. /package/dist/web/assets/{horizon-zJAGUQ3j.js → horizon-CU8Bi_ss.js} +0 -0
  382. /package/dist/web/assets/{horizon-bright-CRNyrJy8.js → horizon-bright-iSQ3_3jP.js} +0 -0
  383. /package/dist/web/assets/{houston-BFKa4W1-.js → houston-CTXv3Puz.js} +0 -0
  384. /package/dist/web/assets/{hy-W1hNjMBM.js → hy-Cd4hTidD.js} +0 -0
  385. /package/dist/web/assets/{image-gallery-BycaVWOu.js → image-gallery-J8h8IY0c.js} +0 -0
  386. /package/dist/web/assets/{imba-CPphaV-V.js → imba-BipCHEY2.js} +0 -0
  387. /package/dist/web/assets/{ini-CayaZ4vW.js → ini-Dd1KkMrB.js} +0 -0
  388. /package/dist/web/assets/{java-BPAE_9Ej.js → java-rGr0OQD8.js} +0 -0
  389. /package/dist/web/assets/{javascript-C5SKIVqe.js → javascript-DHhCH2TN.js} +0 -0
  390. /package/dist/web/assets/{json-C-0EUYmu.js → json-CMMLBCUf.js} +0 -0
  391. /package/dist/web/assets/{json5-BqVetEZL.js → json5-mPOwTOsB.js} +0 -0
  392. /package/dist/web/assets/{jsonc-DnjIzkUB.js → jsonc-Bie0E6D3.js} +0 -0
  393. /package/dist/web/assets/{jsonl-rbV-3EqO.js → jsonl-CpqHmtC1.js} +0 -0
  394. /package/dist/web/assets/{jsonnet-9hvXw4qr.js → jsonnet-D21Ms51e.js} +0 -0
  395. /package/dist/web/assets/{jssm-1ifXyIhu.js → jssm-BXnl1nur.js} +0 -0
  396. /package/dist/web/assets/{jsx-hPumywTY.js → jsx-Chnii_vB.js} +0 -0
  397. /package/dist/web/assets/{kanagawa-dragon-BCPjmoMO.js → kanagawa-dragon-DhxR0UjL.js} +0 -0
  398. /package/dist/web/assets/{kanagawa-lotus-DN2VNjy7.js → kanagawa-lotus-fupRg5wp.js} +0 -0
  399. /package/dist/web/assets/{kanagawa-wave-B8RZEsgc.js → kanagawa-wave-DSWbRS9M.js} +0 -0
  400. /package/dist/web/assets/{kdl-CkvjWQIa.js → kdl-DirGHqUy.js} +0 -0
  401. /package/dist/web/assets/{kotlin-D8cnRi5o.js → kotlin-DkhUVMDC.js} +0 -0
  402. /package/dist/web/assets/{kusto-CmeeBEJG.js → kusto-DU7OpovF.js} +0 -0
  403. /package/dist/web/assets/{laserwave--rtV8Mv9.js → laserwave-iLKb1ZCT.js} +0 -0
  404. /package/dist/web/assets/{lean-CS-Pyi42.js → lean-Cuvh_QAP.js} +0 -0
  405. /package/dist/web/assets/{less-Ddi_7qGm.js → less-B5tQZOdI.js} +0 -0
  406. /package/dist/web/assets/{lib-DIrxSyLb.js → lib-el9rA30D.js} +0 -0
  407. /package/dist/web/assets/{libesm-CYLrAeW3.js → libesm-CdttTIAd.js} +0 -0
  408. /package/dist/web/assets/{light-plus-CrEjpkkX.js → light-plus-DiHU2KL5.js} +0 -0
  409. /package/dist/web/assets/{llvm-Cm7ZXmAO.js → llvm-sCBTKCKN.js} +0 -0
  410. /package/dist/web/assets/{log-lW2sYxtp.js → log-DtyR34Ie.js} +0 -0
  411. /package/dist/web/assets/{logo-B-PiRb53.js → logo-CP91aQyG.js} +0 -0
  412. /package/dist/web/assets/{luau-8St0pC-R.js → luau-nfGo2ulP.js} +0 -0
  413. /package/dist/web/assets/{make-DbNdhH54.js → make-XbDn9GHe.js} +0 -0
  414. /package/dist/web/assets/{markdown-CYocYSGd.js → markdown-BB1_3xLr.js} +0 -0
  415. /package/dist/web/assets/{material-theme-CVBF1Cbi.js → material-theme-CIx_sxAy.js} +0 -0
  416. /package/dist/web/assets/{material-theme-darker-HFrlNZD8.js → material-theme-darker-DsQeueDD.js} +0 -0
  417. /package/dist/web/assets/{material-theme-lighter-BM-uz2ft.js → material-theme-lighter-x_lMi74j.js} +0 -0
  418. /package/dist/web/assets/{material-theme-ocean-PbvUez8m.js → material-theme-ocean-Bkgh25P8.js} +0 -0
  419. /package/dist/web/assets/{material-theme-palenight-B22Ck6qd.js → material-theme-palenight-CoOjdbti.js} +0 -0
  420. /package/dist/web/assets/{matlab-GFFNzucw.js → matlab-D6xZas_8.js} +0 -0
  421. /package/dist/web/assets/{mdx-BVnJzMDx.js → mdx-Cl5_YNoz.js} +0 -0
  422. /package/dist/web/assets/{mermaid-BlCmSTCM.js → mermaid-8Eow4jz_.js} +0 -0
  423. /package/dist/web/assets/{min-dark-B0PwlAfC.js → min-dark-D4DhjgRE.js} +0 -0
  424. /package/dist/web/assets/{min-light-C_H2ABKu.js → min-light-DzAckd0t.js} +0 -0
  425. /package/dist/web/assets/{mipsasm-C3rf2fo6.js → mipsasm-zI_zu0tj.js} +0 -0
  426. /package/dist/web/assets/{mojo-CDRuzM3o.js → mojo-DQnGGPHf.js} +0 -0
  427. /package/dist/web/assets/{monokai-KiebNy_Y.js → monokai-CrFoD2VD.js} +0 -0
  428. /package/dist/web/assets/{moonbit-CdVUHoWl.js → moonbit-DdphIGs6.js} +0 -0
  429. /package/dist/web/assets/{move-Dq9iKZRY.js → move-BUlkn0xW.js} +0 -0
  430. /package/dist/web/assets/{narrat-7y5L5sGM.js → narrat-CbOBdtCn.js} +0 -0
  431. /package/dist/web/assets/{nextflow-groovy-Cwcbkcrx.js → nextflow-groovy-CeVLUTuQ.js} +0 -0
  432. /package/dist/web/assets/{night-owl-TBgLPzj4.js → night-owl-Bm4LhUR1.js} +0 -0
  433. /package/dist/web/assets/{night-owl-light-Dehb9My2.js → night-owl-light-DtcBiMEf.js} +0 -0
  434. /package/dist/web/assets/{nix-BKj-gzoX.js → nix-DrdwQ70g.js} +0 -0
  435. /package/dist/web/assets/{nord-BF_r8PeX.js → nord-B0Head1v.js} +0 -0
  436. /package/dist/web/assets/{nushell-CeAjk9_E.js → nushell-CmUdltKn.js} +0 -0
  437. /package/dist/web/assets/{objective-c-Xl1OMcDp.js → objective-c-BGDR33XN.js} +0 -0
  438. /package/dist/web/assets/{objective-cpp-C4ZgzrRq.js → objective-cpp-Buc1Zhd0.js} +0 -0
  439. /package/dist/web/assets/{ocaml-CGj8IYTq.js → ocaml-xdzl9rRD.js} +0 -0
  440. /package/dist/web/assets/{odin-C4veqvW2.js → odin-DiUFngnd.js} +0 -0
  441. /package/dist/web/assets/{one-dark-pro-gAcWejsV.js → one-dark-pro-BURxmIp3.js} +0 -0
  442. /package/dist/web/assets/{one-light-B7E-UUXy.js → one-light-BMRMInAj.js} +0 -0
  443. /package/dist/web/assets/{openscad-C-wN9BEv.js → openscad-DAgLA5J3.js} +0 -0
  444. /package/dist/web/assets/{pascal-C8WBtxMs.js → pascal-CoDZxcRB.js} +0 -0
  445. /package/dist/web/assets/{pkl-BBfF4G2A.js → pkl-DzKM6BuM.js} +0 -0
  446. /package/dist/web/assets/{plastic-DFOAb89P.js → plastic-vF15LmNS.js} +0 -0
  447. /package/dist/web/assets/{plsql-BS2CEMMV.js → plsql-C1v07teA.js} +0 -0
  448. /package/dist/web/assets/{po-BKJDtPmy.js → po-CLLC8BuA.js} +0 -0
  449. /package/dist/web/assets/{poimandres-Cg3hL13e.js → poimandres-Uq0xysxM.js} +0 -0
  450. /package/dist/web/assets/{polar-B9ebiXUU.js → polar-2-luY1Pc.js} +0 -0
  451. /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DKymYOY-.js} +0 -0
  452. /package/dist/web/assets/{postcss-B5REwNY_.js → postcss-lbFhe0rz.js} +0 -0
  453. /package/dist/web/assets/{powerquery-stc0Gzkf.js → powerquery-RL8O9Wie.js} +0 -0
  454. /package/dist/web/assets/{powershell-jgd0ahJN.js → powershell-upFWhb-b.js} +0 -0
  455. /package/dist/web/assets/{prisma-CWuZjRhI.js → prisma-DBtYaWFk.js} +0 -0
  456. /package/dist/web/assets/{prolog-D5zNFE63.js → prolog-D8jSMykJ.js} +0 -0
  457. /package/dist/web/assets/{proto-B-6RrU7n.js → proto-BM4eadF7.js} +0 -0
  458. /package/dist/web/assets/{puppet-DONP8TDR.js → puppet-BQDQ3Snu.js} +0 -0
  459. /package/dist/web/assets/{purescript-DDJITf-A.js → purescript-Cj2aTX4s.js} +0 -0
  460. /package/dist/web/assets/{python-bmWy9j1-.js → python-BYpqq6u4.js} +0 -0
  461. /package/dist/web/assets/{qmldir-CKDwMt7X.js → qmldir-4uiTcwAu.js} +0 -0
  462. /package/dist/web/assets/{qss-DptQQzBn.js → qss-D5xB-Mqo.js} +0 -0
  463. /package/dist/web/assets/{r-BorKpJ8r.js → r-P6Ujy8rf.js} +0 -0
  464. /package/dist/web/assets/{racket-BaHpYVsZ.js → racket-COKgCFuM.js} +0 -0
  465. /package/dist/web/assets/{raku-DFJIV4k_.js → raku-z14Q9i7K.js} +0 -0
  466. /package/dist/web/assets/{react-X4jUntEf.js → react-D1Yg256j.js} +0 -0
  467. /package/dist/web/assets/{red-70oJGrkb.js → red-ObAvgvQ5.js} +0 -0
  468. /package/dist/web/assets/{reg-C4g235Dv.js → reg-Qv4f0JFA.js} +0 -0
  469. /package/dist/web/assets/{regexp-Cw1UVmti.js → regexp-CEOVGIzy.js} +0 -0
  470. /package/dist/web/assets/{rel-DeLhIz5L.js → rel-cWOyTUwd.js} +0 -0
  471. /package/dist/web/assets/{resolve-theme-b_yGlUFQ.js → resolve-theme-CMp5xxCW.js} +0 -0
  472. /package/dist/web/assets/{riscv-ChnTiBRK.js → riscv-BZDwx-lv.js} +0 -0
  473. /package/dist/web/assets/{ron-C5IWeqDn.js → ron-BpjosPS0.js} +0 -0
  474. /package/dist/web/assets/{rose-pine-DCR0ohYW.js → rose-pine-DhxfJWcm.js} +0 -0
  475. /package/dist/web/assets/{rose-pine-dawn-DvGZs1PR.js → rose-pine-dawn-BbGt9Wy_.js} +0 -0
  476. /package/dist/web/assets/{rose-pine-moon-BWACHjeS.js → rose-pine-moon-dj4Zxgik.js} +0 -0
  477. /package/dist/web/assets/{rosmsg-CQlIVazE.js → rosmsg-EciOaHo2.js} +0 -0
  478. /package/dist/web/assets/{rust-DGGVzWI8.js → rust-C_eH59O_.js} +0 -0
  479. /package/dist/web/assets/{sass-bj1C0rFI.js → sass-Dos3R5lL.js} +0 -0
  480. /package/dist/web/assets/{scala-MU1tLKDi.js → scala-8lVKsTvf.js} +0 -0
  481. /package/dist/web/assets/{scheme-CeGXtv7t.js → scheme-Bd3VdaZj.js} +0 -0
  482. /package/dist/web/assets/{sdbl-D0HLSGKp.js → sdbl-C4Yrjlgh.js} +0 -0
  483. /package/dist/web/assets/{shellscript-DkYiDvh1.js → shellscript-OFZbPKZH.js} +0 -0
  484. /package/dist/web/assets/{slack-dark-YqeHiGWH.js → slack-dark-aL6vlxZs.js} +0 -0
  485. /package/dist/web/assets/{slack-ochin-9Oe0DljJ.js → slack-ochin-BKt1E7sL.js} +0 -0
  486. /package/dist/web/assets/{smalltalk-CaaxedR7.js → smalltalk-D6qVBL1U.js} +0 -0
  487. /package/dist/web/assets/{snazzy-light-C8s2FHNC.js → snazzy-light-BrWerT0t.js} +0 -0
  488. /package/dist/web/assets/{solarized-dark-0ryY6oN3.js → solarized-dark-CzxTJgVQ.js} +0 -0
  489. /package/dist/web/assets/{solarized-light-bltgZeNh.js → solarized-light-BecaDAnG.js} +0 -0
  490. /package/dist/web/assets/{solidity-DOf5HmLZ.js → solidity-C9t7pZ84.js} +0 -0
  491. /package/dist/web/assets/{splunk-D1u4WHDW.js → splunk-CtxfFKtF.js} +0 -0
  492. /package/dist/web/assets/{sql-G8uQZljX.js → sql-7FE_Duz0.js} +0 -0
  493. /package/dist/web/assets/{ssh-config-rbXvly7Q.js → ssh-config-3Fr37ACC.js} +0 -0
  494. /package/dist/web/assets/{stylus-Cii1iADy.js → stylus-BP4mE1sO.js} +0 -0
  495. /package/dist/web/assets/{swift-DpIgonN4.js → swift-0uqTFouD.js} +0 -0
  496. /package/dist/web/assets/{synthwave-84-DjGLzU2b.js → synthwave-84-DQaNM3DI.js} +0 -0
  497. /package/dist/web/assets/{system-verilog-_Z0M0Hs1.js → system-verilog-DUIVrZHZ.js} +0 -0
  498. /package/dist/web/assets/{systemd-BhyDCh9P.js → systemd-CtNo_WIh.js} +0 -0
  499. /package/dist/web/assets/{talonscript-CNchgCRD.js → talonscript-B0HXaCVT.js} +0 -0
  500. /package/dist/web/assets/{tasl-m--W7Pyr.js → tasl-Cb7RAl11.js} +0 -0
  501. /package/dist/web/assets/{tcl-gY-M_2BC.js → tcl-B79aC6l5.js} +0 -0
  502. /package/dist/web/assets/{terraform-CB6CzMwo.js → terraform-75jJDjpW.js} +0 -0
  503. /package/dist/web/assets/{tokyo-night-COh9oRYi.js → tokyo-night-Cz9Uh9qb.js} +0 -0
  504. /package/dist/web/assets/{toml-Bg2bsY-v.js → toml-CD6y9A-z.js} +0 -0
  505. /package/dist/web/assets/{tsv-DceGDiJC.js → tsv-CXJMbBrb.js} +0 -0
  506. /package/dist/web/assets/{tsx-EccDYa7i.js → tsx-BuYN0I2t.js} +0 -0
  507. /package/dist/web/assets/{turtle-C_l2JhvX.js → turtle-DWH-Rjse.js} +0 -0
  508. /package/dist/web/assets/{typescript-C1ytmMcr.js → typescript-BPd-hsrR.js} +0 -0
  509. /package/dist/web/assets/{typespec-De2ztzG5.js → typespec-B0wvVykx.js} +0 -0
  510. /package/dist/web/assets/{typst-DNcS7gSr.js → typst-DWG2c48-.js} +0 -0
  511. /package/dist/web/assets/{use-is-mobile-CYW3FJFE.js → use-is-mobile-D1weanbj.js} +0 -0
  512. /package/dist/web/assets/{use-visual-viewport-D9O48HQt.js → use-visual-viewport-Bfl3Bxxb.js} +0 -0
  513. /package/dist/web/assets/{utils-C9OjCrou.js → utils-IrnQujwR.js} +0 -0
  514. /package/dist/web/assets/{v-DSMUsdMO.js → v-Ch6E4Egd.js} +0 -0
  515. /package/dist/web/assets/{vala-BEazLpkO.js → vala-CGVKwbPx.js} +0 -0
  516. /package/dist/web/assets/{vb-CV9pEJzW.js → vb-BIEbSxyT.js} +0 -0
  517. /package/dist/web/assets/{vendor-xterm-cuGQmUjN.js → vendor-xterm-YQlzIWv2.js} +0 -0
  518. /package/dist/web/assets/{verilog-DhXkLVMk.js → verilog-A-3pYPad.js} +0 -0
  519. /package/dist/web/assets/{vesper-n4IltYq-.js → vesper-CK1naZAV.js} +0 -0
  520. /package/dist/web/assets/{vhdl-CePjFbvs.js → vhdl-CVawmgMg.js} +0 -0
  521. /package/dist/web/assets/{viml-ChndFsm5.js → viml-CiWjaqBY.js} +0 -0
  522. /package/dist/web/assets/{vitesse-black-BytVdvhC.js → vitesse-black-PYXW4-BO.js} +0 -0
  523. /package/dist/web/assets/{vitesse-dark-83Wech0N.js → vitesse-dark-BU5s4AuG.js} +0 -0
  524. /package/dist/web/assets/{vitesse-light-Xg4wbeMO.js → vitesse-light-DgkIT-N7.js} +0 -0
  525. /package/dist/web/assets/{vyper-eW1NC3FG.js → vyper-D8cRDPp3.js} +0 -0
  526. /package/dist/web/assets/{wasm-BucxKwBZ.js → wasm-C02wlRbP.js} +0 -0
  527. /package/dist/web/assets/{wasm-Bhucqu1z.js → wasm-ClFJgzmT.js} +0 -0
  528. /package/dist/web/assets/{wenyan-BJFBuXuH.js → wenyan-B8plxIr8.js} +0 -0
  529. /package/dist/web/assets/{wgsl-6z4FUyMK.js → wgsl-CVujtm3V.js} +0 -0
  530. /package/dist/web/assets/{wikitext-BoDU6teJ.js → wikitext-CmcG9B69.js} +0 -0
  531. /package/dist/web/assets/{wit-DerMPpgt.js → wit--gl2Jium.js} +0 -0
  532. /package/dist/web/assets/{wolfram-D78v0Ap-.js → wolfram-6T_1D-NS.js} +0 -0
  533. /package/dist/web/assets/{x-YDu4m2Iq.js → x-CxoBA0po.js} +0 -0
  534. /package/dist/web/assets/{yaml-C4TIgIw4.js → yaml-CIVV9uA1.js} +0 -0
  535. /package/dist/web/assets/{zenscript-BydW-dLC.js → zenscript-CoT4yNdA.js} +0 -0
  536. /package/dist/web/assets/{zig-b9lTqL5E.js → zig-BWs2Qo3G.js} +0 -0
@@ -15,6 +15,7 @@ import {
15
15
  GitCommitHorizontal,
16
16
  GitBranch,
17
17
  Check,
18
+ SquareDashedMousePointer,
18
19
  } from "lucide-react";
19
20
  import { SidebarHeader } from "@/components/ui/sidebar-header";
20
21
  import { api, projectUrl } from "@/lib/api-client";
@@ -26,6 +27,7 @@ import { useProjectStore } from "@/stores/project-store";
26
27
  import { useGitStatusStore } from "@/stores/git-status-store";
27
28
  import { useExtensionStore } from "@/stores/extension-store";
28
29
  import { GitWorktreePanel } from "./git-worktree-panel";
30
+ import { HunkStageDialog, type HunkStageTarget } from "./hunk-stage-dialog";
29
31
  import { Button } from "@/components/ui/button";
30
32
  import { ScrollArea } from "@/components/ui/scroll-area";
31
33
  import {
@@ -124,6 +126,8 @@ export function GitStatusPanel({ metadata, tabId, onNavigate }: GitStatusPanelPr
124
126
  label: string;
125
127
  files: string[];
126
128
  } | null>(null);
129
+ // Non-null while the hunk picker is open, for the file it was opened on.
130
+ const [hunkTarget, setHunkTarget] = useState<HunkStageTarget | null>(null);
127
131
  const { openTab } = useTabStore(useShallow((s) => ({ openTab: s.openTab })));
128
132
  const viewMode = useSettingsStore((s) => s.gitStatusViewMode);
129
133
  const setViewMode = useSettingsStore((s) => s.setGitStatusViewMode);
@@ -531,6 +535,7 @@ export function GitStatusPanel({ metadata, tabId, onNavigate }: GitStatusPanelPr
531
535
  onFolderAction={(files) => unstageFiles(files.map((f) => f.path))}
532
536
  onClickFile={openDiff}
533
537
  onOpenFile={openFile}
538
+ onPickHunks={(f) => setHunkTarget({ filePath: f.path, scope: "index" })}
534
539
  disabled={acting}
535
540
  />
536
541
 
@@ -553,6 +558,7 @@ export function GitStatusPanel({ metadata, tabId, onNavigate }: GitStatusPanelPr
553
558
  onFolderAction={(files) => stageFiles(files.map((f) => f.path))}
554
559
  onClickFile={openDiff}
555
560
  onOpenFile={openFile}
561
+ onPickHunks={(f) => setHunkTarget({ filePath: f.path, scope: "worktree" })}
556
562
  disabled={acting}
557
563
  showRevert
558
564
  onRevert={(f) =>
@@ -571,6 +577,14 @@ export function GitStatusPanel({ metadata, tabId, onNavigate }: GitStatusPanelPr
571
577
  {/* Commit block — bottom on mobile */}
572
578
  <div className="md:hidden border-t border-border shrink-0">{commitBox}</div>
573
579
 
580
+ {/* Hunk / line picker */}
581
+ <HunkStageDialog
582
+ projectName={projectName}
583
+ target={hunkTarget}
584
+ onClose={() => setHunkTarget(null)}
585
+ onApplied={fetchStatus}
586
+ />
587
+
574
588
  {/* Revert confirmation dialog */}
575
589
  <Dialog
576
590
  open={!!revertTarget}
@@ -622,6 +636,7 @@ function ActionButtons({
622
636
  onRevert,
623
637
  onAction,
624
638
  onOpenFile,
639
+ onPickHunks,
625
640
  actionIcon,
626
641
  actionTitle,
627
642
  disabled,
@@ -630,6 +645,7 @@ function ActionButtons({
630
645
  onRevert?: () => void;
631
646
  onAction: () => void;
632
647
  onOpenFile?: () => void;
648
+ onPickHunks?: () => void;
633
649
  actionIcon: React.ReactNode;
634
650
  actionTitle: string;
635
651
  disabled: boolean;
@@ -647,6 +663,17 @@ function ActionButtons({
647
663
  <FileText className="size-3" />
648
664
  </button>
649
665
  )}
666
+ {onPickHunks && (
667
+ <button
668
+ type="button"
669
+ className="flex items-center justify-center size-5 rounded text-muted-foreground hover:text-primary active:scale-95 transition-colors"
670
+ onClick={(e) => { e.stopPropagation(); onPickHunks(); }}
671
+ disabled={disabled}
672
+ title={`${actionTitle} lines…`}
673
+ >
674
+ <SquareDashedMousePointer className="size-3" />
675
+ </button>
676
+ )}
650
677
  {showRevert && onRevert && (
651
678
  <button
652
679
  type="button"
@@ -689,6 +716,7 @@ function FileSection({
689
716
  onFolderAction,
690
717
  onClickFile,
691
718
  onOpenFile,
719
+ onPickHunks,
692
720
  disabled,
693
721
  showRevert,
694
722
  onRevert,
@@ -707,6 +735,7 @@ function FileSection({
707
735
  onFolderAction?: (files: GitFileChange[]) => void;
708
736
  onClickFile: (f: GitFileChange) => void;
709
737
  onOpenFile?: (f: GitFileChange) => void;
738
+ onPickHunks?: (f: GitFileChange) => void;
710
739
  disabled: boolean;
711
740
  showRevert?: boolean;
712
741
  onRevert?: (f: GitFileChange) => void;
@@ -743,6 +772,7 @@ function FileSection({
743
772
  onAction={onAction}
744
773
  onClickFile={onClickFile}
745
774
  onOpenFile={onOpenFile}
775
+ onPickHunks={onPickHunks}
746
776
  disabled={disabled}
747
777
  showRevert={showRevert}
748
778
  onRevert={onRevert}
@@ -758,6 +788,7 @@ function FileSection({
758
788
  onFolderAction={onFolderAction}
759
789
  onClickFile={onClickFile}
760
790
  onOpenFile={onOpenFile}
791
+ onPickHunks={onPickHunks}
761
792
  disabled={disabled}
762
793
  showRevert={showRevert}
763
794
  onRevert={onRevert}
@@ -817,6 +848,7 @@ function FileRow({
817
848
  onAction,
818
849
  onClickFile,
819
850
  onOpenFile,
851
+ onPickHunks,
820
852
  disabled,
821
853
  showRevert,
822
854
  onRevert,
@@ -828,6 +860,7 @@ function FileRow({
828
860
  onAction: (f: GitFileChange) => void;
829
861
  onClickFile: (f: GitFileChange) => void;
830
862
  onOpenFile?: (f: GitFileChange) => void;
863
+ onPickHunks?: (f: GitFileChange) => void;
831
864
  disabled: boolean;
832
865
  showRevert?: boolean;
833
866
  onRevert?: (f: GitFileChange) => void;
@@ -864,6 +897,7 @@ function FileRow({
864
897
  showRevert={showRevert}
865
898
  onRevert={onRevert ? () => onRevert(file) : undefined}
866
899
  onOpenFile={onOpenFile ? () => onOpenFile(file) : undefined}
900
+ onPickHunks={onPickHunks ? () => onPickHunks(file) : undefined}
867
901
  onAction={() => onAction(file)}
868
902
  actionIcon={actionIcon}
869
903
  actionTitle={actionTitle}
@@ -892,6 +926,11 @@ function FileRow({
892
926
  <DropdownMenuItem onClick={() => onAction(file)} disabled={disabled}>
893
927
  {actionTitle}
894
928
  </DropdownMenuItem>
929
+ {onPickHunks && (
930
+ <DropdownMenuItem onClick={() => onPickHunks(file)} disabled={disabled}>
931
+ {actionTitle} Lines…
932
+ </DropdownMenuItem>
933
+ )}
895
934
  {showRevert && onRevert && (
896
935
  <DropdownMenuItem
897
936
  className="text-destructive focus:text-destructive"
@@ -920,6 +959,7 @@ function TreeView({
920
959
  onFolderAction,
921
960
  onClickFile,
922
961
  onOpenFile,
962
+ onPickHunks,
923
963
  disabled,
924
964
  showRevert,
925
965
  onRevert,
@@ -932,6 +972,7 @@ function TreeView({
932
972
  onFolderAction?: (files: GitFileChange[]) => void;
933
973
  onClickFile: (f: GitFileChange) => void;
934
974
  onOpenFile?: (f: GitFileChange) => void;
975
+ onPickHunks?: (f: GitFileChange) => void;
935
976
  disabled: boolean;
936
977
  showRevert?: boolean;
937
978
  onRevert?: (f: GitFileChange) => void;
@@ -953,6 +994,7 @@ function TreeView({
953
994
  onFolderAction={onFolderAction}
954
995
  onClickFile={onClickFile}
955
996
  onOpenFile={onOpenFile}
997
+ onPickHunks={onPickHunks}
956
998
  disabled={disabled}
957
999
  showRevert={showRevert}
958
1000
  onRevert={onRevert}
@@ -977,6 +1019,7 @@ function TreeNodeView({
977
1019
  onFolderAction,
978
1020
  onClickFile,
979
1021
  onOpenFile,
1022
+ onPickHunks,
980
1023
  disabled,
981
1024
  showRevert,
982
1025
  onRevert,
@@ -991,6 +1034,7 @@ function TreeNodeView({
991
1034
  onFolderAction?: (files: GitFileChange[]) => void;
992
1035
  onClickFile: (f: GitFileChange) => void;
993
1036
  onOpenFile?: (f: GitFileChange) => void;
1037
+ onPickHunks?: (f: GitFileChange) => void;
994
1038
  disabled: boolean;
995
1039
  showRevert?: boolean;
996
1040
  onRevert?: (f: GitFileChange) => void;
@@ -1024,6 +1068,7 @@ function TreeNodeView({
1024
1068
  onAction={onAction}
1025
1069
  onClickFile={onClickFile}
1026
1070
  onOpenFile={onOpenFile}
1071
+ onPickHunks={onPickHunks}
1027
1072
  disabled={disabled}
1028
1073
  showRevert={showRevert}
1029
1074
  onRevert={onRevert}
@@ -1123,6 +1168,7 @@ function TreeNodeView({
1123
1168
  onFolderAction={onFolderAction}
1124
1169
  onClickFile={onClickFile}
1125
1170
  onOpenFile={onOpenFile}
1171
+ onPickHunks={onPickHunks}
1126
1172
  disabled={disabled}
1127
1173
  showRevert={showRevert}
1128
1174
  onRevert={onRevert}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Selection arithmetic for the hunk picker.
3
+ *
4
+ * Kept apart from the component so the mapping from "which lines are ticked" to
5
+ * "what the server is asked to apply" can be tested directly — it is the part
6
+ * that has to be right, since a wrong index stages the wrong line.
7
+ */
8
+
9
+ export interface DiffLine {
10
+ kind: " " | "+" | "-";
11
+ text: string;
12
+ noNewline?: boolean;
13
+ }
14
+
15
+ export interface DiffHunk {
16
+ oldStart: number;
17
+ oldLines: number;
18
+ newStart: number;
19
+ newLines: number;
20
+ heading: string;
21
+ lines: DiffLine[];
22
+ /**
23
+ * Content address of this hunk, from `GET /git/hunks`. Echoed back on apply
24
+ * so the server resolves the selection against the diff that was on screen
25
+ * rather than against whatever the file says by the time the request lands.
26
+ */
27
+ id: string;
28
+ }
29
+
30
+ /** `${hunkIndex}:${lineIndex}` — flat, so one Set holds the whole selection. */
31
+ export type LineKey = string;
32
+
33
+ export const lineKey = (hunk: number, line: number): LineKey => `${hunk}:${line}`;
34
+
35
+ /** Indexes of the changed lines in one hunk. Context is never selectable. */
36
+ export function changedLineIndexes(hunk: DiffHunk): number[] {
37
+ const out: number[] = [];
38
+ hunk.lines.forEach((line, i) => {
39
+ if (line.kind !== " ") out.push(i);
40
+ });
41
+ return out;
42
+ }
43
+
44
+ /** Every selectable line across every hunk. */
45
+ export function allChangedKeys(hunks: DiffHunk[]): LineKey[] {
46
+ return hunks.flatMap((hunk, h) => changedLineIndexes(hunk).map((i) => lineKey(h, i)));
47
+ }
48
+
49
+ /** How much of one hunk is ticked — drives its checkbox's three states. */
50
+ export function hunkState(
51
+ hunks: DiffHunk[],
52
+ index: number,
53
+ selected: Set<LineKey>,
54
+ ): { picked: number; total: number } {
55
+ const hunk = hunks[index];
56
+ if (!hunk) return { picked: 0, total: 0 };
57
+ const changed = changedLineIndexes(hunk);
58
+ return {
59
+ picked: changed.filter((i) => selected.has(lineKey(index, i))).length,
60
+ total: changed.length,
61
+ };
62
+ }
63
+
64
+ /** Tick a whole hunk, or untick it when it is already fully ticked. */
65
+ export function toggleHunk(
66
+ hunks: DiffHunk[],
67
+ index: number,
68
+ selected: Set<LineKey>,
69
+ ): Set<LineKey> {
70
+ const hunk = hunks[index];
71
+ if (!hunk) return selected;
72
+ const keys = changedLineIndexes(hunk).map((i) => lineKey(index, i));
73
+ const next = new Set(selected);
74
+ const allOn = keys.every((k) => next.has(k));
75
+ for (const key of keys) {
76
+ if (allOn) next.delete(key);
77
+ else next.add(key);
78
+ }
79
+ return next;
80
+ }
81
+
82
+ export function toggleLine(hunk: number, line: number, selected: Set<LineKey>): Set<LineKey> {
83
+ const next = new Set(selected);
84
+ const key = lineKey(hunk, line);
85
+ if (next.has(key)) next.delete(key);
86
+ else next.add(key);
87
+ return next;
88
+ }
89
+
90
+ export interface HunkRequest {
91
+ /** Position in the list as shown. A hint for the server, not the key. */
92
+ hunk: number;
93
+ /** The hunk's content address — what the server actually resolves by. */
94
+ id: string;
95
+ /** Line indexes within the hunk; omitted means the whole hunk. */
96
+ lines?: number[];
97
+ }
98
+
99
+ /**
100
+ * The body for `/git/{stage,unstage,discard}-hunks`.
101
+ *
102
+ * A fully ticked hunk is sent without `lines` so the server can take it
103
+ * verbatim; a hunk with nothing ticked is left out entirely rather than sent
104
+ * empty, which the server would reject.
105
+ */
106
+ export function buildHunkRequest(hunks: DiffHunk[], selected: Set<LineKey>): HunkRequest[] {
107
+ const out: HunkRequest[] = [];
108
+ hunks.forEach((hunk, h) => {
109
+ const changed = changedLineIndexes(hunk);
110
+ const picked = changed.filter((i) => selected.has(lineKey(h, i)));
111
+ if (picked.length === 0) return;
112
+ out.push(
113
+ picked.length === changed.length
114
+ ? { hunk: h, id: hunk.id }
115
+ : { hunk: h, id: hunk.id, lines: picked },
116
+ );
117
+ });
118
+ return out;
119
+ }
120
+
121
+ /**
122
+ * The old/new line number for each row, walked the way git numbers a diff: an
123
+ * addition has no old number and a deletion has no new one.
124
+ */
125
+ export function lineNumbers(hunk: DiffHunk): { old: string; next: string }[] {
126
+ let oldNo = hunk.oldStart;
127
+ let newNo = hunk.newStart;
128
+ return hunk.lines.map((line) => ({
129
+ old: line.kind === "+" ? "" : String(oldNo++),
130
+ next: line.kind === "-" ? "" : String(newNo++),
131
+ }));
132
+ }