@mandipadk7/kavi 0.1.0 → 0.1.2
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/README.md +25 -7
- package/dist/adapters/claude.js +136 -13
- package/dist/adapters/codex.js +235 -30
- package/dist/adapters/shared.js +35 -0
- package/dist/approvals.js +72 -1
- package/dist/codex-app-server.js +310 -0
- package/dist/command-queue.js +1 -0
- package/dist/daemon.js +446 -5
- package/dist/decision-ledger.js +75 -0
- package/dist/git.js +171 -0
- package/dist/main.js +251 -36
- package/dist/paths.js +1 -1
- package/dist/prompts.js +13 -0
- package/dist/router.js +190 -5
- package/dist/rpc.js +226 -0
- package/dist/runtime.js +4 -1
- package/dist/session.js +10 -1
- package/dist/task-artifacts.js +10 -2
- package/dist/tui.js +1653 -72
- package/package.json +7 -12
package/dist/git.js
CHANGED
|
@@ -51,6 +51,53 @@ export async function getBranchCommit(repoRoot, ref) {
|
|
|
51
51
|
}
|
|
52
52
|
return result.stdout.trim();
|
|
53
53
|
}
|
|
54
|
+
function parsePathList(output) {
|
|
55
|
+
return output.split(/\r?\n/).map((line)=>line.trim()).filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
function uniqueSorted(values) {
|
|
58
|
+
return [
|
|
59
|
+
...new Set(values)
|
|
60
|
+
].sort();
|
|
61
|
+
}
|
|
62
|
+
async function isUntrackedPath(worktreePath, filePath) {
|
|
63
|
+
const result = await runCommand("git", [
|
|
64
|
+
"ls-files",
|
|
65
|
+
"--others",
|
|
66
|
+
"--exclude-standard",
|
|
67
|
+
"--",
|
|
68
|
+
filePath
|
|
69
|
+
], {
|
|
70
|
+
cwd: worktreePath
|
|
71
|
+
});
|
|
72
|
+
if (result.code !== 0) {
|
|
73
|
+
throw new Error(result.stderr.trim() || `Unable to inspect untracked status for ${filePath}.`);
|
|
74
|
+
}
|
|
75
|
+
return parsePathList(result.stdout).includes(filePath);
|
|
76
|
+
}
|
|
77
|
+
async function buildSyntheticAddedFilePatch(worktreePath, filePath) {
|
|
78
|
+
const absolutePath = path.join(worktreePath, filePath);
|
|
79
|
+
const content = await fs.readFile(absolutePath, "utf8");
|
|
80
|
+
const normalized = content.replaceAll("\r", "");
|
|
81
|
+
const endsWithNewline = normalized.endsWith("\n");
|
|
82
|
+
const lines = normalized.length === 0 ? [] : normalized.replace(/\n$/, "").split("\n");
|
|
83
|
+
const patchLines = [
|
|
84
|
+
`diff --git a/${filePath} b/${filePath}`,
|
|
85
|
+
"new file mode 100644",
|
|
86
|
+
"--- /dev/null",
|
|
87
|
+
`+++ b/${filePath}`
|
|
88
|
+
];
|
|
89
|
+
if (lines.length > 0) {
|
|
90
|
+
patchLines.push(`@@ -0,0 +1,${lines.length} @@`);
|
|
91
|
+
patchLines.push(...lines.map((line)=>`+${line}`));
|
|
92
|
+
if (!endsWithNewline) {
|
|
93
|
+
patchLines.push("\");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
stat: lines.length > 0 ? `new file | ${lines.length} insertion${lines.length === 1 ? "" : "s"}(+)` : "new file | empty",
|
|
98
|
+
patch: patchLines.join("\n")
|
|
99
|
+
};
|
|
100
|
+
}
|
|
54
101
|
export async function resolveTargetBranch(repoRoot, configuredBranch) {
|
|
55
102
|
const exists = await runCommand("git", [
|
|
56
103
|
"show-ref",
|
|
@@ -149,6 +196,130 @@ export async function createGitignoreEntries(repoRoot) {
|
|
|
149
196
|
const prefix = content.trimEnd() ? "\n" : "";
|
|
150
197
|
await fs.writeFile(gitignorePath, `${content.trimEnd()}${prefix}${missing.join("\n")}\n`, "utf8");
|
|
151
198
|
}
|
|
199
|
+
export async function listWorktreeChangedPaths(worktreePath, baseCommit) {
|
|
200
|
+
const [committed, staged, unstaged, untracked] = await Promise.all([
|
|
201
|
+
runCommand("git", [
|
|
202
|
+
"diff",
|
|
203
|
+
"--name-only",
|
|
204
|
+
`${baseCommit}..HEAD`
|
|
205
|
+
], {
|
|
206
|
+
cwd: worktreePath
|
|
207
|
+
}),
|
|
208
|
+
runCommand("git", [
|
|
209
|
+
"diff",
|
|
210
|
+
"--name-only",
|
|
211
|
+
"--cached"
|
|
212
|
+
], {
|
|
213
|
+
cwd: worktreePath
|
|
214
|
+
}),
|
|
215
|
+
runCommand("git", [
|
|
216
|
+
"diff",
|
|
217
|
+
"--name-only"
|
|
218
|
+
], {
|
|
219
|
+
cwd: worktreePath
|
|
220
|
+
}),
|
|
221
|
+
runCommand("git", [
|
|
222
|
+
"ls-files",
|
|
223
|
+
"--others",
|
|
224
|
+
"--exclude-standard"
|
|
225
|
+
], {
|
|
226
|
+
cwd: worktreePath
|
|
227
|
+
})
|
|
228
|
+
]);
|
|
229
|
+
const outputs = [
|
|
230
|
+
committed,
|
|
231
|
+
staged,
|
|
232
|
+
unstaged,
|
|
233
|
+
untracked
|
|
234
|
+
];
|
|
235
|
+
const failures = outputs.filter((result)=>result.code !== 0);
|
|
236
|
+
if (failures.length > 0) {
|
|
237
|
+
throw new Error(failures.map((result)=>result.stderr.trim() || "Unable to inspect worktree changes.").join("\n"));
|
|
238
|
+
}
|
|
239
|
+
return uniqueSorted([
|
|
240
|
+
...parsePathList(committed.stdout),
|
|
241
|
+
...parsePathList(staged.stdout),
|
|
242
|
+
...parsePathList(unstaged.stdout),
|
|
243
|
+
...parsePathList(untracked.stdout)
|
|
244
|
+
]);
|
|
245
|
+
}
|
|
246
|
+
export async function getWorktreeDiffReview(agent, worktreePath, baseCommit, filePath) {
|
|
247
|
+
const changedPaths = await listWorktreeChangedPaths(worktreePath, baseCommit);
|
|
248
|
+
const selectedPath = filePath && changedPaths.includes(filePath) ? filePath : changedPaths[0] ?? null;
|
|
249
|
+
if (!selectedPath) {
|
|
250
|
+
return {
|
|
251
|
+
agent,
|
|
252
|
+
changedPaths,
|
|
253
|
+
selectedPath: null,
|
|
254
|
+
stat: "No changed files in this worktree.",
|
|
255
|
+
patch: ""
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (await isUntrackedPath(worktreePath, selectedPath)) {
|
|
259
|
+
const synthetic = await buildSyntheticAddedFilePatch(worktreePath, selectedPath);
|
|
260
|
+
return {
|
|
261
|
+
agent,
|
|
262
|
+
changedPaths,
|
|
263
|
+
selectedPath,
|
|
264
|
+
stat: synthetic.stat,
|
|
265
|
+
patch: synthetic.patch
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const [statResult, patchResult] = await Promise.all([
|
|
269
|
+
runCommand("git", [
|
|
270
|
+
"diff",
|
|
271
|
+
"--stat",
|
|
272
|
+
"--find-renames",
|
|
273
|
+
baseCommit,
|
|
274
|
+
"--",
|
|
275
|
+
selectedPath
|
|
276
|
+
], {
|
|
277
|
+
cwd: worktreePath
|
|
278
|
+
}),
|
|
279
|
+
runCommand("git", [
|
|
280
|
+
"diff",
|
|
281
|
+
"--find-renames",
|
|
282
|
+
"--unified=3",
|
|
283
|
+
baseCommit,
|
|
284
|
+
"--",
|
|
285
|
+
selectedPath
|
|
286
|
+
], {
|
|
287
|
+
cwd: worktreePath
|
|
288
|
+
})
|
|
289
|
+
]);
|
|
290
|
+
if (statResult.code !== 0) {
|
|
291
|
+
throw new Error(statResult.stderr.trim() || `Unable to build diff stat for ${selectedPath}.`);
|
|
292
|
+
}
|
|
293
|
+
if (patchResult.code !== 0) {
|
|
294
|
+
throw new Error(patchResult.stderr.trim() || `Unable to build diff patch for ${selectedPath}.`);
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
agent,
|
|
298
|
+
changedPaths,
|
|
299
|
+
selectedPath,
|
|
300
|
+
stat: statResult.stdout.trim() || "No diff stat available.",
|
|
301
|
+
patch: patchResult.stdout.trim() || "No textual patch available."
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
export async function findOverlappingWorktreePaths(worktrees, baseCommit) {
|
|
305
|
+
const pathSets = await Promise.all(worktrees.map(async (worktree)=>({
|
|
306
|
+
agent: worktree.agent,
|
|
307
|
+
paths: await listWorktreeChangedPaths(worktree.path, baseCommit)
|
|
308
|
+
})));
|
|
309
|
+
const overlaps = [];
|
|
310
|
+
for(let index = 0; index < pathSets.length; index += 1){
|
|
311
|
+
const current = pathSets[index];
|
|
312
|
+
const rest = pathSets.slice(index + 1);
|
|
313
|
+
for (const other of rest){
|
|
314
|
+
for (const filePath of current.paths){
|
|
315
|
+
if (other.paths.includes(filePath)) {
|
|
316
|
+
overlaps.push(filePath);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return uniqueSorted(overlaps);
|
|
322
|
+
}
|
|
152
323
|
export async function landBranches(repoRoot, targetBranch, worktrees, validationCommand, sessionId, integrationRoot) {
|
|
153
324
|
const commandsRun = [];
|
|
154
325
|
const snapshotCommits = [];
|