@cogit/cli 0.23.2 → 0.24.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.
|
@@ -43,8 +43,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
43
43
|
|
|
44
44
|
// src/git-hooks.ts
|
|
45
45
|
import { realpathSync } from "fs";
|
|
46
|
-
import { chmod, mkdir as mkdir5, readFile as readFile5, rm as rm3, stat as
|
|
47
|
-
import { join as
|
|
46
|
+
import { chmod, mkdir as mkdir5, readFile as readFile5, rm as rm3, stat as stat6 } from "fs/promises";
|
|
47
|
+
import { join as join8 } from "path";
|
|
48
48
|
|
|
49
49
|
// src/git.ts
|
|
50
50
|
import { execFile } from "child_process";
|
|
@@ -20951,25 +20951,107 @@ async function writeProjectSetup(root) {
|
|
|
20951
20951
|
}
|
|
20952
20952
|
|
|
20953
20953
|
// src/agents/claude/transcripts.ts
|
|
20954
|
-
import { createReadStream } from "fs";
|
|
20955
|
-
import { access, open as open3, readdir as
|
|
20954
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
20955
|
+
import { access, open as open3, readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
20956
20956
|
import { homedir as homedir3 } from "os";
|
|
20957
|
-
import { join as
|
|
20957
|
+
import { join as join7 } from "path";
|
|
20958
|
+
import { createInterface as createInterface2 } from "readline";
|
|
20959
|
+
|
|
20960
|
+
// src/agents/claude/fork.ts
|
|
20961
|
+
import { createReadStream } from "fs";
|
|
20962
|
+
import { readdir as readdir2, stat as stat4 } from "fs/promises";
|
|
20963
|
+
import { basename as basename2, dirname as dirname4, join as join6 } from "path";
|
|
20958
20964
|
import { createInterface } from "readline";
|
|
20965
|
+
var MAX_DEPTH = 8;
|
|
20966
|
+
var USER_LINE = /"type":"user"/;
|
|
20967
|
+
var LINE_UUID = /"uuid":"([^"]+)"/;
|
|
20968
|
+
var firstUuids = /* @__PURE__ */ new Map();
|
|
20969
|
+
async function firstMessageUuid(file2, isMessage) {
|
|
20970
|
+
const known = firstUuids.get(file2);
|
|
20971
|
+
if (known !== void 0) return known;
|
|
20972
|
+
const input2 = createReadStream(file2, "utf8");
|
|
20973
|
+
const lines = createInterface({ input: input2, crlfDelay: Infinity });
|
|
20974
|
+
let found = null;
|
|
20975
|
+
try {
|
|
20976
|
+
for await (const raw of lines) {
|
|
20977
|
+
if (!USER_LINE.test(raw)) continue;
|
|
20978
|
+
const line = parseLine(raw);
|
|
20979
|
+
if (line === null || !isMessage(line)) continue;
|
|
20980
|
+
found = LINE_UUID.exec(raw)?.[1] ?? null;
|
|
20981
|
+
break;
|
|
20982
|
+
}
|
|
20983
|
+
} finally {
|
|
20984
|
+
lines.close();
|
|
20985
|
+
input2.destroy();
|
|
20986
|
+
}
|
|
20987
|
+
if (found !== null) firstUuids.set(file2, found);
|
|
20988
|
+
return found;
|
|
20989
|
+
}
|
|
20990
|
+
function parseLine(raw) {
|
|
20991
|
+
try {
|
|
20992
|
+
return JSON.parse(raw);
|
|
20993
|
+
} catch {
|
|
20994
|
+
return null;
|
|
20995
|
+
}
|
|
20996
|
+
}
|
|
20997
|
+
async function bornAt(file2) {
|
|
20998
|
+
const birth = (await stat4(file2).catch(() => null))?.birthtimeMs ?? 0;
|
|
20999
|
+
return birth > 0 ? birth : null;
|
|
21000
|
+
}
|
|
21001
|
+
function sharedPrefix(a, b) {
|
|
21002
|
+
let count = 0;
|
|
21003
|
+
while (count < a.length && count < b.length) {
|
|
21004
|
+
const uuid3 = a[count]?.uuid;
|
|
21005
|
+
if (uuid3 === void 0 || uuid3 !== b[count]?.uuid) break;
|
|
21006
|
+
count++;
|
|
21007
|
+
}
|
|
21008
|
+
return count;
|
|
21009
|
+
}
|
|
21010
|
+
async function forkOrigin(file2, turns, readTurns, isMessage, depth = 0) {
|
|
21011
|
+
const first = turns[0];
|
|
21012
|
+
if (first?.uuid === void 0 || depth > MAX_DEPTH) return null;
|
|
21013
|
+
const born = await bornAt(file2);
|
|
21014
|
+
const dir = dirname4(file2);
|
|
21015
|
+
const names = (await readdir2(dir).catch(() => [])).filter(
|
|
21016
|
+
(name) => name.endsWith(".jsonl")
|
|
21017
|
+
);
|
|
21018
|
+
let best = null;
|
|
21019
|
+
for (const name of names) {
|
|
21020
|
+
const other = join6(dir, name);
|
|
21021
|
+
if (other === file2) continue;
|
|
21022
|
+
if (await firstMessageUuid(other, isMessage).catch(() => null) !== first.uuid) continue;
|
|
21023
|
+
const otherBorn = await bornAt(other) ?? 0;
|
|
21024
|
+
if (born !== null && otherBorn >= born) continue;
|
|
21025
|
+
const shared = sharedPrefix(turns, await readTurns(other).catch(() => []));
|
|
21026
|
+
if (shared > 0 && (best === null || shared > best.shared || shared === best.shared && otherBorn > best.born))
|
|
21027
|
+
best = { file: other, shared, born: otherBorn };
|
|
21028
|
+
}
|
|
21029
|
+
if (best === null) return null;
|
|
21030
|
+
const last = turns[best.shared - 1];
|
|
21031
|
+
if (last?.uuid === void 0) return null;
|
|
21032
|
+
const copy = { uuid: last.uuid, at: last.at, text: last.text };
|
|
21033
|
+
const parentTurns = await readTurns(best.file).catch(() => null);
|
|
21034
|
+
const deeper = parentTurns ? await forkOrigin(best.file, parentTurns, readTurns, isMessage, depth + 1) : null;
|
|
21035
|
+
if (deeper && best.shared <= deeper.copied)
|
|
21036
|
+
return { sessionId: deeper.sessionId, copied: best.shared, last: copy };
|
|
21037
|
+
return { sessionId: basename2(best.file, ".jsonl"), copied: best.shared, last: copy };
|
|
21038
|
+
}
|
|
21039
|
+
|
|
21040
|
+
// src/agents/claude/transcripts.ts
|
|
20959
21041
|
function claudeConfigDir(env = process.env) {
|
|
20960
|
-
return env.CLAUDE_CONFIG_DIR ??
|
|
21042
|
+
return env.CLAUDE_CONFIG_DIR ?? join7(homedir3(), ".claude");
|
|
20961
21043
|
}
|
|
20962
21044
|
async function findTranscript(sessionId, env = process.env) {
|
|
20963
|
-
const projectsDir =
|
|
21045
|
+
const projectsDir = join7(claudeConfigDir(env), "projects");
|
|
20964
21046
|
let dirs;
|
|
20965
21047
|
try {
|
|
20966
|
-
dirs = await
|
|
21048
|
+
dirs = await readdir3(projectsDir, { withFileTypes: true });
|
|
20967
21049
|
} catch {
|
|
20968
21050
|
return null;
|
|
20969
21051
|
}
|
|
20970
21052
|
for (const dir of dirs) {
|
|
20971
21053
|
if (!dir.isDirectory()) continue;
|
|
20972
|
-
const file2 =
|
|
21054
|
+
const file2 = join7(projectsDir, dir.name, `${sessionId}.jsonl`);
|
|
20973
21055
|
try {
|
|
20974
21056
|
await access(file2);
|
|
20975
21057
|
return file2;
|
|
@@ -20980,24 +21062,24 @@ async function findTranscript(sessionId, env = process.env) {
|
|
|
20980
21062
|
}
|
|
20981
21063
|
async function collectTranscripts(env = process.env) {
|
|
20982
21064
|
const found = /* @__PURE__ */ new Map();
|
|
20983
|
-
const projectsDir =
|
|
21065
|
+
const projectsDir = join7(claudeConfigDir(env), "projects");
|
|
20984
21066
|
let projectDirs;
|
|
20985
21067
|
try {
|
|
20986
|
-
projectDirs = await
|
|
21068
|
+
projectDirs = await readdir3(projectsDir, { withFileTypes: true });
|
|
20987
21069
|
} catch {
|
|
20988
21070
|
return found;
|
|
20989
21071
|
}
|
|
20990
21072
|
for (const entry of projectDirs) {
|
|
20991
21073
|
if (!entry.isDirectory()) continue;
|
|
20992
|
-
const dir =
|
|
21074
|
+
const dir = join7(projectsDir, entry.name);
|
|
20993
21075
|
let files;
|
|
20994
21076
|
try {
|
|
20995
|
-
files = await
|
|
21077
|
+
files = await readdir3(dir);
|
|
20996
21078
|
} catch {
|
|
20997
21079
|
continue;
|
|
20998
21080
|
}
|
|
20999
21081
|
for (const file2 of files) {
|
|
21000
|
-
if (file2.endsWith(".jsonl")) found.set(file2.slice(0, -".jsonl".length),
|
|
21082
|
+
if (file2.endsWith(".jsonl")) found.set(file2.slice(0, -".jsonl".length), join7(dir, file2));
|
|
21001
21083
|
}
|
|
21002
21084
|
}
|
|
21003
21085
|
return found;
|
|
@@ -21067,7 +21149,7 @@ function displayTurn(turn, roots) {
|
|
|
21067
21149
|
}
|
|
21068
21150
|
var EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
21069
21151
|
var CLEAR = /<command-name>\s*\/clear\s*<\/command-name>/;
|
|
21070
|
-
var
|
|
21152
|
+
var LINE_UUID2 = /"uuid":"([^"]+)"/;
|
|
21071
21153
|
var LINE_PARENT = /"parentUuid":"([^"]+)"/;
|
|
21072
21154
|
var LIST_LIMIT = 40;
|
|
21073
21155
|
function addOnce(tools, key, text) {
|
|
@@ -21103,13 +21185,38 @@ function addAssistant(turn, line) {
|
|
|
21103
21185
|
}
|
|
21104
21186
|
}
|
|
21105
21187
|
async function readConversation(file2) {
|
|
21188
|
+
const turns = await readAllTurns(file2);
|
|
21189
|
+
const origin = await forkOrigin(file2, turns, readTranscriptTurns, isMessageLine);
|
|
21190
|
+
if (origin === null) return turns;
|
|
21191
|
+
return turns.slice(origin.copied).map((turn, index) => {
|
|
21192
|
+
const { resumed: _, ...rest } = turn;
|
|
21193
|
+
return { ...index === 0 ? rest : turn, id: `m${index + 1}` };
|
|
21194
|
+
});
|
|
21195
|
+
}
|
|
21196
|
+
async function readForkOrigin(file2) {
|
|
21197
|
+
return forkOrigin(file2, await readAllTurns(file2), readTranscriptTurns, isMessageLine);
|
|
21198
|
+
}
|
|
21199
|
+
function isMessageLine(line) {
|
|
21200
|
+
return messageText(line) !== null && typeof line.timestamp === "string";
|
|
21201
|
+
}
|
|
21202
|
+
var turnCache = /* @__PURE__ */ new Map();
|
|
21203
|
+
async function readTranscriptTurns(file2) {
|
|
21204
|
+
const size = (await stat5(file2)).size;
|
|
21205
|
+
const cached2 = turnCache.get(file2);
|
|
21206
|
+
if (cached2 && cached2.size === size) return cached2.turns;
|
|
21207
|
+
const turns = readAllTurns(file2);
|
|
21208
|
+
turnCache.set(file2, { size, turns });
|
|
21209
|
+
turns.catch(() => turnCache.delete(file2));
|
|
21210
|
+
return turns;
|
|
21211
|
+
}
|
|
21212
|
+
async function readAllTurns(file2) {
|
|
21106
21213
|
const turns = [];
|
|
21107
21214
|
const seen = /* @__PURE__ */ new Set();
|
|
21108
21215
|
let pendingResume = false;
|
|
21109
|
-
const lines =
|
|
21216
|
+
const lines = createInterface2({ input: createReadStream2(file2, "utf8"), crlfDelay: Infinity });
|
|
21110
21217
|
for await (const raw of lines) {
|
|
21111
21218
|
if (raw.includes("<command-name>") && CLEAR.test(raw)) pendingResume = true;
|
|
21112
|
-
const uuid3 =
|
|
21219
|
+
const uuid3 = LINE_UUID2.exec(raw)?.[1];
|
|
21113
21220
|
const parent = LINE_PARENT.exec(raw)?.[1];
|
|
21114
21221
|
if (seen.size > 0 && parent !== void 0 && !seen.has(parent) && !raw.includes('"isSidechain":true'))
|
|
21115
21222
|
pendingResume = true;
|
|
@@ -21223,7 +21330,7 @@ async function readLastTurn(file2) {
|
|
|
21223
21330
|
}
|
|
21224
21331
|
}
|
|
21225
21332
|
async function readsHandoff(file2) {
|
|
21226
|
-
const lines =
|
|
21333
|
+
const lines = createInterface2({ input: createReadStream2(file2, "utf8"), crlfDelay: Infinity });
|
|
21227
21334
|
for await (const raw of lines) {
|
|
21228
21335
|
if (!raw.includes("handoff")) continue;
|
|
21229
21336
|
if (/"name":"(?:Read|Bash)"/.test(raw) && /"file_path":"[^"]*handoff[^"]*"/i.test(raw))
|
|
@@ -21234,7 +21341,7 @@ async function readsHandoff(file2) {
|
|
|
21234
21341
|
}
|
|
21235
21342
|
async function countUserLines(file2) {
|
|
21236
21343
|
let count = 0;
|
|
21237
|
-
const lines =
|
|
21344
|
+
const lines = createInterface2({ input: createReadStream2(file2, "utf8"), crlfDelay: Infinity });
|
|
21238
21345
|
for await (const raw of lines) {
|
|
21239
21346
|
if (!raw.includes('"type":"user"')) continue;
|
|
21240
21347
|
try {
|
|
@@ -21277,6 +21384,7 @@ var claude = {
|
|
|
21277
21384
|
collectTranscripts,
|
|
21278
21385
|
collectTranscriptIds,
|
|
21279
21386
|
readConversation,
|
|
21387
|
+
readForkOrigin,
|
|
21280
21388
|
readsHandoff,
|
|
21281
21389
|
readLastTurn,
|
|
21282
21390
|
countUserLines,
|
|
@@ -21307,7 +21415,7 @@ import { createHash } from "crypto";
|
|
|
21307
21415
|
|
|
21308
21416
|
// src/store/conversations.ts
|
|
21309
21417
|
import { appendFile, mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
|
|
21310
|
-
import { dirname as
|
|
21418
|
+
import { dirname as dirname5 } from "path";
|
|
21311
21419
|
import { constants as constants2, gunzipSync, gzipSync } from "zlib";
|
|
21312
21420
|
|
|
21313
21421
|
// src/redact.ts
|
|
@@ -21421,7 +21529,7 @@ async function appendConversationTurns(root, sessionId, turns) {
|
|
|
21421
21529
|
const chunk = `${value.map((turn) => JSON.stringify(turn)).join("\n")}
|
|
21422
21530
|
`;
|
|
21423
21531
|
const file2 = projectPaths(root).conversation(sessionId);
|
|
21424
|
-
await mkdir4(
|
|
21532
|
+
await mkdir4(dirname5(file2), { recursive: true });
|
|
21425
21533
|
await appendFile(file2, gzipSync(Buffer.from(chunk, "utf8")));
|
|
21426
21534
|
return fresh.length;
|
|
21427
21535
|
}
|
|
@@ -21433,7 +21541,7 @@ async function appendConversationHashes(root, sessionId, hashes) {
|
|
|
21433
21541
|
const chunk = `${fresh.map((turn) => JSON.stringify(turn)).join("\n")}
|
|
21434
21542
|
`;
|
|
21435
21543
|
const file2 = projectPaths(root).conversation(sessionId);
|
|
21436
|
-
await mkdir4(
|
|
21544
|
+
await mkdir4(dirname5(file2), { recursive: true });
|
|
21437
21545
|
await appendFile(file2, gzipSync(Buffer.from(chunk, "utf8")));
|
|
21438
21546
|
return fresh.length;
|
|
21439
21547
|
}
|
|
@@ -21741,8 +21849,8 @@ async function installGitHook(root, event) {
|
|
|
21741
21849
|
const dir = await gitHooksDir(gitRoot);
|
|
21742
21850
|
if (dir === void 0) return false;
|
|
21743
21851
|
await mkdir5(dir, { recursive: true });
|
|
21744
|
-
const file2 =
|
|
21745
|
-
const exists = await
|
|
21852
|
+
const file2 = join8(dir, event);
|
|
21853
|
+
const exists = await stat6(file2).then(
|
|
21746
21854
|
() => true,
|
|
21747
21855
|
() => false
|
|
21748
21856
|
);
|
|
@@ -21775,7 +21883,7 @@ async function refreshGitHooks(root) {
|
|
|
21775
21883
|
if (dir === void 0) return [];
|
|
21776
21884
|
const refreshed = [];
|
|
21777
21885
|
for (const event of GIT_HOOK_EVENTS) {
|
|
21778
|
-
const current = await readFile5(
|
|
21886
|
+
const current = await readFile5(join8(dir, event), "utf8").catch(() => void 0);
|
|
21779
21887
|
if (current === void 0 || !current.includes(BLOCK_START)) continue;
|
|
21780
21888
|
if (await installGitHook(root, event)) refreshed.push(event);
|
|
21781
21889
|
}
|
|
@@ -21788,7 +21896,7 @@ async function uninstallGitHooks(root) {
|
|
|
21788
21896
|
if (dir === void 0) return [];
|
|
21789
21897
|
const removed = [];
|
|
21790
21898
|
for (const event of GIT_HOOK_EVENTS) {
|
|
21791
|
-
const file2 =
|
|
21899
|
+
const file2 = join8(dir, event);
|
|
21792
21900
|
const current = await readFile5(file2, "utf8").catch(() => void 0);
|
|
21793
21901
|
if (current === void 0 || !current.includes(BLOCK_START)) continue;
|
|
21794
21902
|
const next = withoutHookBlock(current);
|
|
@@ -21838,6 +21946,7 @@ export {
|
|
|
21838
21946
|
appendConversationTurns,
|
|
21839
21947
|
appendConversationHashes,
|
|
21840
21948
|
MESSAGE_HASH,
|
|
21949
|
+
messageHash,
|
|
21841
21950
|
hashTurns,
|
|
21842
21951
|
readSessionMessages,
|
|
21843
21952
|
storedMessages,
|