@nkzw/codiff-core 1.8.1

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/SharedPlanApp.d.ts +32 -0
  4. package/dist/SharedWalkthroughApp.d.ts +40 -0
  5. package/dist/app/components/Avatar.d.ts +6 -0
  6. package/dist/app/components/Button.d.ts +12 -0
  7. package/dist/app/components/CommandBar.d.ts +8 -0
  8. package/dist/app/components/FileTree.d.ts +10 -0
  9. package/dist/app/components/KeyboardShortcutsHelp.d.ts +5 -0
  10. package/dist/app/components/MarkdownDocumentEditor.d.ts +26 -0
  11. package/dist/app/components/Panels.d.ts +71 -0
  12. package/dist/app/components/PlanEditorView.d.ts +18 -0
  13. package/dist/app/components/ReadOnlyMarkdownView.d.ts +16 -0
  14. package/dist/app/components/ReviewCodeView.d.ts +103 -0
  15. package/dist/app/components/Sidebar.d.ts +48 -0
  16. package/dist/app/components/WalkthroughFileError.d.ts +4 -0
  17. package/dist/app/components/merge-request/GeneralComments.d.ts +49 -0
  18. package/dist/app/components/useCopiedState.d.ts +1 -0
  19. package/dist/app/components/walkthrough/CommitView.d.ts +23 -0
  20. package/dist/app/components/walkthrough/NarrativeSidebar.d.ts +12 -0
  21. package/dist/app/components/walkthrough/NarrativeWalkthroughView.d.ts +44 -0
  22. package/dist/app/components/walkthrough/WalkthroughDiffSurface.d.ts +16 -0
  23. package/dist/app/components/walkthrough/WalkthroughProgress.d.ts +8 -0
  24. package/dist/app/components/walkthrough/parts.d.ts +15 -0
  25. package/dist/app/components/walkthrough/useNarrativeNavigation.d.ts +34 -0
  26. package/dist/app/hooks/useAppCommands.d.ts +22 -0
  27. package/dist/app/hooks/useAppKeyboardShortcuts.d.ts +18 -0
  28. package/dist/app/hooks/useAppReviewComments.d.ts +38 -0
  29. package/dist/app/hooks/useAppWalkthrough.d.ts +96 -0
  30. package/dist/app/hooks/useDiffSearch.d.ts +24 -0
  31. package/dist/app/hooks/useDocumentAppearance.d.ts +10 -0
  32. package/dist/app/hooks/useResizableSidebar.d.ts +12 -0
  33. package/dist/app/hooks/useReviewCommentDrafts.d.ts +23 -0
  34. package/dist/app/hooks/useReviewState.d.ts +22 -0
  35. package/dist/config/defaults.d.ts +4 -0
  36. package/dist/config/keymap.d.ts +3 -0
  37. package/dist/config/types.d.ts +44 -0
  38. package/dist/defaults.d.ts +2 -0
  39. package/dist/fonts/firacode/FiraCode-Regular.woff2 +0 -0
  40. package/dist/fonts/firacode/FiraCode-SemiBold.woff2 +0 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.mjs +12 -0
  43. package/dist/lib/app-constants.d.ts +7 -0
  44. package/dist/lib/app-types.d.ts +137 -0
  45. package/dist/lib/code-view-options.d.ts +26 -0
  46. package/dist/lib/command-registry.d.ts +14 -0
  47. package/dist/lib/diff-search.d.ts +3 -0
  48. package/dist/lib/diff.d.ts +35 -0
  49. package/dist/lib/files.d.ts +14 -0
  50. package/dist/lib/item-version.d.ts +1 -0
  51. package/dist/lib/keyboard.d.ts +2 -0
  52. package/dist/lib/markdown.d.ts +3 -0
  53. package/dist/lib/narrative-walkthrough-diff.d.ts +113 -0
  54. package/dist/lib/narrative-walkthrough-diff.mjs +257 -0
  55. package/dist/lib/narrative-walkthrough.d.ts +108 -0
  56. package/dist/lib/reload-selection.d.ts +23 -0
  57. package/dist/lib/review-command-target.d.ts +15 -0
  58. package/dist/lib/review-comments.d.ts +29 -0
  59. package/dist/lib/review-identity.d.ts +7 -0
  60. package/dist/lib/review-scroll.d.ts +5 -0
  61. package/dist/lib/search-highlights.d.ts +5 -0
  62. package/dist/lib/sidebar-width.d.ts +9 -0
  63. package/dist/lib/source.d.ts +18 -0
  64. package/dist/lib/viewed.d.ts +2 -0
  65. package/dist/react.d.ts +3 -0
  66. package/dist/react.mjs +9355 -0
  67. package/dist/share.d.ts +301 -0
  68. package/dist/share.mjs +103 -0
  69. package/dist/style.css +9142 -0
  70. package/dist/styles.css.d.ts +2 -0
  71. package/dist/types.d.ts +702 -0
  72. package/package.json +71 -0
