difit 4.0.4 → 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.
- package/README.ja.md +3 -2
- package/README.ko.md +3 -2
- package/README.md +3 -2
- package/README.zh.md +3 -2
- package/dist/cli/comment.d.ts +2 -0
- package/dist/cli/comment.js +91 -0
- package/dist/cli/comment.test.d.ts +1 -0
- package/dist/cli/comment.test.js +164 -0
- package/dist/cli/index.js +104 -13
- package/dist/cli/index.test.js +5 -5
- package/dist/cli/utils.d.ts +1 -0
- package/dist/cli/utils.js +7 -0
- package/dist/client/assets/{_baseFor-DKyA49xd.js → _baseFor-Dq1lbcoh.js} +1 -1
- package/dist/client/assets/{arc-COOp7iVe.js → arc-1g1LrDb3.js} +1 -1
- package/dist/client/assets/architecture-YZFGNWBL-MZfdAdY6.js +1 -0
- package/dist/client/assets/architectureDiagram-Q4EWVU46-D87-Rmwy.js +36 -0
- package/dist/client/assets/{blockDiagram-DXYQGD6D-CtNJnEWN.js → blockDiagram-DXYQGD6D-Cep-MIFv.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-BqG-1m6C.js → c4Diagram-AHTNJAMY-BQuH9Txx.js} +1 -1
- package/dist/client/assets/channel-CJqLEVLU.js +1 -0
- package/dist/client/assets/{chunk-2KRD3SAO-DqP2NJNd.js → chunk-2KRD3SAO-CpQQpmvx.js} +1 -1
- package/dist/client/assets/chunk-336JU56O-Ddk9EzgO.js +2 -0
- package/dist/client/assets/chunk-426QAEUC-2xhUznDE.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-BT78EnQ6.js → chunk-4BX2VUAB-Ca-N0Wd9.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-C4w_Bwzw.js → chunk-4TB4RGXK-ZTWP_Onw.js} +2 -2
- package/dist/client/assets/{chunk-55IACEB6-z3MQSTaj.js → chunk-55IACEB6-Dub40zHG.js} +1 -1
- package/dist/client/assets/{chunk-5FUZZQ4R-Chei69aj.js → chunk-5FUZZQ4R-Cgda0gtZ.js} +1 -1
- package/dist/client/assets/{chunk-5PVQY5BW-HgRiIs0X.js → chunk-5PVQY5BW-D8JPH_tm.js} +1 -1
- package/dist/client/assets/{chunk-67CJDMHE-B2q10-fp.js → chunk-67CJDMHE-U1KyLHzG.js} +1 -1
- package/dist/client/assets/{chunk-7N4EOEYR-DPgxysWq.js → chunk-7N4EOEYR-WzOy51nD.js} +1 -1
- package/dist/client/assets/{chunk-AA7GKIK3-BqmVmKLq.js → chunk-AA7GKIK3-DlWOj4lr.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-CaIgleFn.js → chunk-BSJP7CBP-CcZ0op08.js} +1 -1
- package/dist/client/assets/{chunk-CIAEETIT-ByD-tlNF.js → chunk-CIAEETIT-qVSphnw5.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-d3RUKKAj.js → chunk-EDXVE4YY-76SPH4sf.js} +1 -1
- package/dist/client/assets/{chunk-ENJZ2VHE-CNq5Qmg9.js → chunk-ENJZ2VHE-CKULNIzL.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-DYfHJ6MV.js → chunk-FMBD7UC4-CvDPP3mb.js} +1 -1
- package/dist/client/assets/{chunk-FOC6F5B3-BRpSWlZj.js → chunk-FOC6F5B3-DceW0hWA.js} +1 -1
- package/dist/client/assets/{chunk-ICPOFSXX-B_MThwG6.js → chunk-ICPOFSXX-ChGBNZMk.js} +2 -2
- package/dist/client/assets/{chunk-K5T4RW27-DmamW1Ds.js → chunk-K5T4RW27-DBHdC4ln.js} +10 -10
- package/dist/client/assets/{chunk-KGLVRYIC-CRbg4c4z.js → chunk-KGLVRYIC-DRS7yiGQ.js} +1 -1
- package/dist/client/assets/{chunk-LIHQZDEY-CHQPSdB3.js → chunk-LIHQZDEY-KsE8dyJP.js} +1 -1
- package/dist/client/assets/{chunk-ORNJ4GCN-CIsQ4Zi4.js → chunk-ORNJ4GCN-Dnp4oHRD.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-Cxi0kdGg.js → chunk-OYMX7WX6-CciaotDu.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-BiVE5u_E.js +1 -0
- package/dist/client/assets/{chunk-U2HBQHQK-V_hneCfR.js → chunk-U2HBQHQK-nbp7CjBP.js} +1 -1
- package/dist/client/assets/{chunk-X2U36JSP-De4pvO-I.js → chunk-X2U36JSP-Chs85loT.js} +1 -1
- package/dist/client/assets/{chunk-XPW4576I-B_osXKp6.js → chunk-XPW4576I-VtI9b561.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-C_kqXssD.js → chunk-YZCP3GAM-sBsewSoO.js} +1 -1
- package/dist/client/assets/{chunk-ZZ45TVLE-B_xtlma5.js → chunk-ZZ45TVLE-TMgeW_px.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-CfyHazmg.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-D7Rb-bnu.js +1 -0
- package/dist/client/assets/clone-8xC1huEg.js +1 -0
- package/dist/client/assets/cose-bilkent-S5V4N54A-5TzM3w9g.js +1 -0
- package/dist/client/assets/{cytoscape.esm-DRReFUEO.js → cytoscape.esm-DdcHPZAZ.js} +2 -2
- package/dist/client/assets/{dagre-KV5264BT-BWYGReXF.js → dagre-KV5264BT-xvyFOxd3.js} +1 -1
- package/dist/client/assets/{dagre-DU-XBdcU.js → dagre-sb6WtN4K.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-DpUUhvWz.js → diagram-5BDNPKRD-ChRpAe5p.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-BJoTrUAx.js → diagram-G4DWMVQ6-C_8BED4A.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-CAk1GW5g.js → diagram-MMDJMWI5-BMwXEou2.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-Cct6g7FA.js → diagram-TYMM5635-CeAkx82D.js} +1 -1
- package/dist/client/assets/{dist-61sCfOmN.js → dist-CwC9dd2Z.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DHs2bXUj.js → erDiagram-SMLLAGMA-yGCTeXGt.js} +1 -1
- package/dist/client/assets/{flatten-mnWyE-RB.js → flatten-SRIRKgqP.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-DLu-6dfC.js → flowDiagram-DWJPFMVM-CugkvbmM.js} +1 -1
- package/dist/client/assets/ganttDiagram-T4ZO3ILL-BXnlBFgK.js +292 -0
- package/dist/client/assets/gitGraph-7Q5UKJZL-BeTWkPrd.js +1 -0
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-Bc_rL3_k.js → gitGraphDiagram-UUTBAWPF-B61aCwwu.js} +1 -1
- package/dist/client/assets/{graphlib-BVMK0xYE.js → graphlib-BMWKz3zT.js} +1 -1
- package/dist/client/assets/index-D2Y8-unG.css +2 -0
- package/dist/client/assets/index-D9v_eYzS.js +79 -0
- package/dist/client/assets/info-OMHHGYJF-MUNR2tTt.js +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-Cf8u4jgP.js → infoDiagram-42DDH7IO-Bkh6nTL2.js} +1 -1
- package/dist/client/assets/{isEmpty-CiiIHfXR.js → isEmpty-CStpjy4G.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-7n7DvfEb.js → ishikawaDiagram-UXIWVN3A-D_fdVT6_.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-BMkeQqJb.js → journeyDiagram-VCZTEJTY-DkXVokNF.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-B8KkeZLS.js → kanban-definition-6JOO6SKY-y8qq7qvL.js} +1 -1
- package/dist/client/assets/{line-CVpcI6kj.js → line-B0LcTqNY.js} +1 -1
- package/dist/client/assets/{linear-DmhiOOKU.js → linear-CqIjr2qp.js} +1 -1
- package/dist/client/assets/mermaid-parser.core-Du6QzpZO.js +4 -0
- package/dist/client/assets/{mermaid.core-R7nXpPx-.js → mermaid.core-CZBu-oKJ.js} +3 -3
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-CwcHocMZ.js → mindmap-definition-QFDTVHPH-BJrRxSkM.js} +1 -1
- package/dist/client/assets/{ordinal-k--hYEme.js → ordinal-DIg8h6NI.js} +1 -1
- package/dist/client/assets/packet-4T2RLAQJ-Ci-Uu57s.js +1 -0
- package/dist/client/assets/pie-ZZUOXDRM-pm57XGIg.js +1 -0
- package/dist/client/assets/{pieDiagram-DEJITSTG-BVAn8Lmr.js → pieDiagram-DEJITSTG-Debmhc0u.js} +1 -1
- package/dist/client/assets/prism-clojure-BpoF2XhX.js +1 -0
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-C2XZ_zxa.js → quadrantDiagram-34T5L4WZ-SE3g2BC9.js} +1 -1
- package/dist/client/assets/radar-PYXPWWZC-CH-AuSDw.js +1 -0
- package/dist/client/assets/{reduce-BTlHjXna.js → reduce-CG4cgj93.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-CfO16pkI.js → requirementDiagram-MS252O5E-1mv41puC.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-D_4_234M.js → sankeyDiagram-XADWPNL6-CLjPRtOP.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-B-yHKMuK.js → sequenceDiagram-FGHM5R23-Cs-P3AtR.js} +1 -1
- package/dist/client/assets/src-5XpQHeIJ.js +1 -0
- package/dist/client/assets/{stateDiagram-FHFEXIEX-BeG2di4I.js → stateDiagram-FHFEXIEX-CmB1fohY.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-D6jsrR-f.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-DhtnMGcE.js → timeline-definition-GMOUNBTQ-BMUafJOI.js} +1 -1
- package/dist/client/assets/treeView-SZITEDCU-BGsVMAdJ.js +1 -0
- package/dist/client/assets/treemap-W4RFUUIX-DXnhegXy.js +1 -0
- package/dist/client/assets/{vennDiagram-DHZGUBPP-CBn69TcQ.js → vennDiagram-DHZGUBPP-CpZ1Qhjz.js} +1 -1
- package/dist/client/assets/wardley-RL74JXVD-COd5nWj-.js +1 -0
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-CEoSJmN1.js → wardleyDiagram-NUSXRM2D-C-zH0lsd.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-BZ_X9tkn.js → xychartDiagram-5P7HB3ND-SkLFuEHZ.js} +1 -1
- package/dist/client/index.html +2 -4
- package/dist/client/site-data/blobs/080c0e6/cHVibGljL3NpdGUtZGF0YS9vZy1pbWFnZS5wbmc.png +0 -0
- package/dist/client/site-data/blobs/55f23a1/bGFuZGluZy9wdWJsaWMvZGlmaXQvbG9nby5wbmc.png +0 -0
- package/dist/client/site-data/blobs/66ff7c6/cHVibGljL2xvZ28ucG5n.png +0 -0
- package/dist/client/site-data/blobs/e6977fe/cHVibGljL2xvZ28ucG5n.png +0 -0
- package/dist/client/site-data/og-image.png +0 -0
- package/dist/server/file-watcher.d.ts +2 -1
- package/dist/server/file-watcher.js +9 -3
- package/dist/server/git-diff.d.ts +5 -0
- package/dist/server/git-diff.js +65 -1
- package/dist/server/git-diff.test.js +50 -0
- package/dist/server/server.js +265 -68
- package/dist/server/server.test.js +228 -0
- package/dist/tui/App.js +0 -1
- package/dist/types/diff.d.ts +4 -4
- package/dist/types/watch.d.ts +30 -1
- package/dist/utils/commentImports.d.ts +2 -0
- package/dist/utils/commentImports.js +119 -1
- package/dist/utils/editorOptions.d.ts +58 -35
- package/dist/utils/editorOptions.js +150 -24
- package/dist/utils/editorOptions.test.js +201 -9
- package/package.json +9 -6
- package/dist/client/assets/architecture-YZFGNWBL-Cs2Q6RQP.js +0 -1
- package/dist/client/assets/architectureDiagram-Q4EWVU46-BO4dVPUA.js +0 -36
- package/dist/client/assets/channel-_xDT1u3-.js +0 -1
- package/dist/client/assets/chunk-336JU56O-D1qa7Qzb.js +0 -2
- package/dist/client/assets/chunk-426QAEUC-6J_A_wvD.js +0 -1
- package/dist/client/assets/chunk-CFjPhJqf.js +0 -1
- package/dist/client/assets/chunk-QZHKN3VN-C0QzfgZ8.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-5XrS-DAQ.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-Covl2vKy.js +0 -1
- package/dist/client/assets/clone-rhRH8pyW.js +0 -1
- package/dist/client/assets/cose-bilkent-S5V4N54A-BvXFc7Rr.js +0 -1
- package/dist/client/assets/ganttDiagram-T4ZO3ILL-CMIzlKAR.js +0 -292
- package/dist/client/assets/gitGraph-7Q5UKJZL-A_wWsXju.js +0 -1
- package/dist/client/assets/index-Cq_APK7Y.css +0 -2
- package/dist/client/assets/index-RcU838Ah.js +0 -79
- package/dist/client/assets/info-OMHHGYJF-Bv3kK2Bb.js +0 -1
- package/dist/client/assets/mermaid-parser.core-CnJ9Tv8l.js +0 -4
- package/dist/client/assets/packet-4T2RLAQJ-D2q3-9ae.js +0 -1
- package/dist/client/assets/pie-ZZUOXDRM-GivlQcUF.js +0 -1
- package/dist/client/assets/preload-helper-DSXbuxSR.js +0 -1
- package/dist/client/assets/radar-PYXPWWZC-C9pD6VNR.js +0 -1
- package/dist/client/assets/src-CjDs0_Ij.js +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DvcSq7KE.js +0 -1
- package/dist/client/assets/treeView-SZITEDCU-BSNk8_yV.js +0 -1
- package/dist/client/assets/treemap-W4RFUUIX-ym4zQztE.js +0 -1
- package/dist/client/assets/wardley-RL74JXVD-B02H6ReJ.js +0 -1
- /package/dist/client/assets/{array-BNor45A1.js → array-DOVTz2Mq.js} +0 -0
- /package/dist/client/assets/{defaultLocale-DPzUsThw.js → defaultLocale-Ck2Xxk-C.js} +0 -0
- /package/dist/client/assets/{init-C0L3woqb.js → init-Bft5Ffpj.js} +0 -0
- /package/dist/client/assets/{katex-FOM3xZj7.js → katex-CeIlAR55.js} +0 -0
- /package/dist/client/assets/{path-sMK4d_s9.js → path-DfRbCp9y.js} +0 -0
- /package/dist/client/assets/{prism-bash-iQBez6et.js → prism-bash-CPkZUJMA.js} +0 -0
- /package/dist/client/assets/{prism-csharp-C1RDHXRk.js → prism-csharp-BEk8D1-3.js} +0 -0
- /package/dist/client/assets/{prism-dart-nIH9vDUM.js → prism-dart-ByLYrdQB.js} +0 -0
- /package/dist/client/assets/{prism-elixir-DUMUOd7H.js → prism-elixir-BZtyIEab.js} +0 -0
- /package/dist/client/assets/{prism-haskell-BP3SRvzt.js → prism-haskell-NAsbeo3V.js} +0 -0
- /package/dist/client/assets/{prism-hcl-C-ZHJGEE.js → prism-hcl-crnGqmVp.js} +0 -0
- /package/dist/client/assets/{prism-java-scuShSv5.js → prism-java-BovStacA.js} +0 -0
- /package/dist/client/assets/{prism-markup-templating-BFXREXfb.js → prism-markup-templating-Cl8NiLjy.js} +0 -0
- /package/dist/client/assets/{prism-nix-CO4UPu3E.js → prism-nix-BS_cm_1n.js} +0 -0
- /package/dist/client/assets/{prism-perl-BBDKnHRR.js → prism-perl-DGLVMq5H.js} +0 -0
- /package/dist/client/assets/{prism-php-DjIafOi_.js → prism-php-BskSwJN8.js} +0 -0
- /package/dist/client/assets/{prism-protobuf-BE1MoFmZ.js → prism-protobuf-DfbIYpO7.js} +0 -0
- /package/dist/client/assets/{prism-ruby-CZ-lrXfL.js → prism-ruby-FBVh1PRE.js} +0 -0
- /package/dist/client/assets/{prism-scala-DgnxHuDn.js → prism-scala--9AfMHPY.js} +0 -0
- /package/dist/client/assets/{prism-solidity-5fSUcW9Y.js → prism-solidity-BgJNkj1z.js} +0 -0
- /package/dist/client/assets/{prism-sql-CKkohPI_.js → prism-sql-C9Czmpov.js} +0 -0
- /package/dist/client/assets/{prism-vim-CkRmxTmK.js → prism-vim-CzUNf0WQ.js} +0 -0
- /package/dist/client/assets/{rough.esm-DeLgKbOI.js → rough.esm-Bbn_-PMU.js} +0 -0
package/README.ja.md
CHANGED
|
@@ -151,6 +151,7 @@ git diff --cached | difit -
|
|
|
151
151
|
| `--clean` | false | 起動時に既存コメントと閲覧済みファイルをすべてクリア |
|
|
152
152
|
| `--include-untracked` | false | diffにuntrackedファイルを自動的に含める(`.`または`working`のみ有効) |
|
|
153
153
|
| `--keep-alive` | false | ブラウザ切断後もサーバーを終了せず起動したままにする(Ctrl+Cで手動停止) |
|
|
154
|
+
| `--background` | false | サーバーをバックグラウンドで起動したままにし、接続情報をJSONで出力 |
|
|
154
155
|
| `--context <lines>` | Gitの既定値 (3) | 変更ごとの前後コンテキスト行数を制限(`0` は変更行のみ表示。`--pr` と stdin では使用不可) |
|
|
155
156
|
|
|
156
157
|
## 💬 コメントシステム
|
|
@@ -197,10 +198,10 @@ npx skills add yoshiko-pg/difit
|
|
|
197
198
|
- **JavaScript/TypeScript**:`.js`, `.jsx`, `.ts`, `.tsx`
|
|
198
199
|
- **Web技術**:HTML, CSS, JSON, XML, Markdown
|
|
199
200
|
- **シェルスクリプト**:`.sh`, `.bash`, `.zsh`, `.fish`
|
|
200
|
-
- **バックエンド言語**:PHP, SQL, Ruby, Java, Scala, Perl, Elixir
|
|
201
|
+
- **バックエンド言語**:PHP, SQL, Ruby, Java, Scala, Perl, Elixir, Haskell, Clojure
|
|
201
202
|
- **システム言語**:C, C++, C#, Rust, Go
|
|
202
203
|
- **モバイル言語**:Swift, Kotlin, Dart
|
|
203
|
-
- **IaC**:Terraform (HCL)
|
|
204
|
+
- **IaC**:Terraform (HCL), Nix
|
|
204
205
|
- **その他**:Python, Protobuf, YAML, Solidity, Vim Script
|
|
205
206
|
|
|
206
207
|
## 🔍 自動折りたたみファイル
|
package/README.ko.md
CHANGED
|
@@ -151,6 +151,7 @@ git diff --cached | difit -
|
|
|
151
151
|
| `--clean` | false | 시작 시 모든 기존 코멘트와 열람된 파일 표시 초기화 |
|
|
152
152
|
| `--include-untracked` | false | diff에 untracked 파일 자동 포함 (`.` 또는 `working`에서만 유효) |
|
|
153
153
|
| `--keep-alive` | false | 브라우저 연결이 끊겨도 서버 유지 (Ctrl+C로 수동 종료) |
|
|
154
|
+
| `--background` | false | 서버를 백그라운드에서 계속 실행하고 JSON 연결 정보 출력 |
|
|
154
155
|
| `--context <lines>` | Git 기본값 (3) | 변경 주변의 컨텍스트 줄 수를 제한 (`0`이면 변경된 줄만 표시, `--pr` 및 stdin에서는 사용 불가) |
|
|
155
156
|
|
|
156
157
|
## 💬 코멘트 시스템
|
|
@@ -197,10 +198,10 @@ npx skills add yoshiko-pg/difit
|
|
|
197
198
|
- **JavaScript/TypeScript**: `.js`, `.jsx`, `.ts`, `.tsx`
|
|
198
199
|
- **웹 기술**: HTML, CSS, JSON, XML, Markdown
|
|
199
200
|
- **셸 스크립트**: `.sh`, `.bash`, `.zsh`, `.fish`
|
|
200
|
-
- **백엔드 언어**: PHP, SQL, Ruby, Java, Scala, Perl, Elixir
|
|
201
|
+
- **백엔드 언어**: PHP, SQL, Ruby, Java, Scala, Perl, Elixir, Haskell, Clojure
|
|
201
202
|
- **시스템 언어**: C, C++, C#, Rust, Go
|
|
202
203
|
- **모바일 언어**: Swift, Kotlin, Dart
|
|
203
|
-
- **인프라 코드**: Terraform (HCL)
|
|
204
|
+
- **인프라 코드**: Terraform (HCL), Nix
|
|
204
205
|
- **기타**: Python, Protobuf, YAML, Solidity, Vim 스크립트
|
|
205
206
|
|
|
206
207
|
## 🔍 자동 접힘 파일
|
package/README.md
CHANGED
|
@@ -151,6 +151,7 @@ Stdin mode is selected with intent-first rules:
|
|
|
151
151
|
| `--clean` | false | Clear all existing comments and viewed files on startup |
|
|
152
152
|
| `--include-untracked` | false | Automatically include untracked files in diff (only with `.` or `working`) |
|
|
153
153
|
| `--keep-alive` | false | Keep server running after browser disconnects (stop manually with Ctrl+C) |
|
|
154
|
+
| `--background` | false | Keep the server running in the background and output JSON connection info |
|
|
154
155
|
| `--context <lines>` | git default (3) | Limit surrounding context lines per change (`0` shows changes only; not available with `--pr` or stdin) |
|
|
155
156
|
|
|
156
157
|
## 💬 Comment System
|
|
@@ -197,10 +198,10 @@ After code edits or automated review, the agent can start the difit server with
|
|
|
197
198
|
- **JavaScript/TypeScript**: `.js`, `.jsx`, `.ts`, `.tsx`
|
|
198
199
|
- **Web Technologies**: HTML, CSS, JSON, XML, Markdown
|
|
199
200
|
- **Shell Scripts**: `.sh`, `.bash`, `.zsh`, `.fish`
|
|
200
|
-
- **Backend Languages**: PHP, SQL, Ruby, Java, Scala, Perl, Elixir
|
|
201
|
+
- **Backend Languages**: PHP, SQL, Ruby, Java, Scala, Perl, Elixir, Haskell, Clojure
|
|
201
202
|
- **Systems Languages**: C, C++, C#, Rust, Go
|
|
202
203
|
- **Mobile Languages**: Swift, Kotlin, Dart
|
|
203
|
-
- **Infrastructure as Code**: Terraform (HCL)
|
|
204
|
+
- **Infrastructure as Code**: Terraform (HCL), Nix
|
|
204
205
|
- **Others**: Python, Protobuf, YAML, Solidity, Vim script
|
|
205
206
|
|
|
206
207
|
## 🔍 Auto-collapsed Files
|
package/README.zh.md
CHANGED
|
@@ -151,6 +151,7 @@ git diff --cached | difit -
|
|
|
151
151
|
| `--clean` | false | 启动时清除所有现有评论和已查看的文件 |
|
|
152
152
|
| `--include-untracked` | false | 自动将 untracked 文件包含在 diff 中(仅在 `.` 或 `working` 时有效) |
|
|
153
153
|
| `--keep-alive` | false | 浏览器断开后保持服务器运行(使用 Ctrl+C 手动停止) |
|
|
154
|
+
| `--background` | false | 在后台保持服务器运行,并输出 JSON 连接信息 |
|
|
154
155
|
| `--context <lines>` | Git 默认值 (3) | 限制每处变更周围的上下文行数(`0` 仅显示变更行;不可与 `--pr` 或 stdin 一起使用) |
|
|
155
156
|
|
|
156
157
|
## 💬 评论系统
|
|
@@ -197,10 +198,10 @@ npx skills add yoshiko-pg/difit
|
|
|
197
198
|
- **JavaScript/TypeScript**:`.js`, `.jsx`, `.ts`, `.tsx`
|
|
198
199
|
- **Web 技术**:HTML, CSS, JSON, XML, Markdown
|
|
199
200
|
- **Shell 脚本**:`.sh`, `.bash`, `.zsh`, `.fish`
|
|
200
|
-
- **后端语言**:PHP, SQL, Ruby, Java, Scala, Perl, Elixir
|
|
201
|
+
- **后端语言**:PHP, SQL, Ruby, Java, Scala, Perl, Elixir, Haskell, Clojure
|
|
201
202
|
- **系统语言**:C, C++, C#, Rust, Go
|
|
202
203
|
- **移动语言**:Swift, Kotlin, Dart
|
|
203
|
-
- **基础设施即代码**:Terraform (HCL)
|
|
204
|
+
- **基础设施即代码**:Terraform (HCL), Nix
|
|
204
205
|
- **其他**:Python, Protobuf, YAML, Solidity, Vim Script
|
|
205
206
|
|
|
206
207
|
## 🔍 自动折叠文件
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Command, Option } from 'commander';
|
|
2
|
+
import { parseCommentImportValue } from '../utils/commentImports.js';
|
|
3
|
+
import { detectStdinSource, readStdin } from './utils.js';
|
|
4
|
+
async function parseCommentAddInput(json) {
|
|
5
|
+
if (typeof json === 'string') {
|
|
6
|
+
return json;
|
|
7
|
+
}
|
|
8
|
+
if (detectStdinSource() === 'tty') {
|
|
9
|
+
throw new Error('Provide comment JSON as an argument or via stdin');
|
|
10
|
+
}
|
|
11
|
+
const stdin = await readStdin();
|
|
12
|
+
if (!stdin.trim()) {
|
|
13
|
+
throw new Error('No comment JSON received from stdin');
|
|
14
|
+
}
|
|
15
|
+
return stdin;
|
|
16
|
+
}
|
|
17
|
+
export function createCommentCommand() {
|
|
18
|
+
const comment = new Command('comment').description('Add or retrieve comments on a running difit server');
|
|
19
|
+
comment
|
|
20
|
+
.command('add')
|
|
21
|
+
.description('Add comments to a running difit server')
|
|
22
|
+
.argument('[json]', 'comment import JSON (object or array)')
|
|
23
|
+
.requiredOption('--port <port>', 'port of the running difit server', parseInt)
|
|
24
|
+
.action(async (json, opts) => {
|
|
25
|
+
try {
|
|
26
|
+
const input = await parseCommentAddInput(json);
|
|
27
|
+
const imports = parseCommentImportValue(input);
|
|
28
|
+
const response = await fetch(`http://localhost:${opts.port}/api/comment-imports`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify(imports),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorBody = (await response.json().catch(() => ({})));
|
|
35
|
+
console.error(`Error: ${errorBody.error ?? 'Failed to add comments'}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const result = (await response.json());
|
|
39
|
+
console.log(JSON.stringify({
|
|
40
|
+
success: result.success ?? true,
|
|
41
|
+
importId: result.importId,
|
|
42
|
+
count: result.count ?? imports.length,
|
|
43
|
+
warnings: result.warnings ?? [],
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof TypeError && error.message.includes('fetch failed')) {
|
|
48
|
+
console.error(`Error: Cannot connect to difit server on port ${opts.port}. Is the server running?`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
52
|
+
}
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
comment
|
|
57
|
+
.command('get')
|
|
58
|
+
.description('Retrieve comments from a running difit server')
|
|
59
|
+
.requiredOption('--port <port>', 'port of the running difit server', parseInt)
|
|
60
|
+
.addOption(new Option('--format <format>', 'output format').choices(['text', 'json']).default('text'))
|
|
61
|
+
.action(async (opts) => {
|
|
62
|
+
try {
|
|
63
|
+
const endpoint = opts.format === 'json' ? '/api/comments-json' : '/api/comments-output';
|
|
64
|
+
const response = await fetch(`http://localhost:${opts.port}${endpoint}`);
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
console.error('Error: Failed to retrieve comments');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
if (opts.format === 'json') {
|
|
70
|
+
const data = await response.json();
|
|
71
|
+
console.log(JSON.stringify(data));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const text = await response.text();
|
|
75
|
+
if (text.trim()) {
|
|
76
|
+
console.log(text);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof TypeError && error.message.includes('fetch failed')) {
|
|
82
|
+
console.error(`Error: Cannot connect to difit server on port ${opts.port}. Is the server running?`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
86
|
+
}
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return comment;
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { createCommentCommand } from './comment.js';
|
|
3
|
+
describe('createCommentCommand', () => {
|
|
4
|
+
const command = createCommentCommand();
|
|
5
|
+
it('creates a command named "comment"', () => {
|
|
6
|
+
expect(command.name()).toBe('comment');
|
|
7
|
+
});
|
|
8
|
+
it('has "add" and "get" subcommands', () => {
|
|
9
|
+
const subcommandNames = command.commands.map((c) => c.name());
|
|
10
|
+
expect(subcommandNames).toContain('add');
|
|
11
|
+
expect(subcommandNames).toContain('get');
|
|
12
|
+
});
|
|
13
|
+
describe('add subcommand', () => {
|
|
14
|
+
const addCommand = command.commands.find((c) => c.name() === 'add');
|
|
15
|
+
it('requires --port option', () => {
|
|
16
|
+
const portOption = addCommand.options.find((o) => o.long === '--port');
|
|
17
|
+
expect(portOption).toBeDefined();
|
|
18
|
+
expect(portOption?.mandatory).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('accepts optional json argument', () => {
|
|
21
|
+
const args = addCommand.registeredArguments;
|
|
22
|
+
expect(args).toHaveLength(1);
|
|
23
|
+
expect(args[0].name()).toBe('json');
|
|
24
|
+
expect(args[0].required).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('get subcommand', () => {
|
|
28
|
+
const getCommand = command.commands.find((c) => c.name() === 'get');
|
|
29
|
+
it('requires --port option', () => {
|
|
30
|
+
const portOption = getCommand.options.find((o) => o.long === '--port');
|
|
31
|
+
expect(portOption).toBeDefined();
|
|
32
|
+
expect(portOption?.mandatory).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('has --format option with choices', () => {
|
|
35
|
+
const formatOption = getCommand.options.find((o) => o.long === '--format');
|
|
36
|
+
expect(formatOption).toBeDefined();
|
|
37
|
+
expect(formatOption?.defaultValue).toBe('text');
|
|
38
|
+
expect(formatOption?.argChoices).toEqual(['text', 'json']);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
function jsonResponse(body, status = 200) {
|
|
43
|
+
return new Response(JSON.stringify(body), {
|
|
44
|
+
status,
|
|
45
|
+
headers: { 'Content-Type': 'application/json' },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function textResponse(body, status = 200) {
|
|
49
|
+
return new Response(body, {
|
|
50
|
+
status,
|
|
51
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
describe('comment subcommand integration', () => {
|
|
55
|
+
const originalFetch = globalThis.fetch;
|
|
56
|
+
let mockFetch;
|
|
57
|
+
let originalProcessExit;
|
|
58
|
+
let consoleOutput;
|
|
59
|
+
let consoleErrors;
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
mockFetch = vi.fn();
|
|
62
|
+
globalThis.fetch = mockFetch;
|
|
63
|
+
originalProcessExit = process.exit;
|
|
64
|
+
process.exit = vi.fn();
|
|
65
|
+
consoleOutput = [];
|
|
66
|
+
consoleErrors = [];
|
|
67
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
68
|
+
consoleOutput.push(args.join(' '));
|
|
69
|
+
});
|
|
70
|
+
vi.spyOn(console, 'error').mockImplementation((...args) => {
|
|
71
|
+
consoleErrors.push(args.join(' '));
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
globalThis.fetch = originalFetch;
|
|
76
|
+
process.exit = originalProcessExit;
|
|
77
|
+
vi.restoreAllMocks();
|
|
78
|
+
});
|
|
79
|
+
describe('add', () => {
|
|
80
|
+
it('sends comment imports to the server', async () => {
|
|
81
|
+
mockFetch.mockResolvedValue(jsonResponse({ success: true, importId: 'abc123', count: 1 }));
|
|
82
|
+
const command = createCommentCommand();
|
|
83
|
+
await command.parseAsync([
|
|
84
|
+
'node',
|
|
85
|
+
'difit',
|
|
86
|
+
'add',
|
|
87
|
+
'--port',
|
|
88
|
+
'4966',
|
|
89
|
+
'{"type":"thread","filePath":"test.ts","position":{"side":"new","line":1},"body":"Test"}',
|
|
90
|
+
]);
|
|
91
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:4966/api/comment-imports', expect.objectContaining({
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Content-Type': 'application/json' },
|
|
94
|
+
}));
|
|
95
|
+
expect(consoleOutput[0]).toContain('"success":true');
|
|
96
|
+
});
|
|
97
|
+
it('validates JSON before sending', async () => {
|
|
98
|
+
const command = createCommentCommand();
|
|
99
|
+
await command.parseAsync(['node', 'difit', 'add', '--port', '4966', 'not-valid-json']);
|
|
100
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
101
|
+
expect(consoleErrors[0]).toContain('Error:');
|
|
102
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
103
|
+
});
|
|
104
|
+
it('handles server error response', async () => {
|
|
105
|
+
mockFetch.mockResolvedValue(jsonResponse({ error: 'Bad request' }, 400));
|
|
106
|
+
const command = createCommentCommand();
|
|
107
|
+
await command.parseAsync([
|
|
108
|
+
'node',
|
|
109
|
+
'difit',
|
|
110
|
+
'add',
|
|
111
|
+
'--port',
|
|
112
|
+
'4966',
|
|
113
|
+
'{"type":"thread","filePath":"test.ts","position":{"side":"new","line":1},"body":"Test"}',
|
|
114
|
+
]);
|
|
115
|
+
expect(consoleErrors[0]).toContain('Bad request');
|
|
116
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
117
|
+
});
|
|
118
|
+
it('handles connection error', async () => {
|
|
119
|
+
const fetchError = new TypeError('fetch failed');
|
|
120
|
+
mockFetch.mockRejectedValue(fetchError);
|
|
121
|
+
const command = createCommentCommand();
|
|
122
|
+
await command.parseAsync([
|
|
123
|
+
'node',
|
|
124
|
+
'difit',
|
|
125
|
+
'add',
|
|
126
|
+
'--port',
|
|
127
|
+
'9999',
|
|
128
|
+
'{"type":"thread","filePath":"test.ts","position":{"side":"new","line":1},"body":"Test"}',
|
|
129
|
+
]);
|
|
130
|
+
expect(consoleErrors[0]).toContain('Cannot connect');
|
|
131
|
+
expect(consoleErrors[0]).toContain('9999');
|
|
132
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('get', () => {
|
|
136
|
+
it('fetches comments in text format by default', async () => {
|
|
137
|
+
mockFetch.mockResolvedValue(textResponse('Comments output text'));
|
|
138
|
+
const command = createCommentCommand();
|
|
139
|
+
await command.parseAsync(['node', 'difit', 'get', '--port', '4966']);
|
|
140
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:4966/api/comments-output');
|
|
141
|
+
expect(consoleOutput[0]).toBe('Comments output text');
|
|
142
|
+
});
|
|
143
|
+
it('fetches comments in json format', async () => {
|
|
144
|
+
mockFetch.mockResolvedValue(jsonResponse({ threads: [{ id: '1' }] }));
|
|
145
|
+
const command = createCommentCommand();
|
|
146
|
+
await command.parseAsync(['node', 'difit', 'get', '--port', '4966', '--format', 'json']);
|
|
147
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:4966/api/comments-json');
|
|
148
|
+
expect(consoleOutput[0]).toContain('"threads"');
|
|
149
|
+
});
|
|
150
|
+
it('handles connection error', async () => {
|
|
151
|
+
mockFetch.mockRejectedValue(new TypeError('fetch failed'));
|
|
152
|
+
const command = createCommentCommand();
|
|
153
|
+
await command.parseAsync(['node', 'difit', 'get', '--port', '9999']);
|
|
154
|
+
expect(consoleErrors[0]).toContain('Cannot connect');
|
|
155
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
156
|
+
});
|
|
157
|
+
it('handles empty text output silently', async () => {
|
|
158
|
+
mockFetch.mockResolvedValue(textResponse(' '));
|
|
159
|
+
const command = createCommentCommand();
|
|
160
|
+
await command.parseAsync(['node', 'difit', 'get', '--port', '4966']);
|
|
161
|
+
expect(consoleOutput).toHaveLength(0);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
package/dist/cli/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { simpleGit } from 'simple-git';
|
|
@@ -7,7 +8,8 @@ import { startServer } from '../server/server.js';
|
|
|
7
8
|
import { createDiffSelection } from '../utils/diffSelection.js';
|
|
8
9
|
import { DiffMode } from '../types/watch.js';
|
|
9
10
|
import { DEFAULT_DIFF_VIEW_MODE, normalizeDiffViewMode } from '../utils/diffMode.js';
|
|
10
|
-
import { shouldReadStdin, findUntrackedFiles, markFilesIntentToAdd, promptUser, parseCommentOptions, validateDiffArguments, getGitRoot, } from './utils.js';
|
|
11
|
+
import { shouldReadStdin, findUntrackedFiles, markFilesIntentToAdd, promptUser, parseCommentOptions, validateDiffArguments, getGitRoot, readStdin, } from './utils.js';
|
|
12
|
+
import { createCommentCommand } from './comment.js';
|
|
11
13
|
import { getPrPatch, getPrCommentImports } from './github.js';
|
|
12
14
|
import { warnAboutTuiDeprecation } from './tuiDeprecation.js';
|
|
13
15
|
function isSpecialArg(arg) {
|
|
@@ -48,27 +50,99 @@ function determineDiffMode(selection, compareWith) {
|
|
|
48
50
|
// Default mode: HEAD^ vs HEAD or HEAD vs other commits (watch for HEAD changes)
|
|
49
51
|
return DiffMode.DEFAULT;
|
|
50
52
|
}
|
|
53
|
+
async function startBackgroundProcess() {
|
|
54
|
+
const scriptPath = process.argv[1];
|
|
55
|
+
if (!scriptPath) {
|
|
56
|
+
throw new Error('Unable to determine difit entrypoint for background process');
|
|
57
|
+
}
|
|
58
|
+
const childArgs = process.argv.slice(2).filter((arg) => arg !== '--background');
|
|
59
|
+
if (!childArgs.includes('--keep-alive')) {
|
|
60
|
+
childArgs.push('--keep-alive');
|
|
61
|
+
}
|
|
62
|
+
if (!childArgs.includes('--no-open')) {
|
|
63
|
+
childArgs.push('--no-open');
|
|
64
|
+
}
|
|
65
|
+
const child = spawn(process.execPath, [scriptPath, ...childArgs], {
|
|
66
|
+
detached: true,
|
|
67
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
68
|
+
env: {
|
|
69
|
+
...process.env,
|
|
70
|
+
[BACKGROUND_CHILD_ENV]: '1',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
child.stdout.setEncoding('utf8');
|
|
74
|
+
child.stderr.setEncoding('utf8');
|
|
75
|
+
await new Promise((resolve, reject) => {
|
|
76
|
+
const timeout = setTimeout(() => {
|
|
77
|
+
reject(new Error('Timed out while starting background difit server'));
|
|
78
|
+
}, 10_000);
|
|
79
|
+
let stderr = '';
|
|
80
|
+
let settled = false;
|
|
81
|
+
const finish = (callback) => {
|
|
82
|
+
if (settled) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
settled = true;
|
|
86
|
+
clearTimeout(timeout);
|
|
87
|
+
callback();
|
|
88
|
+
};
|
|
89
|
+
child.stdout.on('data', (chunk) => {
|
|
90
|
+
const line = chunk
|
|
91
|
+
.split(/\r?\n/u)
|
|
92
|
+
.map((value) => value.trim())
|
|
93
|
+
.find((value) => value.length > 0);
|
|
94
|
+
if (!line) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
finish(() => {
|
|
98
|
+
console.log(line);
|
|
99
|
+
child.unref();
|
|
100
|
+
resolve();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
child.stderr.on('data', (chunk) => {
|
|
104
|
+
stderr += chunk;
|
|
105
|
+
});
|
|
106
|
+
child.once('error', (error) => {
|
|
107
|
+
finish(() => {
|
|
108
|
+
reject(error);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
child.once('exit', (code) => {
|
|
112
|
+
finish(() => {
|
|
113
|
+
const trimmedStderr = stderr.trim();
|
|
114
|
+
reject(new Error(trimmedStderr || `Background difit server exited early (code ${code ?? 'unknown'})`));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const BACKGROUND_CHILD_ENV = 'DIFIT_BACKGROUND_CHILD';
|
|
51
120
|
const program = new Command();
|
|
52
121
|
program
|
|
53
122
|
.name('difit')
|
|
54
123
|
.description('A lightweight Git diff viewer with GitHub-like interface')
|
|
55
124
|
.version(pkg.version, '-v, --version', 'output the version number')
|
|
125
|
+
.enablePositionalOptions()
|
|
126
|
+
.addCommand(createCommentCommand())
|
|
56
127
|
.argument('[commit-ish]', 'Git commit, tag, branch, HEAD~n reference, or "working"/"staged"/"."', 'HEAD')
|
|
57
128
|
.argument('[compare-with]', 'Optional: Compare with this commit/branch (shows diff between commit-ish and compare-with)')
|
|
58
129
|
.option('--port <port>', 'preferred port (auto-assigned if occupied)', parseInt)
|
|
59
130
|
.option('--host <host>', 'host address to bind', '')
|
|
60
131
|
.option('--no-open', 'do not automatically open browser')
|
|
61
132
|
.option('--mode <mode>', 'diff mode (split or unified)', normalizeDiffViewMode, DEFAULT_DIFF_VIEW_MODE)
|
|
62
|
-
.option('--comment <json>', 'inject initial review comments (repeatable, accepts a JSON object or array)', (value, previous
|
|
133
|
+
.option('--comment <json>', 'inject initial review comments (repeatable, accepts a JSON object or array)', (value, previous) => [...previous, value], [])
|
|
63
134
|
.option('--tui', 'use terminal UI instead of web interface')
|
|
64
135
|
.option('--pr <url>', 'GitHub PR URL to review (e.g., https://github.com/owner/repo/pull/123)')
|
|
65
136
|
.option('--clean', 'start with a clean slate by clearing all existing comments')
|
|
66
137
|
.option('--include-untracked', 'automatically include untracked files in diff')
|
|
67
138
|
.option('--keep-alive', 'keep server running even after browser disconnects')
|
|
139
|
+
.option('--background', 'keep the server running in the background and output JSON info')
|
|
68
140
|
.option('--context <lines>', 'number of context lines shown around each change', parseInt)
|
|
69
141
|
.option('--merge-base', 'resolve the base revision with git merge-base before diffing (Git revision mode only)')
|
|
70
142
|
.action(async (commitish, compareWith, options) => {
|
|
71
143
|
try {
|
|
144
|
+
const isBackgroundChild = process.env[BACKGROUND_CHILD_ENV] === '1';
|
|
145
|
+
const backgroundMode = options.background || isBackgroundChild;
|
|
72
146
|
let stdinDiff;
|
|
73
147
|
let stdinReviewLabel = 'diff from stdin';
|
|
74
148
|
let manualCommentImports = [];
|
|
@@ -78,6 +152,10 @@ program
|
|
|
78
152
|
console.error('Error: --context must be a non-negative integer');
|
|
79
153
|
process.exit(1);
|
|
80
154
|
}
|
|
155
|
+
if (options.background && !isBackgroundChild) {
|
|
156
|
+
await startBackgroundProcess();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
81
159
|
try {
|
|
82
160
|
manualCommentImports = parseCommentOptions(options.comment);
|
|
83
161
|
commentImports = manualCommentImports;
|
|
@@ -86,6 +164,10 @@ program
|
|
|
86
164
|
console.error(`Error: ${error instanceof Error ? error.message : 'Invalid --comment value'}`);
|
|
87
165
|
process.exit(1);
|
|
88
166
|
}
|
|
167
|
+
if (backgroundMode) {
|
|
168
|
+
options.keepAlive = true;
|
|
169
|
+
options.open = false;
|
|
170
|
+
}
|
|
89
171
|
if (options.pr) {
|
|
90
172
|
if (commitish !== 'HEAD' || compareWith) {
|
|
91
173
|
console.error('Error: --pr option cannot be used with positional arguments');
|
|
@@ -146,7 +228,7 @@ program
|
|
|
146
228
|
}
|
|
147
229
|
if (stdinDiff) {
|
|
148
230
|
// Start server with stdin diff (including --pr patch)
|
|
149
|
-
const { url } = await startServer({
|
|
231
|
+
const { url, port } = await startServer({
|
|
150
232
|
stdinDiff,
|
|
151
233
|
preferredPort: options.port,
|
|
152
234
|
host: options.host,
|
|
@@ -156,6 +238,10 @@ program
|
|
|
156
238
|
keepAlive: options.keepAlive,
|
|
157
239
|
...(commentImports.length > 0 ? { commentImports } : {}),
|
|
158
240
|
});
|
|
241
|
+
if (backgroundMode) {
|
|
242
|
+
console.log(JSON.stringify({ port, url, pid: process.pid }));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
159
245
|
console.log(`\n🚀 difit server started on ${url}`);
|
|
160
246
|
console.log(`📋 Reviewing: ${stdinReviewLabel}`);
|
|
161
247
|
if (options.keepAlive) {
|
|
@@ -180,9 +266,18 @@ program
|
|
|
180
266
|
}
|
|
181
267
|
if (selection.targetCommitish === 'working' || selection.targetCommitish === '.') {
|
|
182
268
|
const git = simpleGit(repoPath);
|
|
183
|
-
|
|
269
|
+
if (isBackgroundChild && !options.includeUntracked) {
|
|
270
|
+
// Skip interactive prompts in detached background mode.
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
await handleUntrackedFiles(git, options.includeUntracked);
|
|
274
|
+
}
|
|
184
275
|
}
|
|
185
276
|
if (options.tui) {
|
|
277
|
+
if (backgroundMode) {
|
|
278
|
+
console.error('Error: --background option cannot be used with --tui');
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
186
281
|
if (commentImports.length > 0) {
|
|
187
282
|
console.error('Error: --comment option cannot be used with --tui');
|
|
188
283
|
process.exit(1);
|
|
@@ -223,6 +318,10 @@ program
|
|
|
223
318
|
repoPath,
|
|
224
319
|
...(commentImports.length > 0 ? { commentImports } : {}),
|
|
225
320
|
});
|
|
321
|
+
if (backgroundMode) {
|
|
322
|
+
console.log(JSON.stringify({ port, url, pid: process.pid }));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
226
325
|
console.log(`\n🚀 difit server started on ${url}`);
|
|
227
326
|
console.log(`📋 Reviewing: ${selection.targetCommitish}`);
|
|
228
327
|
if (options.keepAlive) {
|
|
@@ -264,15 +363,7 @@ program
|
|
|
264
363
|
process.exit(1);
|
|
265
364
|
}
|
|
266
365
|
});
|
|
267
|
-
program.
|
|
268
|
-
// Check for untracked files and prompt user to add them for diff visibility
|
|
269
|
-
async function readStdin() {
|
|
270
|
-
const chunks = [];
|
|
271
|
-
for await (const chunk of process.stdin) {
|
|
272
|
-
chunks.push(chunk);
|
|
273
|
-
}
|
|
274
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
275
|
-
}
|
|
366
|
+
void program.parseAsync();
|
|
276
367
|
async function handleUntrackedFiles(git, addAutomatically) {
|
|
277
368
|
const files = await findUntrackedFiles(git);
|
|
278
369
|
if (files.length === 0) {
|
package/dist/cli/index.test.js
CHANGED
|
@@ -640,7 +640,7 @@ describe('CLI index.ts', () => {
|
|
|
640
640
|
program
|
|
641
641
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
642
642
|
.argument('[compare-with]', 'compare-with')
|
|
643
|
-
.option('--comment <json>', 'comment', (value, previous
|
|
643
|
+
.option('--comment <json>', 'comment', (value, previous) => [...previous, value], [])
|
|
644
644
|
.option('--port <port>', 'port', parseInt)
|
|
645
645
|
.option('--host <host>', 'host', '')
|
|
646
646
|
.option('--no-open', 'no-open')
|
|
@@ -706,7 +706,7 @@ describe('CLI index.ts', () => {
|
|
|
706
706
|
program
|
|
707
707
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
708
708
|
.argument('[compare-with]', 'compare-with')
|
|
709
|
-
.option('--comment <json>', 'comment', (value, previous
|
|
709
|
+
.option('--comment <json>', 'comment', (value, previous) => [...previous, value], [])
|
|
710
710
|
.option('--port <port>', 'port', parseInt)
|
|
711
711
|
.option('--host <host>', 'host', '')
|
|
712
712
|
.option('--no-open', 'no-open')
|
|
@@ -808,7 +808,7 @@ describe('CLI index.ts', () => {
|
|
|
808
808
|
const program = new Command();
|
|
809
809
|
program
|
|
810
810
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
811
|
-
.option('--comment <json>', 'comment', (value, previous
|
|
811
|
+
.option('--comment <json>', 'comment', (value, previous) => [...previous, value], [])
|
|
812
812
|
.option('--port <port>', 'port', parseInt)
|
|
813
813
|
.option('--host <host>', 'host', '')
|
|
814
814
|
.option('--no-open', 'no-open')
|
|
@@ -853,7 +853,7 @@ describe('CLI index.ts', () => {
|
|
|
853
853
|
const program = new Command();
|
|
854
854
|
program
|
|
855
855
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
856
|
-
.option('--comment <json>', 'comment', (value, previous
|
|
856
|
+
.option('--comment <json>', 'comment', (value, previous) => [...previous, value], [])
|
|
857
857
|
.option('--tui', 'tui')
|
|
858
858
|
.action(async (_commitish, options) => {
|
|
859
859
|
const commentImports = actualParseCommentOptions(options.comment);
|
|
@@ -874,7 +874,7 @@ describe('CLI index.ts', () => {
|
|
|
874
874
|
const program = new Command();
|
|
875
875
|
program
|
|
876
876
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
877
|
-
.option('--comment <json>', 'comment', (value, previous
|
|
877
|
+
.option('--comment <json>', 'comment', (value, previous) => [...previous, value], [])
|
|
878
878
|
.action(async (_commitish, options) => {
|
|
879
879
|
try {
|
|
880
880
|
actualParseCommentOptions(options.comment);
|
package/dist/cli/utils.d.ts
CHANGED
|
@@ -25,4 +25,5 @@ export declare function findUntrackedFiles(git: SimpleGit): Promise<string[]>;
|
|
|
25
25
|
export declare function markFilesIntentToAdd(git: SimpleGit, files: string[]): Promise<void>;
|
|
26
26
|
export declare function promptUser(message: string): Promise<boolean>;
|
|
27
27
|
export declare function waitForEnter(message: string): Promise<void>;
|
|
28
|
+
export declare function readStdin(): Promise<string>;
|
|
28
29
|
export {};
|
package/dist/cli/utils.js
CHANGED
|
@@ -212,3 +212,10 @@ export async function waitForEnter(message) {
|
|
|
212
212
|
rl.close();
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
+
export async function readStdin() {
|
|
216
|
+
const chunks = [];
|
|
217
|
+
for await (const chunk of process.stdin) {
|
|
218
|
+
chunks.push(chunk);
|
|
219
|
+
}
|
|
220
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
221
|
+
}
|