@ycodium-ai/plugin-pull-requests 0.2.2994 → 0.2.2998

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 (3) hide show
  1. package/assets/ui.js +14 -14
  2. package/dist/index.js +175 -165
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -493,7 +493,7 @@ var callGitHubGraphQl = async (ctx, input) => {
493
493
  return data;
494
494
  };
495
495
 
496
- // src/githubMapping.ts
496
+ // src/githubValues.ts
497
497
  var asObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
498
498
  var asArray = (value) => Array.isArray(value) ? value : [];
499
499
  var text2 = (value) => {
@@ -710,6 +710,8 @@ var toReactions = (value, viewer) => {
710
710
  }
711
711
  return reactions;
712
712
  };
713
+
714
+ // src/githubGraphqlDocuments.ts
713
715
  var PAGE_SIZE = 100;
714
716
  var SEARCH_MAX_ROWS = PAGE_SIZE;
715
717
  var reactionGroups = (canReadOrg2) => `reactionGroups {
@@ -958,6 +960,50 @@ ${selections.join("\n")}
958
960
  ${RATE_LIMIT_SELECTION}
959
961
  }`;
960
962
  };
963
+
964
+ // src/githubFilesPatch.ts
965
+ var decodeFiles = (value) => {
966
+ if (!Array.isArray(value)) return null;
967
+ const sections = [];
968
+ const omittedFileStats = [];
969
+ let truncated = false;
970
+ for (const entry of value) {
971
+ const raw = asObject2(entry);
972
+ const filename = text2(raw?.["filename"]);
973
+ if (filename === null) continue;
974
+ const hunks = typeof raw?.["patch"] === "string" ? raw["patch"] : "";
975
+ const status = text2(raw?.["status"])?.toLowerCase();
976
+ if (hunks.length === 0) {
977
+ const additions = int(raw?.["additions"]) ?? 0;
978
+ const deletions = int(raw?.["deletions"]) ?? 0;
979
+ if (additions + deletions > 0) {
980
+ truncated = true;
981
+ omittedFileStats.push({ path: filename, additions, deletions });
982
+ }
983
+ }
984
+ const oldPath = status === "renamed" ? text2(raw?.["previous_filename"]) ?? filename : filename;
985
+ const header = [
986
+ `diff --git a/${oldPath} b/${filename}`,
987
+ // files 端点不报文件模式,用寻常那个顶上:查看器读这两行是"新增"和"删除",不是读模式。
988
+ ...status === "added" ? ["new file mode 100644"] : [],
989
+ ...status === "removed" ? ["deleted file mode 100644"] : [],
990
+ ...status === "renamed" ? [`rename from ${oldPath}`, `rename to ${filename}`] : [],
991
+ `--- ${status === "added" ? "/dev/null" : `a/${oldPath}`}`,
992
+ `+++ ${status === "removed" ? "/dev/null" : `b/${filename}`}`
993
+ ].join("\n");
994
+ sections.push(hunks.length === 0 ? `${header}
995
+ ` : `${header}
996
+ ${hunks.replace(/\n?$/, "\n")}`);
997
+ }
998
+ return { patch: sections.join(""), truncated, rawCount: value.length, omittedFileStats };
999
+ };
1000
+ var decodeRevisions = (value, kind) => {
1001
+ const raw = asObject2(value);
1002
+ if (raw === null) return null;
1003
+ return kind === "pull-request" ? { baseRef: text2(at(raw, "base", "sha")), headRef: text2(at(raw, "head", "sha")) } : { baseRef: text2(at(asArray(raw["parents"])[0], "sha")), headRef: text2(raw["sha"]) };
1004
+ };
1005
+
1006
+ // src/githubMapping.ts
961
1007
  var decodeViewerLogin = (value) => text2(asObject2(value)?.["login"]);
962
1008
  var toReviewRequestLogins = (value) => nodes(value).flatMap((node) => text2(at(node, "requestedReviewer", "login")) ?? []);
963
1009
  var toRow = (raw) => {
@@ -1351,46 +1397,6 @@ var decodeReviewerCandidates = (value) => {
1351
1397
  truncated: at(assignable, "pageInfo", "hasNextPage") === true
1352
1398
  };
1353
1399
  };
