@imenam/mcp-documentor 1.0.71 → 1.0.74
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/dist/src/core/conflict-inspector.d.ts +63 -0
- package/dist/src/core/conflict-inspector.js +157 -0
- package/dist/src/core/git-sync.d.ts +113 -8
- package/dist/src/core/git-sync.js +296 -45
- package/dist/src/core/merge-drivers/merge-config.d.ts +1 -0
- package/dist/src/core/merge-drivers/merge-config.js +68 -0
- package/dist/src/core/merge-drivers/merge-doc.d.ts +1 -0
- package/dist/src/core/merge-drivers/merge-doc.js +105 -0
- package/dist/src/core/merge-drivers/text-merge.d.ts +15 -0
- package/dist/src/core/merge-drivers/text-merge.js +53 -0
- package/dist/src/core/merge-drivers/three-way.d.ts +34 -0
- package/dist/src/core/merge-drivers/three-way.js +86 -0
- package/dist/src/gui-worker.js +21 -0
- package/dist/src/index.js +146 -12
- package/dist/src/tools/conflicts.d.ts +12 -0
- package/dist/src/tools/conflicts.js +190 -0
- package/dist/src/tools/sync.js +55 -11
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/gui/dist/assets/{arc-Carsq0k3.js → arc-BNuZ3dSL.js} +1 -1
- package/gui/dist/assets/{architectureDiagram-3BPJPVTR-caqcwdTw.js → architectureDiagram-3BPJPVTR-D8g3tPQx.js} +1 -1
- package/gui/dist/assets/{blockDiagram-GPEHLZMM-0wUO8k2I.js → blockDiagram-GPEHLZMM-limhup8_.js} +1 -1
- package/gui/dist/assets/{c4Diagram-AAUBKEIU-DS6q7fMy.js → c4Diagram-AAUBKEIU-Ct39JMIy.js} +1 -1
- package/gui/dist/assets/channel-uoEIgtym.js +1 -0
- package/gui/dist/assets/{chunk-2J33WTMH-CrJc-G6D.js → chunk-2J33WTMH-BkLJTezj.js} +1 -1
- package/gui/dist/assets/{chunk-4BX2VUAB-C5vtPFbB.js → chunk-4BX2VUAB-CR5NbhDR.js} +1 -1
- package/gui/dist/assets/{chunk-55IACEB6-BchyQUFM.js → chunk-55IACEB6-CtQYMnJS.js} +1 -1
- package/gui/dist/assets/{chunk-727SXJPM-BCIaWtKq.js → chunk-727SXJPM-B2q7tUn8.js} +1 -1
- package/gui/dist/assets/{chunk-AQP2D5EJ-BEQJDJt5.js → chunk-AQP2D5EJ-Bbcnrfrp.js} +1 -1
- package/gui/dist/assets/{chunk-FMBD7UC4-IfQ3QtrC.js → chunk-FMBD7UC4-D8gd4zRe.js} +1 -1
- package/gui/dist/assets/{chunk-ND2GUHAM-4Du33w7t.js → chunk-ND2GUHAM-DiZKzZtG.js} +1 -1
- package/gui/dist/assets/{chunk-QZHKN3VN-HR0CP6fa.js → chunk-QZHKN3VN-CrKx-e2_.js} +1 -1
- package/gui/dist/assets/classDiagram-4FO5ZUOK-DmhYb54l.js +1 -0
- package/gui/dist/assets/classDiagram-v2-Q7XG4LA2-DmhYb54l.js +1 -0
- package/gui/dist/assets/{cose-bilkent-S5V4N54A-C9Re3ENx.js → cose-bilkent-S5V4N54A-BDUCVkTl.js} +1 -1
- package/gui/dist/assets/{dagre-BM42HDAG-DZmcvMMp.js → dagre-BM42HDAG-DkoYBHXK.js} +1 -1
- package/gui/dist/assets/{diagram-2AECGRRQ-EyJrAGht.js → diagram-2AECGRRQ-BT1YJHon.js} +1 -1
- package/gui/dist/assets/{diagram-5GNKFQAL-CHd3T9_b.js → diagram-5GNKFQAL-C00r6F35.js} +1 -1
- package/gui/dist/assets/{diagram-KO2AKTUF-CIyFrZSR.js → diagram-KO2AKTUF-B4wcN5a_.js} +1 -1
- package/gui/dist/assets/{diagram-LMA3HP47-BlkJALyz.js → diagram-LMA3HP47-B9FqCfel.js} +1 -1
- package/gui/dist/assets/{diagram-OG6HWLK6-P8LA7IZE.js → diagram-OG6HWLK6-COPCDzdG.js} +1 -1
- package/gui/dist/assets/{erDiagram-TEJ5UH35-BPywgWN1.js → erDiagram-TEJ5UH35-BGQGT2wN.js} +1 -1
- package/gui/dist/assets/{flowDiagram-I6XJVG4X-ByL0kGiV.js → flowDiagram-I6XJVG4X-A7jKWUpi.js} +1 -1
- package/gui/dist/assets/{ganttDiagram-6RSMTGT7-_pnaYCU4.js → ganttDiagram-6RSMTGT7-NhFkpY-x.js} +1 -1
- package/gui/dist/assets/{gitGraphDiagram-PVQCEYII-DN67CDGs.js → gitGraphDiagram-PVQCEYII-z0AqyYG4.js} +1 -1
- package/gui/dist/assets/{index-Bjc5MOe1.js → index-Dub5OLKk.js} +98 -98
- package/gui/dist/assets/index-QkCDSQ2A.css +1 -0
- package/gui/dist/assets/{infoDiagram-5YYISTIA-Bm5LEpzH.js → infoDiagram-5YYISTIA-D69UR9u9.js} +1 -1
- package/gui/dist/assets/{ishikawaDiagram-YF4QCWOH-DUYSULkT.js → ishikawaDiagram-YF4QCWOH-DSTqIoro.js} +1 -1
- package/gui/dist/assets/{journeyDiagram-JHISSGLW-BvJ1_f0L.js → journeyDiagram-JHISSGLW-CekXdcoE.js} +1 -1
- package/gui/dist/assets/{kanban-definition-UN3LZRKU-DDYKg6RY.js → kanban-definition-UN3LZRKU-CseGvFK9.js} +1 -1
- package/gui/dist/assets/{linear-HlpG9u6P.js → linear-BtVl_9_C.js} +1 -1
- package/gui/dist/assets/{mindmap-definition-RKZ34NQL-CPa_wo_s.js → mindmap-definition-RKZ34NQL-XLjQIU37.js} +1 -1
- package/gui/dist/assets/{pieDiagram-4H26LBE5-BWo0c4DP.js → pieDiagram-4H26LBE5-BcvUzWoW.js} +1 -1
- package/gui/dist/assets/{quadrantDiagram-W4KKPZXB-CLahU-6B.js → quadrantDiagram-W4KKPZXB-BzoYEmNW.js} +1 -1
- package/gui/dist/assets/{requirementDiagram-4Y6WPE33-BoYbgzQ7.js → requirementDiagram-4Y6WPE33-icKC1_Nd.js} +1 -1
- package/gui/dist/assets/{sankeyDiagram-5OEKKPKP-CGm79aMo.js → sankeyDiagram-5OEKKPKP-mi3i-2dZ.js} +1 -1
- package/gui/dist/assets/{sequenceDiagram-3UESZ5HK-BkknTD52.js → sequenceDiagram-3UESZ5HK-XrcDkRlM.js} +1 -1
- package/gui/dist/assets/{stateDiagram-AJRCARHV-DSBurgwC.js → stateDiagram-AJRCARHV-UXaqrCNT.js} +1 -1
- package/gui/dist/assets/stateDiagram-v2-BHNVJYJU-Bhdu4lv4.js +1 -0
- package/gui/dist/assets/{timeline-definition-PNZ67QCA-CBHyrGuz.js → timeline-definition-PNZ67QCA-yd6607p6.js} +1 -1
- package/gui/dist/assets/{vennDiagram-CIIHVFJN-Dn9fr_bR.js → vennDiagram-CIIHVFJN-BsRqUcIp.js} +1 -1
- package/gui/dist/assets/{wardley-L42UT6IY-nMuySeAb.js → wardley-L42UT6IY-BmdA7yk0.js} +1 -1
- package/gui/dist/assets/{wardleyDiagram-YWT4CUSO-Byn2STLI.js → wardleyDiagram-YWT4CUSO-CRdmckD8.js} +1 -1
- package/gui/dist/assets/{xychartDiagram-2RQKCTM6-Bi-Y9wp5.js → xychartDiagram-2RQKCTM6-DWpNIQY-.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +65 -65
- package/gui/dist/assets/channel-D51HexOc.js +0 -1
- package/gui/dist/assets/classDiagram-4FO5ZUOK-CU0dQ3zy.js +0 -1
- package/gui/dist/assets/classDiagram-v2-Q7XG4LA2-CU0dQ3zy.js +0 -1
- package/gui/dist/assets/index-hjkEDRmc.css +0 -1
- package/gui/dist/assets/stateDiagram-v2-BHNVJYJU-DfKn22XF.js +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads and rewrites git conflict markers so the agent can resolve a document
|
|
3
|
+
* hunk by hunk without ever loading the document itself.
|
|
4
|
+
*
|
|
5
|
+
* Sides are named "local" and "remote" throughout, never git's ours/theirs:
|
|
6
|
+
* those two swap meaning between a merge and a rebase, and the whole point of
|
|
7
|
+
* this layer is that the caller never has to know which one is running.
|
|
8
|
+
*/
|
|
9
|
+
/** Direct marker check, independent of hunk parsing - the invariant before staging. */
|
|
10
|
+
export declare function hasConflictMarkers(text: string): boolean;
|
|
11
|
+
export type HunkSide = "local" | "remote";
|
|
12
|
+
export interface ConflictHunk {
|
|
13
|
+
/** 1-based index within the file; the id the caller resolves against. */
|
|
14
|
+
index: number;
|
|
15
|
+
/** Nearest markdown heading above the hunk, for locating it without reading the doc. */
|
|
16
|
+
section: string;
|
|
17
|
+
/** 1-based line where the hunk's opening marker sits. */
|
|
18
|
+
line: number;
|
|
19
|
+
local: string[];
|
|
20
|
+
remote: string[];
|
|
21
|
+
/** Common ancestor, present only when the markers were written in diff3 style. */
|
|
22
|
+
base?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* The hunk concerns frontmatter, either because it sits inside the YAML block
|
|
25
|
+
* or because the doc merge driver hoisted a frontmatter disagreement to the
|
|
26
|
+
* top of the body. Keeping both sides of one of these would duplicate a key,
|
|
27
|
+
* so that choice is refused rather than silently producing broken YAML.
|
|
28
|
+
*/
|
|
29
|
+
inFrontmatter: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The hunk is the block the doc merge driver hoisted out of the frontmatter.
|
|
32
|
+
* Its sides are `key: value` lines that belong back in the YAML, not in the
|
|
33
|
+
* body where the markers physically sit.
|
|
34
|
+
*/
|
|
35
|
+
hoisted: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface ParsedFile {
|
|
38
|
+
lines: string[];
|
|
39
|
+
hunks: ConflictHunk[];
|
|
40
|
+
}
|
|
41
|
+
/** Splits a conflicted file into hunks. Handles both diff3 and plain markers. */
|
|
42
|
+
export declare function parseConflicts(text: string, operation: "merge" | "rebase" | "none"): ParsedFile;
|
|
43
|
+
export type Decision = {
|
|
44
|
+
index: number;
|
|
45
|
+
take: "local" | "remote" | "both" | "none";
|
|
46
|
+
} | {
|
|
47
|
+
index: number;
|
|
48
|
+
take: "custom";
|
|
49
|
+
content: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Rewrites the file with the chosen resolution for each listed hunk. Hunks with
|
|
53
|
+
* no decision keep their markers, so a partial resolution is safe: the file
|
|
54
|
+
* stays conflicted until every hunk has been decided.
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyResolutions(text: string, operation: "merge" | "rebase" | "none", decisions: Decision[]): {
|
|
57
|
+
text: string;
|
|
58
|
+
applied: number[];
|
|
59
|
+
unknown: number[];
|
|
60
|
+
remaining: number;
|
|
61
|
+
};
|
|
62
|
+
/** Truncates a side to a character budget, saying how much was withheld. */
|
|
63
|
+
export declare function preview(side: string[], maxChars: number): string;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads and rewrites git conflict markers so the agent can resolve a document
|
|
3
|
+
* hunk by hunk without ever loading the document itself.
|
|
4
|
+
*
|
|
5
|
+
* Sides are named "local" and "remote" throughout, never git's ours/theirs:
|
|
6
|
+
* those two swap meaning between a merge and a rebase, and the whole point of
|
|
7
|
+
* this layer is that the caller never has to know which one is running.
|
|
8
|
+
*/
|
|
9
|
+
const START = /^<{7}(?: (.*))?$/;
|
|
10
|
+
const BASE = /^\|{7}(?: (.*))?$/;
|
|
11
|
+
const SEPARATOR = /^={7}$/;
|
|
12
|
+
const END = /^>{7}(?: (.*))?$/;
|
|
13
|
+
const HEADING = /^(#{1,6})\s+(.*)$/;
|
|
14
|
+
/**
|
|
15
|
+
* git checks documents out with the platform's line endings, so a working-tree
|
|
16
|
+
* file on Windows is CRLF even though the driver wrote LF. Splitting on "\n"
|
|
17
|
+
* alone would leave a trailing CR on every line and no marker would ever match.
|
|
18
|
+
*/
|
|
19
|
+
function splitLines(text) {
|
|
20
|
+
return text.split(/\r?\n/);
|
|
21
|
+
}
|
|
22
|
+
function lineEnding(text) {
|
|
23
|
+
return /\r\n/.test(text) ? "\r\n" : "\n";
|
|
24
|
+
}
|
|
25
|
+
/** Direct marker check, independent of hunk parsing - the invariant before staging. */
|
|
26
|
+
export function hasConflictMarkers(text) {
|
|
27
|
+
return splitLines(text).some((line) => START.test(line) || SEPARATOR.test(line) || END.test(line));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Maps a marker block onto absolute sides. In the file, the first block is
|
|
31
|
+
* always git's "ours": the branch being merged into for a merge, but the
|
|
32
|
+
* upstream being replayed onto for a rebase.
|
|
33
|
+
*/
|
|
34
|
+
function sidesFor(operation, first, second) {
|
|
35
|
+
return operation === "rebase" ? { local: second, remote: first } : { local: first, remote: second };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Line range of the YAML frontmatter block, if the file opens with one.
|
|
39
|
+
* Returns null when there is none.
|
|
40
|
+
*/
|
|
41
|
+
function frontmatterRange(lines) {
|
|
42
|
+
if (lines.length === 0 || lines[0].trim() !== "---")
|
|
43
|
+
return null;
|
|
44
|
+
for (let i = 1; i < lines.length; i++) {
|
|
45
|
+
if (lines[i].trim() === "---")
|
|
46
|
+
return { start: 0, end: i };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function sectionFor(lines, hunkStart) {
|
|
51
|
+
for (let i = hunkStart - 1; i >= 0; i--) {
|
|
52
|
+
const match = lines[i].match(HEADING);
|
|
53
|
+
if (match)
|
|
54
|
+
return match[2].trim();
|
|
55
|
+
}
|
|
56
|
+
return "(document root)";
|
|
57
|
+
}
|
|
58
|
+
/** Splits a conflicted file into hunks. Handles both diff3 and plain markers. */
|
|
59
|
+
export function parseConflicts(text, operation) {
|
|
60
|
+
const lines = splitLines(text);
|
|
61
|
+
const frontmatter = frontmatterRange(lines);
|
|
62
|
+
const hunks = [];
|
|
63
|
+
for (let i = 0; i < lines.length; i++) {
|
|
64
|
+
if (!START.test(lines[i]))
|
|
65
|
+
continue;
|
|
66
|
+
const first = [];
|
|
67
|
+
const base = [];
|
|
68
|
+
const second = [];
|
|
69
|
+
let target = first;
|
|
70
|
+
let sawBase = false;
|
|
71
|
+
let closed = false;
|
|
72
|
+
let j = i + 1;
|
|
73
|
+
const label = lines[i].match(START)?.[1] ?? "";
|
|
74
|
+
for (; j < lines.length; j++) {
|
|
75
|
+
const line = lines[j];
|
|
76
|
+
if (BASE.test(line)) {
|
|
77
|
+
sawBase = true;
|
|
78
|
+
target = base;
|
|
79
|
+
}
|
|
80
|
+
else if (SEPARATOR.test(line)) {
|
|
81
|
+
target = second;
|
|
82
|
+
}
|
|
83
|
+
else if (END.test(line)) {
|
|
84
|
+
closed = true;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
target.push(line);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// An unterminated marker is malformed input, not a hunk — leave it alone.
|
|
92
|
+
if (!closed)
|
|
93
|
+
continue;
|
|
94
|
+
const { local, remote } = sidesFor(operation, first, second);
|
|
95
|
+
hunks.push({
|
|
96
|
+
index: hunks.length + 1,
|
|
97
|
+
section: sectionFor(lines, i),
|
|
98
|
+
line: i + 1,
|
|
99
|
+
local,
|
|
100
|
+
remote,
|
|
101
|
+
...(sawBase ? { base } : {}),
|
|
102
|
+
inFrontmatter: label.includes("frontmatter") || (frontmatter !== null && i >= frontmatter.start && i <= frontmatter.end),
|
|
103
|
+
hoisted: label.includes("frontmatter"),
|
|
104
|
+
});
|
|
105
|
+
i = j;
|
|
106
|
+
}
|
|
107
|
+
return { lines, hunks };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Rewrites the file with the chosen resolution for each listed hunk. Hunks with
|
|
111
|
+
* no decision keep their markers, so a partial resolution is safe: the file
|
|
112
|
+
* stays conflicted until every hunk has been decided.
|
|
113
|
+
*/
|
|
114
|
+
export function applyResolutions(text, operation, decisions) {
|
|
115
|
+
const { lines, hunks } = parseConflicts(text, operation);
|
|
116
|
+
const byIndex = new Map(decisions.map((d) => [d.index, d]));
|
|
117
|
+
const unknown = decisions.map((d) => d.index).filter((i) => !hunks.some((h) => h.index === i));
|
|
118
|
+
const applied = [];
|
|
119
|
+
const out = [];
|
|
120
|
+
let cursor = 0;
|
|
121
|
+
for (const hunk of hunks) {
|
|
122
|
+
const start = hunk.line - 1;
|
|
123
|
+
// Re-find the closing marker: hunk bodies are stored without their markers.
|
|
124
|
+
let end = start;
|
|
125
|
+
while (end < lines.length && !END.test(lines[end]))
|
|
126
|
+
end++;
|
|
127
|
+
out.push(...lines.slice(cursor, start));
|
|
128
|
+
const decision = byIndex.get(hunk.index);
|
|
129
|
+
if (!decision) {
|
|
130
|
+
out.push(...lines.slice(start, end + 1));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
applied.push(hunk.index);
|
|
134
|
+
if (decision.take === "local")
|
|
135
|
+
out.push(...hunk.local);
|
|
136
|
+
else if (decision.take === "remote")
|
|
137
|
+
out.push(...hunk.remote);
|
|
138
|
+
else if (decision.take === "both")
|
|
139
|
+
out.push(...hunk.local, ...hunk.remote);
|
|
140
|
+
else if (decision.take === "custom")
|
|
141
|
+
out.push(...splitLines(decision.content));
|
|
142
|
+
// "none" drops the hunk entirely.
|
|
143
|
+
}
|
|
144
|
+
cursor = end + 1;
|
|
145
|
+
}
|
|
146
|
+
out.push(...lines.slice(cursor));
|
|
147
|
+
return { text: out.join(lineEnding(text)), applied, unknown, remaining: hunks.length - applied.length };
|
|
148
|
+
}
|
|
149
|
+
/** Truncates a side to a character budget, saying how much was withheld. */
|
|
150
|
+
export function preview(side, maxChars) {
|
|
151
|
+
const text = side.join("\n");
|
|
152
|
+
if (text.length <= maxChars)
|
|
153
|
+
return text;
|
|
154
|
+
const kept = text.slice(0, maxChars);
|
|
155
|
+
const hiddenLines = text.slice(maxChars).split("\n").length;
|
|
156
|
+
return `${kept}\n… [${hiddenLines} more line(s), ${text.length - maxChars} chars withheld]`;
|
|
157
|
+
}
|
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
import type { StorageEngine } from "./storage-engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* A merge and a rebase both leave conflicts in the index, but they invert the
|
|
4
|
+
* meaning of "ours" and "theirs" - so every side-picking decision has to know
|
|
5
|
+
* which one is running.
|
|
6
|
+
*/
|
|
7
|
+
export type SyncOperation = "merge" | "rebase" | "none";
|
|
8
|
+
/** Which side of a conflict to keep, in terms that stay true under both operations. */
|
|
9
|
+
export type ConflictSide = "local" | "remote";
|
|
10
|
+
/** Who last touched a conflicted file on one side, for reporting without reading it. */
|
|
11
|
+
export interface ConflictAuthor {
|
|
12
|
+
author: string;
|
|
13
|
+
date: string;
|
|
14
|
+
/** Commit subject; push() puts the machine name in it. */
|
|
15
|
+
subject: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ConflictedFile {
|
|
18
|
+
/** Path relative to the data directory. */
|
|
19
|
+
path: string;
|
|
20
|
+
kind: "content" | "delete-modify" | "add-add";
|
|
21
|
+
/** For delete-modify: the side that deleted the file. */
|
|
22
|
+
deletedOn?: ConflictSide;
|
|
23
|
+
local?: ConflictAuthor;
|
|
24
|
+
remote?: ConflictAuthor;
|
|
25
|
+
}
|
|
26
|
+
export interface ContinueResult {
|
|
27
|
+
operation: SyncOperation;
|
|
28
|
+
done: boolean;
|
|
29
|
+
/** Files still conflicted - a rebase stops once per replayed commit. */
|
|
30
|
+
remaining: string[];
|
|
31
|
+
/** Set only when the operation neither completed nor left a conflict to explain why. */
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
2
34
|
export interface SyncStatus {
|
|
3
35
|
branch: string;
|
|
36
|
+
operation: SyncOperation;
|
|
4
37
|
ahead: number;
|
|
5
38
|
behind: number;
|
|
6
39
|
dirty: string[];
|
|
@@ -11,13 +44,11 @@ export type PullResult = {
|
|
|
11
44
|
} | {
|
|
12
45
|
status: "updated";
|
|
13
46
|
changed: string[];
|
|
14
|
-
|
|
15
|
-
status: "diverged";
|
|
16
|
-
ahead: number;
|
|
17
|
-
behind: number;
|
|
47
|
+
autoCommitted?: boolean;
|
|
18
48
|
} | {
|
|
19
49
|
status: "conflict";
|
|
20
50
|
conflicted: string[];
|
|
51
|
+
autoCommitted?: boolean;
|
|
21
52
|
};
|
|
22
53
|
export declare class SyncEngine {
|
|
23
54
|
private storage;
|
|
@@ -31,6 +62,13 @@ export declare class SyncEngine {
|
|
|
31
62
|
*/
|
|
32
63
|
private authedUrl;
|
|
33
64
|
private requireConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Registers the structured merge drivers in .git/config, which git never
|
|
67
|
+
* versions - so this runs on every machine, not just the one that created the
|
|
68
|
+
* repo. Values are absolute paths to the shipped scripts; git invokes them
|
|
69
|
+
* through a shell, hence the quoting and the forward slashes on Windows.
|
|
70
|
+
*/
|
|
71
|
+
private ensureMergeDrivers;
|
|
34
72
|
/**
|
|
35
73
|
* Ensures the data dir is a git repo with a .gitignore and an authenticated
|
|
36
74
|
* origin. The token is stored only in .git/config (which git never commits),
|
|
@@ -40,17 +78,84 @@ export declare class SyncEngine {
|
|
|
40
78
|
ensureRepo(): Promise<void>;
|
|
41
79
|
status(): Promise<SyncStatus>;
|
|
42
80
|
/**
|
|
43
|
-
* Defensive pull
|
|
44
|
-
*
|
|
81
|
+
* Defensive pull. A clean tree that is purely behind fast-forwards; a
|
|
82
|
+
* divergent one is rebased, so local commits replay on top of the remote and
|
|
83
|
+
* the history stays linear - which is what makes per-doc `git log` attribution
|
|
84
|
+
* readable when reporting who changed what. An uncommitted local change is
|
|
85
|
+
* never risked: the pull reports the divergence and applies nothing.
|
|
45
86
|
*/
|
|
46
87
|
pull(): Promise<PullResult>;
|
|
47
88
|
private diffNames;
|
|
89
|
+
/**
|
|
90
|
+
* Stages and commits whatever the working tree holds. Committing is what makes
|
|
91
|
+
* local edits safe to rebase over, so both push and pull go through here
|
|
92
|
+
* rather than asking the caller to tidy up first.
|
|
93
|
+
*
|
|
94
|
+
* .gitignore (written by ensureRepo) excludes all derived and machine-local
|
|
95
|
+
* state, so `add -A` only ever stages versioned files.
|
|
96
|
+
*/
|
|
97
|
+
private commitLocalChanges;
|
|
48
98
|
/** Stages versioned files, commits if there is anything to commit, and pushes. */
|
|
49
99
|
push(message?: string): Promise<{
|
|
50
100
|
pushed: boolean;
|
|
51
101
|
committed: boolean;
|
|
52
102
|
message: string;
|
|
53
103
|
}>;
|
|
54
|
-
/**
|
|
55
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Detects whether a merge or a rebase is mid-flight. Read through
|
|
106
|
+
* `rev-parse --git-path` rather than assuming `.git` is a directory, so this
|
|
107
|
+
* still works in a worktree or a submodule.
|
|
108
|
+
*/
|
|
109
|
+
operationInProgress(): Promise<SyncOperation>;
|
|
110
|
+
/** Index stages recorded for a conflicted path: 1 = base, 2 = ours, 3 = theirs. */
|
|
111
|
+
private conflictStages;
|
|
112
|
+
/**
|
|
113
|
+
* Finishes the in-flight merge or rebase once every conflict is staged.
|
|
114
|
+
* A rebase can stop again on the next replayed commit, so the caller is told
|
|
115
|
+
* what is still outstanding rather than being promised completion.
|
|
116
|
+
*
|
|
117
|
+
* `git rebase --continue` insists on an editor for the replayed commit
|
|
118
|
+
* message, and simple-git blocks both `-c core.editor` and GIT_EDITOR as
|
|
119
|
+
* injection vectors. This one command therefore goes out directly with a no-op
|
|
120
|
+
* editor - the value is a fixed literal here, never user input.
|
|
121
|
+
*/
|
|
122
|
+
continueOperation(): Promise<ContinueResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Runs one git command outside simple-git, which rejects a handful of config
|
|
125
|
+
* keys and environment variables as injection vectors - merge.*.driver and
|
|
126
|
+
* GIT_EDITOR among them. Everything passed here is a fixed literal or a path
|
|
127
|
+
* derived from the install location, never agent or user input.
|
|
128
|
+
*/
|
|
129
|
+
private gitDirect;
|
|
130
|
+
/**
|
|
131
|
+
* The refs holding each side during the operation in flight. A rebase replays
|
|
132
|
+
* our commits onto the remote, so HEAD is the *remote* there - the mapping
|
|
133
|
+
* that makes every side label absolute.
|
|
134
|
+
*/
|
|
135
|
+
private sideRefs;
|
|
136
|
+
private lastCommitFor;
|
|
137
|
+
/**
|
|
138
|
+
* Every conflicted file with its shape and its two authors - enough for the
|
|
139
|
+
* agent to decide what to look at without opening a single document.
|
|
140
|
+
*/
|
|
141
|
+
listConflicts(): Promise<{
|
|
142
|
+
operation: SyncOperation;
|
|
143
|
+
files: ConflictedFile[];
|
|
144
|
+
}>;
|
|
145
|
+
/** Reads a conflicted file from the working tree, refusing to escape the data dir. */
|
|
146
|
+
readWorkingFile(relativePath: string): string;
|
|
147
|
+
/** Writes a resolved file back and stages it when nothing is left conflicted in it. */
|
|
148
|
+
writeResolvedFile(relativePath: string, content: string, stage: boolean): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Bulk-resolve conflicts by keeping one side, then stage the result.
|
|
151
|
+
*
|
|
152
|
+
* The git flag depends on the operation in flight: a merge replays the remote
|
|
153
|
+
* onto our branch (--ours = local), while a rebase replays our commits onto
|
|
154
|
+
* the remote (--ours = remote). Picking the flag from the strategy alone would
|
|
155
|
+
* silently keep the wrong side under rebase.
|
|
156
|
+
*/
|
|
157
|
+
resolveConflict(side: ConflictSide, paths?: string[]): Promise<{
|
|
158
|
+
resolved: string[];
|
|
159
|
+
operation: SyncOperation;
|
|
160
|
+
}>;
|
|
56
161
|
}
|