@inetafrica/open-claudia 1.20.0 → 1.20.1
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/bot.js +25 -4
- package/package.json +1 -1
- package/project-transcripts.js +17 -12
package/bot.js
CHANGED
|
@@ -651,6 +651,20 @@ function getLastProjectSession(userId, projectName) {
|
|
|
651
651
|
return sessions.length > 0 ? sessions[0] : null;
|
|
652
652
|
}
|
|
653
653
|
|
|
654
|
+
// Guard against cross-user session-id leakage from migration glitches:
|
|
655
|
+
// confirm sessionId is recorded under this userId in sessions.json
|
|
656
|
+
// before we hand it to `claude --resume`.
|
|
657
|
+
function userOwnsClaudeSession(userId, sessionId) {
|
|
658
|
+
if (!sessionId) return false;
|
|
659
|
+
const all = loadSessions();
|
|
660
|
+
const bucket = all[normalizeCanonicalUserId(userId)];
|
|
661
|
+
if (!bucket) return false;
|
|
662
|
+
for (const list of Object.values(bucket)) {
|
|
663
|
+
if (Array.isArray(list) && list.some((s) => s && s.id === sessionId)) return true;
|
|
664
|
+
}
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
|
|
654
668
|
function isAuthorized(msg) {
|
|
655
669
|
const chatId = String(msg.chat.id);
|
|
656
670
|
if (CHAT_IDS.includes(chatId)) return true;
|
|
@@ -1348,12 +1362,12 @@ if (PROJECT_TRANSCRIPTS) {
|
|
|
1348
1362
|
|
|
1349
1363
|
function transcriptProjectInfo(state = currentState()) {
|
|
1350
1364
|
if (!state.currentSession) return null;
|
|
1351
|
-
return projectTranscripts.pointer(state.currentSession.dir, state.currentSession.name);
|
|
1365
|
+
return projectTranscripts.pointer(state.currentSession.dir, state.currentSession.name, state.userId);
|
|
1352
1366
|
}
|
|
1353
1367
|
|
|
1354
1368
|
function transcriptPointerNote(state = currentState()) {
|
|
1355
1369
|
if (!state.currentSession) return "";
|
|
1356
|
-
return projectTranscripts.buildPointerNote(state.currentSession.dir, state.currentSession.name);
|
|
1370
|
+
return projectTranscripts.buildPointerNote(state.currentSession.dir, state.currentSession.name, state.userId);
|
|
1357
1371
|
}
|
|
1358
1372
|
|
|
1359
1373
|
function appendProjectTranscript(role, text, metadata = {}, state = currentState()) {
|
|
@@ -1378,7 +1392,7 @@ function appendProjectTranscript(role, text, metadata = {}, state = currentState
|
|
|
1378
1392
|
|
|
1379
1393
|
function promptWithTranscriptPointer(prompt, state = currentState()) {
|
|
1380
1394
|
if (!state.currentSession) return prompt;
|
|
1381
|
-
return projectTranscripts.withPointer(prompt, state.currentSession.dir, state.currentSession.name);
|
|
1395
|
+
return projectTranscripts.withPointer(prompt, state.currentSession.dir, state.currentSession.name, state.userId);
|
|
1382
1396
|
}
|
|
1383
1397
|
|
|
1384
1398
|
function stripTranscriptPointerForStorage(prompt) {
|
|
@@ -1728,7 +1742,14 @@ function buildClaudeArgs(prompt, opts = {}) {
|
|
|
1728
1742
|
if (transcriptInfo) args.push("--add-dir", transcriptInfo.transcriptsDir);
|
|
1729
1743
|
if (opts.resumeSessionId) args.push("--resume", opts.resumeSessionId);
|
|
1730
1744
|
else if (opts.continueSession) args.push("--continue");
|
|
1731
|
-
else if (state.lastSessionId && !opts.fresh)
|
|
1745
|
+
else if (state.lastSessionId && !opts.fresh) {
|
|
1746
|
+
if (userOwnsClaudeSession(state.userId, state.lastSessionId)) {
|
|
1747
|
+
args.push("--resume", state.lastSessionId);
|
|
1748
|
+
} else {
|
|
1749
|
+
console.warn(`[session-guard] dropping stale lastSessionId=${state.lastSessionId.slice(0, 8)} for ${state.userId}; not present in sessions.json — starting fresh`);
|
|
1750
|
+
state.lastSessionId = null;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1732
1753
|
if (settings.model) args.push("--model", settings.model);
|
|
1733
1754
|
if (settings.effort) args.push("--effort", settings.effort);
|
|
1734
1755
|
if (settings.budget) args.push("--max-budget-usd", String(settings.budget));
|
package/package.json
CHANGED
package/project-transcripts.js
CHANGED
|
@@ -21,8 +21,10 @@ function safeName(value) {
|
|
|
21
21
|
return String(value || "project").replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "project";
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function projectHash(projectPath) {
|
|
25
|
-
|
|
24
|
+
function projectHash(projectPath, userId) {
|
|
25
|
+
const normalized = normalizeProjectPath(projectPath);
|
|
26
|
+
const seed = userId ? `${String(userId)} ${normalized}` : normalized;
|
|
27
|
+
return crypto.createHash("sha256").update(seed).digest("hex").slice(0, 24);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
function mkdirp(dir) {
|
|
@@ -39,13 +41,14 @@ class ProjectTranscripts {
|
|
|
39
41
|
this.redact = redact;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
projectInfo(projectPath, projectName) {
|
|
44
|
+
projectInfo(projectPath, projectName, userId) {
|
|
43
45
|
const normalizedPath = normalizeProjectPath(projectPath);
|
|
44
|
-
const hash = projectHash(normalizedPath);
|
|
46
|
+
const hash = projectHash(normalizedPath, userId);
|
|
45
47
|
const name = projectName || path.basename(normalizedPath) || "project";
|
|
46
48
|
const baseName = `${hash}-${safeName(name)}`;
|
|
47
49
|
return {
|
|
48
50
|
hash,
|
|
51
|
+
userId: userId || null,
|
|
49
52
|
projectName: name,
|
|
50
53
|
projectPath: normalizedPath,
|
|
51
54
|
transcriptPath: path.join(this.transcriptsDir, `${baseName}.jsonl`),
|
|
@@ -54,13 +57,13 @@ class ProjectTranscripts {
|
|
|
54
57
|
};
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
pointer(projectPath, projectName) {
|
|
60
|
+
pointer(projectPath, projectName, userId) {
|
|
58
61
|
if (!this.enabled || !projectPath) return null;
|
|
59
|
-
return this.projectInfo(projectPath, projectName);
|
|
62
|
+
return this.projectInfo(projectPath, projectName, userId);
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
buildPointerNote(projectPath, projectName) {
|
|
63
|
-
const info = this.pointer(projectPath, projectName);
|
|
65
|
+
buildPointerNote(projectPath, projectName, userId) {
|
|
66
|
+
const info = this.pointer(projectPath, projectName, userId);
|
|
64
67
|
if (!info) return "";
|
|
65
68
|
return [
|
|
66
69
|
"## Project Transcript Memory",
|
|
@@ -71,8 +74,8 @@ class ProjectTranscripts {
|
|
|
71
74
|
].join("\n");
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
withPointer(prompt, projectPath, projectName) {
|
|
75
|
-
const note = this.buildPointerNote(projectPath, projectName);
|
|
77
|
+
withPointer(prompt, projectPath, projectName, userId) {
|
|
78
|
+
const note = this.buildPointerNote(projectPath, projectName, userId);
|
|
76
79
|
if (!note) return prompt;
|
|
77
80
|
return `${note}\n\nCurrent user request:\n${prompt}`;
|
|
78
81
|
}
|
|
@@ -96,13 +99,14 @@ class ProjectTranscripts {
|
|
|
96
99
|
|
|
97
100
|
append(entry) {
|
|
98
101
|
if (!this.enabled || !entry || !entry.projectPath) return null;
|
|
99
|
-
const
|
|
102
|
+
const canonicalUserId = entry.userId || entry.canonicalUserId || null;
|
|
103
|
+
const info = this.projectInfo(entry.projectPath, entry.projectName, canonicalUserId);
|
|
100
104
|
mkdirp(this.transcriptsDir);
|
|
101
105
|
const textData = this.truncateText(entry.text);
|
|
102
106
|
const now = new Date().toISOString();
|
|
103
107
|
const record = {
|
|
104
108
|
timestamp: entry.timestamp || now,
|
|
105
|
-
canonicalUserId
|
|
109
|
+
canonicalUserId,
|
|
106
110
|
chat: entry.chat || null,
|
|
107
111
|
project: { name: info.projectName, path: info.projectPath, hash: info.hash },
|
|
108
112
|
backend: entry.backend || null,
|
|
@@ -118,6 +122,7 @@ class ProjectTranscripts {
|
|
|
118
122
|
fs.appendFileSync(info.transcriptPath, JSON.stringify(record) + "\n", { mode: 0o600 });
|
|
119
123
|
const metadata = {
|
|
120
124
|
projectHash: info.hash,
|
|
125
|
+
canonicalUserId,
|
|
121
126
|
projectName: info.projectName,
|
|
122
127
|
projectPath: info.projectPath,
|
|
123
128
|
transcriptPath: info.transcriptPath,
|