1354
- var decodeFiles = (value) => {
1355
- if (!Array.isArray(value)) return null;
1356
- const sections = [];
1357
- const omittedFileStats = [];
1358
- let truncated = false;
1359
- for (const entry of value) {
1360
- const raw = asObject2(entry);
1361
- const filename = text2(raw?.["filename"]);
1362
- if (filename === null) continue;
1363
- const hunks = typeof raw?.["patch"] === "string" ? raw["patch"] : "";
1364
- const status = text2(raw?.["status"])?.toLowerCase();
1365
- if (hunks.length === 0) {
1366
- const additions = int(raw?.["additions"]) ?? 0;
1367
- const deletions = int(raw?.["deletions"]) ?? 0;
1368
- if (additions + deletions > 0) {
1369
- truncated = true;
1370
- omittedFileStats.push({ path: filename, additions, deletions });
1371
- }
1372
- }
1373
- const oldPath = status === "renamed" ? text2(raw?.["previous_filename"]) ?? filename : filename;
1374
- const header = [
1375
- `diff --git a/${oldPath} b/${filename}`,
1376
- // files 端点不报文件模式,用寻常那个顶上:查看器读这两行是"新增"和"删除",不是读模式。
1377
- ...status === "added" ? ["new file mode 100644"] : [],
1378
- ...status === "removed" ? ["deleted file mode 100644"] : [],
1379
- ...status === "renamed" ? [`rename from ${oldPath}`, `rename to ${filename}`] : [],
1380
- `--- ${status === "added" ? "/dev/null" : `a/${oldPath}`}`,
1381
- `+++ ${status === "removed" ? "/dev/null" : `b/${filename}`}`
1382
- ].join("\n");
1383
- sections.push(hunks.length === 0 ? `${header}
1384
- ` : `${header}
1385
- ${hunks.replace(/\n?$/, "\n")}`);
1386
- }
1387
- return { patch: sections.join(""), truncated, rawCount: value.length, omittedFileStats };
1388
- };
1389
- var decodeRevisions = (value, kind) => {
1390
- const raw = asObject2(value);
1391
- if (raw === null) return null;
1392
- return kind === "pull-request" ? { baseRef: text2(at(raw, "base", "sha")), headRef: text2(at(raw, "head", "sha")) } : { baseRef: text2(at(asArray(raw["parents"])[0], "sha")), headRef: text2(raw["sha"]) };
1393
- };
1394
1400
 
1395
1401
  // src/githubCommands.ts
