@orion-agents/orion-code 0.3.14 → 0.3.17

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 (49) hide show
  1. package/CHANGELOG.md +286 -0
  2. package/README.md +6 -8
  3. package/README.zh-CN.md +4 -5
  4. package/dist/runtime/release-receipts.d.ts +15 -3
  5. package/dist/runtime/release-receipts.js +27 -1
  6. package/dist/services/session-storage.d.ts +9 -0
  7. package/dist/services/session-storage.js +27 -1
  8. package/dist/web/git-compare-service.d.ts +45 -0
  9. package/dist/web/git-compare-service.js +160 -0
  10. package/dist/web/git-diff-document.d.ts +83 -0
  11. package/dist/web/git-diff-document.js +214 -0
  12. package/dist/web/git-file-source.d.ts +25 -0
  13. package/dist/web/git-file-source.js +21 -0
  14. package/dist/web/git-history-service.d.ts +151 -0
  15. package/dist/web/git-history-service.js +610 -0
  16. package/dist/web/git-index-transaction.d.ts +45 -0
  17. package/dist/web/git-index-transaction.js +174 -0
  18. package/dist/web/git-patch-builder.d.ts +30 -0
  19. package/dist/web/git-patch-builder.js +134 -0
  20. package/dist/web/git-read-model-service.d.ts +338 -18
  21. package/dist/web/git-read-model-service.js +1029 -110
  22. package/dist/web/git-version-service.d.ts +71 -0
  23. package/dist/web/git-version-service.js +255 -0
  24. package/dist/web/native-directory-picker.d.ts +63 -0
  25. package/dist/web/native-directory-picker.js +169 -0
  26. package/dist/web/protocol.d.ts +51 -2
  27. package/dist/web/server.js +384 -8
  28. package/dist/web/workbench-controller.d.ts +126 -10
  29. package/dist/web/workbench-controller.js +383 -15
  30. package/dist/web/workspace-open-telemetry.d.ts +55 -0
  31. package/dist/web/workspace-open-telemetry.js +73 -0
  32. package/dist/web-client/assets/FilesPanel-BARQCmne.js +1 -0
  33. package/dist/web-client/assets/GitPanel-DjB9eSiJ.js +4 -0
  34. package/dist/web-client/assets/ReviewPanel-YhEGlp-G.js +5 -0
  35. package/dist/web-client/assets/{TerminalPanel-IkCttxgw.js → TerminalPanel-DnWh3Vp2.js} +1 -1
  36. package/dist/web-client/assets/index--hnGXXjj.css +1 -0
  37. package/dist/web-client/assets/index-Drja0_BT.js +20 -0
  38. package/dist/web-client/assets/useAutoNotice-DfQi4G1X.js +1 -0
  39. package/dist/web-client/favicon.svg +9 -0
  40. package/dist/web-client/index.html +3 -2
  41. package/npm-shrinkwrap.json +2 -2
  42. package/package.json +1 -1
  43. package/dist/web-client/assets/DiffViewer-BrHqudpK.js +0 -5
  44. package/dist/web-client/assets/FilesPanel-BcFY6L1a.js +0 -1
  45. package/dist/web-client/assets/GitPanel-B6E5IEXm.js +0 -1
  46. package/dist/web-client/assets/ResourceSplitLayout-fPYE9JKJ.js +0 -1
  47. package/dist/web-client/assets/ReviewPanel-5ecTVmhT.js +0 -1
  48. package/dist/web-client/assets/index-DgVNIqmE.js +0 -20
  49. package/dist/web-client/assets/index-R6E589Fc.css +0 -1
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGitCompareReader = createGitCompareReader;
4
+ /**
5
+ * v0.3.17 S5 — branch and version comparison (plan G5).
6
+ *
7
+ * Two modes, and the difference between them is the whole point:
8
+ * - `snapshot`: the tree difference between A and B;
9
+ * - `merge-base`: what B introduced since the branches diverged.
10
+ *
11
+ * Semantics this module is responsible for:
12
+ * - refs are resolved to **commits** before anything else, and the resolved OIDs are part of
13
+ * the result, so the UI can detect that a ref moved and freeze the opened result instead
14
+ * of silently comparing against a different tree (plan G5);
15
+ * - `merge-base --all` with more than one answer is refused — picking one candidate would
16
+ * present an arbitrary choice as if it were the unique divergence point, so the caller is
17
+ * told to use the two-endpoint mode instead (plan G5);
18
+ * - no common ancestor and a shallow clone with missing objects produce distinct, explicit
19
+ * errors rather than an empty file list that looks like a legitimate answer;
20
+ * - a ref name is validated before it ever reaches argv: revision expressions, ranges and
21
+ * pathspec magic are refused.
22
+ */
23
+ const redaction_1 = require("../services/redaction");
24
+ const errors_1 = require("./errors");
25
+ const REF_NAME_PATTERN = /^[0-9A-Za-z](?:[0-9A-Za-z._/-]{0,250}[0-9A-Za-z])?$/u;
26
+ const COMPARE_FILE_LIMIT = 2000;
27
+ /** Resolves a ref-ish name to a commit, refusing anything that is not a plain ref name. */
28
+ function assertRefName(value, name) {
29
+ if (typeof value !== 'string' || !REF_NAME_PATTERN.test(value) || value.includes('..')) {
30
+ throw new errors_1.WebWorkbenchError(400, `${name} must be a branch, tag or commit hash.`, 'git_ref_invalid');
31
+ }
32
+ return value;
33
+ }
34
+ async function resolveCommit(runGit, ref) {
35
+ const resolved = (await runGit(['rev-parse', '--verify', '--quiet', `${ref}^{commit}`]).catch(() => ''))
36
+ .toString()
37
+ .trim();
38
+ if (!/^[0-9a-f]{7,64}$/iu.test(resolved)) {
39
+ throw new errors_1.WebWorkbenchError(404, `The ref ${ref} could not be resolved to a commit.`, 'git_ref_not_found');
40
+ }
41
+ return resolved;
42
+ }
43
+ function createGitCompareReader(options) {
44
+ const { runGit } = options;
45
+ const numstat = async (base, head) => {
46
+ const raw = await runGit([
47
+ 'diff',
48
+ '--numstat',
49
+ '-z',
50
+ '--no-ext-diff',
51
+ '--no-textconv',
52
+ base,
53
+ head,
54
+ ]);
55
+ const files = [];
56
+ const fields = raw.split('\0');
57
+ let index = 0;
58
+ while (index < fields.length) {
59
+ const record = fields[index];
60
+ index += 1;
61
+ if (!record)
62
+ continue;
63
+ const [added, deleted, inlinePath] = record.split('\t');
64
+ let path = inlinePath ?? '';
65
+ let renamedFrom = null;
66
+ if (path === '' && index + 1 < fields.length) {
67
+ renamedFrom = fields[index];
68
+ path = fields[index + 1];
69
+ index += 2;
70
+ }
71
+ if (!path)
72
+ continue;
73
+ const binary = added === '-' || deleted === '-';
74
+ files.push(Object.freeze({
75
+ path,
76
+ renamedFrom: renamedFrom || null,
77
+ additions: binary ? 0 : Number(added) || 0,
78
+ deletions: binary ? 0 : Number(deleted) || 0,
79
+ binary,
80
+ sensitive: (0, redaction_1.isSensitiveFilePath)(path),
81
+ }));
82
+ if (files.length >= COMPARE_FILE_LIMIT)
83
+ break;
84
+ }
85
+ return Object.freeze({
86
+ files,
87
+ additions: files.reduce((sum, file) => sum + file.additions, 0),
88
+ deletions: files.reduce((sum, file) => sum + file.deletions, 0),
89
+ truncated: files.length >= COMPARE_FILE_LIMIT,
90
+ });
91
+ };
92
+ return {
93
+ /** Validates a pair of refs and returns their commits, without computing anything yet. */
94
+ async resolvePair(baseRef, headRef) {
95
+ const base = assertRefName(baseRef, 'base');
96
+ const head = assertRefName(headRef, 'head');
97
+ const [baseOid, headOid] = await Promise.all([
98
+ resolveCommit(runGit, base),
99
+ resolveCommit(runGit, head),
100
+ ]);
101
+ return Object.freeze({
102
+ baseRef: base,
103
+ headRef: head,
104
+ baseOid,
105
+ headOid,
106
+ baseLabel: base,
107
+ headLabel: head,
108
+ });
109
+ },
110
+ async compare(input) {
111
+ const pair = await this.resolvePair(input.baseRef, input.headRef);
112
+ const mode = input.mode === 'merge-base' ? 'merge-base' : 'snapshot';
113
+ let baseOid = pair.baseOid;
114
+ let mergeBaseOid = null;
115
+ if (mode === 'merge-base') {
116
+ // `--all` is the honest way to ask: a single answer means one divergence point, and
117
+ // more than one means the question has no unique answer.
118
+ const raw = await runGit(['merge-base', '--all', pair.baseOid, pair.headOid]).catch(error => {
119
+ const message = error instanceof Error ? error.message : '';
120
+ if (/missing|bad object/iu.test(message)) {
121
+ throw new errors_1.WebWorkbenchError(409, 'The repository does not contain the objects needed for this comparison (a shallow clone?).', 'git_shallow_history');
122
+ }
123
+ // git exits non-zero with no candidates when the histories are unrelated, and with
124
+ // a diagnostic when objects are missing — those are different failures.
125
+ throw new errors_1.WebWorkbenchError(409, 'The two refs have no common ancestor; use the two-endpoint comparison instead.', 'git_merge_base_missing');
126
+ });
127
+ const candidates = raw
128
+ .split('\n')
129
+ .map(line => line.trim())
130
+ .filter(line => /^[0-9a-f]{7,64}$/iu.test(line));
131
+ if (candidates.length === 0) {
132
+ throw new errors_1.WebWorkbenchError(409, 'The two refs have no common ancestor; use the two-endpoint comparison instead.', 'git_merge_base_missing');
133
+ }
134
+ if (candidates.length > 1) {
135
+ throw new errors_1.WebWorkbenchError(409, `These refs have ${candidates.length} merge bases, so there is no unique divergence point. Use the two-endpoint comparison instead.`, 'git_merge_base_multiple');
136
+ }
137
+ mergeBaseOid = candidates[0];
138
+ baseOid = mergeBaseOid;
139
+ }
140
+ const stats = await numstat(baseOid, pair.headOid);
141
+ return Object.freeze({
142
+ mode,
143
+ requestedBaseRef: pair.baseRef,
144
+ requestedHeadRef: pair.headRef,
145
+ baseOid,
146
+ headOid: pair.headOid,
147
+ baseLabel: mode === 'merge-base' && mergeBaseOid !== null
148
+ ? `共同祖先 ${mergeBaseOid.slice(0, 10)}`
149
+ : pair.baseLabel,
150
+ headLabel: pair.headLabel,
151
+ mergeBaseOid,
152
+ files: stats.files,
153
+ additions: stats.additions,
154
+ deletions: stats.deletions,
155
+ truncated: stats.truncated,
156
+ });
157
+ },
158
+ };
159
+ }
160
+ //# sourceMappingURL=git-compare-service.js.map
@@ -0,0 +1,83 @@
1
+ /**
2
+ * v0.3.17 S2 — structured Git diff document.
3
+ *
4
+ * The v1 diff page exposed raw unified-diff text lines and a `## Staged` style section
5
+ * banner. That shape made line numbers, side-by-side rendering, hunk folding and the
6
+ * "jump to next change" navigation impossible without re-parsing text in the browser.
7
+ *
8
+ * This module parses the raw lines the Host already produces into a hunk/line model with
9
+ * real old/new line numbers, a stable line id, per-hunk completeness, and the write
10
+ * capabilities that apply to the selected comparison source.
11
+ *
12
+ * Deliberate limits for S2:
13
+ * - No hunk or line level writes. `capabilities.stageHunk` / `stageLines` are always
14
+ * false and carry a reason; staging granularity is S3 (plan §10).
15
+ * - Word level highlighting and ignore-whitespace views are S5. This model preserves the
16
+ * original text so those can be computed later without a protocol change.
17
+ */
18
+ import type { WebGitFileSourceV1 } from './git-file-source';
19
+ export type GitDiffLineKindV2 = 'context' | 'addition' | 'deletion' | 'meta';
20
+ export interface GitDiffLineV2 {
21
+ /** Stable inside one document: `<hunkId>#<index>`. */
22
+ readonly lineId: string;
23
+ readonly kind: GitDiffLineKindV2;
24
+ readonly oldLineNumber: number | null;
25
+ readonly newLineNumber: number | null;
26
+ /** Content without the leading `+`/`-`/space marker. */
27
+ readonly text: string;
28
+ /** The original line including its marker, so copy never loses fidelity. */
29
+ readonly raw: string;
30
+ }
31
+ export interface GitHunkV2 {
32
+ readonly hunkId: string;
33
+ readonly header: string;
34
+ readonly oldStart: number;
35
+ readonly oldLines: number;
36
+ readonly newStart: number;
37
+ readonly newLines: number;
38
+ readonly contextLabel: string;
39
+ readonly lines: readonly GitDiffLineV2[];
40
+ /** False when pagination cut this hunk; partial hunks must not be written (plan G3). */
41
+ readonly complete: boolean;
42
+ }
43
+ export type GitDiffDocumentKindV2 = 'text' | 'binary' | 'symlink' | 'submodule' | 'metadata';
44
+ export interface GitDiffCapabilitiesV2 {
45
+ readonly stageFile: boolean;
46
+ readonly unstageFile: boolean;
47
+ readonly stageHunk: boolean;
48
+ readonly unstageHunk: boolean;
49
+ readonly stageLines: boolean;
50
+ readonly reason?: string;
51
+ }
52
+ export interface GitDiffDocumentV2 {
53
+ readonly schemaVersion: 2;
54
+ readonly fileToken: string;
55
+ readonly path: string;
56
+ readonly source: WebGitFileSourceV1;
57
+ /** Set only for a historical comparison: the base tree and how it was chosen. */
58
+ readonly baseOid?: string;
59
+ readonly baseLabel?: string;
60
+ readonly repositoryRevision: string;
61
+ readonly kind: GitDiffDocumentKindV2;
62
+ readonly binary: boolean;
63
+ readonly hunks: readonly GitHunkV2[];
64
+ /** Metadata lines that are not part of any hunk (file headers, mode changes, …). */
65
+ readonly meta: readonly string[];
66
+ readonly completeness: 'complete' | 'paged' | 'limited';
67
+ readonly additions: number;
68
+ readonly deletions: number;
69
+ readonly lineCount: number;
70
+ readonly nextCursor: string | null;
71
+ readonly capabilities: GitDiffCapabilitiesV2;
72
+ }
73
+ export declare function parseGitDiffDocument(input: {
74
+ readonly fileToken: string;
75
+ readonly path: string;
76
+ readonly source: WebGitFileSourceV1;
77
+ readonly repositoryRevision: string;
78
+ readonly lines: readonly string[];
79
+ readonly hasMore: boolean;
80
+ /** Host-signed continuation cursor, or null. Never synthesised here. */
81
+ readonly nextCursor: string | null;
82
+ }): GitDiffDocumentV2;
83
+ //# sourceMappingURL=git-diff-document.d.ts.map
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseGitDiffDocument = parseGitDiffDocument;
4
+ const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/u;
5
+ const NO_NEWLINE = '\';
6
+ /** Document level header lines Git emits before the first hunk. */
7
+ function isMetaLine(line) {
8
+ return (line.startsWith('## ') ||
9
+ line.startsWith('diff --git ') ||
10
+ line.startsWith('index ') ||
11
+ line.startsWith('--- ') ||
12
+ line.startsWith('+++ ') ||
13
+ line.startsWith('new file mode ') ||
14
+ line.startsWith('deleted file mode ') ||
15
+ line.startsWith('old mode ') ||
16
+ line.startsWith('new mode ') ||
17
+ line.startsWith('similarity index ') ||
18
+ line.startsWith('dissimilarity index ') ||
19
+ line.startsWith('rename from ') ||
20
+ line.startsWith('rename to ') ||
21
+ line.startsWith('copy from ') ||
22
+ line.startsWith('copy to ') ||
23
+ line.startsWith('Binary files ') ||
24
+ line.startsWith('GIT binary patch') ||
25
+ line.startsWith('Submodule '));
26
+ }
27
+ function detectKind(lines) {
28
+ if (lines.some(line => line.startsWith('Binary files ') || line.startsWith('GIT binary patch'))) {
29
+ return 'binary';
30
+ }
31
+ if (lines.some(line => line.startsWith('Submodule ')))
32
+ return 'submodule';
33
+ if (lines.some(line => line.startsWith('old mode ') || line.startsWith('new mode '))) {
34
+ return 'metadata';
35
+ }
36
+ return 'text';
37
+ }
38
+ /** Write capabilities implied by the comparison source. */
39
+ function capabilitiesFor(source) {
40
+ const hunkWritesUnavailable = 'Hunk 与选中行级写入将在 S3 提供。';
41
+ if (source === 'staged') {
42
+ return Object.freeze({
43
+ stageFile: false,
44
+ unstageFile: true,
45
+ stageHunk: false,
46
+ unstageHunk: false,
47
+ stageLines: false,
48
+ reason: hunkWritesUnavailable,
49
+ });
50
+ }
51
+ if (source === 'unstaged' || source === 'untracked') {
52
+ return Object.freeze({
53
+ stageFile: true,
54
+ unstageFile: false,
55
+ stageHunk: false,
56
+ unstageHunk: false,
57
+ stageLines: false,
58
+ reason: hunkWritesUnavailable,
59
+ });
60
+ }
61
+ return Object.freeze({
62
+ stageFile: false,
63
+ unstageFile: false,
64
+ stageHunk: false,
65
+ unstageHunk: false,
66
+ stageLines: false,
67
+ reason: '冲突文件本版不提供一键解决,请在 Files 打开处理。',
68
+ });
69
+ }
70
+ function parseGitDiffDocument(input) {
71
+ const kind = detectKind(input.lines);
72
+ const binary = kind === 'binary';
73
+ const meta = [];
74
+ const hunks = [];
75
+ let additions = 0;
76
+ let deletions = 0;
77
+ let current;
78
+ const closeHunk = () => {
79
+ if (!current)
80
+ return;
81
+ const hunkId = `${current.index}:${current.oldStart}:${current.newStart}`;
82
+ // A hunk is complete when it accounts for every line its header promised. The final
83
+ // hunk of a paged read is reported incomplete so callers cannot write a partial patch.
84
+ const consumedOld = current.oldCursor - current.oldStart;
85
+ const consumedNew = current.newCursor - current.newStart;
86
+ const reached = consumedOld >= current.oldLines && consumedNew >= current.newLines;
87
+ hunks.push(Object.freeze({
88
+ hunkId,
89
+ header: current.header,
90
+ oldStart: current.oldStart,
91
+ oldLines: current.oldLines,
92
+ newStart: current.newStart,
93
+ newLines: current.newLines,
94
+ contextLabel: current.contextLabel,
95
+ lines: Object.freeze(current.lines),
96
+ complete: reached,
97
+ }));
98
+ current = undefined;
99
+ };
100
+ for (const raw of input.lines) {
101
+ const headerMatch = HUNK_HEADER.exec(raw);
102
+ if (headerMatch) {
103
+ closeHunk();
104
+ const oldStart = Number(headerMatch[1]);
105
+ const newStart = Number(headerMatch[3]);
106
+ current = {
107
+ header: raw,
108
+ oldStart,
109
+ oldLines: headerMatch[2] === undefined ? 1 : Number(headerMatch[2]),
110
+ newStart,
111
+ newLines: headerMatch[4] === undefined ? 1 : Number(headerMatch[4]),
112
+ contextLabel: (headerMatch[5] ?? '').trim(),
113
+ lines: [],
114
+ oldCursor: oldStart,
115
+ newCursor: newStart,
116
+ index: hunks.length,
117
+ };
118
+ continue;
119
+ }
120
+ if (!current) {
121
+ // Everything before the first hunk is document metadata.
122
+ if (raw)
123
+ meta.push(raw);
124
+ continue;
125
+ }
126
+ if (raw === NO_NEWLINE) {
127
+ current.lines.push(Object.freeze({
128
+ lineId: `${current.index}:${current.oldStart}:${current.newStart}#${current.lines.length}`,
129
+ kind: 'meta',
130
+ oldLineNumber: null,
131
+ newLineNumber: null,
132
+ text: raw,
133
+ raw,
134
+ }));
135
+ continue;
136
+ }
137
+ if (isMetaLine(raw)) {
138
+ // A file boundary inside one page (multi-command reads) closes the current hunk.
139
+ closeHunk();
140
+ if (raw)
141
+ meta.push(raw);
142
+ continue;
143
+ }
144
+ const marker = raw[0];
145
+ const text = raw.length > 0 ? raw.slice(1) : '';
146
+ let lineKind;
147
+ let oldLineNumber = null;
148
+ let newLineNumber = null;
149
+ if (marker === '+') {
150
+ lineKind = 'addition';
151
+ newLineNumber = current.newCursor;
152
+ current.newCursor += 1;
153
+ additions += 1;
154
+ }
155
+ else if (marker === '-') {
156
+ lineKind = 'deletion';
157
+ oldLineNumber = current.oldCursor;
158
+ current.oldCursor += 1;
159
+ deletions += 1;
160
+ }
161
+ else if (marker === ' ') {
162
+ lineKind = 'context';
163
+ oldLineNumber = current.oldCursor;
164
+ newLineNumber = current.newCursor;
165
+ current.oldCursor += 1;
166
+ current.newCursor += 1;
167
+ }
168
+ else if (raw === '') {
169
+ // An empty line in a hunk body is a context line for an empty source line.
170
+ lineKind = 'context';
171
+ oldLineNumber = current.oldCursor;
172
+ newLineNumber = current.newCursor;
173
+ current.oldCursor += 1;
174
+ current.newCursor += 1;
175
+ }
176
+ else {
177
+ lineKind = 'meta';
178
+ }
179
+ current.lines.push(Object.freeze({
180
+ lineId: `${current.index}:${current.oldStart}:${current.newStart}#${current.lines.length}`,
181
+ kind: lineKind,
182
+ oldLineNumber,
183
+ newLineNumber,
184
+ text,
185
+ raw,
186
+ }));
187
+ }
188
+ closeHunk();
189
+ const frozenHunks = Object.freeze(hunks);
190
+ let completeness = 'complete';
191
+ if (input.hasMore)
192
+ completeness = 'paged';
193
+ else if (frozenHunks.some(hunk => !hunk.complete))
194
+ completeness = 'limited';
195
+ return Object.freeze({
196
+ schemaVersion: 2,
197
+ fileToken: input.fileToken,
198
+ // A digest keeps the document self-describing without leaking the raw path shape.
199
+ path: input.path,
200
+ source: input.source,
201
+ repositoryRevision: input.repositoryRevision,
202
+ kind,
203
+ binary,
204
+ hunks: frozenHunks,
205
+ meta: Object.freeze(meta),
206
+ completeness,
207
+ additions,
208
+ deletions,
209
+ lineCount: input.lines.length,
210
+ nextCursor: input.nextCursor,
211
+ capabilities: capabilitiesFor(input.source),
212
+ });
213
+ }
214
+ //# sourceMappingURL=git-diff-document.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * v0.3.17 — Git comparison source.
3
+ *
4
+ * Lives in its own module so both the read model service and the diff document parser can
5
+ * depend on it without forming a cycle. A path with an index change *and* a further
6
+ * worktree change (`MM`) is two distinct selectable objects, so the source is part of a
7
+ * Git file identity, not a display attribute.
8
+ */
9
+ /**
10
+ * `commit` is not a working-tree state: it identifies a historical comparison (a commit
11
+ * against its base). Plan §6.1 makes the comparison target a first-class field, so it is a
12
+ * distinct value rather than being smuggled in as `staged` or a display flag. It is
13
+ * read-only: no mutation path accepts it (plan G3 keeps history read-only).
14
+ */
15
+ export type WebGitFileSourceV1 = 'staged' | 'unstaged' | 'untracked' | 'conflict' | 'commit';
16
+ /**
17
+ * The four sources a `git status` record can belong to. A commit comparison is never a
18
+ * working-tree state, so status buckets and counts are typed against this narrower set —
19
+ * adding a comparison source must not force status code to handle an impossible case.
20
+ */
21
+ export type GitWorktreeSourceV1 = 'staged' | 'unstaged' | 'untracked' | 'conflict';
22
+ export declare const GIT_WORKTREE_SOURCES_V1: readonly GitWorktreeSourceV1[];
23
+ export declare const GIT_FILE_SOURCES_V1: readonly WebGitFileSourceV1[];
24
+ export declare function isGitFileSourceV1(value: unknown): value is WebGitFileSourceV1;
25
+ //# sourceMappingURL=git-file-source.d.ts.map
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GIT_FILE_SOURCES_V1 = exports.GIT_WORKTREE_SOURCES_V1 = void 0;
4
+ exports.isGitFileSourceV1 = isGitFileSourceV1;
5
+ exports.GIT_WORKTREE_SOURCES_V1 = Object.freeze([
6
+ 'staged',
7
+ 'unstaged',
8
+ 'untracked',
9
+ 'conflict',
10
+ ]);
11
+ exports.GIT_FILE_SOURCES_V1 = Object.freeze([
12
+ 'staged',
13
+ 'unstaged',
14
+ 'untracked',
15
+ 'conflict',
16
+ 'commit',
17
+ ]);
18
+ function isGitFileSourceV1(value) {
19
+ return (typeof value === 'string' && exports.GIT_FILE_SOURCES_V1.includes(value));
20
+ }
21
+ //# sourceMappingURL=git-file-source.js.map
@@ -0,0 +1,151 @@
1
+ /** `git hash-object -t tree /dev/null` — the canonical empty tree, used for root commits. */
2
+ export declare const GIT_EMPTY_TREE_OID = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
3
+ export type GitRefKindV1 = 'branch' | 'tag' | 'remote' | 'other';
4
+ export interface GitRefV1 {
5
+ /** e.g. `refs/heads/main`, `refs/tags/v1`, `refs/remotes/origin/main`. */
6
+ readonly name: string;
7
+ /** Short display form, e.g. `main`, `v1`, `origin/main`. */
8
+ readonly shortName: string;
9
+ readonly kind: GitRefKindV1;
10
+ readonly oid: string;
11
+ /** True for the ref HEAD points at. */
12
+ readonly isHead: boolean;
13
+ }
14
+ export interface GitRefsV1 {
15
+ readonly refs: readonly GitRefV1[];
16
+ readonly head: string | null;
17
+ readonly detached: boolean;
18
+ readonly truncated: boolean;
19
+ }
20
+ export interface GitCommitSummaryV1 {
21
+ readonly id: string;
22
+ readonly shortId: string;
23
+ readonly subject: string;
24
+ readonly authorName: string;
25
+ readonly authoredAt: string;
26
+ /** Parents, first parent first. Empty for a root commit. */
27
+ readonly parents: readonly string[];
28
+ /** True when the commit has more than one parent. */
29
+ readonly isMerge: boolean;
30
+ /** `%D` decoration, trimmed; never used to infer identity. */
31
+ readonly decoration: readonly string[];
32
+ }
33
+ export interface GitCommitDetailV1 extends GitCommitSummaryV1 {
34
+ readonly message: string;
35
+ readonly committerName: string;
36
+ readonly committedAt: string;
37
+ readonly authorEmail: string;
38
+ /**
39
+ * The tree the commit is compared against: the first parent, or a caller-chosen parent, or
40
+ * the empty tree for a root commit. Exposed so the UI states the real comparison.
41
+ */
42
+ readonly baseOid: string;
43
+ readonly baseLabel: string;
44
+ readonly parentIndex: number;
45
+ }
46
+ export interface GitCommitFileV1 {
47
+ readonly path: string;
48
+ /** Rename source, when Git detected one. */
49
+ readonly renamedFrom: string | null;
50
+ readonly additions: number;
51
+ readonly deletions: number;
52
+ /** True for a binary entry, where numstat reports `-` for both counts. */
53
+ readonly binary: boolean;
54
+ readonly sensitive: boolean;
55
+ }
56
+ export interface GitCommitFilesV1 {
57
+ readonly commitSha: string;
58
+ readonly baseOid: string;
59
+ readonly baseLabel: string;
60
+ readonly files: readonly GitCommitFileV1[];
61
+ readonly additions: number;
62
+ readonly deletions: number;
63
+ readonly truncated: boolean;
64
+ }
65
+ export interface GitHistoryQueryV1 {
66
+ /** Substring of the commit message. */
67
+ readonly message?: string;
68
+ /** Substring of the author name or email. */
69
+ readonly author?: string;
70
+ /** Full or abbreviated commit SHA. */
71
+ readonly sha?: string;
72
+ /** Restricts to commits touching this path. */
73
+ readonly path?: string;
74
+ /** ISO date or `YYYY-MM-DD`; passed through as `--since`/`--until`. */
75
+ readonly since?: string;
76
+ readonly until?: string;
77
+ /** Defaults to HEAD. */
78
+ readonly rev?: string;
79
+ readonly cursor?: string;
80
+ readonly pageSize?: number;
81
+ }
82
+ export interface GitHistoryPageV1 {
83
+ readonly items: readonly GitCommitSummaryV1[];
84
+ readonly nextCursor: string | null;
85
+ /** The tip the page was frozen against, so the UI can state it. */
86
+ readonly tipOid: string | null;
87
+ readonly truncated: boolean;
88
+ }
89
+ export interface GitBlameLineV1 {
90
+ readonly lineNumber: number;
91
+ readonly commitShort: string;
92
+ readonly author: string;
93
+ readonly authoredAt: string;
94
+ readonly summary: string;
95
+ /** True when the commit predates the history git can see (a grafted/shallow boundary). */
96
+ readonly isBoundary: boolean;
97
+ }
98
+ export interface GitBlameResultV1 {
99
+ readonly path: string;
100
+ readonly rev: string | null;
101
+ readonly lines: readonly GitBlameLineV1[];
102
+ readonly truncated: boolean;
103
+ }
104
+ export interface GitGraphRowV1 {
105
+ /** The graph column prefix exactly as git drew it (never re-derived by us). */
106
+ readonly graph: string;
107
+ /** Commit id when the row belongs to a commit; graph-only rows have null. */
108
+ readonly id: string | null;
109
+ readonly shortId: string | null;
110
+ readonly subject: string;
111
+ }
112
+ export interface GitGraphPageV1 {
113
+ readonly rows: readonly GitGraphRowV1[];
114
+ readonly truncated: boolean;
115
+ }
116
+ export interface GitFileHistoryPageV1 {
117
+ readonly path: string;
118
+ readonly items: readonly GitCommitSummaryV1[];
119
+ /** True when Git followed a rename across the boundary; the UI must say so. */
120
+ readonly followed: boolean;
121
+ readonly truncated: boolean;
122
+ }
123
+ export interface GitHistoryReader {
124
+ refs(): Promise<GitRefsV1>;
125
+ commit(oid: string, parentIndex?: number): Promise<GitCommitDetailV1>;
126
+ commitFiles(oid: string, parentIndex?: number): Promise<GitCommitFilesV1>;
127
+ history(query: GitHistoryQueryV1): Promise<GitHistoryPageV1>;
128
+ graph(input: {
129
+ readonly limit?: number;
130
+ }): Promise<GitGraphPageV1>;
131
+ blame(input: {
132
+ readonly path: string;
133
+ readonly rev?: string;
134
+ readonly limit?: number;
135
+ }): Promise<GitBlameResultV1>;
136
+ fileHistory(input: {
137
+ readonly path: string;
138
+ readonly rev?: string;
139
+ readonly limit?: number;
140
+ }): Promise<GitFileHistoryPageV1>;
141
+ }
142
+ export interface GitHistoryReaderOptions {
143
+ /** Runs a read-profile git command in the repository root. */
144
+ readonly runGit: (args: readonly string[]) => Promise<string>;
145
+ /** Resolves the repository root, throwing when it is unavailable. */
146
+ readonly requireRoot: () => Promise<string>;
147
+ /** Current repository state version, used to bind cursors. */
148
+ readonly revision: () => Promise<string>;
149
+ }
150
+ export declare function createGitHistoryReader(options: GitHistoryReaderOptions): GitHistoryReader;
151
+ //# sourceMappingURL=git-history-service.d.ts.map