difit 4.0.5 → 4.0.6

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 (171) hide show
  1. package/README.ja.md +1 -0
  2. package/README.ko.md +1 -0
  3. package/README.md +1 -0
  4. package/README.zh.md +1 -0
  5. package/dist/cli/comment.d.ts +2 -0
  6. package/dist/cli/comment.js +91 -0
  7. package/dist/cli/comment.test.d.ts +1 -0
  8. package/dist/cli/comment.test.js +164 -0
  9. package/dist/cli/index.js +103 -12
  10. package/dist/cli/utils.d.ts +1 -0
  11. package/dist/cli/utils.js +7 -0
  12. package/dist/client/assets/{_baseFor-DKyA49xd.js → _baseFor-Dq1lbcoh.js} +1 -1
  13. package/dist/client/assets/{arc-COOp7iVe.js → arc-1g1LrDb3.js} +1 -1
  14. package/dist/client/assets/architecture-YZFGNWBL-MZfdAdY6.js +1 -0
  15. package/dist/client/assets/architectureDiagram-Q4EWVU46-D87-Rmwy.js +36 -0
  16. package/dist/client/assets/{blockDiagram-DXYQGD6D-CtNJnEWN.js → blockDiagram-DXYQGD6D-Cep-MIFv.js} +1 -1
  17. package/dist/client/assets/{c4Diagram-AHTNJAMY-BqG-1m6C.js → c4Diagram-AHTNJAMY-BQuH9Txx.js} +1 -1
  18. package/dist/client/assets/channel-CJqLEVLU.js +1 -0
  19. package/dist/client/assets/{chunk-2KRD3SAO-DqP2NJNd.js → chunk-2KRD3SAO-CpQQpmvx.js} +1 -1
  20. package/dist/client/assets/chunk-336JU56O-Ddk9EzgO.js +2 -0
  21. package/dist/client/assets/chunk-426QAEUC-2xhUznDE.js +1 -0
  22. package/dist/client/assets/{chunk-4BX2VUAB-BT78EnQ6.js → chunk-4BX2VUAB-Ca-N0Wd9.js} +1 -1
  23. package/dist/client/assets/{chunk-4TB4RGXK-C4w_Bwzw.js → chunk-4TB4RGXK-ZTWP_Onw.js} +2 -2
  24. package/dist/client/assets/{chunk-55IACEB6-z3MQSTaj.js → chunk-55IACEB6-Dub40zHG.js} +1 -1
  25. package/dist/client/assets/{chunk-5FUZZQ4R-Chei69aj.js → chunk-5FUZZQ4R-Cgda0gtZ.js} +1 -1
  26. package/dist/client/assets/{chunk-5PVQY5BW-HgRiIs0X.js → chunk-5PVQY5BW-D8JPH_tm.js} +1 -1
  27. package/dist/client/assets/{chunk-67CJDMHE-B2q10-fp.js → chunk-67CJDMHE-U1KyLHzG.js} +1 -1
  28. package/dist/client/assets/{chunk-7N4EOEYR-DPgxysWq.js → chunk-7N4EOEYR-WzOy51nD.js} +1 -1
  29. package/dist/client/assets/{chunk-AA7GKIK3-BqmVmKLq.js → chunk-AA7GKIK3-DlWOj4lr.js} +1 -1
  30. package/dist/client/assets/{chunk-BSJP7CBP-CaIgleFn.js → chunk-BSJP7CBP-CcZ0op08.js} +1 -1
  31. package/dist/client/assets/{chunk-CIAEETIT-ByD-tlNF.js → chunk-CIAEETIT-qVSphnw5.js} +1 -1
  32. package/dist/client/assets/{chunk-EDXVE4YY-d3RUKKAj.js → chunk-EDXVE4YY-76SPH4sf.js} +1 -1
  33. package/dist/client/assets/{chunk-ENJZ2VHE-CNq5Qmg9.js → chunk-ENJZ2VHE-CKULNIzL.js} +1 -1
  34. package/dist/client/assets/{chunk-FMBD7UC4-DYfHJ6MV.js → chunk-FMBD7UC4-CvDPP3mb.js} +1 -1
  35. package/dist/client/assets/{chunk-FOC6F5B3-BRpSWlZj.js → chunk-FOC6F5B3-DceW0hWA.js} +1 -1
  36. package/dist/client/assets/{chunk-ICPOFSXX-B_MThwG6.js → chunk-ICPOFSXX-ChGBNZMk.js} +2 -2
  37. package/dist/client/assets/{chunk-K5T4RW27-DmamW1Ds.js → chunk-K5T4RW27-DBHdC4ln.js} +10 -10
  38. package/dist/client/assets/{chunk-KGLVRYIC-CRbg4c4z.js → chunk-KGLVRYIC-DRS7yiGQ.js} +1 -1
  39. package/dist/client/assets/{chunk-LIHQZDEY-CHQPSdB3.js → chunk-LIHQZDEY-KsE8dyJP.js} +1 -1
  40. package/dist/client/assets/{chunk-ORNJ4GCN-CIsQ4Zi4.js → chunk-ORNJ4GCN-Dnp4oHRD.js} +1 -1
  41. package/dist/client/assets/{chunk-OYMX7WX6-Cxi0kdGg.js → chunk-OYMX7WX6-CciaotDu.js} +1 -1
  42. package/dist/client/assets/chunk-QZHKN3VN-BiVE5u_E.js +1 -0
  43. package/dist/client/assets/{chunk-U2HBQHQK-V_hneCfR.js → chunk-U2HBQHQK-nbp7CjBP.js} +1 -1
  44. package/dist/client/assets/{chunk-X2U36JSP-De4pvO-I.js → chunk-X2U36JSP-Chs85loT.js} +1 -1
  45. package/dist/client/assets/{chunk-XPW4576I-B_osXKp6.js → chunk-XPW4576I-VtI9b561.js} +1 -1
  46. package/dist/client/assets/{chunk-YZCP3GAM-C_kqXssD.js → chunk-YZCP3GAM-sBsewSoO.js} +1 -1
  47. package/dist/client/assets/{chunk-ZZ45TVLE-B_xtlma5.js → chunk-ZZ45TVLE-TMgeW_px.js} +1 -1
  48. package/dist/client/assets/classDiagram-6PBFFD2Q-CfyHazmg.js +1 -0
  49. package/dist/client/assets/classDiagram-v2-HSJHXN6E-D7Rb-bnu.js +1 -0
  50. package/dist/client/assets/clone-8xC1huEg.js +1 -0
  51. package/dist/client/assets/cose-bilkent-S5V4N54A-5TzM3w9g.js +1 -0
  52. package/dist/client/assets/{cytoscape.esm-DRReFUEO.js → cytoscape.esm-DdcHPZAZ.js} +2 -2
  53. package/dist/client/assets/{dagre-KV5264BT-BWYGReXF.js → dagre-KV5264BT-xvyFOxd3.js} +1 -1
  54. package/dist/client/assets/{dagre-DU-XBdcU.js → dagre-sb6WtN4K.js} +1 -1
  55. package/dist/client/assets/{diagram-5BDNPKRD-DpUUhvWz.js → diagram-5BDNPKRD-ChRpAe5p.js} +1 -1
  56. package/dist/client/assets/{diagram-G4DWMVQ6-BJoTrUAx.js → diagram-G4DWMVQ6-C_8BED4A.js} +1 -1
  57. package/dist/client/assets/{diagram-MMDJMWI5-CAk1GW5g.js → diagram-MMDJMWI5-BMwXEou2.js} +1 -1
  58. package/dist/client/assets/{diagram-TYMM5635-Cct6g7FA.js → diagram-TYMM5635-CeAkx82D.js} +1 -1
  59. package/dist/client/assets/{dist-61sCfOmN.js → dist-CwC9dd2Z.js} +1 -1
  60. package/dist/client/assets/{erDiagram-SMLLAGMA-DHs2bXUj.js → erDiagram-SMLLAGMA-yGCTeXGt.js} +1 -1
  61. package/dist/client/assets/{flatten-mnWyE-RB.js → flatten-SRIRKgqP.js} +1 -1
  62. package/dist/client/assets/{flowDiagram-DWJPFMVM-DLu-6dfC.js → flowDiagram-DWJPFMVM-CugkvbmM.js} +1 -1
  63. package/dist/client/assets/ganttDiagram-T4ZO3ILL-BXnlBFgK.js +292 -0
  64. package/dist/client/assets/gitGraph-7Q5UKJZL-BeTWkPrd.js +1 -0
  65. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-Bc_rL3_k.js → gitGraphDiagram-UUTBAWPF-B61aCwwu.js} +1 -1
  66. package/dist/client/assets/{graphlib-BVMK0xYE.js → graphlib-BMWKz3zT.js} +1 -1
  67. package/dist/client/assets/index-D2Y8-unG.css +2 -0
  68. package/dist/client/assets/index-D9v_eYzS.js +79 -0
  69. package/dist/client/assets/info-OMHHGYJF-MUNR2tTt.js +1 -0
  70. package/dist/client/assets/{infoDiagram-42DDH7IO-Cf8u4jgP.js → infoDiagram-42DDH7IO-Bkh6nTL2.js} +1 -1
  71. package/dist/client/assets/{isEmpty-CiiIHfXR.js → isEmpty-CStpjy4G.js} +1 -1
  72. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-7n7DvfEb.js → ishikawaDiagram-UXIWVN3A-D_fdVT6_.js} +1 -1
  73. package/dist/client/assets/{journeyDiagram-VCZTEJTY-BMkeQqJb.js → journeyDiagram-VCZTEJTY-DkXVokNF.js} +1 -1
  74. package/dist/client/assets/{kanban-definition-6JOO6SKY-B8KkeZLS.js → kanban-definition-6JOO6SKY-y8qq7qvL.js} +1 -1
  75. package/dist/client/assets/{line-CVpcI6kj.js → line-B0LcTqNY.js} +1 -1
  76. package/dist/client/assets/{linear-DmhiOOKU.js → linear-CqIjr2qp.js} +1 -1
  77. package/dist/client/assets/mermaid-parser.core-Du6QzpZO.js +4 -0
  78. package/dist/client/assets/{mermaid.core-R7nXpPx-.js → mermaid.core-CZBu-oKJ.js} +3 -3
  79. package/dist/client/assets/{mindmap-definition-QFDTVHPH-CwcHocMZ.js → mindmap-definition-QFDTVHPH-BJrRxSkM.js} +1 -1
  80. package/dist/client/assets/{ordinal-k--hYEme.js → ordinal-DIg8h6NI.js} +1 -1
  81. package/dist/client/assets/packet-4T2RLAQJ-Ci-Uu57s.js +1 -0
  82. package/dist/client/assets/pie-ZZUOXDRM-pm57XGIg.js +1 -0
  83. package/dist/client/assets/{pieDiagram-DEJITSTG-BVAn8Lmr.js → pieDiagram-DEJITSTG-Debmhc0u.js} +1 -1
  84. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-C2XZ_zxa.js → quadrantDiagram-34T5L4WZ-SE3g2BC9.js} +1 -1
  85. package/dist/client/assets/radar-PYXPWWZC-CH-AuSDw.js +1 -0
  86. package/dist/client/assets/{reduce-BTlHjXna.js → reduce-CG4cgj93.js} +1 -1
  87. package/dist/client/assets/{requirementDiagram-MS252O5E-CfO16pkI.js → requirementDiagram-MS252O5E-1mv41puC.js} +1 -1
  88. package/dist/client/assets/{sankeyDiagram-XADWPNL6-D_4_234M.js → sankeyDiagram-XADWPNL6-CLjPRtOP.js} +1 -1
  89. package/dist/client/assets/{sequenceDiagram-FGHM5R23-B-yHKMuK.js → sequenceDiagram-FGHM5R23-Cs-P3AtR.js} +1 -1
  90. package/dist/client/assets/src-5XpQHeIJ.js +1 -0
  91. package/dist/client/assets/{stateDiagram-FHFEXIEX-BeG2di4I.js → stateDiagram-FHFEXIEX-CmB1fohY.js} +1 -1
  92. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-D6jsrR-f.js +1 -0
  93. package/dist/client/assets/{timeline-definition-GMOUNBTQ-DhtnMGcE.js → timeline-definition-GMOUNBTQ-BMUafJOI.js} +1 -1
  94. package/dist/client/assets/treeView-SZITEDCU-BGsVMAdJ.js +1 -0
  95. package/dist/client/assets/treemap-W4RFUUIX-DXnhegXy.js +1 -0
  96. package/dist/client/assets/{vennDiagram-DHZGUBPP-CBn69TcQ.js → vennDiagram-DHZGUBPP-CpZ1Qhjz.js} +1 -1
  97. package/dist/client/assets/wardley-RL74JXVD-COd5nWj-.js +1 -0
  98. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-CEoSJmN1.js → wardleyDiagram-NUSXRM2D-C-zH0lsd.js} +1 -1
  99. package/dist/client/assets/{xychartDiagram-5P7HB3ND-BZ_X9tkn.js → xychartDiagram-5P7HB3ND-SkLFuEHZ.js} +1 -1
  100. package/dist/client/index.html +2 -4
  101. package/dist/client/site-data/blobs/080c0e6/cHVibGljL3NpdGUtZGF0YS9vZy1pbWFnZS5wbmc.png +0 -0
  102. package/dist/client/site-data/blobs/55f23a1/bGFuZGluZy9wdWJsaWMvZGlmaXQvbG9nby5wbmc.png +0 -0
  103. package/dist/client/site-data/blobs/66ff7c6/cHVibGljL2xvZ28ucG5n.png +0 -0
  104. package/dist/client/site-data/blobs/e6977fe/cHVibGljL2xvZ28ucG5n.png +0 -0
  105. package/dist/client/site-data/og-image.png +0 -0
  106. package/dist/server/file-watcher.d.ts +2 -1
  107. package/dist/server/file-watcher.js +9 -3
  108. package/dist/server/git-diff.d.ts +5 -0
  109. package/dist/server/git-diff.js +65 -1
  110. package/dist/server/git-diff.test.js +50 -0
  111. package/dist/server/server.js +265 -68
  112. package/dist/server/server.test.js +228 -0
  113. package/dist/tui/App.js +0 -1
  114. package/dist/types/diff.d.ts +4 -4
  115. package/dist/types/watch.d.ts +30 -1
  116. package/dist/utils/commentImports.d.ts +2 -0
  117. package/dist/utils/commentImports.js +119 -1
  118. package/dist/utils/editorOptions.d.ts +58 -35
  119. package/dist/utils/editorOptions.js +150 -24
  120. package/dist/utils/editorOptions.test.js +201 -9
  121. package/package.json +7 -4
  122. package/dist/client/assets/architecture-YZFGNWBL-Cs2Q6RQP.js +0 -1
  123. package/dist/client/assets/architectureDiagram-Q4EWVU46-BO4dVPUA.js +0 -36
  124. package/dist/client/assets/channel-_xDT1u3-.js +0 -1
  125. package/dist/client/assets/chunk-336JU56O-D1qa7Qzb.js +0 -2
  126. package/dist/client/assets/chunk-426QAEUC-6J_A_wvD.js +0 -1
  127. package/dist/client/assets/chunk-CFjPhJqf.js +0 -1
  128. package/dist/client/assets/chunk-QZHKN3VN-C0QzfgZ8.js +0 -1
  129. package/dist/client/assets/classDiagram-6PBFFD2Q-5XrS-DAQ.js +0 -1
  130. package/dist/client/assets/classDiagram-v2-HSJHXN6E-Covl2vKy.js +0 -1
  131. package/dist/client/assets/clone-rhRH8pyW.js +0 -1
  132. package/dist/client/assets/cose-bilkent-S5V4N54A-BvXFc7Rr.js +0 -1
  133. package/dist/client/assets/ganttDiagram-T4ZO3ILL-CMIzlKAR.js +0 -292
  134. package/dist/client/assets/gitGraph-7Q5UKJZL-A_wWsXju.js +0 -1
  135. package/dist/client/assets/index-BPoqJmrs.js +0 -79
  136. package/dist/client/assets/index-Cq_APK7Y.css +0 -2
  137. package/dist/client/assets/info-OMHHGYJF-Bv3kK2Bb.js +0 -1
  138. package/dist/client/assets/mermaid-parser.core-CnJ9Tv8l.js +0 -4
  139. package/dist/client/assets/packet-4T2RLAQJ-D2q3-9ae.js +0 -1
  140. package/dist/client/assets/pie-ZZUOXDRM-GivlQcUF.js +0 -1
  141. package/dist/client/assets/preload-helper-DSXbuxSR.js +0 -1
  142. package/dist/client/assets/radar-PYXPWWZC-C9pD6VNR.js +0 -1
  143. package/dist/client/assets/src-CjDs0_Ij.js +0 -1
  144. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DvcSq7KE.js +0 -1
  145. package/dist/client/assets/treeView-SZITEDCU-BSNk8_yV.js +0 -1
  146. package/dist/client/assets/treemap-W4RFUUIX-ym4zQztE.js +0 -1
  147. package/dist/client/assets/wardley-RL74JXVD-B02H6ReJ.js +0 -1
  148. /package/dist/client/assets/{array-BNor45A1.js → array-DOVTz2Mq.js} +0 -0
  149. /package/dist/client/assets/{defaultLocale-DPzUsThw.js → defaultLocale-Ck2Xxk-C.js} +0 -0
  150. /package/dist/client/assets/{init-C0L3woqb.js → init-Bft5Ffpj.js} +0 -0
  151. /package/dist/client/assets/{katex-FOM3xZj7.js → katex-CeIlAR55.js} +0 -0
  152. /package/dist/client/assets/{path-sMK4d_s9.js → path-DfRbCp9y.js} +0 -0
  153. /package/dist/client/assets/{prism-bash-iQBez6et.js → prism-bash-CPkZUJMA.js} +0 -0
  154. /package/dist/client/assets/{prism-clojure-CTkJ-FW_.js → prism-clojure-BpoF2XhX.js} +0 -0
  155. /package/dist/client/assets/{prism-csharp-DAAROvjt.js → prism-csharp-BEk8D1-3.js} +0 -0
  156. /package/dist/client/assets/{prism-dart-CMjMHaBW.js → prism-dart-ByLYrdQB.js} +0 -0
  157. /package/dist/client/assets/{prism-elixir-B9cwzXs0.js → prism-elixir-BZtyIEab.js} +0 -0
  158. /package/dist/client/assets/{prism-haskell-Vgx7BCAm.js → prism-haskell-NAsbeo3V.js} +0 -0
  159. /package/dist/client/assets/{prism-hcl-Du4YC80h.js → prism-hcl-crnGqmVp.js} +0 -0
  160. /package/dist/client/assets/{prism-java-CWuFbfVD.js → prism-java-BovStacA.js} +0 -0
  161. /package/dist/client/assets/{prism-markup-templating-h9TC-ifW.js → prism-markup-templating-Cl8NiLjy.js} +0 -0
  162. /package/dist/client/assets/{prism-nix-CqauNIYa.js → prism-nix-BS_cm_1n.js} +0 -0
  163. /package/dist/client/assets/{prism-perl-DhcRwJzx.js → prism-perl-DGLVMq5H.js} +0 -0
  164. /package/dist/client/assets/{prism-php-DcBIrISj.js → prism-php-BskSwJN8.js} +0 -0
  165. /package/dist/client/assets/{prism-protobuf-DuPg7Jbg.js → prism-protobuf-DfbIYpO7.js} +0 -0
  166. /package/dist/client/assets/{prism-ruby-lhDmuasn.js → prism-ruby-FBVh1PRE.js} +0 -0
  167. /package/dist/client/assets/{prism-scala-YlPat9I4.js → prism-scala--9AfMHPY.js} +0 -0
  168. /package/dist/client/assets/{prism-solidity-C3nR0EVH.js → prism-solidity-BgJNkj1z.js} +0 -0
  169. /package/dist/client/assets/{prism-sql-Cz-8DmQS.js → prism-sql-C9Czmpov.js} +0 -0
  170. /package/dist/client/assets/{prism-vim-C3oukvmk.js → prism-vim-CzUNf0WQ.js} +0 -0
  171. /package/dist/client/assets/{rough.esm-DeLgKbOI.js → rough.esm-Bbn_-PMU.js} +0 -0
