@patravishek/memex 0.2.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.
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.wrapProcess = wrapProcess;
37
+ const child_process = __importStar(require("child_process"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ // Common binary locations — checked in order when shell lookup fails
42
+ const COMMON_BIN_DIRS = [
43
+ "/opt/homebrew/bin",
44
+ "/usr/local/bin",
45
+ "/usr/bin",
46
+ "/bin",
47
+ process.env.HOME ? `${process.env.HOME}/.local/bin` : "",
48
+ ].filter(Boolean);
49
+ function resolveCommandPath(command) {
50
+ if (command.startsWith("/"))
51
+ return command;
52
+ try {
53
+ const shell = process.env.SHELL ?? "/bin/zsh";
54
+ const result = child_process.spawnSync(shell, ["-lc", `which ${command}`], {
55
+ encoding: "utf-8",
56
+ timeout: 5000,
57
+ });
58
+ const resolved = result.stdout?.trim().split("\n")[0];
59
+ if (resolved && resolved.startsWith("/"))
60
+ return resolved;
61
+ }
62
+ catch {
63
+ // fall through
64
+ }
65
+ for (const dir of COMMON_BIN_DIRS) {
66
+ const candidate = path.join(dir, command);
67
+ try {
68
+ fs.accessSync(candidate, fs.constants.X_OK);
69
+ return candidate;
70
+ }
71
+ catch {
72
+ // keep scanning
73
+ }
74
+ }
75
+ return command;
76
+ }
77
+ /**
78
+ * Primary strategy: record via macOS `script` command (no native bindings).
79
+ * `script -q <logfile> <cmd>` transparently records all terminal I/O.
80
+ */
81
+ async function wrapWithScript(logger, options, resolvedCommand) {
82
+ return new Promise((resolve, reject) => {
83
+ // script records raw terminal output; we use a separate txt file for it
84
+ const rawLogPath = logger.getLogPath().replace(".jsonl", "-raw.txt");
85
+ // If we need to inject a resume prompt, write it to a temp file
86
+ // and prepend a note so the agent reads it on first turn
87
+ let injectFile = null;
88
+ if (options.injectOnReady) {
89
+ injectFile = path.join(os.tmpdir(), `memex-context-${Date.now()}.txt`);
90
+ fs.writeFileSync(injectFile, options.injectOnReady, "utf-8");
91
+ }
92
+ const args = options.args ?? [];
93
+ // macOS `script` syntax: script [-q] [-F pipe] [file [command [args]]]
94
+ // -q = quiet (no typescript start/stop messages)
95
+ const scriptArgs = ["-q", rawLogPath, resolvedCommand, ...args];
96
+ const proc = child_process.spawn("script", scriptArgs, {
97
+ stdio: "inherit",
98
+ cwd: options.cwd ?? process.cwd(),
99
+ env: {
100
+ ...sanitizeEnv(process.env),
101
+ ...(injectFile ? { MEMEX_CONTEXT_FILE: injectFile } : {}),
102
+ },
103
+ });
104
+ // If injecting a resume prompt, auto-type it via a stdin write after delay
105
+ if (injectFile && options.injectOnReady) {
106
+ const delay = options.injectDelayMs ?? 3000;
107
+ const text = options.injectOnReady;
108
+ setTimeout(() => {
109
+ try {
110
+ if (proc.stdin) {
111
+ proc.stdin.write(text + "\n");
112
+ }
113
+ else {
114
+ // stdin is inherited — write directly to process.stdin
115
+ process.stdin.write(text + "\n");
116
+ }
117
+ }
118
+ catch {
119
+ // ignore — session may have ended
120
+ }
121
+ }, delay);
122
+ }
123
+ proc.on("error", (err) => {
124
+ reject(new Error(`Failed to start session: ${err.message}`));
125
+ });
126
+ proc.on("close", (code) => {
127
+ // Parse the raw script log into a readable transcript
128
+ const transcript = parseScriptLog(rawLogPath);
129
+ // Feed into session logger so it's saved in structured format
130
+ transcript.split("\n").forEach((line) => {
131
+ if (line.trim())
132
+ logger.logOutput(line);
133
+ });
134
+ logger.close();
135
+ if (injectFile && fs.existsSync(injectFile)) {
136
+ fs.unlinkSync(injectFile);
137
+ }
138
+ resolve({
139
+ exitCode: code ?? 0,
140
+ transcript,
141
+ logPath: logger.getLogPath(),
142
+ });
143
+ });
144
+ });
145
+ }
146
+ /**
147
+ * Fallback strategy: spawn directly with inherited stdio.
148
+ * No transcript capture — compression will work from minimal context.
149
+ */
150
+ async function wrapWithSpawn(logger, options, resolvedCommand) {
151
+ return new Promise((resolve, reject) => {
152
+ const proc = child_process.spawn(resolvedCommand, options.args ?? [], {
153
+ stdio: "inherit",
154
+ cwd: options.cwd ?? process.cwd(),
155
+ env: sanitizeEnv(process.env),
156
+ });
157
+ proc.on("error", (err) => {
158
+ reject(new Error(`Could not start "${resolvedCommand}": ${err.message}\n` +
159
+ `Verify it is installed: which ${options.command}`));
160
+ });
161
+ proc.on("close", (code) => {
162
+ logger.close();
163
+ resolve({
164
+ exitCode: code ?? 0,
165
+ transcript: logger.getTranscript(),
166
+ logPath: logger.getLogPath(),
167
+ });
168
+ });
169
+ });
170
+ }
171
+ /**
172
+ * Strip Memex-internal API keys from the environment before passing it to the
173
+ * wrapped agent. This prevents conflicts like Claude CLI warning about
174
+ * ANTHROPIC_API_KEY clashing with a claude.ai login session.
175
+ */
176
+ function sanitizeEnv(env) {
177
+ const MEMEX_ONLY_KEYS = [
178
+ "ANTHROPIC_API_KEY",
179
+ "OPENAI_API_KEY",
180
+ "LITELLM_API_KEY",
181
+ "LITELLM_BASE_URL",
182
+ "LITELLM_MODEL",
183
+ "LITELLM_TEAM_ID",
184
+ "ANTHROPIC_MODEL",
185
+ "OPENAI_MODEL",
186
+ "AI_PROVIDER",
187
+ ];
188
+ return Object.fromEntries(Object.entries(env)
189
+ .filter(([key]) => !MEMEX_ONLY_KEYS.includes(key))
190
+ .filter((entry) => entry[1] !== undefined));
191
+ }
192
+ async function wrapProcess(logger, options) {
193
+ const resolvedCommand = resolveCommandPath(options.command);
194
+ // Check the command actually exists before attempting anything
195
+ try {
196
+ fs.accessSync(resolvedCommand, fs.constants.X_OK);
197
+ }
198
+ catch {
199
+ throw new Error(`Command "${options.command}" not found or not executable.\n` +
200
+ `Expected at: ${resolvedCommand}\n` +
201
+ `Run: which ${options.command}`);
202
+ }
203
+ // Try script-based recording first (macOS built-in, no native deps)
204
+ try {
205
+ return await wrapWithScript(logger, options, resolvedCommand);
206
+ }
207
+ catch (scriptErr) {
208
+ // Fall back to plain spawn with inherited stdio
209
+ console.error(`\n [memex] script recording unavailable, falling back to direct spawn`);
210
+ return await wrapWithSpawn(logger, options, resolvedCommand);
211
+ }
212
+ }
213
+ function parseScriptLog(logPath) {
214
+ if (!fs.existsSync(logPath))
215
+ return "";
216
+ try {
217
+ const raw = fs.readFileSync(logPath, "utf-8");
218
+ // Strip ANSI escape codes and carriage returns
219
+ const clean = raw
220
+ .replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "")
221
+ .replace(/\x1b\[[0-9;]*m/g, "")
222
+ .replace(/\r\n/g, "\n")
223
+ .replace(/\r/g, "\n")
224
+ .replace(/[^\x20-\x7E\n\t]/g, "")
225
+ .replace(/\n{3,}/g, "\n\n")
226
+ .trim();
227
+ return clean;
228
+ }
229
+ catch {
230
+ return "";
231
+ }
232
+ }
233
+ //# sourceMappingURL=pty-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pty-wrapper.js","sourceRoot":"","sources":["../../src/core/pty-wrapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface LogEntry {
2
+ ts: number;
3
+ source: "user" | "agent";
4
+ raw: string;
5
+ text: string;
6
+ }
7
+ export interface ConversationTurn {
8
+ role: "user" | "assistant";
9
+ content: string;
10
+ ts: number;
11
+ }
12
+ export declare class SessionLogger {
13
+ private logPath;
14
+ private buffer;
15
+ private writeStream;
16
+ private inputBuffer;
17
+ constructor(memexDir: string);
18
+ logOutput(raw: string): void;
19
+ logInput(raw: string): void;
20
+ getTranscript(): string;
21
+ /**
22
+ * Collapse sequential entries from the same source into conversation turns.
23
+ * This simulates the message structure of the original session so it can be
24
+ * re-injected as context on resume — replicating Claude's --resume behaviour
25
+ * without depending on Anthropic's server-side session storage.
26
+ */
27
+ getConversationTurns(): ConversationTurn[];
28
+ getLogPath(): string;
29
+ getEntryCount(): number;
30
+ close(): void;
31
+ }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.SessionLogger = void 0;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ // @ts-ignore - strip-ansi v6 CJS has no types issue
43
+ const strip_ansi_1 = __importDefault(require("strip-ansi"));
44
+ class SessionLogger {
45
+ logPath;
46
+ buffer = [];
47
+ writeStream;
48
+ inputBuffer = "";
49
+ constructor(memexDir) {
50
+ const sessionsDir = path.join(memexDir, "sessions");
51
+ fs.mkdirSync(sessionsDir, { recursive: true });
52
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
53
+ this.logPath = path.join(sessionsDir, `${timestamp}.jsonl`);
54
+ this.writeStream = fs.createWriteStream(this.logPath, { flags: "a" });
55
+ }
56
+ logOutput(raw) {
57
+ const text = (0, strip_ansi_1.default)(raw).trim();
58
+ if (!text)
59
+ return;
60
+ const entry = {
61
+ ts: Date.now(),
62
+ source: "agent",
63
+ raw,
64
+ text,
65
+ };
66
+ this.buffer.push(entry);
67
+ this.writeStream.write(JSON.stringify(entry) + "\n");
68
+ }
69
+ logInput(raw) {
70
+ // Buffer input chars and flush on newline
71
+ this.inputBuffer += raw;
72
+ if (this.inputBuffer.includes("\r") || this.inputBuffer.includes("\n")) {
73
+ const text = (0, strip_ansi_1.default)(this.inputBuffer).replace(/[\r\n]/g, "").trim();
74
+ this.inputBuffer = "";
75
+ if (!text)
76
+ return;
77
+ const entry = {
78
+ ts: Date.now(),
79
+ source: "user",
80
+ raw,
81
+ text,
82
+ };
83
+ this.buffer.push(entry);
84
+ this.writeStream.write(JSON.stringify(entry) + "\n");
85
+ }
86
+ }
87
+ getTranscript() {
88
+ return this.buffer
89
+ .map((e) => `[${e.source.toUpperCase()}]: ${e.text}`)
90
+ .join("\n");
91
+ }
92
+ /**
93
+ * Collapse sequential entries from the same source into conversation turns.
94
+ * This simulates the message structure of the original session so it can be
95
+ * re-injected as context on resume — replicating Claude's --resume behaviour
96
+ * without depending on Anthropic's server-side session storage.
97
+ */
98
+ getConversationTurns() {
99
+ const turns = [];
100
+ for (const entry of this.buffer) {
101
+ const role = entry.source === "user" ? "user" : "assistant";
102
+ const last = turns[turns.length - 1];
103
+ if (last && last.role === role) {
104
+ // Merge consecutive messages from the same role into one turn
105
+ last.content += "\n" + entry.text;
106
+ }
107
+ else {
108
+ turns.push({ role, content: entry.text, ts: entry.ts });
109
+ }
110
+ }
111
+ return turns;
112
+ }
113
+ getLogPath() {
114
+ return this.logPath;
115
+ }
116
+ getEntryCount() {
117
+ return this.buffer.length;
118
+ }
119
+ close() {
120
+ this.writeStream.end();
121
+ }
122
+ }
123
+ exports.SessionLogger = SessionLogger;
124
+ //# sourceMappingURL=session-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-logger.js","sourceRoot":"","sources":["../../src/core/session-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { ProjectMemory } from "./store.js";
2
+ export declare function compressSession(transcript: string, projectPath: string, logFile: string): Promise<ProjectMemory>;
3
+ export declare function buildResumePrompt(memory: ProjectMemory): string;
4
+ export declare function writeResumeFile(memory: ProjectMemory, filePath: string): void;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compressSession = compressSession;
4
+ exports.buildResumePrompt = buildResumePrompt;
5
+ exports.writeResumeFile = writeResumeFile;
6
+ const provider_js_1 = require("../ai/provider.js");
7
+ const store_js_1 = require("./store.js");
8
+ const SYSTEM_PROMPT = `You are a memory manager for an AI coding agent.
9
+ Your job is to extract and maintain a structured understanding of a software project
10
+ from conversation transcripts between a developer and an AI assistant.
11
+
12
+ Be concise, accurate, and practical. Focus on what would actually help the AI
13
+ resume work on this project without losing context. Output must always be valid JSON.`;
14
+ async function compressSession(transcript, projectPath, logFile) {
15
+ const existing = (0, store_js_1.loadMemory)(projectPath) ?? (0, store_js_1.initMemory)(projectPath);
16
+ const existingContext = existing.description
17
+ ? `Existing project memory:\n${JSON.stringify(existing, null, 2)}`
18
+ : "No existing memory for this project.";
19
+ const response = await (0, provider_js_1.chat)([
20
+ {
21
+ role: "user",
22
+ content: `Analyze this conversation transcript and update the project memory.
23
+
24
+ ${existingContext}
25
+
26
+ --- TRANSCRIPT ---
27
+ ${transcript.slice(-12000)}
28
+ --- END TRANSCRIPT ---
29
+
30
+ Return an updated JSON object merging existing memory with new information from this session.
31
+ Schema:
32
+ {
33
+ "projectName": "string",
34
+ "projectPath": "${projectPath}",
35
+ "stack": ["array of tech stack items"],
36
+ "description": "string - what this project does",
37
+ "keyDecisions": [
38
+ { "decision": "string", "reason": "string", "date": "ISO date string" }
39
+ ],
40
+ "currentFocus": "string - what is being worked on right now",
41
+ "pendingTasks": ["string array - tasks mentioned but not completed"],
42
+ "importantFiles": [
43
+ { "filePath": "string", "purpose": "string" }
44
+ ],
45
+ "gotchas": ["string array - problems encountered, mistakes made, things to avoid"],
46
+ "recentSessions": ${JSON.stringify(existing.recentSessions ?? [])},
47
+ "lastUpdated": "${new Date().toISOString()}"
48
+ }
49
+
50
+ Add a new entry to recentSessions:
51
+ { "date": "${new Date().toISOString()}", "summary": "2-3 sentence summary of this session", "logFile": "${logFile}" }
52
+
53
+ Keep recentSessions to the last 5 entries only.
54
+ Return ONLY the JSON, no markdown, no explanation.`,
55
+ },
56
+ ], SYSTEM_PROMPT);
57
+ try {
58
+ // Strip markdown code fences if the AI wrapped the JSON in them
59
+ const cleaned = response
60
+ .trim()
61
+ .replace(/^```(?:json)?\s*/i, "")
62
+ .replace(/\s*```$/, "")
63
+ .trim();
64
+ const updated = JSON.parse(cleaned);
65
+ (0, store_js_1.saveMemory)(projectPath, updated);
66
+ return updated;
67
+ }
68
+ catch (parseErr) {
69
+ const reason = response.trim().length === 0
70
+ ? "AI returned an empty response — is your API key set correctly?"
71
+ : `Could not parse AI response as JSON: ${parseErr.message}`;
72
+ existing.recentSessions.push({
73
+ date: new Date().toISOString(),
74
+ summary: `Session recorded but compression failed — ${reason}`,
75
+ logFile,
76
+ });
77
+ if (existing.recentSessions.length > 5) {
78
+ existing.recentSessions = existing.recentSessions.slice(-5);
79
+ }
80
+ (0, store_js_1.saveMemory)(projectPath, existing);
81
+ // Re-throw so the CLI can surface the real reason to the user
82
+ throw new Error(reason);
83
+ }
84
+ }
85
+ function buildResumePrompt(memory) {
86
+ const lastSession = memory.recentSessions.at(-1);
87
+ const lastDate = lastSession
88
+ ? new Date(lastSession.date).toLocaleString()
89
+ : "unknown";
90
+ const sections = [
91
+ `Project: ${memory.projectName}`,
92
+ ];
93
+ if (memory.description)
94
+ sections.push(`Description: ${memory.description}`);
95
+ if (memory.stack.length)
96
+ sections.push(`Stack: ${memory.stack.join(", ")}`);
97
+ if (memory.currentFocus)
98
+ sections.push(`Current focus: ${memory.currentFocus}`);
99
+ if (memory.pendingTasks.length) {
100
+ sections.push(`Pending tasks:\n${memory.pendingTasks.map((t) => `- ${t}`).join("\n")}`);
101
+ }
102
+ if (memory.keyDecisions.length) {
103
+ sections.push(`Key decisions:\n${memory.keyDecisions.map((d) => `- ${d.decision} (${d.reason})`).join("\n")}`);
104
+ }
105
+ if (memory.gotchas.length) {
106
+ sections.push(`Gotchas to avoid:\n${memory.gotchas.map((g) => `- ${g}`).join("\n")}`);
107
+ }
108
+ if (memory.importantFiles.length) {
109
+ sections.push(`Important files:\n${memory.importantFiles.map((f) => `- ${f.filePath}: ${f.purpose}`).join("\n")}`);
110
+ }
111
+ if (lastSession) {
112
+ sections.push(`Last session (${lastDate}):\n${lastSession.summary}`);
113
+ }
114
+ return [
115
+ "# Memex — Session Context",
116
+ "",
117
+ "> This file was written by Memex before this session started.",
118
+ "> **When you start, read this fully, then immediately say:**",
119
+ "> _\"Continuing from our last session — [one sentence on where we left off]. Here's what I have in memory: [brief summary]. What would you like to work on?\"_",
120
+ "",
121
+ "---",
122
+ "",
123
+ sections.join("\n\n"),
124
+ ].join("\n");
125
+ }
126
+ /**
127
+ * Write resume context to a markdown file so it can be read cleanly
128
+ * without being piped through stdin (which causes formatting issues).
129
+ * Includes the recent conversation history if available, simulating
130
+ * Claude's --resume behaviour without relying on server-side sessions.
131
+ */
132
+ const CLAUDE_MD_CHAR_LIMIT = 35000; // Stay safely under Claude's 40k warning
133
+ const MAX_TURNS_IN_CLAUDE_MD = 10; // Last N turns of conversation to inject
134
+ const MAX_TURN_CHARS = 1500; // Truncate individual long turns
135
+ function writeResumeFile(memory, filePath) {
136
+ const fs = require("fs");
137
+ const lines = [buildResumePrompt(memory)];
138
+ if (memory.lastConversation && memory.lastConversation.length > 0) {
139
+ const recentTurns = memory.lastConversation.slice(-MAX_TURNS_IN_CLAUDE_MD);
140
+ lines.push("");
141
+ lines.push("---");
142
+ lines.push("");
143
+ lines.push(`Last ${recentTurns.length} conversation turns (use to understand where we left off):`);
144
+ lines.push("");
145
+ for (const turn of recentTurns) {
146
+ const label = turn.role === "user" ? "Human" : "Assistant";
147
+ const content = turn.content.length > MAX_TURN_CHARS
148
+ ? turn.content.slice(0, MAX_TURN_CHARS) + "… [truncated]"
149
+ : turn.content;
150
+ lines.push(`**${label}:** ${content}`);
151
+ lines.push("");
152
+ }
153
+ }
154
+ // Hard cap — truncate from the bottom (trim conversation history, keep memory)
155
+ let content = lines.join("\n");
156
+ if (content.length > CLAUDE_MD_CHAR_LIMIT) {
157
+ content = content.slice(0, CLAUDE_MD_CHAR_LIMIT);
158
+ // Ensure we don't cut mid-line
159
+ const lastNewline = content.lastIndexOf("\n");
160
+ if (lastNewline > CLAUDE_MD_CHAR_LIMIT * 0.8) {
161
+ content = content.slice(0, lastNewline);
162
+ }
163
+ content += "\n\n> [Memex: conversation history truncated to fit size limit]";
164
+ }
165
+ fs.writeFileSync(filePath, content, "utf-8");
166
+ }
167
+ //# sourceMappingURL=compressor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compressor.js","sourceRoot":"","sources":["../../src/memory/compressor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { ConversationTurn } from "../core/session-logger.js";
2
+ export interface KeyDecision {
3
+ decision: string;
4
+ reason: string;
5
+ date: string;
6
+ }
7
+ export interface ImportantFile {
8
+ filePath: string;
9
+ purpose: string;
10
+ }
11
+ export interface RecentSession {
12
+ date: string;
13
+ summary: string;
14
+ logFile: string;
15
+ }
16
+ export interface ProjectMemory {
17
+ projectName: string;
18
+ projectPath: string;
19
+ stack: string[];
20
+ description: string;
21
+ keyDecisions: KeyDecision[];
22
+ currentFocus: string;
23
+ pendingTasks: string[];
24
+ importantFiles: ImportantFile[];
25
+ /** Things that went wrong or surprised us — prevents repeating mistakes */
26
+ gotchas: string[];
27
+ recentSessions: RecentSession[];
28
+ /**
29
+ * Last N conversation turns from the most recent session.
30
+ * Used to simulate Claude's --resume without relying on server-side
31
+ * session storage that expires. Never expires, works across machines.
32
+ */
33
+ lastConversation: ConversationTurn[];
34
+ lastUpdated: string;
35
+ }
36
+ export declare function getMemexDir(projectPath: string): string;
37
+ export declare function memoryExists(projectPath: string): boolean;
38
+ export declare function loadMemory(projectPath: string): ProjectMemory | null;
39
+ export declare function saveMemory(projectPath: string, memory: ProjectMemory): void;
40
+ export declare function initMemory(projectPath: string): ProjectMemory;
41
+ export declare function clearMemory(projectPath: string, keepSessions?: boolean): void;
42
+ export declare function formatMemoryForPrompt(memory: ProjectMemory): string;