@carboncode/cli 0.1.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/LICENSE +21 -0
- package/LICENSES/DeepSeek-Reasonix-MIT.txt +21 -0
- package/README.md +109 -0
- package/README.zh-CN.md +91 -0
- package/THIRD_PARTY_NOTICES.md +14 -0
- package/dashboard/app.css +3233 -0
- package/dashboard/dist/app.js +30444 -0
- package/dashboard/dist/app.js.map +1 -0
- package/dashboard/dist/vendor-hljs.css +10 -0
- package/dashboard/dist/vendor-uplot.css +1 -0
- package/dashboard/index.html +19 -0
- package/data/deepseek-tokenizer.json.gz +0 -0
- package/dist/cli/acp-35C4ME6Y.js +711 -0
- package/dist/cli/acp-35C4ME6Y.js.map +1 -0
- package/dist/cli/chat-A6UJDPGV.js +51 -0
- package/dist/cli/chat-A6UJDPGV.js.map +1 -0
- package/dist/cli/chunk-2425HK6U.js +54 -0
- package/dist/cli/chunk-2425HK6U.js.map +1 -0
- package/dist/cli/chunk-25T6CVUP.js +172 -0
- package/dist/cli/chunk-25T6CVUP.js.map +1 -0
- package/dist/cli/chunk-2UQP6H6T.js +31 -0
- package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
- package/dist/cli/chunk-3OAR6NVL.js +96 -0
- package/dist/cli/chunk-3OAR6NVL.js.map +1 -0
- package/dist/cli/chunk-3T6VBZCL.js +54 -0
- package/dist/cli/chunk-3T6VBZCL.js.map +1 -0
- package/dist/cli/chunk-4IBIPQVB.js +153 -0
- package/dist/cli/chunk-4IBIPQVB.js.map +1 -0
- package/dist/cli/chunk-4MQ3VURH.js +3106 -0
- package/dist/cli/chunk-4MQ3VURH.js.map +1 -0
- package/dist/cli/chunk-4TVNJWMA.js +11619 -0
- package/dist/cli/chunk-4TVNJWMA.js.map +1 -0
- package/dist/cli/chunk-4VR6XF4P.js +341 -0
- package/dist/cli/chunk-4VR6XF4P.js.map +1 -0
- package/dist/cli/chunk-5QCB62C4.js +25319 -0
- package/dist/cli/chunk-5QCB62C4.js.map +1 -0
- package/dist/cli/chunk-6OWJV3YW.js +390 -0
- package/dist/cli/chunk-6OWJV3YW.js.map +1 -0
- package/dist/cli/chunk-7EO27TB3.js +130 -0
- package/dist/cli/chunk-7EO27TB3.js.map +1 -0
- package/dist/cli/chunk-7L2WTRNU.js +308 -0
- package/dist/cli/chunk-7L2WTRNU.js.map +1 -0
- package/dist/cli/chunk-BHTZFEYE.js +47 -0
- package/dist/cli/chunk-BHTZFEYE.js.map +1 -0
- package/dist/cli/chunk-BSGCXZQN.js +343 -0
- package/dist/cli/chunk-BSGCXZQN.js.map +1 -0
- package/dist/cli/chunk-BSINVTTL.js +464 -0
- package/dist/cli/chunk-BSINVTTL.js.map +1 -0
- package/dist/cli/chunk-CPKCNHRR.js +323 -0
- package/dist/cli/chunk-CPKCNHRR.js.map +1 -0
- package/dist/cli/chunk-CXVWUPA3.js +96 -0
- package/dist/cli/chunk-CXVWUPA3.js.map +1 -0
- package/dist/cli/chunk-D5NFKRGO.js +160 -0
- package/dist/cli/chunk-D5NFKRGO.js.map +1 -0
- package/dist/cli/chunk-ECHSFYOY.js +109 -0
- package/dist/cli/chunk-ECHSFYOY.js.map +1 -0
- package/dist/cli/chunk-FEZK652I.js +3644 -0
- package/dist/cli/chunk-FEZK652I.js.map +1 -0
- package/dist/cli/chunk-GALC45Q2.js +696 -0
- package/dist/cli/chunk-GALC45Q2.js.map +1 -0
- package/dist/cli/chunk-IAUOP25G.js +2984 -0
- package/dist/cli/chunk-IAUOP25G.js.map +1 -0
- package/dist/cli/chunk-ILJOIQ5W.js +163 -0
- package/dist/cli/chunk-ILJOIQ5W.js.map +1 -0
- package/dist/cli/chunk-IX6XI2RG.js +225 -0
- package/dist/cli/chunk-IX6XI2RG.js.map +1 -0
- package/dist/cli/chunk-J5BYPUB5.js +62795 -0
- package/dist/cli/chunk-J5BYPUB5.js.map +1 -0
- package/dist/cli/chunk-J5XJHLWM.js +55 -0
- package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
- package/dist/cli/chunk-JKGYMRX5.js +101 -0
- package/dist/cli/chunk-JKGYMRX5.js.map +1 -0
- package/dist/cli/chunk-JMBMLOBP.js +26 -0
- package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
- package/dist/cli/chunk-LN3B5PMX.js +128 -0
- package/dist/cli/chunk-LN3B5PMX.js.map +1 -0
- package/dist/cli/chunk-M2UFZUX3.js +635 -0
- package/dist/cli/chunk-M2UFZUX3.js.map +1 -0
- package/dist/cli/chunk-PJS34556.js +809 -0
- package/dist/cli/chunk-PJS34556.js.map +1 -0
- package/dist/cli/chunk-QJG7OF27.js +655 -0
- package/dist/cli/chunk-QJG7OF27.js.map +1 -0
- package/dist/cli/chunk-QVC75MR3.js +232 -0
- package/dist/cli/chunk-QVC75MR3.js.map +1 -0
- package/dist/cli/chunk-S2KIUQKQ.js +378 -0
- package/dist/cli/chunk-S2KIUQKQ.js.map +1 -0
- package/dist/cli/chunk-S4XVGLRW.js +499 -0
- package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
- package/dist/cli/chunk-T5TQ4NDT.js +190 -0
- package/dist/cli/chunk-T5TQ4NDT.js.map +1 -0
- package/dist/cli/chunk-TH756VLN.js +1924 -0
- package/dist/cli/chunk-TH756VLN.js.map +1 -0
- package/dist/cli/chunk-TUK7OWJA.js +51 -0
- package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
- package/dist/cli/chunk-U4IJVG32.js +363 -0
- package/dist/cli/chunk-U4IJVG32.js.map +1 -0
- package/dist/cli/chunk-UI66BH6D.js +624 -0
- package/dist/cli/chunk-UI66BH6D.js.map +1 -0
- package/dist/cli/chunk-VPMBGAND.js +53 -0
- package/dist/cli/chunk-VPMBGAND.js.map +1 -0
- package/dist/cli/chunk-WLHH3OSR.js +522 -0
- package/dist/cli/chunk-WLHH3OSR.js.map +1 -0
- package/dist/cli/chunk-WRN65TRD.js +908 -0
- package/dist/cli/chunk-WRN65TRD.js.map +1 -0
- package/dist/cli/chunk-X53B3JIX.js +34320 -0
- package/dist/cli/chunk-X53B3JIX.js.map +1 -0
- package/dist/cli/chunk-XJ5SRLKK.js +50 -0
- package/dist/cli/chunk-XJ5SRLKK.js.map +1 -0
- package/dist/cli/chunk-YZSXRGFH.js +54 -0
- package/dist/cli/chunk-YZSXRGFH.js.map +1 -0
- package/dist/cli/code-4TUTAGO5.js +163 -0
- package/dist/cli/code-4TUTAGO5.js.map +1 -0
- package/dist/cli/commands-KMOZEYCF.js +356 -0
- package/dist/cli/commands-KMOZEYCF.js.map +1 -0
- package/dist/cli/commit-DTFA56VQ.js +292 -0
- package/dist/cli/commit-DTFA56VQ.js.map +1 -0
- package/dist/cli/desktop-7N3MHNBD.js +1274 -0
- package/dist/cli/desktop-7N3MHNBD.js.map +1 -0
- package/dist/cli/devtools-HW3WDT3Q.js +91 -0
- package/dist/cli/devtools-HW3WDT3Q.js.map +1 -0
- package/dist/cli/diff-E5OWTF4C.js +165 -0
- package/dist/cli/diff-E5OWTF4C.js.map +1 -0
- package/dist/cli/doctor-IEJQRJMN.js +27 -0
- package/dist/cli/doctor-IEJQRJMN.js.map +1 -0
- package/dist/cli/events-4625EGXI.js +340 -0
- package/dist/cli/events-4625EGXI.js.map +1 -0
- package/dist/cli/index.js +3536 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mcp-PDI2PDLG.js +277 -0
- package/dist/cli/mcp-PDI2PDLG.js.map +1 -0
- package/dist/cli/mcp-browse-OSPXOFPZ.js +178 -0
- package/dist/cli/mcp-browse-OSPXOFPZ.js.map +1 -0
- package/dist/cli/mcp-inspect-QRFVTHMF.js +148 -0
- package/dist/cli/mcp-inspect-QRFVTHMF.js.map +1 -0
- package/dist/cli/package.json +3 -0
- package/dist/cli/prompt-3CDII3UO.js +16 -0
- package/dist/cli/prompt-3CDII3UO.js.map +1 -0
- package/dist/cli/prune-sessions-KZX4SXKW.js +44 -0
- package/dist/cli/prune-sessions-KZX4SXKW.js.map +1 -0
- package/dist/cli/replay-HYOSRQIV.js +291 -0
- package/dist/cli/replay-HYOSRQIV.js.map +1 -0
- package/dist/cli/run-2ZHADOUP.js +220 -0
- package/dist/cli/run-2ZHADOUP.js.map +1 -0
- package/dist/cli/server-X75PAZG5.js +3572 -0
- package/dist/cli/server-X75PAZG5.js.map +1 -0
- package/dist/cli/sessions-POOZA5CQ.js +120 -0
- package/dist/cli/sessions-POOZA5CQ.js.map +1 -0
- package/dist/cli/setup-YLPFI3OH.js +618 -0
- package/dist/cli/setup-YLPFI3OH.js.map +1 -0
- package/dist/cli/stats-NXJ3TO2D.js +16 -0
- package/dist/cli/stats-NXJ3TO2D.js.map +1 -0
- package/dist/cli/update-ZUO5MKQ6.js +15 -0
- package/dist/cli/update-ZUO5MKQ6.js.map +1 -0
- package/dist/cli/version-NXXWE3WN.js +33 -0
- package/dist/cli/version-NXXWE3WN.js.map +1 -0
- package/dist/index.d.ts +2523 -0
- package/dist/index.js +15408 -0
- package/dist/index.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
|
+
|
|
4
|
+
// src/memory/session.ts
|
|
5
|
+
import { execFileSync } from "child_process";
|
|
6
|
+
import {
|
|
7
|
+
appendFileSync,
|
|
8
|
+
chmodSync,
|
|
9
|
+
copyFileSync,
|
|
10
|
+
existsSync,
|
|
11
|
+
mkdirSync,
|
|
12
|
+
readFileSync,
|
|
13
|
+
readdirSync,
|
|
14
|
+
renameSync,
|
|
15
|
+
statSync,
|
|
16
|
+
unlinkSync,
|
|
17
|
+
writeFileSync
|
|
18
|
+
} from "fs";
|
|
19
|
+
import { homedir } from "os";
|
|
20
|
+
import { dirname, join, posix as posixPath, win32 as win32Path } from "path";
|
|
21
|
+
var SESSION_SIDECAR_EXTS = [
|
|
22
|
+
".events.jsonl",
|
|
23
|
+
".meta.json",
|
|
24
|
+
".pending.json",
|
|
25
|
+
".plan.json",
|
|
26
|
+
".jsonl.bak"
|
|
27
|
+
];
|
|
28
|
+
function detectGitBranch(cwd) {
|
|
29
|
+
try {
|
|
30
|
+
const out = execFileSync("git", ["branch", "--show-current"], {
|
|
31
|
+
cwd,
|
|
32
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
33
|
+
timeout: 800,
|
|
34
|
+
encoding: "utf8"
|
|
35
|
+
}).trim();
|
|
36
|
+
return out || void 0;
|
|
37
|
+
} catch {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function sessionsDir() {
|
|
42
|
+
return join(homedir(), ".carboncode", "sessions");
|
|
43
|
+
}
|
|
44
|
+
function legacySessionsDir() {
|
|
45
|
+
return join(homedir(), ".reasonix", "sessions");
|
|
46
|
+
}
|
|
47
|
+
function sessionPath(name) {
|
|
48
|
+
return join(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
49
|
+
}
|
|
50
|
+
function legacySessionPath(name) {
|
|
51
|
+
return join(legacySessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
52
|
+
}
|
|
53
|
+
function existingSessionPath(name) {
|
|
54
|
+
const carbon = sessionPath(name);
|
|
55
|
+
if (existsSync(carbon)) return carbon;
|
|
56
|
+
const legacy = legacySessionPath(name);
|
|
57
|
+
if (existsSync(legacy)) return legacy;
|
|
58
|
+
return carbon;
|
|
59
|
+
}
|
|
60
|
+
function sanitizeName(name) {
|
|
61
|
+
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
62
|
+
return cleaned || "default";
|
|
63
|
+
}
|
|
64
|
+
function timestampSuffix() {
|
|
65
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[^\d]/g, "").slice(0, 12);
|
|
66
|
+
}
|
|
67
|
+
function freshSessionName(currentName) {
|
|
68
|
+
const base = currentName ? currentName.replace(/-\d{12,14}$/, "") : "default";
|
|
69
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[^\d]/g, "").slice(0, 14);
|
|
70
|
+
return `${base || "default"}-${stamp}`;
|
|
71
|
+
}
|
|
72
|
+
function findSessionsByPrefix(prefix) {
|
|
73
|
+
const dirs = [sessionsDir(), legacySessionsDir()];
|
|
74
|
+
const seen = /* @__PURE__ */ new Set();
|
|
75
|
+
try {
|
|
76
|
+
for (const dir of dirs) {
|
|
77
|
+
if (!existsSync(dir)) continue;
|
|
78
|
+
for (const file of readdirSync(dir)) {
|
|
79
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
80
|
+
if (file.endsWith(".events.jsonl")) continue;
|
|
81
|
+
if (!file.startsWith(prefix)) continue;
|
|
82
|
+
seen.add(file.replace(/\.jsonl$/, ""));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return [...seen].sort((a, b) => `${a}.jsonl`.localeCompare(`${b}.jsonl`)).reverse();
|
|
86
|
+
} catch {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function resolveSession(sessionName, forceNew, forceResume) {
|
|
91
|
+
let resolved = sessionName;
|
|
92
|
+
let preview;
|
|
93
|
+
if (sessionName && forceNew) {
|
|
94
|
+
resolved = `${sessionName}-${timestampSuffix()}`;
|
|
95
|
+
} else if (sessionName && !forceResume) {
|
|
96
|
+
let sessionToCheck = sessionName;
|
|
97
|
+
const prefixed = findSessionsByPrefix(`${sessionName}-`);
|
|
98
|
+
if (prefixed.length > 0) {
|
|
99
|
+
sessionToCheck = prefixed[0];
|
|
100
|
+
}
|
|
101
|
+
const prior = loadSessionMessages(sessionToCheck);
|
|
102
|
+
if (prior.length > 0) {
|
|
103
|
+
resolved = sessionToCheck;
|
|
104
|
+
const p = existingSessionPath(sessionToCheck);
|
|
105
|
+
const mtime = existsSync(p) ? statSync(p).mtime : /* @__PURE__ */ new Date();
|
|
106
|
+
preview = { messageCount: prior.length, lastActive: mtime };
|
|
107
|
+
}
|
|
108
|
+
} else if (sessionName && forceResume) {
|
|
109
|
+
const prefixed = findSessionsByPrefix(`${sessionName}-`);
|
|
110
|
+
if (prefixed.length > 0) {
|
|
111
|
+
resolved = prefixed[0];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { resolved, preview };
|
|
115
|
+
}
|
|
116
|
+
function loadSessionMessages(name) {
|
|
117
|
+
const path = existingSessionPath(name);
|
|
118
|
+
if (!existsSync(path)) return [];
|
|
119
|
+
const live = readSessionMessages(path);
|
|
120
|
+
if (live && (live.messages.length > 0 || !live.hadContent)) return live.messages;
|
|
121
|
+
const backup = readSessionMessages(sessionBackupPath(path));
|
|
122
|
+
return backup?.messages ?? live?.messages ?? [];
|
|
123
|
+
}
|
|
124
|
+
function readSessionMessages(path) {
|
|
125
|
+
let raw;
|
|
126
|
+
try {
|
|
127
|
+
raw = readFileSync(path, "utf8");
|
|
128
|
+
} catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const out = [];
|
|
132
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
133
|
+
const trimmed = line.trim();
|
|
134
|
+
if (!trimmed) continue;
|
|
135
|
+
try {
|
|
136
|
+
const msg = JSON.parse(trimmed);
|
|
137
|
+
if (msg && typeof msg === "object" && "role" in msg) out.push(msg);
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { messages: out, hadContent: raw.trim().length > 0 };
|
|
142
|
+
}
|
|
143
|
+
function appendSessionMessage(name, message) {
|
|
144
|
+
const path = existingSessionPath(name);
|
|
145
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
146
|
+
appendFileSync(path, `${JSON.stringify(message)}
|
|
147
|
+
`, "utf8");
|
|
148
|
+
try {
|
|
149
|
+
chmodSync(path, 384);
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function listSessions(opts) {
|
|
154
|
+
const want = opts?.workspaceFilter ? normalizeWorkspace(opts.workspaceFilter) : null;
|
|
155
|
+
const dirs = [sessionsDir(), legacySessionsDir()];
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
try {
|
|
158
|
+
const items = [];
|
|
159
|
+
for (const dir of dirs) {
|
|
160
|
+
if (!existsSync(dir)) continue;
|
|
161
|
+
const files = readdirSync(dir).filter(
|
|
162
|
+
(f) => f.endsWith(".jsonl") && !f.endsWith(".events.jsonl")
|
|
163
|
+
);
|
|
164
|
+
const dirItems = files.filter((file) => {
|
|
165
|
+
const name = file.replace(/\.jsonl$/, "");
|
|
166
|
+
if (seen.has(name)) return false;
|
|
167
|
+
seen.add(name);
|
|
168
|
+
return true;
|
|
169
|
+
}).flatMap((file) => {
|
|
170
|
+
const path = join(dir, file);
|
|
171
|
+
const name = file.replace(/\.jsonl$/, "");
|
|
172
|
+
const meta = loadSessionMetaFromDir(dir, name);
|
|
173
|
+
if (want !== null) {
|
|
174
|
+
if (typeof meta.workspace !== "string") return [];
|
|
175
|
+
if (normalizeWorkspace(meta.workspace) !== want) return [];
|
|
176
|
+
}
|
|
177
|
+
const stat = statSync(path);
|
|
178
|
+
const messageCount = countLines(path);
|
|
179
|
+
return [{ name, path, size: stat.size, messageCount, mtime: stat.mtime, meta }];
|
|
180
|
+
});
|
|
181
|
+
items.push(...dirItems);
|
|
182
|
+
}
|
|
183
|
+
return items.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function normalizeWorkspace(p, platform = process.platform) {
|
|
189
|
+
if (typeof p !== "string" || p.length === 0) return "";
|
|
190
|
+
if (platform === "win32") {
|
|
191
|
+
const resolved = win32Path.resolve(p);
|
|
192
|
+
return resolved.replace(/\\/g, "/").replace(/^([A-Z]):/i, (_, d) => `${d.toLowerCase()}:`);
|
|
193
|
+
}
|
|
194
|
+
return posixPath.resolve(p);
|
|
195
|
+
}
|
|
196
|
+
function listSessionsForWorkspace(workspace) {
|
|
197
|
+
return listSessions({ workspaceFilter: workspace });
|
|
198
|
+
}
|
|
199
|
+
function metaPath(name) {
|
|
200
|
+
return join(dirname(existingSessionPath(name)), `${sanitizeName(name)}.meta.json`);
|
|
201
|
+
}
|
|
202
|
+
function loadSessionMetaFromDir(dir, name) {
|
|
203
|
+
const p = join(dir, `${sanitizeName(name)}.meta.json`);
|
|
204
|
+
if (!existsSync(p)) return {};
|
|
205
|
+
try {
|
|
206
|
+
const raw = JSON.parse(readFileSync(p, "utf8"));
|
|
207
|
+
return raw && typeof raw === "object" ? raw : {};
|
|
208
|
+
} catch {
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function loadSessionMeta(name) {
|
|
213
|
+
const p = metaPath(name);
|
|
214
|
+
if (!existsSync(p)) return {};
|
|
215
|
+
try {
|
|
216
|
+
const raw = JSON.parse(readFileSync(p, "utf8"));
|
|
217
|
+
return raw && typeof raw === "object" ? raw : {};
|
|
218
|
+
} catch {
|
|
219
|
+
return {};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function patchSessionMeta(name, patch) {
|
|
223
|
+
const cur = loadSessionMeta(name);
|
|
224
|
+
const next = { ...cur, ...patch };
|
|
225
|
+
const p = metaPath(name);
|
|
226
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
227
|
+
writeFileSync(p, JSON.stringify(next), "utf8");
|
|
228
|
+
try {
|
|
229
|
+
chmodSync(p, 384);
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
return next;
|
|
233
|
+
}
|
|
234
|
+
function renameSession(oldName, newName) {
|
|
235
|
+
const safeOld = sanitizeName(oldName);
|
|
236
|
+
const safeNew = sanitizeName(newName);
|
|
237
|
+
if (safeOld === safeNew) return false;
|
|
238
|
+
const oldJsonl = existingSessionPath(oldName);
|
|
239
|
+
const newJsonl = sessionPath(newName);
|
|
240
|
+
if (!existsSync(oldJsonl) || existsSync(newJsonl)) return false;
|
|
241
|
+
mkdirSync(dirname(newJsonl), { recursive: true });
|
|
242
|
+
renameSync(oldJsonl, newJsonl);
|
|
243
|
+
for (const ext of SESSION_SIDECAR_EXTS) {
|
|
244
|
+
const oldP = oldJsonl.replace(/\.jsonl$/, ext);
|
|
245
|
+
const newP = newJsonl.replace(/\.jsonl$/, ext);
|
|
246
|
+
if (existsSync(oldP)) {
|
|
247
|
+
try {
|
|
248
|
+
renameSync(oldP, newP);
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
function pruneStaleSessions(daysOld = 90) {
|
|
256
|
+
const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1e3;
|
|
257
|
+
const deleted = [];
|
|
258
|
+
for (const s of listSessions()) {
|
|
259
|
+
if (s.mtime.getTime() < cutoff) {
|
|
260
|
+
if (deleteSession(s.name)) deleted.push(s.name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return deleted;
|
|
264
|
+
}
|
|
265
|
+
function deleteSession(name) {
|
|
266
|
+
const path = existingSessionPath(name);
|
|
267
|
+
try {
|
|
268
|
+
unlinkSync(path);
|
|
269
|
+
for (const ext of SESSION_SIDECAR_EXTS) {
|
|
270
|
+
const sidecar = path.replace(/\.jsonl$/, ext);
|
|
271
|
+
try {
|
|
272
|
+
unlinkSync(sidecar);
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return true;
|
|
277
|
+
} catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function rewriteSession(name, messages) {
|
|
282
|
+
const path = existingSessionPath(name);
|
|
283
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
284
|
+
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
285
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
286
|
+
try {
|
|
287
|
+
writeFileSync(tmp, body ? `${body}
|
|
288
|
+
` : "", "utf8");
|
|
289
|
+
chmodPrivate(tmp);
|
|
290
|
+
if (existsSync(path) && statSync(path).size > 0) {
|
|
291
|
+
const backup = sessionBackupPath(path);
|
|
292
|
+
copyFileSync(path, backup);
|
|
293
|
+
chmodPrivate(backup);
|
|
294
|
+
}
|
|
295
|
+
renameSync(tmp, path);
|
|
296
|
+
chmodPrivate(path);
|
|
297
|
+
} catch (err) {
|
|
298
|
+
try {
|
|
299
|
+
unlinkSync(tmp);
|
|
300
|
+
} catch {
|
|
301
|
+
}
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function archiveSession(name) {
|
|
306
|
+
const path = existingSessionPath(name);
|
|
307
|
+
if (!existsSync(path)) return null;
|
|
308
|
+
try {
|
|
309
|
+
if (statSync(path).size === 0) return null;
|
|
310
|
+
} catch {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
314
|
+
const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : ""}`;
|
|
315
|
+
if (renameSession(name, target)) return target;
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
function countLines(path) {
|
|
320
|
+
try {
|
|
321
|
+
const buf = readFileSync(path);
|
|
322
|
+
let count = 0;
|
|
323
|
+
for (let i = 0; i < buf.length; i++) {
|
|
324
|
+
if (buf[i] === 10) count++;
|
|
325
|
+
}
|
|
326
|
+
if (buf.length > 0 && buf[buf.length - 1] !== 10) count++;
|
|
327
|
+
return count;
|
|
328
|
+
} catch {
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function sessionBackupPath(path) {
|
|
333
|
+
return `${path}.bak`;
|
|
334
|
+
}
|
|
335
|
+
function chmodPrivate(path) {
|
|
336
|
+
try {
|
|
337
|
+
chmodSync(path, 384);
|
|
338
|
+
} catch {
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export {
|
|
343
|
+
detectGitBranch,
|
|
344
|
+
sessionsDir,
|
|
345
|
+
sessionPath,
|
|
346
|
+
sanitizeName,
|
|
347
|
+
timestampSuffix,
|
|
348
|
+
freshSessionName,
|
|
349
|
+
resolveSession,
|
|
350
|
+
loadSessionMessages,
|
|
351
|
+
appendSessionMessage,
|
|
352
|
+
listSessions,
|
|
353
|
+
normalizeWorkspace,
|
|
354
|
+
listSessionsForWorkspace,
|
|
355
|
+
loadSessionMeta,
|
|
356
|
+
patchSessionMeta,
|
|
357
|
+
renameSession,
|
|
358
|
+
pruneStaleSessions,
|
|
359
|
+
deleteSession,
|
|
360
|
+
rewriteSession,
|
|
361
|
+
archiveSession
|
|
362
|
+
};
|
|
363
|
+
//# sourceMappingURL=chunk-U4IJVG32.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/memory/session.ts"],"sourcesContent":["/** JSONL append-only message log under `~/.carboncode/sessions/`; concurrent-write safe. */\n\nimport { execFileSync } from \"node:child_process\";\nimport {\n appendFileSync,\n chmodSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, posix as posixPath, win32 as win32Path } from \"node:path\";\nimport type { ChatMessage } from \"../types.js\";\n\nconst SESSION_SIDECAR_EXTS = [\n \".events.jsonl\",\n \".meta.json\",\n \".pending.json\",\n \".plan.json\",\n \".jsonl.bak\",\n] as const;\n\n/** Best-effort git branch sniff; returns undefined if not a git repo or git missing. */\nexport function detectGitBranch(cwd: string): string | undefined {\n try {\n const out = execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 800,\n encoding: \"utf8\",\n }).trim();\n return out || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SessionInfo {\n name: string;\n path: string;\n size: number;\n messageCount: number;\n mtime: Date;\n meta: SessionMeta;\n}\n\nexport interface SessionMeta {\n branch?: string;\n summary?: string;\n totalCostUsd?: number;\n turnCount?: number;\n /** Absolute path of the workspace root the session was created/used in. */\n workspace?: string;\n /** Wallet currency at last save — used to format `totalCostUsd` in the picker without re-fetching balance. */\n balanceCurrency?: string;\n /** Cumulative cache hit / miss tokens across the session — survives resume so /status cache% isn't 0 on a fresh boot. */\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n /** Last turn's promptTokens — lets /status render the context bar before the next turn fires. */\n lastPromptTokens?: number;\n /** True when the session filename/summary was generated from conversation content. */\n autoTitleGenerated?: boolean;\n}\n\nexport function sessionsDir(): string {\n return join(homedir(), \".carboncode\", \"sessions\");\n}\n\nfunction legacySessionsDir(): string {\n return join(homedir(), \".reasonix\", \"sessions\");\n}\n\nexport function sessionPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.jsonl`);\n}\n\nfunction legacySessionPath(name: string): string {\n return join(legacySessionsDir(), `${sanitizeName(name)}.jsonl`);\n}\n\nfunction existingSessionPath(name: string): string {\n const carbon = sessionPath(name);\n if (existsSync(carbon)) return carbon;\n const legacy = legacySessionPath(name);\n if (existsSync(legacy)) return legacy;\n return carbon;\n}\n\nexport function sanitizeName(name: string): string {\n const cleaned = name.replace(/[^\\w\\-\\u4e00-\\u9fa5]/g, \"_\").slice(0, 64);\n return cleaned || \"default\";\n}\n\n/** Sortable timestamp `YYYYMMDDHHmm` — used as a session-name suffix. */\nexport function timestampSuffix(): string {\n return new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 12);\n}\n\n/** Unique name for an in-app \"new session\" — strips a trailing 12/14-digit timestamp from the current name and re-stamps with seconds precision so back-to-back clicks don't collide. */\nexport function freshSessionName(currentName: string | undefined): string {\n const base = currentName ? currentName.replace(/-\\d{12,14}$/, \"\") : \"default\";\n const stamp = new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 14);\n return `${base || \"default\"}-${stamp}`;\n}\n\n/** Names of `.jsonl` sessions starting with `prefix`, newest-first by filename. */\nexport function findSessionsByPrefix(prefix: string): string[] {\n const dirs = [sessionsDir(), legacySessionsDir()];\n const seen = new Set<string>();\n try {\n for (const dir of dirs) {\n if (!existsSync(dir)) continue;\n for (const file of readdirSync(dir)) {\n if (!file.endsWith(\".jsonl\")) continue;\n if (file.endsWith(\".events.jsonl\")) continue;\n if (!file.startsWith(prefix)) continue;\n seen.add(file.replace(/\\.jsonl$/, \"\"));\n }\n }\n return [...seen].sort((a, b) => `${a}.jsonl`.localeCompare(`${b}.jsonl`)).reverse();\n } catch {\n return [];\n }\n}\n\nexport interface SessionPreview {\n messageCount: number;\n lastActive: Date;\n}\n\n/** Resolve launch-time session: forceNew → timestamped suffix; else latest `${name}-*` if any, else base. Preview returned only on the default branch when messages exist. */\nexport function resolveSession(\n sessionName: string | undefined,\n forceNew?: boolean,\n forceResume?: boolean,\n): { resolved: string | undefined; preview: SessionPreview | undefined } {\n let resolved = sessionName;\n let preview: SessionPreview | undefined;\n\n if (sessionName && forceNew) {\n resolved = `${sessionName}-${timestampSuffix()}`;\n } else if (sessionName && !forceResume) {\n let sessionToCheck = sessionName;\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n sessionToCheck = prefixed[0]!;\n }\n const prior = loadSessionMessages(sessionToCheck);\n if (prior.length > 0) {\n resolved = sessionToCheck;\n const p = existingSessionPath(sessionToCheck);\n const mtime = existsSync(p) ? statSync(p).mtime : new Date();\n preview = { messageCount: prior.length, lastActive: mtime };\n }\n } else if (sessionName && forceResume) {\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n resolved = prefixed[0]!;\n }\n }\n\n return { resolved, preview };\n}\n\nexport function loadSessionMessages(name: string): ChatMessage[] {\n const path = existingSessionPath(name);\n if (!existsSync(path)) return [];\n const live = readSessionMessages(path);\n if (live && (live.messages.length > 0 || !live.hadContent)) return live.messages;\n\n const backup = readSessionMessages(sessionBackupPath(path));\n return backup?.messages ?? live?.messages ?? [];\n}\n\nfunction readSessionMessages(\n path: string,\n): { messages: ChatMessage[]; hadContent: boolean } | null {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const out: ChatMessage[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const msg = JSON.parse(trimmed) as ChatMessage;\n if (msg && typeof msg === \"object\" && \"role\" in msg) out.push(msg);\n } catch {\n /* skip malformed line */\n }\n }\n return { messages: out, hadContent: raw.trim().length > 0 };\n}\n\nexport function appendSessionMessage(name: string, message: ChatMessage): void {\n const path = existingSessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(message)}\\n`, \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported on this platform */\n }\n}\n\nexport function listSessions(opts?: { workspaceFilter?: string }): SessionInfo[] {\n const want = opts?.workspaceFilter ? normalizeWorkspace(opts.workspaceFilter) : null;\n const dirs = [sessionsDir(), legacySessionsDir()];\n const seen = new Set<string>();\n try {\n const items: SessionInfo[] = [];\n for (const dir of dirs) {\n if (!existsSync(dir)) continue;\n // Exclude `.events.jsonl` sidecars — they share the .jsonl suffix.\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\"),\n );\n const dirItems = files\n .filter((file) => {\n const name = file.replace(/\\.jsonl$/, \"\");\n if (seen.has(name)) return false;\n seen.add(name);\n return true;\n })\n .flatMap((file) => {\n const path = join(dir, file);\n const name = file.replace(/\\.jsonl$/, \"\");\n const meta = loadSessionMetaFromDir(dir, name);\n // Workspace pre-filter: cheap meta read first, skip the\n // (potentially multi-MB) jsonl read for sessions that don't\n // belong to the current workspace. Issue #1179.\n if (want !== null) {\n if (typeof meta.workspace !== \"string\") return [];\n if (normalizeWorkspace(meta.workspace) !== want) return [];\n }\n const stat = statSync(path);\n const messageCount = countLines(path);\n return [{ name, path, size: stat.size, messageCount, mtime: stat.mtime, meta }];\n });\n items.push(...dirItems);\n }\n return items.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n } catch {\n return [];\n }\n}\n\n/** Canonical form for workspace path comparisons — Windows drive-case + separator drift between session writes (yesterday) and reads (today) used to hide sessions from the sidebar. Issue #878. */\nexport function normalizeWorkspace(\n p: string | undefined,\n platform: NodeJS.Platform = process.platform,\n): string {\n if (typeof p !== \"string\" || p.length === 0) return \"\";\n if (platform === \"win32\") {\n const resolved = win32Path.resolve(p);\n return resolved\n .replace(/\\\\/g, \"/\")\n .replace(/^([A-Z]):/i, (_, d: string) => `${d.toLowerCase()}:`);\n }\n return posixPath.resolve(p);\n}\n\n/** Sessions without `meta.workspace` are still hidden — resume by name still works. */\nexport function listSessionsForWorkspace(workspace: string): SessionInfo[] {\n return listSessions({ workspaceFilter: workspace });\n}\n\nfunction metaPath(name: string): string {\n return join(dirname(existingSessionPath(name)), `${sanitizeName(name)}.meta.json`);\n}\n\nfunction loadSessionMetaFromDir(dir: string, name: string): SessionMeta {\n const p = join(dir, `${sanitizeName(name)}.meta.json`);\n if (!existsSync(p)) return {};\n try {\n const raw = JSON.parse(readFileSync(p, \"utf8\")) as SessionMeta;\n return raw && typeof raw === \"object\" ? raw : {};\n } catch {\n return {};\n }\n}\n\nexport function loadSessionMeta(name: string): SessionMeta {\n const p = metaPath(name);\n if (!existsSync(p)) return {};\n try {\n const raw = JSON.parse(readFileSync(p, \"utf8\")) as SessionMeta;\n return raw && typeof raw === \"object\" ? raw : {};\n } catch {\n return {};\n }\n}\n\nexport function patchSessionMeta(name: string, patch: Partial<SessionMeta>): SessionMeta {\n const cur = loadSessionMeta(name);\n const next: SessionMeta = { ...cur, ...patch };\n const p = metaPath(name);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(next), \"utf8\");\n try {\n chmodSync(p, 0o600);\n } catch {\n /* chmod not supported */\n }\n return next;\n}\n\n/** Renames the JSONL plus all known sidecars together; returns false if target already exists. */\nexport function renameSession(oldName: string, newName: string): boolean {\n const safeOld = sanitizeName(oldName);\n const safeNew = sanitizeName(newName);\n if (safeOld === safeNew) return false;\n const oldJsonl = existingSessionPath(oldName);\n const newJsonl = sessionPath(newName);\n if (!existsSync(oldJsonl) || existsSync(newJsonl)) return false;\n mkdirSync(dirname(newJsonl), { recursive: true });\n renameSync(oldJsonl, newJsonl);\n for (const ext of SESSION_SIDECAR_EXTS) {\n const oldP = oldJsonl.replace(/\\.jsonl$/, ext);\n const newP = newJsonl.replace(/\\.jsonl$/, ext);\n if (existsSync(oldP)) {\n try {\n renameSync(oldP, newP);\n } catch {\n /* sidecar rename failed — leave the jsonl rename in place */\n }\n }\n }\n return true;\n}\n\n/** Best-effort: per-file delete errors are swallowed so partial pruning still finishes. */\nexport function pruneStaleSessions(daysOld = 90): string[] {\n const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1000;\n const deleted: string[] = [];\n for (const s of listSessions()) {\n if (s.mtime.getTime() < cutoff) {\n if (deleteSession(s.name)) deleted.push(s.name);\n }\n }\n return deleted;\n}\n\nexport function deleteSession(name: string): boolean {\n const path = existingSessionPath(name);\n try {\n unlinkSync(path);\n for (const ext of SESSION_SIDECAR_EXTS) {\n const sidecar = path.replace(/\\.jsonl$/, ext);\n try {\n unlinkSync(sidecar);\n } catch {\n /* expected when the sidecar doesn't exist */\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/** Crash-safe rewrite: snapshot the previous live log, write a sibling tmp file, then atomically swap it in. */\nexport function rewriteSession(name: string, messages: ChatMessage[]): void {\n const path = existingSessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n const body = messages.map((m) => JSON.stringify(m)).join(\"\\n\");\n const tmp = `${path}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;\n try {\n writeFileSync(tmp, body ? `${body}\\n` : \"\", \"utf8\");\n chmodPrivate(tmp);\n if (existsSync(path) && statSync(path).size > 0) {\n const backup = sessionBackupPath(path);\n copyFileSync(path, backup);\n chmodPrivate(backup);\n }\n renameSync(tmp, path);\n chmodPrivate(path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n /* tmp may not exist */\n }\n throw err;\n }\n}\n\n/** Rotate the live jsonl + sidecars to `<name>__archive_<ts>` so /new doesn't destroy history. Returns the archive name, or null if there was nothing to archive. */\nexport function archiveSession(name: string): string | null {\n const path = existingSessionPath(name);\n if (!existsSync(path)) return null;\n try {\n if (statSync(path).size === 0) return null;\n } catch {\n return null;\n }\n for (let attempt = 0; attempt < 5; attempt++) {\n const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : \"\"}`;\n if (renameSession(name, target)) return target;\n }\n return null;\n}\n\n/** Byte-scan for `\\n` — avoids the UTF-8 decode + regex split + per-line filter the previous implementation paid on every list. ~10× faster on multi-MB jsonls. */\nfunction countLines(path: string): number {\n try {\n const buf = readFileSync(path);\n let count = 0;\n for (let i = 0; i < buf.length; i++) {\n if (buf[i] === 0x0a) count++;\n }\n // appendSessionMessage always writes a trailing newline, but a\n // hand-edited file may end without one — account for the dangling line.\n if (buf.length > 0 && buf[buf.length - 1] !== 0x0a) count++;\n return count;\n } catch {\n return 0;\n }\n}\n\nfunction sessionBackupPath(path: string): string {\n return `${path}.bak`;\n}\n\nfunction chmodPrivate(path: string): void {\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported */\n }\n}\n"],"mappings":"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","names":[]}
|