@@ -0,0 +1 @@
1
+ export declare const getItemVersion: (value: string) => number;
@@ -0,0 +1,2 @@
1
+ export declare const isNativeInputTarget: (target: EventTarget | null) => boolean;
2
+ export declare const isDiffSearchShortcut: (event: Pick<KeyboardEvent, 'altKey' | 'ctrlKey' | 'key' | 'metaKey' | 'shiftKey'>, platform?: string) => boolean;
@@ -0,0 +1,3 @@
1
+ import type { ReactNode } from 'react';
2
+ export declare const sanitizeMarkdownImages: (text: string) => string;
3
+ export declare const renderInlineMarkdown: (text: string) => ReactNode;
@@ -0,0 +1,113 @@
1
+ declare const HUNK_HEADER: RegExp;
2
+ /** @param {string} path */
3
+ declare const isGeneratedWalkthroughPath: (path: string) => boolean;
4
+ /** @param {{generated?: boolean; path: string}} file */
5
+ declare const isGeneratedWalkthroughFile: (file: {
6
+ generated?: boolean;
7
+ path: string;
8
+ }) => boolean;
9
+ /** @param {string} line */
10
+ declare const parseHunkHeader: (line: string) => {
11
+ additionCount: number;
12
+ additionEnd: number;
13
+ additionStart: number;
14
+ deletionCount: number;
15
+ deletionEnd: number;
16
+ deletionStart: number;
17
+ } | null;
18
+ /** @param {string} patch */
19
+ declare const extractPatchHunks: (patch: string) => {
20
+ additionCount: number;
21
+ additionEnd: number;
22
+ additionStart: number;
23
+ deletionCount: number;
24
+ deletionEnd: number;
25
+ deletionStart: number;
26
+ added: number;
27
+ deleted: number;
28
+ header: string;
29
+ }[];
30
+ /** @param {ReadonlyArray<{added: number; deleted: number}>} hunks */
31
+ declare const sumHunkLineCounts: (hunks: ReadonlyArray<{
32
+ added: number;
33
+ deleted: number;
34
+ }>) => {
35
+ added: number;
36
+ deleted: number;
37
+ };
38
+ /** @param {{kind?: string} | null | undefined} hunk */
39
+ declare const isSyntheticWalkthroughHunk: (hunk: {
40
+ kind?: string;
41
+ } | null | undefined) => boolean;
42
+ /** @param {ReturnType<typeof extractPatchHunks>[number] & {kind?: string}} hunk */
43
+ declare const hunkDisplayStart: (hunk: ReturnType<typeof extractPatchHunks>[number] & {
44
+ kind?: string;
45
+ }) => number | undefined;
46
+ /** @param {ReturnType<typeof extractPatchHunks>[number] & {kind?: string}} hunk */
47
+ declare const hunkDisplayEnd: (hunk: ReturnType<typeof extractPatchHunks>[number] & {
48
+ kind?: string;
49
+ }) => number | undefined;
50
+ /** @param {string} path @param {ReadonlyArray<ReturnType<typeof extractPatchHunks>[number] & {kind?: string}>} hunks */
51
+ declare const buildAnchorDisplay: (path: string, hunks: ReadonlyArray<ReturnType<typeof extractPatchHunks>[number] & {
52
+ kind?: string;
53
+ }>) => string;
54
+ /**
55
+ * Codiff's walkthrough hunk ids identify the smallest reviewable diff unit.
56
+ * Most are textual patch hunks; non-text or metadata-only sections get one
57
+ * synthetic hunk so walkthroughs remain hunk-based for every visible change.
58
+ *
59
+ * @param {{generated?: boolean; oldPath?: string; path: string; status: string}} file
60
+ * @param {{binary?: boolean; id: string; kind: string; loadState?: string; patch?: string; summary?: {reason?: string}}} section
61
+ */
62
+ declare const getSectionWalkthroughHunks: (file: {
63
+ generated?: boolean;
64
+ oldPath?: string;
65
+ path: string;
66
+ status: string;
67
+ }, section: {
68
+ binary?: boolean;
69
+ id: string;
70
+ kind: string;
71
+ loadState?: string;
72
+ patch?: string;
73
+ summary?: {
74
+ reason?: string;
75
+ };
76
+ }) => {
77
+ added: number;
78
+ deleted: number;
79
+ id: string;
80
+ index: number;
81
+ kind: string;
82
+ oldPath: string | undefined;
83
+ path: string;
84
+ sectionId: string;
85
+ sectionKind: string;
86
+ status: string;
87
+ summary: string | undefined;
88
+ }[] | {
89
+ additionCount: number;
90
+ additionEnd: number;
91
+ additionStart: number;
92
+ deletionCount: number;
93
+ deletionEnd: number;
94
+ deletionStart: number;
95
+ added: number;
96
+ deleted: number;
97
+ header: string;
98
+ id: string;
99
+ index: number;
100
+ kind: string;
101
+ oldPath: string | undefined;
102
+ path: string;
103
+ sectionId: string;
104
+ sectionKind: string;
105
+ status: string;
106
+ }[];
107
+ /**
108
+ * @param {string} patch
109
+ * @param {string} sectionId
110
+ * @param {ReadonlyArray<string>} hunkIds
111
+ */
112
+ declare const filterPatchToHunkIds: (patch: string, sectionId: string, hunkIds: ReadonlyArray<string>) => string | null;
113
+ export { buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getSectionWalkthroughHunks, HUNK_HEADER, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts, };
@@ -0,0 +1,257 @@
1
+ //#region lib/narrative-walkthrough-diff.js
2
+ const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
3
+ const GENERATED_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
4
+ "__generated__",
5
+ "__snapshots__",
6
+ ".generated",
7
+ "codegen",
8
+ "gen",
9
+ "generated",
10
+ "generated-sources",
11
+ "generated-src"
12
+ ]);
13
+ const GENERATED_BASENAMES = /* @__PURE__ */ new Set([
14
+ "bun.lock",
15
+ "bun.lockb",
16
+ "cargo.lock",
17
+ "gemfile.lock",
18
+ "npm-shrinkwrap.json",
19
+ "package-lock.json",
20
+ "pnpm-lock.yaml",
21
+ "poetry.lock",
22
+ "pubspec.lock",
23
+ "uv.lock",
24
+ "yarn.lock"
25
+ ]);
26
+ const GENERATED_EXTENSIONS = [
27
+ ".d.ts.map",
28
+ ".g.dart",
29
+ ".generated.cjs",
30
+ ".generated.css",
31
+ ".generated.js",
32
+ ".generated.jsx",
33
+ ".generated.mjs",
34
+ ".generated.ts",
35
+ ".generated.tsx",
36
+ ".pb.go",
37
+ ".pb.gw.go",
38
+ ".snap",
39
+ ".snapshot"
40
+ ];
41
+ const GENERATED_SUFFIXES = [
42
+ "-generated.js",
43
+ "-generated.ts",
44
+ "-generated.tsx",
45
+ ".min.cjs",
46
+ ".min.css",
47
+ ".min.js",
48
+ ".min.mjs",
49
+ ".pb.cc",
50
+ ".pb.h",
51
+ ".pb.rb",
52
+ "_generated.go",
53
+ "_generated.rs",
54
+ "_pb2.py",
55
+ "_pb2_grpc.py"
56
+ ];
57
+ /** @param {string} path */
58
+ const getPathParts = (path) => path.replaceAll("\\", "/").split("/").filter(Boolean);
59
+ /** @param {string} path */
60
+ const isGeneratedWalkthroughPath = (path) => {
61
+ const parts = getPathParts(path).map((part) => part.toLowerCase());
62
+ const basename = parts.at(-1) || "";
63
+ if (!basename) return false;
64
+ return parts.some((part) => GENERATED_DIRECTORY_NAMES.has(part)) || GENERATED_BASENAMES.has(basename) || GENERATED_EXTENSIONS.some((extension) => basename.endsWith(extension)) || GENERATED_SUFFIXES.some((suffix) => basename.endsWith(suffix)) || basename.endsWith(".map") && !basename.endsWith(".importmap");
65
+ };
66
+ /** @param {{generated?: boolean; path: string}} file */
67
+ const isGeneratedWalkthroughFile = (file) => file.generated ?? isGeneratedWalkthroughPath(file.path);
68
+ /** @param {string} path */
69
+ const getGeneratedWalkthroughSummary = (path) => {
70
+ const parts = getPathParts(path).map((part) => part.toLowerCase());
71
+ const basename = parts.at(-1) || "";
72
+ if (GENERATED_BASENAMES.has(basename)) return "Lockfile collapsed into one generated-file review unit.";
73
+ if (parts.includes("__snapshots__") || basename.endsWith(".snap") || basename.endsWith(".snapshot")) return "Snapshot collapsed into one generated-file review unit.";
74
+ return "Generated file collapsed into one review unit.";
75
+ };
76
+ /** @param {string} line */
77
+ const parseHunkHeader = (line) => {
78
+ const match = HUNK_HEADER.exec(line);
79
+ if (!match) return null;
80
+ const deletionStart = Number(match[1]);
81
+ const deletionCount = Number(match[2] ?? 1);
82
+ const additionStart = Number(match[3]);
83
+ const additionCount = Number(match[4] ?? 1);
84
+ return {
85
+ additionCount,
86
+ additionEnd: additionStart + Math.max(0, additionCount - 1),
87
+ additionStart,
88
+ deletionCount,
89
+ deletionEnd: deletionStart + Math.max(0, deletionCount - 1),
90
+ deletionStart
91
+ };
92
+ };
93
+ /** @param {string} patch */
94
+ const extractPatchHunks = (patch) => {
95
+ const lines = typeof patch === "string" ? patch.split("\n") : [];
96
+ const hunks = [];
97
+ let index = 0;
98
+ while (index < lines.length) {
99
+ const header = lines[index] ?? "";
100
+ const parsed = parseHunkHeader(header);
101
+ if (!parsed) {
102
+ index += 1;
103
+ continue;
104
+ }
105
+ let additions = 0;
106
+ let deletions = 0;
107
+ index += 1;
108
+ while (index < lines.length && !parseHunkHeader(lines[index] ?? "")) {
109
+ const line = lines[index] ?? "";
110
+ if (line.startsWith("+")) additions += 1;
111
+ else if (line.startsWith("-")) deletions += 1;
112
+ index += 1;
113
+ }
114
+ hunks.push({
115
+ ...parsed,
116
+ added: additions,
117
+ deleted: deletions,
118
+ header
119
+ });
120
+ }
121
+ return hunks;
122
+ };
123
+ /** @param {ReadonlyArray<{added: number; deleted: number}>} hunks */
124
+ const sumHunkLineCounts = (hunks) => hunks.reduce((totals, hunk) => ({
125
+ added: totals.added + hunk.added,
126
+ deleted: totals.deleted + hunk.deleted
127
+ }), {
128
+ added: 0,
129
+ deleted: 0
130
+ });
131
+ /** @param {{kind?: string} | null | undefined} hunk */
132
+ const isSyntheticWalkthroughHunk = (hunk) => hunk?.kind === "synthetic";
133
+ /** @param {ReturnType<typeof extractPatchHunks>[number] & {kind?: string}} hunk */
134
+ const hunkDisplayStart = (hunk) => {
135
+ if (isSyntheticWalkthroughHunk(hunk)) return;
136
+ return hunk.added > 0 ? hunk.additionStart : hunk.deletionStart;
137
+ };
138
+ /** @param {ReturnType<typeof extractPatchHunks>[number] & {kind?: string}} hunk */
139
+ const hunkDisplayEnd = (hunk) => {
140
+ if (isSyntheticWalkthroughHunk(hunk)) return;
141
+ return hunk.added > 0 ? hunk.additionEnd : hunk.deletionEnd;
142
+ };
143
+ /** @param {string} path @param {ReadonlyArray<ReturnType<typeof extractPatchHunks>[number] & {kind?: string}>} hunks */
144
+ const buildAnchorDisplay = (path, hunks) => {
145
+ if (hunks.length === 0) return path;
146
+ const first = hunks[0];
147
+ const last = hunks.at(-1);
148
+ if (!first || !last) return path;
149
+ if (isSyntheticWalkthroughHunk(first)) return path;
150
+ const startLine = hunkDisplayStart(first);
151
+ const endLine = hunkDisplayEnd(last);
152
+ return startLine && endLine && endLine !== startLine ? `${path}:${startLine}-${endLine}` : `${path}:${startLine || 1}`;
153
+ };
154
+ /** @param {{oldPath?: string; path: string; status?: string}} file */
155
+ const fileHasRenameMetadata = (file) => file.status === "renamed" && file.oldPath != null && file.oldPath !== file.path;
156
+ /**
157
+ * @param {{oldPath?: string; path: string; status?: string}} file
158
+ * @param {{binary?: boolean; loadState?: string; patch?: string; summary?: {reason?: string}}} section
159
+ */
160
+ const shouldCreateSyntheticHunk = (file, section) => {
161
+ if (section.binary) return true;
162
+ if (section.loadState != null && section.loadState !== "ready") return true;
163
+ if (fileHasRenameMetadata(file)) return true;
164
+ return typeof section.patch === "string" && section.patch.trim().length > 0;
165
+ };
166
+ /**
167
+ * @param {{generated?: boolean; oldPath?: string; path: string; status: string}} file
168
+ * @param {{binary?: boolean; id: string; kind: string; loadState?: string; patch?: string; summary?: {reason?: string}}} section
169
+ */
170
+ const createSyntheticSectionHunk = (file, section, lineCount = {
171
+ added: 0,
172
+ deleted: 0
173
+ }) => ({
174
+ added: lineCount.added,
175
+ deleted: lineCount.deleted,
176
+ id: `${section.id}:h1`,
177
+ index: 1,
178
+ kind: "synthetic",
179
+ oldPath: file.oldPath,
180
+ path: file.path,
181
+ sectionId: section.id,
182
+ sectionKind: section.kind,
183
+ status: file.status,
184
+ summary: section.summary?.reason ?? (isGeneratedWalkthroughFile(file) ? getGeneratedWalkthroughSummary(file.path) : void 0)
185
+ });
186
+ /**
187
+ * Codiff's walkthrough hunk ids identify the smallest reviewable diff unit.
188
+ * Most are textual patch hunks; non-text or metadata-only sections get one
189
+ * synthetic hunk so walkthroughs remain hunk-based for every visible change.
190
+ *
191
+ * @param {{generated?: boolean; oldPath?: string; path: string; status: string}} file
192
+ * @param {{binary?: boolean; id: string; kind: string; loadState?: string; patch?: string; summary?: {reason?: string}}} section
193
+ */
194
+ const getSectionWalkthroughHunks = (file, section) => {
195
+ const patchHunks = extractPatchHunks(section.patch || "");
196
+ if (patchHunks.length > 0 && isGeneratedWalkthroughFile(file)) return [createSyntheticSectionHunk(file, section, sumHunkLineCounts(patchHunks))];
197
+ if (patchHunks.length > 0) return patchHunks.map((hunk, index) => ({
198
+ ...hunk,
199
+ id: `${section.id}:h${index + 1}`,
200
+ index: index + 1,
201
+ kind: "patch",
202
+ oldPath: file.oldPath,
203
+ path: file.path,
204
+ sectionId: section.id,
205
+ sectionKind: section.kind,
206
+ status: file.status
207
+ }));
208
+ return shouldCreateSyntheticHunk(file, section) ? [createSyntheticSectionHunk(file, section)] : [];
209
+ };
210
+ /** @param {string} sectionId @param {string} hunkId */
211
+ const getHunkOrdinal = (sectionId, hunkId) => {
212
+ const prefix = `${sectionId}:h`;
213
+ if (!hunkId.startsWith(prefix)) return null;
214
+ const ordinal = Number(hunkId.slice(prefix.length));
215
+ return Number.isInteger(ordinal) && ordinal > 0 ? ordinal : null;
216
+ };
217
+ /**
218
+ * @param {string} patch
219
+ * @param {string} sectionId
220
+ * @param {ReadonlyArray<string>} hunkIds
221
+ */
222
+ const filterPatchToHunkIds = (patch, sectionId, hunkIds) => {
223
+ if (typeof patch !== "string" || patch.trim().length === 0 || hunkIds.length === 0) return null;
224
+ const patchLines = patch.split("\n");
225
+ const headerLines = [];
226
+ const hunkLinesByOrdinal = /* @__PURE__ */ new Map();
227
+ let index = 0;
228
+ let foundHunk = false;
229
+ let ordinal = 0;
230
+ while (index < patchLines.length) {
231
+ if (parseHunkHeader(patchLines[index] ?? "")) {
232
+ foundHunk = true;
233
+ ordinal += 1;
234
+ const hunkStart = index;
235
+ index += 1;
236
+ while (index < patchLines.length && !parseHunkHeader(patchLines[index] ?? "")) index += 1;
237
+ hunkLinesByOrdinal.set(ordinal, patchLines.slice(hunkStart, index));
238
+ continue;
239
+ }
240
+ if (!foundHunk) headerLines.push(patchLines[index] ?? "");
241
+ index += 1;
242
+ }
243
+ if (!foundHunk) return null;
244
+ const selectedHunkLines = [];
245
+ for (const hunkId of hunkIds) {
246
+ const ordinal = getHunkOrdinal(sectionId, hunkId);
247
+ if (ordinal == null) return null;
248
+ const lines = hunkLinesByOrdinal.get(ordinal);
249
+ if (!lines) return null;
250
+ selectedHunkLines.push(...lines);
251
+ }
252
+ if (selectedHunkLines.length === 0) return null;
253
+ const focused = [...headerLines, ...selectedHunkLines].join("\n");
254
+ return patch.endsWith("\n") && !focused.endsWith("\n") ? `${focused}\n` : focused;
255
+ };
256
+ //#endregion
257
+ export { HUNK_HEADER, buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getSectionWalkthroughHunks, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts };
@@ -0,0 +1,108 @@
1
+ import type { ChangedFile, DiffSection, NarrativeWalkthrough, WalkthroughChangeType, WalkthroughChapter, WalkthroughHunk, WalkthroughHunkGroup, WalkthroughIcon, WalkthroughSupportGroup, WalkthroughStop } from '../types.ts';
2
+ /** A stop with a global position in the walkthrough. */
3
+ export type WalkthroughStopView = WalkthroughStop & {
4
+ chapterId: string;
5
+ index: number;
6
+ };
7
+ /** A chapter with indexed stops. */
8
+ type WalkthroughChapterView = Omit<WalkthroughChapter, 'stops'> & {
9
+ stops: ReadonlyArray<WalkthroughStopView>;
10
+ };
11
+ /** Support grouped by reason, preserving first-seen order. */
12
+ type WalkthroughSupportReason = {
13
+ files: ReadonlyArray<WalkthroughSupportGroup>;
14
+ reason: string;
15
+ };
16
+ /** Everything a narrative walkthrough needs to render. */
17
+ export type WalkthroughView = {
18
+ chapters: ReadonlyArray<WalkthroughChapterView>;
19
+ sequence: ReadonlyArray<WalkthroughStopView>;
20
+ support: ReadonlyArray<WalkthroughSupportGroup>;
21
+ supportByReason: ReadonlyArray<WalkthroughSupportReason>;
22
+ };
23
+ export type WalkthroughFileList = {
24
+ label: string;
25
+ title: string;
26
+ };
27
+ export type WalkthroughFileLineRow = {
28
+ added: number;
29
+ deleted: number;
30
+ label: string;
31
+ path?: string;
32
+ title: string;
33
+ };
34
+ export declare const walkthroughFileName: (path: string) => string;
35
+ export declare const walkthroughItemPaths: (item: WalkthroughHunkGroup) => ReadonlyArray<string>;
36
+ export declare const walkthroughItemTitleFallback: (item: WalkthroughHunkGroup & {
37
+ prose?: string;
38
+ }) => string;
39
+ export declare const formatWalkthroughFileList: (paths: ReadonlyArray<string>, maxVisibleFiles?: number) => WalkthroughFileList;
40
+ export declare const formatWalkthroughFileLineRows: (items: ReadonlyArray<{
41
+ added: number;
42
+ deleted: number;
43
+ path: string;
44
+ }>, maxVisibleFiles?: number) => ReadonlyArray<WalkthroughFileLineRow>;
45
+ export declare const getUncoveredWalkthroughFiles: (files: ReadonlyArray<ChangedFile>, view: WalkthroughView, showWhitespace: boolean) => ReadonlyArray<ChangedFile>;
46
+ export declare const getUncoveredWalkthroughFileLineItems: (files: ReadonlyArray<ChangedFile>, view: WalkthroughView, showWhitespace: boolean) => ReadonlyArray<{
47
+ added: number;
48
+ deleted: number;
49
+ path: string;
50
+ }>;
51
+ export declare const isWalkthroughCommittable: (walkthrough: NarrativeWalkthrough) => boolean;
52
+ /** Build the walkthrough view-model with globally indexed stops. */
53
+ export declare const buildWalkthroughView: (walkthrough: NarrativeWalkthrough) => WalkthroughView | null;
54
+ /** The changed file + diff section a resolved hunk anchors into, if present in the diff. */
55
+ export type ResolvedWalkthroughHunkFile = {
56
+ file: ChangedFile;
57
+ section: DiffSection;
58
+ };
59
+ export type WalkthroughHunkRun = {
60
+ hunks: ReadonlyArray<WalkthroughHunk>;
61
+ key: string;
62
+ resolved: ResolvedWalkthroughHunkFile;
63
+ };
64
+ /** Resolve one normalized hunk to its exact live `ChangedFile` and `DiffSection`. */
65
+ export declare const resolveWalkthroughHunkFile: (hunk: WalkthroughHunk, files: ReadonlyArray<ChangedFile>) => ResolvedWalkthroughHunkFile | null;
66
+ /** Resolve item hunks in authored order, coalescing adjacent hunks from the same file section. */
67
+ export declare const resolveWalkthroughHunkRuns: (item: WalkthroughHunkGroup, files: ReadonlyArray<ChangedFile>) => ReadonlyArray<WalkthroughHunkRun>;
68
+ export declare const getWalkthroughRunNote: (item: WalkthroughHunkGroup, run: WalkthroughHunkRun) => string | undefined;
69
+ /**
70
+ * Return the changed-file view a walkthrough stop should render for one live diff
71
+ * section. The patch contains exactly the provided hunk ids, in that order.
72
+ */
73
+ export declare const focusChangedFileForHunks: (file: ChangedFile, section: DiffSection, hunks: ReadonlyArray<WalkthroughHunk>) => ChangedFile | null;
74
+ /** One unique changed file in the commit composer, with summed line counts. */
75
+ export type CommitFile = {
76
+ added: number;
77
+ changeType?: WalkthroughChangeType;
78
+ deleted: number;
79
+ itemId: string;
80
+ name: string;
81
+ /** The note the generated body uses for this file. */
82
+ note?: string;
83
+ path: string;
84
+ };
85
+ /** A group of files in the composer — one per chapter, plus a final support group. */
86
+ export type CommitGroup = {
87
+ files: ReadonlyArray<CommitFile>;
88
+ icon: WalkthroughIcon;
89
+ id: string;
90
+ isSupport: boolean;
91
+ title: string;
92
+ };
93
+ export type CommitModel = {
94
+ /** Every unique file, in group order. */
95
+ files: ReadonlyArray<CommitFile>;
96
+ groups: ReadonlyArray<CommitGroup>;
97
+ };
98
+ export declare const changeTypeLabel: Record<WalkthroughChangeType, string>;
99
+ export declare const buildGenericCommitModel: (changedFiles: ReadonlyArray<ChangedFile>) => CommitModel;
100
+ /**
101
+ * Collapse the walkthrough view into unique changed files. Line counts are
102
+ * summed across every item that shares a path, and a path is placed in the first
103
+ * group that mentions it.
104
+ */
105
+ export declare const buildCommitModel: (view: WalkthroughView, changedFiles?: ReadonlyArray<ChangedFile>) => CommitModel;
106
+ export declare const getCommitSelectionPaths: (view: WalkthroughView | null, changedFiles: ReadonlyArray<ChangedFile>) => ReadonlyArray<string>;
107
+ export declare const importanceLabel: Record<WalkthroughStop['importance'], string>;
108
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { GitFileStatus, RepositoryState, ReviewSource } from '../types.ts';
2
+ type ReloadSelectionFile = {
3
+ fingerprint: string;
4
+ path: string;
5
+ status: GitFileStatus;
6
+ };
7
+ export type ReloadMainMode = 'commit' | 'review';
8
+ type ReloadSelection = {
9
+ files: ReadonlyArray<ReloadSelectionFile>;
10
+ historySource?: ReviewSource | null;
11
+ mainMode?: ReloadMainMode;
12
+ root: string;
13
+ selectedPath: string | null;
14
+ source: ReviewSource;
15
+ };
16
+ export declare const consumeReloadSelection: () => ReloadSelection | null;
17
+ export declare const getReloadSelectionPath: (selection: ReloadSelection | null, state: RepositoryState) => string | null;
18
+ export declare const getChangedPaths: (previousFiles: ReadonlyArray<ReloadSelectionFile>, nextFiles: ReadonlyArray<ReloadSelectionFile>) => ReadonlySet<string>;
19
+ export declare const getReloadDeltaPaths: (selection: ReloadSelection | null, state: RepositoryState) => ReadonlySet<string>;
20
+ export declare const getReloadHistorySource: (selection: ReloadSelection | null, state: RepositoryState) => ReviewSource | null;
21
+ export declare const getReloadMainMode: (selection: ReloadSelection | null, state: RepositoryState) => ReloadMainMode | null;
22
+ export declare const writeReloadSelection: (state: RepositoryState | null, selectedPath: string | null, historySource?: ReviewSource | null, mainMode?: ReloadMainMode) => void;
23
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { ChangedFile, ReviewSource } from '../types.ts';
2
+ import type { ReviewIdentity } from './app-types.ts';
3
+ export type ReviewCommandTarget = {
4
+ file: ChangedFile;
5
+ reviewIdentity: ReviewIdentity;
6
+ sourceKey: string;
7
+ };
8
+ export declare const createReviewCommandTarget: (source: ReviewSource, file: ChangedFile, reviewIdentity?: ReviewIdentity) => ReviewCommandTarget;
9
+ export declare const resolveReviewCommandTarget: ({ activeTarget, files, selectedPath, source, useActiveTarget, }: {
10
+ activeTarget: ReviewCommandTarget | null;
11
+ files: ReadonlyArray<ChangedFile>;
12
+ selectedPath: string | null;
13
+ source: ReviewSource;
14
+ useActiveTarget: boolean;
15
+ }) => ReviewCommandTarget | null;
@@ -0,0 +1,29 @@
1
+ import type { ChangedFile, PullRequestReviewComment, RepositoryState } from '../types.ts';
2
+ import type { CodeViewInstance, ReviewComment } from './app-types.ts';
3
+ export declare const isInteractiveReviewEvent: (event: PointerEvent) => boolean;
4
+ export declare const hasActiveTextSelection: () => boolean;
5
+ export declare const isFileReviewComment: (comment: Pick<ReviewComment, 'anchor' | 'lineNumber' | 'side'>) => boolean;
6
+ export declare const isLineReviewComment: (comment: ReviewComment) => comment is ReviewComment & {
7
+ lineNumber: number;
8
+ side: 'additions' | 'deletions';
9
+ };
10
+ export declare function updateStickyHeaderState(viewer: CodeViewInstance): void;
11
+ export declare const getReviewCommentLineLabel: (comment: Pick<ReviewComment, 'anchor' | 'lineNumber' | 'side' | 'startLineNumber' | 'startSide'>) => string;
12
+ export declare const getReviewCommentRangeProps: (comment: Pick<ReviewComment, 'anchor' | 'lineNumber' | 'side' | 'startLineNumber' | 'startSide'>) => {
13
+ anchor: 'file';
14
+ } | {
15
+ anchor?: undefined;
16
+ } | {
17
+ anchor?: undefined;
18
+ startLineNumber: number;
19
+ startSide?: "additions" | "deletions" | undefined;
20
+ };
21
+ export declare const toPullRequestReviewComment: (comment: ReviewComment) => PullRequestReviewComment;
22
+ export declare const getPendingPullRequestReviewComments: (comments: ReadonlyArray<ReviewComment>, activeDraft?: Pick<ReviewComment, 'body' | 'id'> | null) => ReviewComment[];
23
+ export declare const findReusableReviewCommentDraft: (comments: ReadonlyArray<ReviewComment>, activeDraft?: Pick<ReviewComment, 'body' | 'id'> | null) => ReviewComment | undefined;
24
+ export declare const getCommentKey: (comment: Pick<ReviewComment, 'anchor' | 'lineNumber' | 'sectionId' | 'side' | 'startLineNumber' | 'startSide'>) => string;
25
+ export declare const getReviewCommentsDigest: (comments: ReadonlyArray<ReviewComment>) => string;
26
+ export declare const buildReviewCommentsMarkdown: (files: ReadonlyArray<ChangedFile>, comments: ReadonlyArray<ReviewComment>, showWhitespace: boolean, prefix?: string) => string;
27
+ export declare const getReviewCommentsFromState: (state: RepositoryState) => ReadonlyArray<ReviewComment>;
28
+ export declare const getVisibleReviewComments: (comments: ReadonlyArray<ReviewComment>, showOutdated: boolean) => ReadonlyArray<ReviewComment>;
29
+ export declare const shouldDiscardReviewCommentOnEscape: (body: string, confirmDiscard?: (message: string) => boolean) => boolean;
@@ -0,0 +1,7 @@
1
+ import type { ChangedFile } from '../types.ts';
2
+ import type { ReviewIdentity } from './app-types.ts';
3
+ export declare const getFileReviewIdentity: (file: ChangedFile) => ReviewIdentity;
4
+ export declare const getReviewIdentity: (file: ChangedFile, identityByPath?: ReadonlyMap<string, ReviewIdentity>) => ReviewIdentity;
5
+ export declare const isReviewIdentityViewed: (viewed: Readonly<Record<string, string>>, identity: ReviewIdentity) => boolean;
6
+ export declare const updateReviewIdentityViewed: (viewed: Readonly<Record<string, string>>, identity: ReviewIdentity, currentlyViewed: boolean) => Record<string, string>;
7
+ export declare const updateReviewIdentityCollapsed: (collapsed: ReadonlySet<string>, identity: ReviewIdentity, currentlyCollapsed: boolean) => Set<string>;
@@ -0,0 +1,5 @@
1
+ import type { ChangedFile } from '../types.ts';
2
+ import type { CodeViewInstance } from './app-types.ts';
3
+ type ReviewScrollViewer = Pick<CodeViewInstance, 'getScrollTop' | 'getTopForItem'>;
4
+ export declare const getSelectedPathFromScroll: (viewer: ReviewScrollViewer, files: ReadonlyArray<ChangedFile>, showWhitespace: boolean) => string | null;
5
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { DiffSearchMatch } from './app-types.ts';
2
+ export declare const applySearchHighlights: (renderedItems: ReadonlyArray<{
3
+ element: HTMLElement;
4
+ id: string;
5
+ }>, query: string, activeMatch: DiffSearchMatch | null) => void;
@@ -0,0 +1,9 @@
1
+ export declare const SIDEBAR_COLLAPSE_THRESHOLD = 80;
2
+ export declare const SIDEBAR_DEFAULT_WIDTH = 292;
3
+ export declare const SIDEBAR_MAX_WIDTH = 640;
4
+ export declare const SIDEBAR_MIN_WIDTH = 220;
5
+ type SidebarWidthStorage = Pick<Storage, 'getItem' | 'setItem'>;
6
+ export declare const clampSidebarWidth: (width: number) => number;
7
+ export declare const readSidebarWidth: (storage?: SidebarWidthStorage) => number;
8
+ export declare const writeSidebarWidth: (width: number, storage?: SidebarWidthStorage) => void;
9
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { ReviewSource } from '../types.ts';
2
+ import type { RepositoryLoadError } from './app-types.ts';
3
+ export declare const getSourceKey: (source: ReviewSource) => string;
4
+ export declare const getRepositoryLoadError: (error: unknown) => RepositoryLoadError;
5
+ export declare const getShortRef: (ref: string) => string;
6
+ export declare const getSourceLabel: (source: ReviewSource) => string;
7
+ export declare const getHistorySource: (source: ReviewSource) => ReviewSource | undefined;
8
+ export declare const getRefreshSource: (source: ReviewSource) => ReviewSource;
9
+ export declare const supportsLazyDiffContent: (source: ReviewSource) => boolean;
10
+ export declare const supportsDiffSearchContentPreload: (source: ReviewSource) => boolean;
11
+ export declare const shouldStartInHistoryWhenEmpty: (source: ReviewSource) => boolean;
12
+ export declare const usesViewedFileState: (source: ReviewSource) => boolean;
13
+ export declare const getEmptySourceTitle: (source: ReviewSource) => string;
14
+ export declare const getEmptySourceDetail: (source: ReviewSource, root: string) => {
15
+ kind: 'code' | 'text';
16
+ text: string;
17
+ title?: string;
18
+ };
@@ -0,0 +1,2 @@
1
+ export declare const readViewed: (root: string) => Record<string, string>;
2
+ export declare const writeViewed: (root: string, viewed: Record<string, string>) => void;
@@ -0,0 +1,3 @@
1
+ export { Button, buttonVariants, type ButtonProps } from './app/components/Button.tsx';
2
+ export { getPlanCommentAffordancePosition, getPlanCommentColorIndex, getPlanCommentIdentityColorIndex, getSharedPlanDownloadContent, PlanReviewSurface, type PlanReviewCommenting, } from './SharedPlanApp.tsx';
3
+ export { ReadOnlyGeneralCommentCard, ReviewSurface, type ReviewCommenting, type ReviewMode, type ReviewSurfaceProps, type ReviewWalkthroughStatus, } from './SharedWalkthroughApp.tsx';