xab 4.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +97 -22
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -531,11 +531,18 @@ ${opts.applicationStrategy}
|
|
|
531
531
|
- If the target already has a different version of the same logic, merge both intents
|
|
532
532
|
- Preserve the target's existing improvements \u2014 do not regress
|
|
533
533
|
- Create or modify files as needed; delete files if the source commit deleted them
|
|
534
|
-
- After applying, run exactly: git add -A && git commit -m "${commitMsg.replace(/"/g, "\\\"")}"
|
|
535
|
-
- You MUST create exactly ONE commit. Not zero, not two.
|
|
536
534
|
- No conflict markers, dead code, or TODO placeholders
|
|
537
535
|
- If impossible to apply cleanly, explain why in notes
|
|
538
536
|
|
|
537
|
+
## CRITICAL \u2014 you MUST commit your changes
|
|
538
|
+
After making all file changes, you MUST run these two commands as your FINAL action:
|
|
539
|
+
|
|
540
|
+
git add -A
|
|
541
|
+
git commit -m "${commitMsg.replace(/"/g, "\\\"")}"
|
|
542
|
+
|
|
543
|
+
If you do not run both commands, your work will be discarded. This is not optional.
|
|
544
|
+
The validation system checks for exactly one new git commit. Zero commits = failure.
|
|
545
|
+
|
|
539
546
|
Report what you did.`;
|
|
540
547
|
const firstPrompt = `${MERGE_PREAMBLE}
|
|
541
548
|
${opts.repoContext ? `## Repository context
|
|
@@ -605,9 +612,16 @@ ${opts.reviewIssues.map((issue, i) => `${i + 1}. ${issue}`).join(`
|
|
|
605
612
|
- Read the affected files to understand the current state
|
|
606
613
|
- Fix every issue the reviewer raised
|
|
607
614
|
- Do NOT introduce new problems while fixing
|
|
608
|
-
- After fixing, amend the commit: git add -A && git commit --amend -m "${commitMsg.replace(/"/g, "\\\"")}"
|
|
609
615
|
- The result must be a single clean commit with no issues
|
|
610
616
|
|
|
617
|
+
## CRITICAL \u2014 you MUST amend the commit after fixing
|
|
618
|
+
After making all fixes, you MUST run these two commands as your FINAL action:
|
|
619
|
+
|
|
620
|
+
git add -A
|
|
621
|
+
git commit --amend -m "${commitMsg.replace(/"/g, "\\\"")}"
|
|
622
|
+
|
|
623
|
+
If you do not run both commands, your fixes will be discarded. This is not optional.
|
|
624
|
+
|
|
611
625
|
Report what you fixed.`;
|
|
612
626
|
const turn = await thread.run(prompt, { outputSchema: applyResultSchema });
|
|
613
627
|
return parseJson(turn.finalResponse, {
|
|
@@ -1166,17 +1180,17 @@ async function validateApply(worktreeGit, beforeHash) {
|
|
|
1166
1180
|
const notAdded = status.not_added.filter((f) => !isOurs(f));
|
|
1167
1181
|
const conflicted = status.conflicted.filter((f) => !isOurs(f));
|
|
1168
1182
|
const worktreeClean = modified.length === 0 && created.length === 0 && deleted.length === 0 && conflicted.length === 0 && notAdded.length === 0;
|
|
1183
|
+
const dirtyFiles = [];
|
|
1169
1184
|
if (!worktreeClean) {
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
errors.push(`Working tree not clean: ${parts.join(", ")}`);
|
|
1185
|
+
for (const f of modified)
|
|
1186
|
+
dirtyFiles.push(`M ${f}`);
|
|
1187
|
+
for (const f of notAdded)
|
|
1188
|
+
dirtyFiles.push(`? ${f}`);
|
|
1189
|
+
for (const f of deleted)
|
|
1190
|
+
dirtyFiles.push(`D ${f}`);
|
|
1191
|
+
for (const f of conflicted)
|
|
1192
|
+
dirtyFiles.push(`C ${f}`);
|
|
1193
|
+
errors.push(`Working tree not clean (${dirtyFiles.length} files): ${dirtyFiles.join(", ")}`);
|
|
1180
1194
|
}
|
|
1181
1195
|
const conflictMarkers = [];
|
|
1182
1196
|
if (newCommitHash) {
|
|
@@ -1196,7 +1210,15 @@ async function validateApply(worktreeGit, beforeHash) {
|
|
|
1196
1210
|
if (conflictMarkers.length > 0) {
|
|
1197
1211
|
errors.push(`Conflict markers in: ${conflictMarkers.join(", ")}`);
|
|
1198
1212
|
}
|
|
1199
|
-
return {
|
|
1213
|
+
return {
|
|
1214
|
+
valid: errors.length === 0,
|
|
1215
|
+
newCommitHash,
|
|
1216
|
+
newCommitCount,
|
|
1217
|
+
worktreeClean,
|
|
1218
|
+
conflictMarkers,
|
|
1219
|
+
dirtyFiles,
|
|
1220
|
+
errors
|
|
1221
|
+
};
|
|
1200
1222
|
}
|
|
1201
1223
|
async function getAppliedDiff(worktreeGit, beforeHash) {
|
|
1202
1224
|
return worktreeGit.raw(["diff", beforeHash, "HEAD"]);
|
|
@@ -1552,6 +1574,11 @@ async function processOneCommit(o) {
|
|
|
1552
1574
|
const validation = await validateApply(o.wtGit, headBefore);
|
|
1553
1575
|
if (!validation.valid) {
|
|
1554
1576
|
cb.onLog(`Validation failed: ${validation.errors.join("; ")}`, "red");
|
|
1577
|
+
if (validation.dirtyFiles.length > 0) {
|
|
1578
|
+
for (const f of validation.dirtyFiles) {
|
|
1579
|
+
cb.onLog(` ${f}`, "red");
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1555
1582
|
await resetHard(o.wtGit, headBefore);
|
|
1556
1583
|
if (attempt === o.maxAttempts)
|
|
1557
1584
|
return mkFailed(commit, "validation", validation.errors.join("; "), start);
|
|
@@ -1751,6 +1778,16 @@ __export(exports_batch, {
|
|
|
1751
1778
|
runBatch: () => runBatch
|
|
1752
1779
|
});
|
|
1753
1780
|
import chalk from "chalk";
|
|
1781
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
1782
|
+
import { join as join6 } from "path";
|
|
1783
|
+
function getVersion() {
|
|
1784
|
+
try {
|
|
1785
|
+
const pkg = JSON.parse(readFileSync5(join6(import.meta.dir, "..", "package.json"), "utf-8"));
|
|
1786
|
+
return pkg.version ?? "?";
|
|
1787
|
+
} catch {
|
|
1788
|
+
return "?";
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1754
1791
|
function shortHash2(h) {
|
|
1755
1792
|
return h.slice(0, 8);
|
|
1756
1793
|
}
|
|
@@ -1806,8 +1843,9 @@ function emitJsonl(obj) {
|
|
|
1806
1843
|
async function runBatch(opts) {
|
|
1807
1844
|
const jsonl = opts.jsonl ?? false;
|
|
1808
1845
|
const startTime = Date.now();
|
|
1846
|
+
const version = getVersion();
|
|
1809
1847
|
log("");
|
|
1810
|
-
log(` ${chalk.cyan.bold("xab")} ${chalk.dim("\u2014 curated branch reconciliation")}`);
|
|
1848
|
+
log(` ${chalk.cyan.bold("xab")} ${chalk.dim(`v${version}`)} ${chalk.dim("\u2014 curated branch reconciliation")}`);
|
|
1811
1849
|
log(` ${chalk.magenta(opts.sourceRef)} ${chalk.dim("\u2192")} ${chalk.green(opts.targetRef)}`);
|
|
1812
1850
|
if (opts.workBranch)
|
|
1813
1851
|
log(` ${chalk.dim("work branch:")} ${chalk.cyan(opts.workBranch)}`);
|
|
@@ -1844,7 +1882,13 @@ async function runBatch(opts) {
|
|
|
1844
1882
|
if (jsonl)
|
|
1845
1883
|
emitJsonl({ event: "analysis", hash: commit.hash, result: analysis });
|
|
1846
1884
|
log(` ${ts()} ${chalk.dim("analysis:")} ${analysisBadge(analysis.alreadyInTarget)}`);
|
|
1847
|
-
log(` ${chalk.dim(" summary:")} ${analysis.summary
|
|
1885
|
+
log(` ${chalk.dim(" summary:")} ${analysis.summary}`);
|
|
1886
|
+
if (analysis.reasoning) {
|
|
1887
|
+
log(` ${chalk.dim(" reasoning:")} ${analysis.reasoning}`);
|
|
1888
|
+
}
|
|
1889
|
+
if (analysis.applicationStrategy && analysis.alreadyInTarget !== "yes") {
|
|
1890
|
+
log(` ${chalk.dim(" strategy:")} ${analysis.applicationStrategy}`);
|
|
1891
|
+
}
|
|
1848
1892
|
if (analysis.affectedComponents.length > 0) {
|
|
1849
1893
|
log(` ${chalk.dim(" components:")} ${analysis.affectedComponents.join(", ")}`);
|
|
1850
1894
|
}
|
|
@@ -1863,13 +1907,24 @@ async function runBatch(opts) {
|
|
|
1863
1907
|
});
|
|
1864
1908
|
const duration = chalk.dim(`${(decision.durationMs / 1000).toFixed(1)}s`);
|
|
1865
1909
|
log(` ${ts()} ${decisionBadge(decision.kind)} ${duration}`);
|
|
1910
|
+
if (decision.newCommitHash) {
|
|
1911
|
+
log(` ${chalk.dim(" commit:")} ${decision.newCommitHash.slice(0, 8)}`);
|
|
1912
|
+
}
|
|
1866
1913
|
if (decision.kind === "failed" && decision.error) {
|
|
1867
|
-
log(` ${chalk.red(` error: ${decision.error
|
|
1914
|
+
log(` ${chalk.red(` error: ${decision.error}`)}`);
|
|
1915
|
+
}
|
|
1916
|
+
if (decision.reason && decision.kind !== "failed") {
|
|
1917
|
+
log(` ${chalk.dim(" reason:")} ${decision.reason}`);
|
|
1868
1918
|
}
|
|
1869
1919
|
if (decision.filesChanged && decision.filesChanged.length > 0) {
|
|
1870
|
-
const
|
|
1871
|
-
|
|
1872
|
-
|
|
1920
|
+
for (const f of decision.filesChanged) {
|
|
1921
|
+
log(` ${chalk.dim(` \xB7 ${f}`)}`);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
if (decision.opsNotes && decision.opsNotes.length > 0) {
|
|
1925
|
+
for (const note of decision.opsNotes) {
|
|
1926
|
+
log(` ${chalk.yellow(` ops: ${note}`)}`);
|
|
1927
|
+
}
|
|
1873
1928
|
}
|
|
1874
1929
|
},
|
|
1875
1930
|
onReview(commit, review) {
|
|
@@ -1984,7 +2039,16 @@ import { useState, useEffect, useCallback, useRef } from "react";
|
|
|
1984
2039
|
import { Box, Text, useInput, useApp, Static, Newline } from "ink";
|
|
1985
2040
|
import SelectInput from "ink-select-input";
|
|
1986
2041
|
import Spinner from "ink-spinner";
|
|
2042
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
2043
|
+
import { join as join5 } from "path";
|
|
1987
2044
|
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
2045
|
+
var XAB_VERSION = (() => {
|
|
2046
|
+
try {
|
|
2047
|
+
return JSON.parse(readFileSync4(join5(import.meta.dir, "..", "package.json"), "utf-8")).version ?? "?";
|
|
2048
|
+
} catch {
|
|
2049
|
+
return "?";
|
|
2050
|
+
}
|
|
2051
|
+
})();
|
|
1988
2052
|
function shortHash(h) {
|
|
1989
2053
|
return h.slice(0, 8);
|
|
1990
2054
|
}
|
|
@@ -2009,8 +2073,15 @@ function Header({
|
|
|
2009
2073
|
/* @__PURE__ */ jsxDEV(Text, {
|
|
2010
2074
|
bold: true,
|
|
2011
2075
|
color: "cyan",
|
|
2012
|
-
children: "\u256D\u2500
|
|
2076
|
+
children: "\u256D\u2500 xab"
|
|
2013
2077
|
}, undefined, false, undefined, this),
|
|
2078
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
2079
|
+
dimColor: true,
|
|
2080
|
+
children: [
|
|
2081
|
+
" v",
|
|
2082
|
+
XAB_VERSION
|
|
2083
|
+
]
|
|
2084
|
+
}, undefined, true, undefined, this),
|
|
2014
2085
|
/* @__PURE__ */ jsxDEV(Text, {
|
|
2015
2086
|
color: "gray",
|
|
2016
2087
|
children: " \u2014 curated branch reconciliation"
|
|
@@ -2782,8 +2853,12 @@ for (let i = 0;i < args.length; i++) {
|
|
|
2782
2853
|
repoPath = arg;
|
|
2783
2854
|
}
|
|
2784
2855
|
if (showHelp) {
|
|
2856
|
+
let version = "?";
|
|
2857
|
+
try {
|
|
2858
|
+
version = JSON.parse(await Bun.file(new URL("./package.json", import.meta.url).pathname).text()).version;
|
|
2859
|
+
} catch {}
|
|
2785
2860
|
console.log(`
|
|
2786
|
-
xab \u2014 AI-powered curated branch reconciliation
|
|
2861
|
+
xab v${version} \u2014 AI-powered curated branch reconciliation
|
|
2787
2862
|
|
|
2788
2863
|
Usage:
|
|
2789
2864
|
xab [repo-path] [options]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xab",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "AI-powered curated branch reconciliation engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"ink-spinner": "^5.0.0",
|
|
33
33
|
"ink-text-input": "^6.0.0",
|
|
34
34
|
"react": "18.3.1",
|
|
35
|
-
"simple-git": "^3.33.0"
|
|
35
|
+
"simple-git": "^3.33.0",
|
|
36
|
+
"xab": "^5.0.0"
|
|
36
37
|
}
|
|
37
38
|
}
|