1396
1402
  var CAPABILITIES = {
@@ -2613,7 +2619,7 @@ var decodeOwnAwardId = (raw, input) => {
2613
2619
  return { awardId: null };
2614
2620
  };
2615
2621
 
2616
- // src/gitlabCommands.ts
2622
+ // src/gitlabCommandQuery.ts
2617
2623
  var CAPABILITIES2 = {
2618
2624
  diff: true,
2619
2625
  comment: true,
@@ -2702,82 +2708,8 @@ var reviewPositionLines = (position) => {
2702
2708
  }
2703
2709
  };
2704
2710
  var mergeRequestPath = (input) => `projects/${projectPath(input.repository)}/merge_requests/${input.number}`;
2705
- var getViewer2 = async (ctx) => {
2706
- const result = await callGitLabApi(ctx, {
2707
- operation: "getViewer",
2708
- path: "user"
2709
- });
2710
- const decoded = decodeViewer(result.body.trim());
2711
- if (decoded === null) throw readError2("getViewer", "getViewerUsername");
2712
- if (decoded.username === null) {
2713
- throw new GitLabError({
2714
- code: "failed",
2715
- operation: "getViewer",
2716
- detail: "GitLab returned no username for the authenticated account."
2717
- });
2718
- }
2719
- return decoded.username;
2720
- };
2721
- var listChangeRequests2 = async (ctx, input) => {
2722
- const delivered = input.cursor?.delivered ?? 0;
2723
- const perPage = Math.min(input.limit + 1, MAX_PAGE_SIZE);
2724
- const firstPage = Math.floor(delivered / perPage) + 1;
2725
- const lastPage = Math.floor((delivered + input.limit) / perPage) + 1;
2726
- let page = firstPage;
2727
- let collected = [];
2728
- let cursorAdvance = 0;
2729
- for (; ; ) {
2730
- const skipOnFirstPage = page === firstPage ? delivered % perPage : 0;
2731
- const result = await callGitLabApi(ctx, {
2732
- operation: "listChangeRequests",
2733
- host: input.host,
2734
- path: `projects/${projectPath(input.repository)}/merge_requests?${query([
2735
- ["state", stateParam(input.state)],
2736
- ...involvementParams(input),
2737
- // 搜索用 REST 自己的 `search` 参数(匹配标题与描述),并像别的值一样 URL
2738
- // 编码,里面的文字变不成另一个参数。
2739
- ...searchParams(input.query),
2740
- ["order_by", "updated_at"],
2741
- ["sort", "desc"],
2742
- ["per_page", String(perPage)],
2743
- ["page", String(page)]
2744
- ])}`
2745
- });
2746
- const raw = result.body.trim();
2747
- if (raw.length === 0) {
2748
- return { items: collected, truncated: false, cursorAdvance, continues: true };
2749
- }
2750
- const decoded = decodeMergeRequestList(raw);
2751
- if (decoded === null) throw readError2("listChangeRequests", "listMergeRequests");
2752
- const pageItems = [];
2753
- const pageRawIndexes = [];
2754
- for (const [index, item] of decoded.items.entries()) {
2755
- const rawIndex = decoded.rawIndexes[index];
2756
- if (rawIndex < skipOnFirstPage) continue;
2757
- pageItems.push(item);
2758
- pageRawIndexes.push(rawIndex);
2759
- }
2760
- const remaining = input.limit - collected.length;
2761
- const lastItemRawIndex = pageRawIndexes[remaining - 1];
2762
- if (lastItemRawIndex !== void 0) {
2763
- return {
2764
- items: [...collected, ...pageItems.slice(0, remaining)],
2765
- truncated: lastItemRawIndex + 1 < decoded.rawCount || decoded.rawCount === perPage,
2766
- cursorAdvance: cursorAdvance + (lastItemRawIndex + 1 - skipOnFirstPage),
2767
- continues: true
2768
- };
2769
- }
2770
- collected = [...collected, ...pageItems];
2771
- cursorAdvance += Math.max(0, decoded.rawCount - skipOnFirstPage);
2772
- if (decoded.rawCount < perPage) {
2773
- return { items: collected, truncated: false, cursorAdvance, continues: true };
2774
- }
2775
- if (page >= lastPage) {
2776
- return { items: collected, truncated: true, cursorAdvance, continues: true };
2777
- }
2778
- page += 1;
2779
- }
2780
- };
2711
+
2712
+ // src/gitlabCommandReads.ts
2781
2713
  var mergeRequestDetail = async (ctx, input, operation) => {
2782
2714
  const result = await callGitLabApi(ctx, {
2783
2715
  operation,
@@ -2800,25 +2732,6 @@ var projectMergeCapabilities = async (ctx, input, operation) => {
2800
2732
  if (decoded === null) throw readError2(operation, "getProjectMergeCapabilities");
2801
2733
  return decoded;
2802
2734
  };
2803
- var getChangeRequest2 = async (ctx, input) => {
2804
- const [mergeRequest, mergeCapabilities] = await Promise.all([
2805
- mergeRequestDetail(ctx, input, "getChangeRequest"),
2806
- projectMergeCapabilities(ctx, input, "getChangeRequest")
2807
- ]);
2808
- return {
2809
- ...mergeRequest,
2810
- mergeCapabilities,
2811
- viewerPermissions: gitLabViewerPermissions(mergeRequest),
2812
- // 数不出分歧数的老 GitLab 什么都不说,而不是说「已是最新」:横幅丢了不要紧,一个
2813
- // 错误的「一切正常」不值得显示。
2814
- baseComparison: mergeRequest.divergedCommits === void 0 ? "unknown" : mergeRequest.divergedCommits > 0 ? "behind" : "up-to-date",
2815
- ...mergeRequest.divergedCommits === void 0 ? {} : { behindBy: mergeRequest.divergedCommits }
2816
- };
2817
- };
2818
- var getViewerPermissions2 = async (ctx, input) => (
2819
- // 与 detail 取自同一次读:`user.can_merge` 就长在合并请求上,没有更便宜的问法。
2820
- gitLabViewerPermissions(await mergeRequestDetail(ctx, input, "getViewerPermissions"))
2821
- );
2822
2735
  var listNotes = async (ctx, input) => {
2823
2736
  let collected = [];
2824
2737
  for (let page = 1; ; page += 1) {
@@ -2896,6 +2809,131 @@ var listReactions = async (ctx, input) => {
2896
2809
  }
2897
2810
  };
2898
2811
  var orElse = (promise, fallback) => promise.catch(() => fallback);
2812
+ var diffPage = async (ctx, input) => {
2813
+ const result = await callGitLabApi(ctx, {
2814
+ operation: "getDiff",
2815
+ host: input.host,
2816
+ path: `projects/${projectPath(input.repository)}/${input.commit === void 0 ? `merge_requests/${input.number}/diffs` : `repository/commits/${input.commit}/diff`}?${query([
2817
+ ["per_page", String(MAX_PAGE_SIZE)],
2818
+ ["page", String(input.page)]
2819
+ ])}`,
2820
+ maxBytes: DIFF_MAX_BYTES2,
2821
+ timeoutMs: DIFF_TIMEOUT_MS2
2822
+ });
2823
+ if (result.truncated) {
2824
+ throw new GitLabError({
2825
+ code: "failed",
2826
+ operation: "getDiff",
2827
+ detail: `Page ${input.page} of the merge request diff was too large to read.`
2828
+ });
2829
+ }
2830
+ const decoded = decodeMergeRequestDiffs(result.body.trim());
2831
+ if (decoded === null) throw readError2("getDiff", "getMergeRequestDiff");
2832
+ const morePages = decoded.rawCount >= MAX_PAGE_SIZE;
2833
+ return {
2834
+ // 切片以换行结尾,GitLab 只给了头没给 hunk 的文件才不会撞进下一段的第一行。
2835
+ patch: decoded.patch.length === 0 ? decoded.patch : decoded.patch.replace(/\n?$/, "\n"),
2836
+ truncated: decoded.truncated,
2837
+ nextCursor: morePages ? String(input.page + 1) : null
2838
+ };
2839
+ };
2840
+
2841
+ // src/gitlabCommands.ts
2842
+ var getViewer2 = async (ctx) => {
2843
+ const result = await callGitLabApi(ctx, {
2844
+ operation: "getViewer",
2845
+ path: "user"
2846
+ });
2847
+ const decoded = decodeViewer(result.body.trim());
2848
+ if (decoded === null) throw readError2("getViewer", "getViewerUsername");
2849
+ if (decoded.username === null) {
2850
+ throw new GitLabError({
2851
+ code: "failed",
2852
+ operation: "getViewer",
2853
+ detail: "GitLab returned no username for the authenticated account."
2854
+ });
2855
+ }
2856
+ return decoded.username;
2857
+ };
2858
+ var listChangeRequests2 = async (ctx, input) => {
2859
+ const delivered = input.cursor?.delivered ?? 0;
2860
+ const perPage = Math.min(input.limit + 1, MAX_PAGE_SIZE);
2861
+ const firstPage = Math.floor(delivered / perPage) + 1;
2862
+ const lastPage = Math.floor((delivered + input.limit) / perPage) + 1;
2863
+ let page = firstPage;
2864
+ let collected = [];
2865
+ let cursorAdvance = 0;
2866
+ for (; ; ) {
2867
+ const skipOnFirstPage = page === firstPage ? delivered % perPage : 0;
2868
+ const result = await callGitLabApi(ctx, {
2869
+ operation: "listChangeRequests",
2870
+ host: input.host,
2871
+ path: `projects/${projectPath(input.repository)}/merge_requests?${query([
2872
+ ["state", stateParam(input.state)],
2873
+ ...involvementParams(input),
2874
+ // 搜索用 REST 自己的 `search` 参数(匹配标题与描述),并像别的值一样 URL
2875
+ // 编码,里面的文字变不成另一个参数。
2876
+ ...searchParams(input.query),
2877
+ ["order_by", "updated_at"],
2878
+ ["sort", "desc"],
2879
+ ["per_page", String(perPage)],
2880
+ ["page", String(page)]
2881
+ ])}`
2882
+ });
2883
+ const raw = result.body.trim();
2884
+ if (raw.length === 0) {
2885
+ return { items: collected, truncated: false, cursorAdvance, continues: true };
2886
+ }
2887
+ const decoded = decodeMergeRequestList(raw);
2888
+ if (decoded === null) throw readError2("listChangeRequests", "listMergeRequests");
2889
+ const pageItems = [];
2890
+ const pageRawIndexes = [];
2891
+ for (const [index, item] of decoded.items.entries()) {
2892
+ const rawIndex = decoded.rawIndexes[index];
2893
+ if (rawIndex < skipOnFirstPage) continue;
2894
+ pageItems.push(item);
2895
+ pageRawIndexes.push(rawIndex);
2896
+ }
2897
+ const remaining = input.limit - collected.length;
2898
+ const lastItemRawIndex = pageRawIndexes[remaining - 1];
2899
+ if (lastItemRawIndex !== void 0) {
2900
+ return {
2901
+ items: [...collected, ...pageItems.slice(0, remaining)],
2902
+ truncated: lastItemRawIndex + 1 < decoded.rawCount || decoded.rawCount === perPage,
2903
+ cursorAdvance: cursorAdvance + (lastItemRawIndex + 1 - skipOnFirstPage),
2904
+ continues: true
2905
+ };
2906
+ }
2907
+ collected = [...collected, ...pageItems];
2908
+ cursorAdvance += Math.max(0, decoded.rawCount - skipOnFirstPage);
2909
+ if (decoded.rawCount < perPage) {
2910
+ return { items: collected, truncated: false, cursorAdvance, continues: true };
2911
+ }
2912
+ if (page >= lastPage) {
2913
+ return { items: collected, truncated: true, cursorAdvance, continues: true };
2914
+ }
2915
+ page += 1;
2916
+ }
2917
+ };
2918
+ var getChangeRequest2 = async (ctx, input) => {
2919
+ const [mergeRequest, mergeCapabilities] = await Promise.all([
2920
+ mergeRequestDetail(ctx, input, "getChangeRequest"),
2921
+ projectMergeCapabilities(ctx, input, "getChangeRequest")
2922
+ ]);
2923
+ return {
2924
+ ...mergeRequest,
2925
+ mergeCapabilities,
2926
+ viewerPermissions: gitLabViewerPermissions(mergeRequest),
2927
+ // 数不出分歧数的老 GitLab 什么都不说,而不是说「已是最新」:横幅丢了不要紧,一个
2928
+ // 错误的「一切正常」不值得显示。
2929
+ baseComparison: mergeRequest.divergedCommits === void 0 ? "unknown" : mergeRequest.divergedCommits > 0 ? "behind" : "up-to-date",
2930
+ ...mergeRequest.divergedCommits === void 0 ? {} : { behindBy: mergeRequest.divergedCommits }
2931
+ };
2932
+ };
2933
+ var getViewerPermissions2 = async (ctx, input) => (
2934
+ // 与 detail 取自同一次读:`user.can_merge` 就长在合并请求上,没有更便宜的问法。
2935
+ gitLabViewerPermissions(await mergeRequestDetail(ctx, input, "getViewerPermissions"))
2936
+ );
2899
2937
  var getChangeRequestActivity2 = async (ctx, input) => {
2900
2938
  const [notes, commits, discussions, awards] = await Promise.all([
2901
2939
  orElse(listNotes(ctx, input), {
@@ -2933,34 +2971,6 @@ var getChangeRequestActivity2 = async (ctx, input) => {
2933
2971
  commits
2934
2972
  };
2935
2973
  };
2936
- var diffPage = async (ctx, input) => {
2937
- const result = await callGitLabApi(ctx, {
2938
- operation: "getDiff",
2939
- host: input.host,
2940
- path: `projects/${projectPath(input.repository)}/${input.commit === void 0 ? `merge_requests/${input.number}/diffs` : `repository/commits/${input.commit}/diff`}?${query([
2941
- ["per_page", String(MAX_PAGE_SIZE)],
2942
- ["page", String(input.page)]
2943
- ])}`,
2944
- maxBytes: DIFF_MAX_BYTES2,
2945
- timeoutMs: DIFF_TIMEOUT_MS2
2946
- });
2947
- if (result.truncated) {
2948
- throw new GitLabError({
2949
- code: "failed",
2950
- operation: "getDiff",
2951
- detail: `Page ${input.page} of the merge request diff was too large to read.`
2952
- });
2953
- }
2954
- const decoded = decodeMergeRequestDiffs(result.body.trim());
2955
- if (decoded === null) throw readError2("getDiff", "getMergeRequestDiff");
2956
- const morePages = decoded.rawCount >= MAX_PAGE_SIZE;
2957
- return {
2958
- // 切片以换行结尾,GitLab 只给了头没给 hunk 的文件才不会撞进下一段的第一行。
2959
- patch: decoded.patch.length === 0 ? decoded.patch : decoded.patch.replace(/\n?$/, "\n"),
2960
- truncated: decoded.truncated,
2961
- nextCursor: morePages ? String(input.page + 1) : null
2962
- };
2963
- };
2964
2974
  var getDiff2 = (ctx, input) => {
2965
2975
  if (input.commit !== void 0 && !isCommitSha2(input.commit)) {
2966
2976
  return Promise.reject(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-pull-requests",
3
- "version": "0.2.2994",
3
+ "version": "0.2.2998",
4
4
  "description": "The pull request page, for GitHub and GitLab.",
5
5
  "keywords": [
6
6
  "pull-requests",
@@ -30,7 +30,7 @@
30
30
  "tailwindcss": "^4.0.0",
31
31
  "typescript": "~6.0.3",
32
32
  "vite-plus": "0.2.2",
33
- "@ycodium-ai/plugin-api": "0.2.2994",
33
+ "@ycodium-ai/plugin-api": "0.2.2998",
34
34
  "ycodium-markdown-fence": "0.0.0"
35
35
  },
36
36
  "ycodium": {