@adanami/kaleido 0.1.0 → 0.2.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.
- package/CHANGELOG.md +25 -0
- package/README.md +9 -0
- package/dist/cli/index.js +409 -24
- package/dist/client/assets/{abnfDiagram-N423BO3Z-BNC_bOwN.js → abnfDiagram-N423BO3Z-BLtqS4V1.js} +1 -1
- package/dist/client/assets/{arc-BQjVBT7z.js → arc-DyLfH67M.js} +1 -1
- package/dist/client/assets/architecture-TIHT7OUA-B5Ma77Cd.js +1 -0
- package/dist/client/assets/{architectureDiagram-T3A2C74G-NbyTzj4B.js → architectureDiagram-T3A2C74G-tHSqReux.js} +1 -1
- package/dist/client/assets/{blockDiagram-VBNYF7ZC-D7RFrUDl.js → blockDiagram-VBNYF7ZC-qlFul3F2.js} +1 -1
- package/dist/client/assets/{c4Diagram-5PPSVZJV-CVtHbZ8m.js → c4Diagram-5PPSVZJV-8-iQf_3L.js} +1 -1
- package/dist/client/assets/channel-Cde_s6N9.js +1 -0
- package/dist/client/assets/{chunk-2GRJ4B5K-vymlEdvz.js → chunk-2GRJ4B5K-B6HO6-K5.js} +1 -1
- package/dist/client/assets/{chunk-4I5QYGJK-Dru7MVd5.js → chunk-4I5QYGJK-CbWygMHq.js} +1 -1
- package/dist/client/assets/{chunk-5RXB4S5H-_mW4jXZD.js → chunk-5RXB4S5H-qFn-JYXR.js} +1 -1
- package/dist/client/assets/{chunk-6Q2QTUOP-C-Jr6Q1u.js → chunk-6Q2QTUOP-CcE1vTzX.js} +1 -1
- package/dist/client/assets/{chunk-7Z6QIM7H-CH0etl6L.js → chunk-7Z6QIM7H-C08W_EwI.js} +1 -1
- package/dist/client/assets/{chunk-GF5L2VYU-l0ZYrFWn.js → chunk-GF5L2VYU-CHm7JrHM.js} +1 -1
- package/dist/client/assets/{chunk-I66GZJ75-CKcp5S17.js → chunk-I66GZJ75-DY6z-MCi.js} +1 -1
- package/dist/client/assets/{chunk-JQJVKLGR-BXKeK8Yn.js → chunk-JQJVKLGR-DKeiIUQ6.js} +1 -1
- package/dist/client/assets/{chunk-KBJHAD2P-DPP8q1jj.js → chunk-KBJHAD2P-CzT5-hAw.js} +1 -1
- package/dist/client/assets/{chunk-NSK5VX7P-CJvQSFjo.js → chunk-NSK5VX7P-ClHKnN2Z.js} +1 -1
- package/dist/client/assets/{chunk-QR6OTTB3-DAmoW-jk.js → chunk-QR6OTTB3-BOVrt91Y.js} +1 -1
- package/dist/client/assets/{chunk-RYQCIY6F-mEV_z1Vs.js → chunk-RYQCIY6F-DOPazF8k.js} +1 -1
- package/dist/client/assets/{chunk-UBXNYLIW-B9FQ3EVs.js → chunk-UBXNYLIW-CGh3W460.js} +1 -1
- package/dist/client/assets/{chunk-W5SLKNZC-B7q4L6_i.js → chunk-W5SLKNZC-8ST36NWH.js} +1 -1
- package/dist/client/assets/{chunk-WRU74C26-DwPGHVIY.js → chunk-WRU74C26-Dzc5jtNO.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-B_1m3XyG.js → chunk-XXDRQBXY-Cu9anCqu.js} +1 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-CRLogySI.js +1 -0
- package/dist/client/assets/classDiagram-v2-OCEON4UE-CRLogySI.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-_wSiGHW9.js → cose-bilkent-JH36ORCC-DGh8pHuP.js} +1 -1
- package/dist/client/assets/{cynefin-VYW2F7L2-BSXkfF6B.js → cynefin-VYW2F7L2-BpvhYsbg.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-MW4NZA55-DWqP9pCq.js → cynefinDiagram-MW4NZA55-43TbOIHI.js} +1 -1
- package/dist/client/assets/{dagre-VZM6K2ZE-D-6mKeP4.js → dagre-VZM6K2ZE-Cm58tyFt.js} +1 -1
- package/dist/client/assets/{diagram-7IWD3JNH-DwifWIOM.js → diagram-7IWD3JNH-vPJCjCki.js} +1 -1
- package/dist/client/assets/{diagram-B4RE2ZJO-CZy5Cter.js → diagram-B4RE2ZJO-Ba4DsVJc.js} +1 -1
- package/dist/client/assets/{diagram-LBJQPF4R-D64OHGQ1.js → diagram-LBJQPF4R-dtH5ElUa.js} +1 -1
- package/dist/client/assets/{diagram-Q27KOJAE-CYJYm3MT.js → diagram-Q27KOJAE-B6nCxEf9.js} +1 -1
- package/dist/client/assets/{diagram-UB23O5K3-D9XqDFWB.js → diagram-UB23O5K3-BZKG6s89.js} +1 -1
- package/dist/client/assets/{dist-D9557-UX.js → dist-dXsd7Pkc.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-BXEA7PRR-DXv0laGY.js → ebnfDiagram-BXEA7PRR-66kiPxSS.js} +1 -1
- package/dist/client/assets/{erDiagram-JOGREHBK-DtgpDnFq.js → erDiagram-JOGREHBK-BMxnczHt.js} +1 -1
- package/dist/client/assets/eventmodeling-45OFAUF4-dP5YCAk6.js +1 -0
- package/dist/client/assets/flowDiagram-UKHOOZJN-BVSKDVqP.js +1 -0
- package/dist/client/assets/{freemarker2-C0K9bJg3.js → freemarker2-B66RkR3-.js} +1 -1
- package/dist/client/assets/{ganttDiagram-PKOTCBZU-DbPT_9cm.js → ganttDiagram-PKOTCBZU-Dfygs7SY.js} +1 -1
- package/dist/client/assets/{gitGraph-TEB2WS4Q-BSzJ-zot.js → gitGraph-TEB2WS4Q-D4bcJ5qF.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-Dv47ST8y.js → gitGraphDiagram-DS77QQ5N-CpZ3u2XW.js} +1 -1
- package/dist/client/assets/{handlebars-C5Uh7yG8.js → handlebars-DKbKbvfy.js} +1 -1
- package/dist/client/assets/{html-CVq09h_T.js → html-ACV4rbgT.js} +1 -1
- package/dist/client/assets/{index-BdNjwiL_.css → index-C9ouroMB.css} +1 -1
- package/dist/client/assets/{index-C-Az4wQZ.js → index-DSoO6fwm.js} +190 -185
- package/dist/client/assets/{info-DKCQHKI2-DrnuTwtV.js → info-DKCQHKI2-DSdcmL_E.js} +1 -1
- package/dist/client/assets/{infoDiagram-6WML65LV-BbOLkXMO.js → infoDiagram-6WML65LV-CPjw27OG.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-BU0Xf4Jv.js → ishikawaDiagram-WSZJBQD7-AUtwmA_E.js} +1 -1
- package/dist/client/assets/{javascript-BLNuR3ma.js → javascript-BrRHbE_m.js} +1 -1
- package/dist/client/assets/{journeyDiagram-NVQOT4AX-Be02AxgF.js → journeyDiagram-NVQOT4AX-dVKZ1J57.js} +1 -1
- package/dist/client/assets/{kanban-definition-27J2QSJJ-DAJOmq0i.js → kanban-definition-27J2QSJJ-yiBIweU4.js} +1 -1
- package/dist/client/assets/{line-CY8MZqA_.js → line-TmRvsmaZ.js} +1 -1
- package/dist/client/assets/{linear-VmQ0cgWf.js → linear-CGnxQxbf.js} +1 -1
- package/dist/client/assets/{liquid-CqxeTiTR.js → liquid-Dxzl-R2s.js} +1 -1
- package/dist/client/assets/{mdx-CZgnrcpZ.js → mdx-BzdRXa7m.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-BNyH4fWd.js → mermaid-parser.core-x3opGel5.js} +3 -3
- package/dist/client/assets/{mermaid.core-D6SqRXfj.js → mermaid.core-FMl-QNqU.js} +4 -4
- package/dist/client/assets/{mindmap-definition-FAOFIHXS-Cb4njDU8.js → mindmap-definition-FAOFIHXS-mTnBmq5M.js} +1 -1
- package/dist/client/assets/{packet-7NZHBO7P-C0OLtmrN.js → packet-7NZHBO7P-Dur5NQsS.js} +1 -1
- package/dist/client/assets/{pegDiagram-VL7TDLO6-CUlmavTd.js → pegDiagram-VL7TDLO6-Bx7c-RoO.js} +1 -1
- package/dist/client/assets/{pie-RZYD4A2V-BOaXF8wo.js → pie-RZYD4A2V-G_zAP186.js} +1 -1
- package/dist/client/assets/{pieDiagram-7S7Q4E2Y-DAuLOXyl.js → pieDiagram-7S7Q4E2Y-Dusuh84y.js} +1 -1
- package/dist/client/assets/{python-BKTOsIAC.js → python-CkiCBL2_.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-6T2tUzKE.js → quadrantDiagram-CIZ2JOQS-saljoF_q.js} +1 -1
- package/dist/client/assets/{radar-I7S5WNFK-84ZPjfzV.js → radar-I7S5WNFK-SXVwHPoS.js} +1 -1
- package/dist/client/assets/{railroad-3IZDKUUU-BIancogu.js → railroad-3IZDKUUU-CNCO7Ky2.js} +1 -1
- package/dist/client/assets/railroad-abnf-AHOZXSZD-BDQOulCY.js +1 -0
- package/dist/client/assets/railroad-ebnf-EBAXGLYW-C7zEtpgH.js +1 -0
- package/dist/client/assets/railroad-peg-LSFZ7HO6-BRXwZ79v.js +1 -0
- package/dist/client/assets/{railroadDiagram-AXF67PYL-CG4n3oVN.js → railroadDiagram-AXF67PYL-DAlS2_gp.js} +1 -1
- package/dist/client/assets/{razor-D3D2-y9K.js → razor-CwkHcp-G.js} +1 -1
- package/dist/client/assets/{requirementDiagram-LRYGKXZP-mZX3Srsb.js → requirementDiagram-LRYGKXZP-Dl7nCbgE.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-W5VNT64P-yPa5u_0L.js → sankeyDiagram-W5VNT64P-DpKvr-H6.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-SI44F4Z6-CyNIlTWm.js → sequenceDiagram-SI44F4Z6-GHdgL3U8.js} +1 -1
- package/dist/client/assets/{src-CUuFImQF.js → src-I0atgFmE.js} +1 -1
- package/dist/client/assets/{stateDiagram-OKZ733FA-CPylCUxu.js → stateDiagram-OKZ733FA-BMQuOtg3.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-DJySabKQ.js +1 -0
- package/dist/client/assets/{swimlanes-SLNWSIFB-DBNGs0gR.js → swimlanes-SLNWSIFB-Bbv_31ln.js} +1 -1
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-CT5Zed77.js +8 -0
- package/dist/client/assets/{timeline-definition-Z64GVDOM-BAUrOlpT.js → timeline-definition-Z64GVDOM-exSeDWTB.js} +1 -1
- package/dist/client/assets/{treeView-QDETBFTQ-DWU_Tu3e.js → treeView-QDETBFTQ-CNVUn1N1.js} +1 -1
- package/dist/client/assets/{treemap-6X3UGDF4-C0VSsv4b.js → treemap-6X3UGDF4-DwRfsOWe.js} +1 -1
- package/dist/client/assets/{typescript-DHaWXPl5.js → typescript-C48SvnqB.js} +1 -1
- package/dist/client/assets/{vennDiagram-T6HMQDX7-DMDrxVrh.js → vennDiagram-T6HMQDX7-CHNvZB5Q.js} +1 -1
- package/dist/client/assets/{wardley-OPB4EBWU-2FXuD4eH.js → wardley-OPB4EBWU-DmPs7uoZ.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-T6FBY63Y-B6MdwST-.js → wardleyDiagram-T6FBY63Y-DGX-45LC.js} +1 -1
- package/dist/client/assets/{xml-UOCAZ6xX.js → xml-C8VlQ0O4.js} +1 -1
- package/dist/client/assets/{xychartDiagram-ELKLHX3M-4m0lgQEp.js → xychartDiagram-ELKLHX3M-DDMaGc1P.js} +1 -1
- package/dist/client/assets/{yaml-c5v3wojq.js → yaml-ZvDLP3To.js} +1 -1
- package/dist/client/index.html +2 -2
- package/package.json +3 -2
- package/dist/client/assets/architecture-TIHT7OUA-rtiyad39.js +0 -1
- package/dist/client/assets/channel-Cg-CR3Kv.js +0 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-DN-cM4gO.js +0 -1
- package/dist/client/assets/classDiagram-v2-OCEON4UE-DN-cM4gO.js +0 -1
- package/dist/client/assets/eventmodeling-45OFAUF4-CIrFy3PN.js +0 -1
- package/dist/client/assets/flowDiagram-UKHOOZJN-CsaPoqV0.js +0 -1
- package/dist/client/assets/railroad-abnf-AHOZXSZD-DY5Umeyq.js +0 -1
- package/dist/client/assets/railroad-ebnf-EBAXGLYW-BvHqcDCh.js +0 -1
- package/dist/client/assets/railroad-peg-LSFZ7HO6-Bcfw7tSJ.js +0 -1
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-87clA1Da.js +0 -1
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-DrshQU12.js +0 -8
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 (2026-09-09)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- GitHub の pull request を開けるようにした (`kaleido pr 123` / PR の URL)。`gh` 経由で `refs/pull/<N>/head` を fetch するので、fork からの PR も checkout なしで読める
|
|
8
|
+
- PR の本文・会話・レビューコメントを閲覧できるようにした。行に紐づくレビューコメントはエディタ上にも表示する
|
|
9
|
+
- PR 表示中に GitHub の PR ページと github.dev を開くリンクを追加した
|
|
10
|
+
- ツールバーに refresh ボタンを追加し、タブが再表示されたときにも自動で取り直すようにした
|
|
11
|
+
- diff のファイルツリーで、ディレクトリ単位に viewed をトグルできるようにした
|
|
12
|
+
- Orca のターミナルから起動したときは Orca の内蔵ブラウザで開くようにした
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- 行コメント追加ボタンを outlined なモノトーンにした
|
|
17
|
+
- Markdown プレビューの最大幅 (1280px) を外し、ペイン幅いっぱいに表示するようにした
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- merge 済み PR の diff が空になるのを直した。範囲セレクタに merged PR も並ぶようにした
|
|
22
|
+
|
|
23
|
+
## 0.1.0 (2026-08-22)
|
|
24
|
+
|
|
25
|
+
初回リリース。
|
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ kaleido working # unstaged changes (index vs working tree)
|
|
|
29
29
|
kaleido staged # staged changes (HEAD vs index)
|
|
30
30
|
kaleido <commit> # そのコミットの diff (<commit>^ vs <commit>)
|
|
31
31
|
kaleido <target> <base> # 任意の比較 (base vs target)
|
|
32
|
+
kaleido pr 123 # GitHub の pull request (base ブランチとの merge-base vs PR head)
|
|
33
|
+
kaleido https://github.com/owner/repo/pull/123 # PR の URL でも可
|
|
32
34
|
|
|
33
35
|
kaleido comments [target] [base] # 保存済みコメントを AI プロンプト形式で stdout に出力
|
|
34
36
|
```
|
|
@@ -36,6 +38,8 @@ kaleido comments [target] [base] # 保存済みコメントを AI プロンプ
|
|
|
36
38
|
位置引数は「ディレクトリ」または「比較範囲」。commit-ish として解決できなければディレクトリと解釈する (`--dir` で明示もできる)。
|
|
37
39
|
引数なしのときは staged 変更 → working 変更 → 直近コミットの順に自動判定する。
|
|
38
40
|
|
|
41
|
+
PR の表示には [GitHub CLI](https://cli.github.com/) (`gh`、ログイン済み) が必要。`refs/pull/<N>/head` を `origin/pr/<N>` に fetch して開くので、fork からの PR も checkout なしで読める。
|
|
42
|
+
|
|
39
43
|
表示中の状態は URL クエリ (`?target=&base=&path=&tab=`) に同期されるので、リロード・共有できる。
|
|
40
44
|
|
|
41
45
|
| オプション | 説明 |
|
|
@@ -47,6 +51,8 @@ kaleido comments [target] [base] # 保存済みコメントを AI プロンプ
|
|
|
47
51
|
| `--no-open` | ブラウザを自動で開かない |
|
|
48
52
|
| `--no-keep-alive` | 全タブが閉じられたらサーバーを終了する |
|
|
49
53
|
|
|
54
|
+
[Orca](https://github.com/stablyai/orca) のターミナルから起動したときは、OS 既定のブラウザではなく Orca 内蔵ブラウザの新規タブに開く (`TERM_PROGRAM=Orca` で判定)。
|
|
55
|
+
|
|
50
56
|
キーボード: `j` / `k` でファイル移動、`v` でレビュー済みトグル、⌘P で Quick Open、⌘B でサイドバー、⌘S で保存。
|
|
51
57
|
|
|
52
58
|
## 機能
|
|
@@ -57,6 +63,9 @@ kaleido comments [target] [base] # 保存済みコメントを AI プロンプ
|
|
|
57
63
|
- **HTML プレビュー**: `/preview` から配信するので相対パスの CSS / JS / 画像も読め、スクリプトも動く
|
|
58
64
|
- **型情報と診断**: hover / 型エラー / 定義ジャンプ / 参照検索と、プロジェクトの eslint による行マーカー
|
|
59
65
|
- **レビュー** (git のみ): 比較範囲の切替、内容ハッシュで残るレビュー済みマーク、行/範囲コメント。状態はサーバー側にファイル保存されるのでブラウザを変えても消えない
|
|
66
|
+
- **Pull request** (GitHub のみ): 範囲セレクタに open な PR が並び、選ぶと最新の head を fetch して base ブランチとの merge-base 比較で開く。コメントは PR 単位で残る。セレクタの横から PR ページと github.dev を開ける
|
|
67
|
+
- Changes の先頭の **Overview** で PR の本文と会話 (コメント・approve など) を読める。GitHub 上の行コメントはエディタ内の該当行に読み取り専用で表示され、ファイル一覧にも件数が出る
|
|
68
|
+
- merge 済みの PR も開ける (GitHub が固定している base コミットとの merge-base で diff を出す)。セレクタには最近 merge された PR も並ぶ
|
|
60
69
|
- **設定**: 歯車から配色 (既定は OS 追従) と文字サイズ、ライセンス表記
|
|
61
70
|
|
|
62
71
|

|
package/dist/cli/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import open from "open";
|
|
6
5
|
|
|
7
6
|
// src/shared/commentFormat.ts
|
|
8
7
|
function formatCommentPrompt(comment) {
|
|
@@ -20,6 +19,20 @@ function formatAllCommentsPrompt(comments) {
|
|
|
20
19
|
|
|
21
20
|
// src/shared/types.ts
|
|
22
21
|
var BROWSE_RANGE = { target: "browse", base: "browse" };
|
|
22
|
+
function pullRequestRef(number) {
|
|
23
|
+
return `origin/pr/${number}`;
|
|
24
|
+
}
|
|
25
|
+
function pullNumberOfRef(ref) {
|
|
26
|
+
const match = /^origin\/pr\/(\d+)$/.exec(ref);
|
|
27
|
+
return match ? Number(match[1]) : null;
|
|
28
|
+
}
|
|
29
|
+
function pullRange(pull) {
|
|
30
|
+
return {
|
|
31
|
+
target: pullRequestRef(pull.number),
|
|
32
|
+
base: pull.state === "OPEN" ? `origin/${pull.baseRefName}` : pull.baseRefOid,
|
|
33
|
+
baseMode: "merge-base"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
23
36
|
function rangeKey(range) {
|
|
24
37
|
const sanitize = (s) => s.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
25
38
|
const mode = range.baseMode === "merge-base" ? "~mb" : "";
|
|
@@ -30,6 +43,8 @@ function describeRange(range) {
|
|
|
30
43
|
if (range.target === "working") return "unstaged changes";
|
|
31
44
|
if (range.target === "staged") return `${range.base}..staged`;
|
|
32
45
|
if (range.target === ".") return `${range.base}..working tree`;
|
|
46
|
+
const pullNumber = pullNumberOfRef(range.target);
|
|
47
|
+
if (pullNumber !== null) return `PR #${pullNumber} (${range.base}...${range.target})`;
|
|
33
48
|
const sep3 = range.baseMode === "merge-base" ? "..." : "..";
|
|
34
49
|
return `${range.base}${sep3}${range.target}`;
|
|
35
50
|
}
|
|
@@ -305,11 +320,41 @@ function createApp(ctx) {
|
|
|
305
320
|
});
|
|
306
321
|
app.get("/api/ranges", async (c) => {
|
|
307
322
|
if (!ctx.gitRefs) {
|
|
308
|
-
const empty = {
|
|
323
|
+
const empty = {
|
|
324
|
+
branches: [],
|
|
325
|
+
recentCommits: [],
|
|
326
|
+
defaultBranch: null,
|
|
327
|
+
pullRequests: [],
|
|
328
|
+
githubRepoUrl: null
|
|
329
|
+
};
|
|
309
330
|
return c.json(empty);
|
|
310
331
|
}
|
|
311
332
|
return c.json(await ctx.gitRefs.getRanges());
|
|
312
333
|
});
|
|
334
|
+
app.get("/api/pulls/:number", async (c) => {
|
|
335
|
+
if (!ctx.gitPulls) return c.json({ error: "Not a git repository" }, 400);
|
|
336
|
+
const number = Number(c.req.param("number"));
|
|
337
|
+
if (!Number.isInteger(number) || number <= 0) {
|
|
338
|
+
return c.json({ error: "Invalid pull request number" }, 400);
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
return c.json(await ctx.gitPulls.detail(number));
|
|
342
|
+
} catch (error) {
|
|
343
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 502);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
app.post("/api/pulls/:number/fetch", async (c) => {
|
|
347
|
+
if (!ctx.gitPulls) return c.json({ error: "Not a git repository" }, 400);
|
|
348
|
+
const number = Number(c.req.param("number"));
|
|
349
|
+
if (!Number.isInteger(number) || number <= 0) {
|
|
350
|
+
return c.json({ error: "Invalid pull request number" }, 400);
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
return c.json(await ctx.gitPulls.fetch(number));
|
|
354
|
+
} catch (error) {
|
|
355
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 502);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
313
358
|
app.get("/api/files", async (c) => {
|
|
314
359
|
if (ctx.gitDiff) {
|
|
315
360
|
return c.json(applyExcludes(await ctx.gitDiff.listRepoFiles(), ctx.config));
|
|
@@ -542,11 +587,14 @@ function createApp(ctx) {
|
|
|
542
587
|
"/api/viewed",
|
|
543
588
|
zValidator(
|
|
544
589
|
"json",
|
|
545
|
-
z.object({
|
|
590
|
+
z.object({
|
|
591
|
+
files: z.array(z.object({ path: z.string().min(1), hash: z.string().min(1) })).min(1),
|
|
592
|
+
viewed: z.boolean()
|
|
593
|
+
})
|
|
546
594
|
),
|
|
547
595
|
(c) => {
|
|
548
|
-
const {
|
|
549
|
-
ctx.reviewStore.setViewed(
|
|
596
|
+
const { files, viewed } = c.req.valid("json");
|
|
597
|
+
ctx.reviewStore.setViewed(files, viewed);
|
|
550
598
|
return c.json({ ok: true });
|
|
551
599
|
}
|
|
552
600
|
);
|
|
@@ -926,24 +974,300 @@ function decodeGitPath(rawPath) {
|
|
|
926
974
|
return Buffer.from(bytes).toString("utf8");
|
|
927
975
|
}
|
|
928
976
|
|
|
977
|
+
// src/server/git/pulls.ts
|
|
978
|
+
import { execFile as execFile2 } from "child_process";
|
|
979
|
+
import { promisify as promisify2 } from "util";
|
|
980
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
981
|
+
var PR_JSON_FIELDS = "number,title,state,headRefName,baseRefName,baseRefOid,author,isDraft,url,updatedAt";
|
|
982
|
+
var PR_DETAIL_QUERY = `
|
|
983
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
984
|
+
repository(owner: $owner, name: $name) {
|
|
985
|
+
pullRequest(number: $number) {
|
|
986
|
+
number title body state isDraft url createdAt updatedAt
|
|
987
|
+
baseRefName baseRefOid headRefName headRefOid additions deletions changedFiles
|
|
988
|
+
author { login }
|
|
989
|
+
comments(first: 100) {
|
|
990
|
+
nodes { id author { login } body createdAt url }
|
|
991
|
+
}
|
|
992
|
+
reviews(first: 100) {
|
|
993
|
+
nodes { id author { login } body state createdAt url }
|
|
994
|
+
}
|
|
995
|
+
reviewThreads(first: 100) {
|
|
996
|
+
nodes {
|
|
997
|
+
id path line startLine originalLine originalStartLine diffSide isResolved isOutdated
|
|
998
|
+
comments(first: 100) {
|
|
999
|
+
nodes { id author { login } body createdAt url diffHunk }
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}`;
|
|
1006
|
+
function toDetail(pr) {
|
|
1007
|
+
const conversation = [
|
|
1008
|
+
...pr.comments.nodes.map((c) => ({
|
|
1009
|
+
id: c.id,
|
|
1010
|
+
kind: "comment",
|
|
1011
|
+
author: c.author?.login ?? "",
|
|
1012
|
+
body: c.body,
|
|
1013
|
+
createdAt: c.createdAt,
|
|
1014
|
+
url: c.url
|
|
1015
|
+
})),
|
|
1016
|
+
// 本文のない COMMENTED レビューは行コメントの入れ物でしかないので会話には出さない
|
|
1017
|
+
...pr.reviews.nodes.filter((r) => r.body.trim().length > 0 || r.state === "APPROVED" || r.state === "CHANGES_REQUESTED").map((r) => ({
|
|
1018
|
+
id: r.id,
|
|
1019
|
+
kind: "review",
|
|
1020
|
+
author: r.author?.login ?? "",
|
|
1021
|
+
body: r.body,
|
|
1022
|
+
createdAt: r.createdAt,
|
|
1023
|
+
url: r.url,
|
|
1024
|
+
reviewState: r.state
|
|
1025
|
+
}))
|
|
1026
|
+
].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1027
|
+
const reviewThreads = pr.reviewThreads.nodes.map((t) => ({
|
|
1028
|
+
id: t.id,
|
|
1029
|
+
path: t.path,
|
|
1030
|
+
side: t.diffSide === "LEFT" ? "original" : "modified",
|
|
1031
|
+
line: t.line,
|
|
1032
|
+
startLine: t.startLine,
|
|
1033
|
+
originalLine: t.originalLine,
|
|
1034
|
+
originalStartLine: t.originalStartLine,
|
|
1035
|
+
isResolved: t.isResolved,
|
|
1036
|
+
isOutdated: t.isOutdated,
|
|
1037
|
+
diffHunk: t.comments.nodes[0]?.diffHunk ?? "",
|
|
1038
|
+
comments: t.comments.nodes.map((c) => ({
|
|
1039
|
+
id: c.id,
|
|
1040
|
+
author: c.author?.login ?? "",
|
|
1041
|
+
body: c.body,
|
|
1042
|
+
createdAt: c.createdAt,
|
|
1043
|
+
url: c.url
|
|
1044
|
+
}))
|
|
1045
|
+
}));
|
|
1046
|
+
return {
|
|
1047
|
+
number: pr.number,
|
|
1048
|
+
title: pr.title,
|
|
1049
|
+
headRefName: pr.headRefName,
|
|
1050
|
+
baseRefName: pr.baseRefName,
|
|
1051
|
+
baseRefOid: pr.baseRefOid,
|
|
1052
|
+
author: pr.author?.login ?? "",
|
|
1053
|
+
isDraft: pr.isDraft,
|
|
1054
|
+
url: pr.url,
|
|
1055
|
+
updatedAt: pr.updatedAt,
|
|
1056
|
+
body: pr.body,
|
|
1057
|
+
state: pr.state,
|
|
1058
|
+
createdAt: pr.createdAt,
|
|
1059
|
+
headRefOid: pr.headRefOid,
|
|
1060
|
+
additions: pr.additions,
|
|
1061
|
+
deletions: pr.deletions,
|
|
1062
|
+
changedFiles: pr.changedFiles,
|
|
1063
|
+
conversation,
|
|
1064
|
+
reviewThreads
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
function toMeta(pr) {
|
|
1068
|
+
return {
|
|
1069
|
+
number: pr.number,
|
|
1070
|
+
title: pr.title,
|
|
1071
|
+
state: pr.state,
|
|
1072
|
+
headRefName: pr.headRefName,
|
|
1073
|
+
baseRefName: pr.baseRefName,
|
|
1074
|
+
baseRefOid: pr.baseRefOid,
|
|
1075
|
+
author: pr.author?.login ?? "",
|
|
1076
|
+
isDraft: pr.isDraft,
|
|
1077
|
+
url: pr.url,
|
|
1078
|
+
updatedAt: pr.updatedAt
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
function isEnoent(error) {
|
|
1082
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1083
|
+
}
|
|
1084
|
+
function stderrOf(error) {
|
|
1085
|
+
if (typeof error === "object" && error !== null && "stderr" in error) {
|
|
1086
|
+
return String(error.stderr).trim();
|
|
1087
|
+
}
|
|
1088
|
+
return error instanceof Error ? error.message : String(error);
|
|
1089
|
+
}
|
|
1090
|
+
function parsePullNumber(input) {
|
|
1091
|
+
const match = /^#?(\d+)$/.exec(input) ?? /^(?:pr|pull)\/(\d+)$/.exec(input) ?? /^https?:\/\/[^/]+\/[^/]+\/[^/]+\/pull\/(\d+)(?:[/?#].*)?$/.exec(input);
|
|
1092
|
+
return match ? Number(match[1]) : null;
|
|
1093
|
+
}
|
|
1094
|
+
var GitPulls = class {
|
|
1095
|
+
constructor(repoRoot) {
|
|
1096
|
+
this.repoRoot = repoRoot;
|
|
1097
|
+
}
|
|
1098
|
+
repoRoot;
|
|
1099
|
+
/** gh が未インストールなら以後は問い合わせない */
|
|
1100
|
+
isGhMissing = false;
|
|
1101
|
+
async gh(args) {
|
|
1102
|
+
const { stdout } = await execFileAsync2("gh", args, {
|
|
1103
|
+
cwd: this.repoRoot,
|
|
1104
|
+
encoding: "utf8",
|
|
1105
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
1106
|
+
env: { ...process.env, GH_PROMPT_DISABLED: "1", GH_NO_UPDATE_NOTIFIER: "1" }
|
|
1107
|
+
});
|
|
1108
|
+
return stdout;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* open な PR (最大 30 件) と最近 merge された PR (最大 10 件)。
|
|
1112
|
+
* gh が使えない・GitHub リポジトリでない・オフラインなら空
|
|
1113
|
+
*/
|
|
1114
|
+
async list() {
|
|
1115
|
+
if (this.isGhMissing) return [];
|
|
1116
|
+
try {
|
|
1117
|
+
const [open2, merged] = await Promise.all([
|
|
1118
|
+
this.listByState("open", 30),
|
|
1119
|
+
this.listByState("merged", 10)
|
|
1120
|
+
]);
|
|
1121
|
+
return [...open2, ...merged];
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
if (isEnoent(error)) this.isGhMissing = true;
|
|
1124
|
+
return [];
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
async listByState(state, limit) {
|
|
1128
|
+
const out = await this.gh([
|
|
1129
|
+
"pr",
|
|
1130
|
+
"list",
|
|
1131
|
+
"--state",
|
|
1132
|
+
state,
|
|
1133
|
+
"--limit",
|
|
1134
|
+
String(limit),
|
|
1135
|
+
"--json",
|
|
1136
|
+
PR_JSON_FIELDS
|
|
1137
|
+
]);
|
|
1138
|
+
const prs = JSON.parse(out);
|
|
1139
|
+
return prs.map(toMeta);
|
|
1140
|
+
}
|
|
1141
|
+
async view(number) {
|
|
1142
|
+
try {
|
|
1143
|
+
const out = await this.gh(["pr", "view", String(number), "--json", PR_JSON_FIELDS]);
|
|
1144
|
+
const pr = JSON.parse(out);
|
|
1145
|
+
return toMeta(pr);
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
if (isEnoent(error)) {
|
|
1148
|
+
throw new Error("GitHub CLI (gh) is required to open pull requests: https://cli.github.com/");
|
|
1149
|
+
}
|
|
1150
|
+
throw new Error(`Could not read PR #${number}: ${stderrOf(error)}`);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
nameWithOwner = null;
|
|
1154
|
+
/** origin が指す GitHub リポジトリの owner/name (gh が解決する)。一度引いたら使い回す */
|
|
1155
|
+
async getNameWithOwner() {
|
|
1156
|
+
if (this.nameWithOwner === null) {
|
|
1157
|
+
const out = await this.gh(["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"]);
|
|
1158
|
+
this.nameWithOwner = out.trim();
|
|
1159
|
+
}
|
|
1160
|
+
const [owner, name] = this.nameWithOwner.split("/");
|
|
1161
|
+
if (!owner || !name) throw new Error(`Unexpected repository name: ${this.nameWithOwner}`);
|
|
1162
|
+
return { owner, name };
|
|
1163
|
+
}
|
|
1164
|
+
/** PR の本文・会話 (issue コメント / レビュー)・行コメントのスレッド */
|
|
1165
|
+
async detail(number) {
|
|
1166
|
+
try {
|
|
1167
|
+
const { owner, name } = await this.getNameWithOwner();
|
|
1168
|
+
const out = await this.gh([
|
|
1169
|
+
"api",
|
|
1170
|
+
"graphql",
|
|
1171
|
+
"-F",
|
|
1172
|
+
`owner=${owner}`,
|
|
1173
|
+
"-F",
|
|
1174
|
+
`name=${name}`,
|
|
1175
|
+
"-F",
|
|
1176
|
+
`number=${number}`,
|
|
1177
|
+
"-f",
|
|
1178
|
+
`query=${PR_DETAIL_QUERY}`
|
|
1179
|
+
]);
|
|
1180
|
+
const parsed = JSON.parse(out);
|
|
1181
|
+
const pr = parsed.data?.repository?.pullRequest;
|
|
1182
|
+
if (!pr) throw new Error("not found");
|
|
1183
|
+
return toDetail(pr);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
if (isEnoent(error)) {
|
|
1186
|
+
throw new Error("GitHub CLI (gh) is required to read pull requests: https://cli.github.com/");
|
|
1187
|
+
}
|
|
1188
|
+
throw new Error(`Could not read PR #${number}: ${stderrOf(error)}`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
/** PR の head と base ブランチを origin から取り直し、比較範囲を返す */
|
|
1192
|
+
async fetch(number) {
|
|
1193
|
+
const pull = await this.view(number);
|
|
1194
|
+
try {
|
|
1195
|
+
await execFileAsync2(
|
|
1196
|
+
"git",
|
|
1197
|
+
[
|
|
1198
|
+
"fetch",
|
|
1199
|
+
"--no-tags",
|
|
1200
|
+
"origin",
|
|
1201
|
+
`+refs/pull/${number}/head:refs/remotes/${pullRequestRef(number)}`,
|
|
1202
|
+
`+refs/heads/${pull.baseRefName}:refs/remotes/origin/${pull.baseRefName}`
|
|
1203
|
+
],
|
|
1204
|
+
{
|
|
1205
|
+
cwd: this.repoRoot,
|
|
1206
|
+
encoding: "utf8",
|
|
1207
|
+
// 認証が必要なときは対話せずに失敗させる (サーバー内で固まらないように)
|
|
1208
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
1209
|
+
}
|
|
1210
|
+
);
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
throw new Error(`Could not fetch PR #${number} from origin: ${stderrOf(error)}`);
|
|
1213
|
+
}
|
|
1214
|
+
if (pull.state !== "OPEN" && !await this.hasCommit(pull.baseRefOid)) {
|
|
1215
|
+
try {
|
|
1216
|
+
await execFileAsync2("git", ["fetch", "--no-tags", "origin", pull.baseRefOid], {
|
|
1217
|
+
cwd: this.repoRoot,
|
|
1218
|
+
encoding: "utf8",
|
|
1219
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
1220
|
+
});
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
throw new Error(
|
|
1223
|
+
`Could not fetch the base commit ${pull.baseRefOid.slice(0, 7)} of PR #${number}: ${stderrOf(error)}`
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
return { range: pullRange(pull), pull };
|
|
1228
|
+
}
|
|
1229
|
+
async hasCommit(sha) {
|
|
1230
|
+
try {
|
|
1231
|
+
await execFileAsync2("git", ["cat-file", "-e", `${sha}^{commit}`], { cwd: this.repoRoot });
|
|
1232
|
+
return true;
|
|
1233
|
+
} catch {
|
|
1234
|
+
return false;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
|
|
929
1239
|
// src/server/git/refs.ts
|
|
930
1240
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
931
1241
|
var GitRefs = class {
|
|
932
|
-
|
|
933
|
-
|
|
1242
|
+
constructor(repoRoot, pulls) {
|
|
1243
|
+
this.pulls = pulls;
|
|
934
1244
|
this.git = simpleGit2(repoRoot);
|
|
935
1245
|
}
|
|
1246
|
+
pulls;
|
|
1247
|
+
git;
|
|
936
1248
|
async getRanges() {
|
|
937
|
-
const [branches, log, defaultBranch] = await Promise.all([
|
|
1249
|
+
const [branches, log, defaultBranch, pullRequests, githubRepoUrl] = await Promise.all([
|
|
938
1250
|
this.getBranches(),
|
|
939
1251
|
this.getRecentCommits(),
|
|
940
|
-
this.getDefaultBranch()
|
|
1252
|
+
this.getDefaultBranch(),
|
|
1253
|
+
this.pulls.list(),
|
|
1254
|
+
this.getGithubRepoUrl()
|
|
941
1255
|
]);
|
|
942
|
-
return { branches, recentCommits: log, defaultBranch };
|
|
1256
|
+
return { branches, recentCommits: log, defaultBranch, pullRequests, githubRepoUrl };
|
|
1257
|
+
}
|
|
1258
|
+
async getGithubRepoUrl() {
|
|
1259
|
+
try {
|
|
1260
|
+
const out = await this.git.raw(["remote", "get-url", "origin"]);
|
|
1261
|
+
return parseGithubRepoUrl(out.trim());
|
|
1262
|
+
} catch {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
943
1265
|
}
|
|
944
1266
|
async getBranches() {
|
|
945
1267
|
const summary = await this.git.branch(["--sort=-committerdate"]);
|
|
946
|
-
return summary.all.filter(
|
|
1268
|
+
return summary.all.filter(
|
|
1269
|
+
(b) => (!b.startsWith("remotes/") || b.startsWith("remotes/origin/")) && !b.startsWith("remotes/origin/pr/")
|
|
1270
|
+
);
|
|
947
1271
|
}
|
|
948
1272
|
async getRecentCommits() {
|
|
949
1273
|
const log = await this.git.log({ maxCount: 50 });
|
|
@@ -970,6 +1294,14 @@ var GitRefs = class {
|
|
|
970
1294
|
}
|
|
971
1295
|
}
|
|
972
1296
|
};
|
|
1297
|
+
function parseGithubRepoUrl(remote) {
|
|
1298
|
+
const match = /^(?:https?:\/\/|ssh:\/\/)?(?:[^@/]+@)?([^:/]+)(?::\d+)?[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/.exec(remote);
|
|
1299
|
+
if (!match) return null;
|
|
1300
|
+
const [, host, owner, repo] = match;
|
|
1301
|
+
if (!host || !owner || !repo) return null;
|
|
1302
|
+
const isGithubHost = host === "github.com" || host.endsWith(".ghe.com") || host.startsWith("github.");
|
|
1303
|
+
return isGithubHost ? `https://${host}/${owner}/${repo}` : null;
|
|
1304
|
+
}
|
|
973
1305
|
|
|
974
1306
|
// src/server/events.ts
|
|
975
1307
|
var EventBus = class {
|
|
@@ -1053,12 +1385,15 @@ var ReviewStore = class {
|
|
|
1053
1385
|
if (!data || data.version !== STORE_VERSION) return { entries: {} };
|
|
1054
1386
|
return { entries: data.entries };
|
|
1055
1387
|
}
|
|
1056
|
-
setViewed(
|
|
1388
|
+
setViewed(files, isViewed) {
|
|
1057
1389
|
const state = this.getViewed();
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1390
|
+
const viewedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1391
|
+
for (const { path, hash } of files) {
|
|
1392
|
+
if (isViewed) {
|
|
1393
|
+
state.entries[path] = { hash, viewedAt };
|
|
1394
|
+
} else {
|
|
1395
|
+
delete state.entries[path];
|
|
1396
|
+
}
|
|
1062
1397
|
}
|
|
1063
1398
|
this.writeAtomic(this.viewedPath, { version: STORE_VERSION, entries: state.entries });
|
|
1064
1399
|
}
|
|
@@ -1197,6 +1532,7 @@ var TsWorkerClient = class {
|
|
|
1197
1532
|
function createAppContext(rootDir, initialRange, options) {
|
|
1198
1533
|
const realRoot = realpathSync3(rootDir);
|
|
1199
1534
|
const repoId = computeRepoId(realRoot);
|
|
1535
|
+
const gitPulls = options.isGitRepo ? new GitPulls(realRoot) : null;
|
|
1200
1536
|
return {
|
|
1201
1537
|
rootDir: realRoot,
|
|
1202
1538
|
repoId,
|
|
@@ -1204,7 +1540,8 @@ function createAppContext(rootDir, initialRange, options) {
|
|
|
1204
1540
|
initialRange,
|
|
1205
1541
|
config: loadViewerConfig(realRoot, options.excludes),
|
|
1206
1542
|
gitDiff: options.isGitRepo ? new GitDiff(realRoot) : null,
|
|
1207
|
-
gitRefs:
|
|
1543
|
+
gitRefs: gitPulls ? new GitRefs(realRoot, gitPulls) : null,
|
|
1544
|
+
gitPulls,
|
|
1208
1545
|
fileContent: new FileContent(realRoot, options.isGitRepo),
|
|
1209
1546
|
tsService: new TsWorkerClient(realRoot),
|
|
1210
1547
|
reviewStore: new ReviewStore(repoId, realRoot),
|
|
@@ -1330,8 +1667,32 @@ function isDirectory(path) {
|
|
|
1330
1667
|
return false;
|
|
1331
1668
|
}
|
|
1332
1669
|
}
|
|
1333
|
-
function
|
|
1670
|
+
function parsePullTarget(target, base) {
|
|
1671
|
+
if (target === void 0) return null;
|
|
1672
|
+
if (target === "pr") {
|
|
1673
|
+
const number2 = base === void 0 ? null : parsePullNumber(base);
|
|
1674
|
+
if (number2 === null) {
|
|
1675
|
+
throw new Error("Usage: kaleido pr <number | GitHub PR URL>");
|
|
1676
|
+
}
|
|
1677
|
+
return number2;
|
|
1678
|
+
}
|
|
1679
|
+
if (!/^(#|pr\/|pull\/|https?:\/\/)/.test(target)) return null;
|
|
1680
|
+
const number = parsePullNumber(target);
|
|
1681
|
+
if (number === null) return null;
|
|
1682
|
+
if (base !== void 0) throw new Error("A base cannot be given when opening a pull request");
|
|
1683
|
+
return number;
|
|
1684
|
+
}
|
|
1685
|
+
async function resolveViewerTarget(params) {
|
|
1334
1686
|
const { cwd, target, base } = params;
|
|
1687
|
+
const pullNumber = parsePullTarget(target, base);
|
|
1688
|
+
if (pullNumber !== null) {
|
|
1689
|
+
const startDir = params.dir === void 0 ? cwd : resolve3(cwd, params.dir);
|
|
1690
|
+
const gitRoot2 = findGitRoot(startDir);
|
|
1691
|
+
if (gitRoot2 === null) throw new Error(`Not a git repository: ${startDir}`);
|
|
1692
|
+
const pulls = new GitPulls(gitRoot2);
|
|
1693
|
+
const range = params.shouldFetchPull ? (await pulls.fetch(pullNumber)).range : pullRange(await pulls.view(pullNumber));
|
|
1694
|
+
return { rootDir: gitRoot2, isGitRepo: true, range };
|
|
1695
|
+
}
|
|
1335
1696
|
if (params.dir !== void 0) {
|
|
1336
1697
|
const dir = resolve3(cwd, params.dir);
|
|
1337
1698
|
if (!isDirectory(dir)) throw new Error(`Not a directory: ${params.dir}`);
|
|
@@ -1412,20 +1773,44 @@ function resolveDefaultRange(rootDir) {
|
|
|
1412
1773
|
return { target: ".", base: "HEAD" };
|
|
1413
1774
|
}
|
|
1414
1775
|
|
|
1776
|
+
// src/cli/browser.ts
|
|
1777
|
+
import { execFile as execFile3 } from "child_process";
|
|
1778
|
+
import { promisify as promisify3 } from "util";
|
|
1779
|
+
import open from "open";
|
|
1780
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
1781
|
+
function isInsideOrca(env = process.env) {
|
|
1782
|
+
return env.TERM_PROGRAM === "Orca" || env.ORCA_PANE_KEY !== void 0;
|
|
1783
|
+
}
|
|
1784
|
+
async function openInBrowser(url) {
|
|
1785
|
+
if (isInsideOrca()) {
|
|
1786
|
+
try {
|
|
1787
|
+
const orca = process.env.ORCA_CLI_COMMAND || "orca";
|
|
1788
|
+
await execFileAsync3(orca, ["tab", "create", "--url", url], { timeout: 15e3 });
|
|
1789
|
+
return;
|
|
1790
|
+
} catch (error) {
|
|
1791
|
+
const detail = typeof error === "object" && error !== null && "stderr" in error && String(error.stderr).trim() ? String(error.stderr).trim() : error instanceof Error ? error.message : String(error);
|
|
1792
|
+
console.error(`kaleido: could not open in Orca's browser, falling back to the default browser
|
|
1793
|
+
${detail}`);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
await open(url);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1415
1799
|
// src/cli/index.ts
|
|
1416
1800
|
var program = new Command();
|
|
1417
1801
|
var collect = (value, previous) => [...previous, value];
|
|
1418
1802
|
program.name("kaleido").description("Monaco-based local web file viewer with TypeScript hover, diff and review tools").version("0.1.0");
|
|
1419
1803
|
program.command("serve", { isDefault: true }).description("start the viewer (default command)").argument(
|
|
1420
1804
|
"[target]",
|
|
1421
|
-
'directory to browse, commit-ish to view,
|
|
1805
|
+
'directory to browse, commit-ish to view, "working" / "staged" / ".", or "pr <number|url>" (default: auto-detect)'
|
|
1422
1806
|
).argument("[base]", "commit-ish to compare against (default: HEAD or <target>^)").option("--port <port>", "preferred port (auto-increments if taken)", "4890").option("--host <host>", "host to bind", "127.0.0.1").option("--dir <path>", "directory to open (default: current directory)").option("--repo <path>", "alias of --dir").option("--exclude <pattern>", "extra path pattern to hide from the file tree", collect, []).option("--no-open", "do not open the browser").option("--no-keep-alive", "shut down the server when all browser tabs are closed").action(async (target, base, options) => {
|
|
1423
1807
|
try {
|
|
1424
|
-
const { rootDir, isGitRepo, range } = resolveViewerTarget({
|
|
1808
|
+
const { rootDir, isGitRepo, range } = await resolveViewerTarget({
|
|
1425
1809
|
cwd: process.cwd(),
|
|
1426
1810
|
dir: options.dir ?? options.repo,
|
|
1427
1811
|
target,
|
|
1428
|
-
base
|
|
1812
|
+
base,
|
|
1813
|
+
shouldFetchPull: true
|
|
1429
1814
|
});
|
|
1430
1815
|
const printCommentsAndExit = () => {
|
|
1431
1816
|
try {
|
|
@@ -1455,16 +1840,16 @@ ${comments.length} comment(s) for ${describeRange(range)}:
|
|
|
1455
1840
|
console.log(`kaleido: ${describeRange(range)} @ ${rootDir}`);
|
|
1456
1841
|
console.log(` ${url}`);
|
|
1457
1842
|
if (options.open) {
|
|
1458
|
-
await
|
|
1843
|
+
await openInBrowser(url);
|
|
1459
1844
|
}
|
|
1460
1845
|
} catch (error) {
|
|
1461
1846
|
console.error(error instanceof Error ? error.message : error);
|
|
1462
1847
|
process.exit(1);
|
|
1463
1848
|
}
|
|
1464
1849
|
});
|
|
1465
|
-
program.command("comments").description("print saved comments for a range as an AI prompt").argument("[target]", 'commit-ish,
|
|
1850
|
+
program.command("comments").description("print saved comments for a range as an AI prompt").argument("[target]", 'commit-ish, "working" / "staged" / ".", or "pr <number|url>" (default: ".")').argument("[base]", "commit-ish to compare against (default: HEAD or <target>^)").option("--dir <path>", "directory to read comments for (default: current directory)").option("--repo <path>", "alias of --dir").option("--json", "output as JSON instead of prompt text").action(async (target, base, options) => {
|
|
1466
1851
|
try {
|
|
1467
|
-
const { rootDir, range } = resolveViewerTarget({
|
|
1852
|
+
const { rootDir, range } = await resolveViewerTarget({
|
|
1468
1853
|
cwd: process.cwd(),
|
|
1469
1854
|
dir: options.dir ?? options.repo,
|
|
1470
1855
|
target,
|
package/dist/client/assets/{abnfDiagram-N423BO3Z-BNC_bOwN.js → abnfDiagram-N423BO3Z-BLtqS4V1.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-x3opGel5.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-I0atgFmE.js";import"./chunk-I66GZJ75-DY6z-MCi.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-CcE1vTzX.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-FMl-QNqU.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-
|
|
1
|
+
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-dXsd7Pkc.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-KEIR6QF5-BICK3FdT.js";import{M as e}from"./mermaid-parser.core-x3opGel5.js";export{e as createArchitectureServices};
|