@@ -32,7 +32,7 @@ export interface ParsedDiff {
32
32
  chunks: DiffChunk[];
33
33
  }
34
34
  export type DiffViewMode = 'split' | 'unified';
35
- export type LegacyDiffViewMode = 'side-by-side' | 'inline';
35
+ type LegacyDiffViewMode = 'side-by-side' | 'inline';
36
36
  export type DiffSide = 'old' | 'new';
37
37
  export type DiffLineRange = number | {
38
38
  start: number;
@@ -168,11 +168,11 @@ export interface CommentThread {
168
168
  codeContent?: string;
169
169
  messages: DiffCommentMessage[];
170
170
  }
171
- export interface RevisionOption {
171
+ interface RevisionOption {
172
172
  value: string;
173
173
  label: string;
174
174
  }
175
- export interface BranchInfo {
175
+ interface BranchInfo {
176
176
  name: string;
177
177
  current: boolean;
178
178
  }
@@ -199,7 +199,7 @@ export interface FileExpandedState {
199
199
  oldTotalLines?: number;
200
200
  newTotalLines?: number;
201
201
  }
202
- export interface ExpandedRange {
202
+ interface ExpandedRange {
203
203
  chunkIndex: number;
204
204
  direction: 'up' | 'down';
205
205
  count: number;
@@ -5,12 +5,41 @@ export declare enum DiffMode {
5
5
  DOT = "dot",// HEAD vs working (all changes)
6
6
  SPECIFIC = "specific"
7
7
  }
8
+ type WatchChangeType = 'file' | 'commit' | 'staging';
9
+ interface ConnectedWatchEvent {
10
+ type: 'connected';
11
+ diffMode: DiffMode;
12
+ changeType: WatchChangeType;
13
+ timestamp: string;
14
+ message?: string;
15
+ }
16
+ interface ReloadWatchEvent {
17
+ type: 'reload';
18
+ diffMode: DiffMode;
19
+ changeType: WatchChangeType;
20
+ timestamp: string;
21
+ message?: string;
22
+ }
23
+ interface ErrorWatchEvent {
24
+ type: 'error';
25
+ diffMode: DiffMode;
26
+ changeType: WatchChangeType;
27
+ timestamp: string;
28
+ message?: string;
29
+ }
30
+ interface CommentsChangedWatchEvent {
31
+ type: 'commentsChanged';
32
+ version: number;
33
+ timestamp: string;
34
+ }
35
+ export type WatchEvent = ConnectedWatchEvent | ReloadWatchEvent | ErrorWatchEvent | CommentsChangedWatchEvent;
8
36
  export interface ClientWatchState {
9
37
  isWatchEnabled: boolean;
10
38
  diffMode: DiffMode;
11
39
  shouldReload: boolean;
12
40
  isReloading: boolean;
13
41
  lastChangeTime: Date | null;
14
- lastChangeType: 'file' | 'commit' | 'staging' | null;
42
+ lastChangeType: WatchChangeType | null;
15
43
  connectionStatus: 'connected' | 'disconnected' | 'reconnecting';
16
44
  }
45
+ export {};
@@ -3,7 +3,9 @@ interface MergeCommentImportsResult {
3
3
  threads: DiffCommentThread[];
4
4
  warnings: string[];
5
5
  }
6
+ export declare function normalizeCommentImports(input: unknown): CommentImport[];
6
7
  export declare function parseCommentImportValue(value: string): CommentImport[];
8
+ export declare function mergeCommentThreads(existingThreads: DiffCommentThread[], incomingThreads: DiffCommentThread[]): MergeCommentImportsResult;
7
9
  export declare function serializeCommentImports(commentImports: CommentImport[]): string;
8
10
  export declare function mergeCommentImports(existingThreads: DiffCommentThread[], commentImports: CommentImport[]): MergeCommentImportsResult;
9
11
  export {};
@@ -105,7 +105,7 @@ function normalizeCommentImportEntry(value) {
105
105
  };
106
106
  return normalized;
107
107
  }
108
- function normalizeCommentImports(input) {
108
+ export function normalizeCommentImports(input) {
109
109
  if (Array.isArray(input)) {
110
110
  return input.map((entry) => normalizeCommentImportEntry(entry));
111
111
  }
@@ -204,6 +204,124 @@ function createImportedReply(commentImport, now) {
204
204
  updatedAt,
205
205
  };
206
206
  }
207
+ function cloneLineRange(line) {
208
+ if (typeof line === 'number') {
209
+ return line;
210
+ }
211
+ return {
212
+ start: line.start,
213
+ end: line.end,
214
+ };
215
+ }
216
+ function clonePosition(position) {
217
+ return {
218
+ side: position.side,
219
+ line: cloneLineRange(position.line),
220
+ };
221
+ }
222
+ function cloneCodeSnapshot(snapshot) {
223
+ if (!snapshot) {
224
+ return undefined;
225
+ }
226
+ return {
227
+ content: snapshot.content,
228
+ language: snapshot.language,
229
+ };
230
+ }
231
+ function cloneMessage(message) {
232
+ return {
233
+ id: message.id,
234
+ body: message.body,
235
+ author: message.author,
236
+ createdAt: message.createdAt,
237
+ updatedAt: message.updatedAt,
238
+ };
239
+ }
240
+ function cloneThread(thread) {
241
+ return {
242
+ id: thread.id,
243
+ filePath: thread.filePath,
244
+ createdAt: thread.createdAt,
245
+ updatedAt: thread.updatedAt,
246
+ position: clonePosition(thread.position),
247
+ codeSnapshot: cloneCodeSnapshot(thread.codeSnapshot),
248
+ messages: thread.messages.map(cloneMessage),
249
+ };
250
+ }
251
+ function messagesMatch(left, right) {
252
+ if (left.id === right.id) {
253
+ return true;
254
+ }
255
+ if (normalizeAuthor(left.author) !== normalizeAuthor(right.author)) {
256
+ return false;
257
+ }
258
+ return left.body === right.body && left.createdAt === right.createdAt;
259
+ }
260
+ function threadsMatch(left, right) {
261
+ if (left.id === right.id) {
262
+ return true;
263
+ }
264
+ if (left.filePath !== right.filePath || !positionsMatch(left.position, right.position)) {
265
+ return false;
266
+ }
267
+ const leftRoot = left.messages[0];
268
+ const rightRoot = right.messages[0];
269
+ if (!leftRoot || !rightRoot) {
270
+ return false;
271
+ }
272
+ return messagesMatch(leftRoot, rightRoot);
273
+ }
274
+ function sortReplies(left, right) {
275
+ const createdAtOrder = left.createdAt.localeCompare(right.createdAt);
276
+ if (createdAtOrder !== 0) {
277
+ return createdAtOrder;
278
+ }
279
+ return left.id.localeCompare(right.id);
280
+ }
281
+ function pickNewerMessage(existingMessage, incomingMessage) {
282
+ if (incomingMessage.updatedAt.localeCompare(existingMessage.updatedAt) >= 0) {
283
+ return cloneMessage(incomingMessage);
284
+ }
285
+ return cloneMessage(existingMessage);
286
+ }
287
+ function mergeThread(existingThread, incomingThread) {
288
+ const mergedMessages = existingThread.messages.map(cloneMessage);
289
+ for (const incomingMessage of incomingThread.messages) {
290
+ const matchIndex = mergedMessages.findIndex((message) => messagesMatch(message, incomingMessage));
291
+ if (matchIndex >= 0) {
292
+ mergedMessages[matchIndex] = pickNewerMessage(mergedMessages[matchIndex], incomingMessage);
293
+ continue;
294
+ }
295
+ mergedMessages.push(cloneMessage(incomingMessage));
296
+ }
297
+ const [rootMessage, ...replyMessages] = mergedMessages;
298
+ const orderedMessages = rootMessage
299
+ ? [rootMessage, ...replyMessages.sort(sortReplies)]
300
+ : replyMessages.sort(sortReplies);
301
+ const updatedAt = orderedMessages.reduce((latest, message) => maxIsoTimestamp(latest, message.updatedAt), maxIsoTimestamp(existingThread.updatedAt, incomingThread.updatedAt));
302
+ return {
303
+ ...cloneThread(existingThread),
304
+ createdAt: existingThread.createdAt.localeCompare(incomingThread.createdAt) <= 0
305
+ ? existingThread.createdAt
306
+ : incomingThread.createdAt,
307
+ updatedAt,
308
+ position: clonePosition(existingThread.position),
309
+ codeSnapshot: cloneCodeSnapshot(incomingThread.codeSnapshot ?? existingThread.codeSnapshot),
310
+ messages: orderedMessages,
311
+ };
312
+ }
313
+ export function mergeCommentThreads(existingThreads, incomingThreads) {
314
+ const threads = existingThreads.map(cloneThread);
315
+ for (const incomingThread of incomingThreads) {
316
+ const existingIndex = threads.findIndex((thread) => threadsMatch(thread, incomingThread));
317
+ if (existingIndex < 0) {
318
+ threads.push(cloneThread(incomingThread));
319
+ continue;
320
+ }
321
+ threads[existingIndex] = mergeThread(threads[existingIndex], incomingThread);
322
+ }
323
+ return { threads, warnings: [] };
324
+ }
207
325
  function serializeLineRange(line) {
208
326
  if (typeof line === 'number') {
209
327
  return line;
@@ -1,37 +1,60 @@
1
- export declare const EDITOR_OPTIONS: readonly [{
2
- readonly id: "vscode";
3
- readonly label: "VS Code";
4
- readonly protocol: "vscode";
5
- readonly cliCommand: "code";
6
- readonly cliArgs: readonly [];
7
- readonly lineFormat: "goto-flag";
8
- readonly aliases: readonly ["vscode", "code"];
9
- }, {
10
- readonly id: "cursor";
11
- readonly label: "Cursor";
12
- readonly protocol: "cursor";
13
- readonly cliCommand: "cursor";
14
- readonly cliArgs: readonly [];
15
- readonly lineFormat: "goto-flag";
16
- readonly aliases: readonly ["cursor"];
17
- }, {
18
- readonly id: "zed";
19
- readonly label: "Zed";
20
- readonly protocol: "zed";
21
- readonly cliCommand: "zed";
22
- readonly cliArgs: readonly [];
23
- readonly lineFormat: "path-suffix";
24
- readonly aliases: readonly ["zed"];
25
- }, {
26
- readonly id: "none";
27
- readonly label: "Hide “Open in editor” button";
28
- readonly protocol: null;
29
- readonly cliCommand: null;
30
- readonly cliArgs: readonly [];
31
- readonly lineFormat: "goto-flag";
32
- readonly aliases: readonly ["none", "disabled", "off"];
33
- }];
34
- export type EditorOption = (typeof EDITOR_OPTIONS)[number];
35
- export type EditorOptionId = EditorOption['id'];
1
+ export type EditorOptionId = 'vscode' | 'cursor' | 'zed' | 'textmate' | 'bbedit' | 'emacs' | 'macvim' | 'sublime' | 'nova' | 'custom' | 'none';
2
+ interface EditorOption {
3
+ readonly id: EditorOptionId;
4
+ readonly label: string;
5
+ /**
6
+ * Executable to run. Empty string for the `custom` placeholder (filled in by
7
+ * the user) and for `none` (open-in-editor disabled).
8
+ */
9
+ readonly command: string;
10
+ /**
11
+ * Whitespace-separated argument template. Supports the `%file` and `%line`
12
+ * placeholders. Parsed just before spawning so quoted segments survive:
13
+ * e.g. `'-l %line "%file"'`.
14
+ */
15
+ readonly argsTemplate: string;
16
+ }
17
+ export declare const CUSTOM_EDITOR_ID: EditorOptionId;
18
+ export declare const NONE_EDITOR_ID: EditorOptionId;
36
19
  export declare const DEFAULT_EDITOR_ID: EditorOptionId;
20
+ export declare const EDITOR_OPTIONS: readonly [EditorOption, ...EditorOption[]];
21
+ export declare const DEFAULT_EDITOR_OPTION: EditorOption;
22
+ /**
23
+ * Case-insensitive lookup by id. Used mostly for the `DIFIT_EDITOR` / `EDITOR`
24
+ * environment-variable fallback on the server; the browser UI passes the full
25
+ * `{id, command, argsTemplate}` shape so it does not rely on this helper.
26
+ */
37
27
  export declare const resolveEditorOption: (input?: string) => EditorOption;
28
+ /**
29
+ * Tokenise a user-supplied arguments template string into individual CLI
30
+ * arguments. Supports single and double quoted segments so paths and flags
31
+ * containing spaces can be preserved.
32
+ *
33
+ * Inside double-quoted segments `\"` decodes to a literal `"` and `\\` to a
34
+ * literal `\`, mirroring common shell intuition. Other `\x` sequences pass
35
+ * through untouched so Lisp/regex fragments like `\s` or `\$` stay intact.
36
+ * Single-quoted segments are fully literal. The template is handed to
37
+ * `spawn` as argv directly – no shell is involved.
38
+ */
39
+ export declare const parseEditorArgsTemplate: (template: string | undefined | null) => string[];
40
+ interface EditorSpawnSpec {
41
+ readonly command: string;
42
+ readonly args: readonly string[];
43
+ }
44
+ interface BuildEditorSpawnSpecInput {
45
+ readonly command: string;
46
+ readonly argsTemplate: string;
47
+ readonly filePath: string;
48
+ readonly lineNumber: number | null;
49
+ }
50
+ /**
51
+ * Build the final `{ command, args }` tuple to hand to `child_process.spawn`.
52
+ * Returns `null` when the command is empty so callers can surface a clear
53
+ * "not configured" error instead of spawning an empty process.
54
+ *
55
+ * `%file` and `%line` are substituted as-is inside each token, so composite
56
+ * tokens such as `"%file:%line"` become `"/abs/file.ts:42"`. When no line
57
+ * number is available the substitution falls back to `1`.
58
+ */
59
+ export declare const buildEditorSpawnSpec: (input: BuildEditorSpawnSpecInput) => EditorSpawnSpec | null;
60
+ export {};
@@ -1,45 +1,171 @@
1
+ export const CUSTOM_EDITOR_ID = 'custom';
2
+ export const NONE_EDITOR_ID = 'none';
3
+ export const DEFAULT_EDITOR_ID = 'vscode';
1
4
  export const EDITOR_OPTIONS = [
2
5
  {
3
6
  id: 'vscode',
4
7
  label: 'VS Code',
5
- protocol: 'vscode',
6
- cliCommand: 'code',
7
- cliArgs: [],
8
- lineFormat: 'goto-flag',
9
- aliases: ['vscode', 'code'],
8
+ command: 'code',
9
+ argsTemplate: '-g %file:%line',
10
10
  },
11
11
  {
12
12
  id: 'cursor',
13
13
  label: 'Cursor',
14
- protocol: 'cursor',
15
- cliCommand: 'cursor',
16
- cliArgs: [],
17
- lineFormat: 'goto-flag',
18
- aliases: ['cursor'],
14
+ command: 'cursor',
15
+ argsTemplate: '-g %file:%line',
19
16
  },
20
17
  {
21
18
  id: 'zed',
22
19
  label: 'Zed',
23
- protocol: 'zed',
24
- cliCommand: 'zed',
25
- cliArgs: [],
26
- lineFormat: 'path-suffix',
27
- aliases: ['zed'],
20
+ command: 'zed',
21
+ argsTemplate: '%file:%line',
22
+ },
23
+ {
24
+ id: 'textmate',
25
+ label: 'TextMate',
26
+ command: 'mate',
27
+ argsTemplate: '-l %line %file',
28
+ },
29
+ {
30
+ id: 'bbedit',
31
+ label: 'BBEdit',
32
+ command: 'bbedit',
33
+ argsTemplate: '+%line %file',
34
+ },
35
+ {
36
+ id: 'emacs',
37
+ label: 'Emacs',
38
+ command: 'emacsclient',
39
+ argsTemplate: '--no-wait +%line %file',
40
+ },
41
+ {
42
+ id: 'macvim',
43
+ label: 'MacVim',
44
+ command: 'mvim',
45
+ argsTemplate: '--remote-silent +%line %file',
46
+ },
47
+ {
48
+ id: 'sublime',
49
+ label: 'Sublime Text',
50
+ command: 'subl',
51
+ argsTemplate: '%file:%line',
52
+ },
53
+ {
54
+ id: 'nova',
55
+ label: 'Nova',
56
+ command: 'nova',
57
+ argsTemplate: 'open %file -l %line',
58
+ },
59
+ {
60
+ id: 'custom',
61
+ label: 'Custom…',
62
+ command: '',
63
+ argsTemplate: '',
28
64
  },
29
65
  {
30
66
  id: 'none',
31
67
  label: 'Hide “Open in editor” button',
32
- protocol: null,
33
- cliCommand: null,
34
- cliArgs: [],
35
- lineFormat: 'goto-flag',
36
- aliases: ['none', 'disabled', 'off'],
68
+ command: '',
69
+ argsTemplate: '',
37
70
  },
38
71
  ];
39
- export const DEFAULT_EDITOR_ID = 'vscode';
72
+ export const DEFAULT_EDITOR_OPTION = EDITOR_OPTIONS.find((option) => option.id === DEFAULT_EDITOR_ID) ?? EDITOR_OPTIONS[0];
73
+ /**
74
+ * Case-insensitive lookup by id. Used mostly for the `DIFIT_EDITOR` / `EDITOR`
75
+ * environment-variable fallback on the server; the browser UI passes the full
76
+ * `{id, command, argsTemplate}` shape so it does not rely on this helper.
77
+ */
40
78
  export const resolveEditorOption = (input) => {
41
79
  const normalized = (input ?? DEFAULT_EDITOR_ID).toLowerCase();
42
- const matched = EDITOR_OPTIONS.find((option) => option.id === normalized || option.aliases.some((alias) => alias === normalized));
43
- const fallback = EDITOR_OPTIONS.find((option) => option.id === DEFAULT_EDITOR_ID);
44
- return matched ?? fallback ?? EDITOR_OPTIONS[0];
80
+ const matched = EDITOR_OPTIONS.find((option) => option.id === normalized);
81
+ return matched ?? DEFAULT_EDITOR_OPTION;
82
+ };
83
+ /**
84
+ * Tokenise a user-supplied arguments template string into individual CLI
85
+ * arguments. Supports single and double quoted segments so paths and flags
86
+ * containing spaces can be preserved.
87
+ *
88
+ * Inside double-quoted segments `\"` decodes to a literal `"` and `\\` to a
89
+ * literal `\`, mirroring common shell intuition. Other `\x` sequences pass
90
+ * through untouched so Lisp/regex fragments like `\s` or `\$` stay intact.
91
+ * Single-quoted segments are fully literal. The template is handed to
92
+ * `spawn` as argv directly – no shell is involved.
93
+ */
94
+ export const parseEditorArgsTemplate = (template) => {
95
+ const input = template ?? '';
96
+ const tokens = [];
97
+ const n = input.length;
98
+ let i = 0;
99
+ while (i < n) {
100
+ while (i < n && /\s/.test(input[i] ?? ''))
101
+ i++;
102
+ if (i >= n)
103
+ break;
104
+ let token = '';
105
+ let inQuote = null;
106
+ while (i < n) {
107
+ const ch = input[i];
108
+ if (ch === undefined)
109
+ break;
110
+ if (inQuote === '"') {
111
+ if (ch === '\\' && i + 1 < n) {
112
+ const next = input[i + 1];
113
+ if (next === '"' || next === '\\') {
114
+ token += next;
115
+ i += 2;
116
+ continue;
117
+ }
118
+ }
119
+ if (ch === inQuote) {
120
+ inQuote = null;
121
+ i++;
122
+ }
123
+ else {
124
+ token += ch;
125
+ i++;
126
+ }
127
+ continue;
128
+ }
129
+ if (inQuote === "'") {
130
+ if (ch === inQuote) {
131
+ inQuote = null;
132
+ i++;
133
+ }
134
+ else {
135
+ token += ch;
136
+ i++;
137
+ }
138
+ continue;
139
+ }
140
+ if (ch === '"' || ch === "'") {
141
+ inQuote = ch;
142
+ i++;
143
+ continue;
144
+ }
145
+ if (/\s/.test(ch))
146
+ break;
147
+ token += ch;
148
+ i++;
149
+ }
150
+ tokens.push(token);
151
+ }
152
+ return tokens;
153
+ };
154
+ /**
155
+ * Build the final `{ command, args }` tuple to hand to `child_process.spawn`.
156
+ * Returns `null` when the command is empty so callers can surface a clear
157
+ * "not configured" error instead of spawning an empty process.
158
+ *
159
+ * `%file` and `%line` are substituted as-is inside each token, so composite
160
+ * tokens such as `"%file:%line"` become `"/abs/file.ts:42"`. When no line
161
+ * number is available the substitution falls back to `1`.
162
+ */
163
+ export const buildEditorSpawnSpec = (input) => {
164
+ const command = input.command.trim();
165
+ if (!command)
166
+ return null;
167
+ const tokens = parseEditorArgsTemplate(input.argsTemplate);
168
+ const lineValue = String(input.lineNumber ?? 1);
169
+ const args = tokens.map((piece) => piece.replaceAll('%file', input.filePath).replaceAll('%line', lineValue));
170
+ return { command, args };
45
171
  };