apsolut-cortex 0.2.0 → 0.2.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.
Files changed (2) hide show
  1. package/dist/cli.js +121 -19
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import {
5
- existsSync as existsSync2,
6
- mkdirSync as mkdirSync2,
5
+ existsSync as existsSync3,
6
+ mkdirSync as mkdirSync3,
7
7
  readFileSync as readFileSync2,
8
8
  writeFileSync as writeFileSync2
9
9
  } from "fs";
@@ -12,21 +12,124 @@ import { homedir as homedir2 } from "os";
12
12
  import { fileURLToPath, pathToFileURL } from "url";
13
13
 
14
14
  // src/registry.ts
15
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
15
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
16
16
  import { dirname } from "path";
17
17
 
18
18
  // src/db.ts
19
19
  import Database from "better-sqlite3";
20
+ import { existsSync, mkdirSync } from "fs";
20
21
  import { homedir } from "os";
21
22
  import { join } from "path";
22
23
  var CORTEX_DIR = join(homedir(), ".apsolut");
23
24
  var DB_PATH = join(CORTEX_DIR, "memory.db");
24
25
  var REGISTRY_PATH = join(CORTEX_DIR, "registry.json");
25
26
  var MODELS_DIR = join(CORTEX_DIR, "models");
27
+ var _db = null;
28
+ function getDb() {
29
+ if (_db)
30
+ return _db;
31
+ if (!existsSync(CORTEX_DIR))
32
+ mkdirSync(CORTEX_DIR, { recursive: true });
33
+ if (!existsSync(MODELS_DIR))
34
+ mkdirSync(MODELS_DIR, { recursive: true });
35
+ _db = new Database(DB_PATH);
36
+ _db.pragma("journal_mode = WAL");
37
+ _db.pragma("synchronous = NORMAL");
38
+ _db.pragma("foreign_keys = ON");
39
+ _db.pragma("cache_size = -32000");
40
+ _db.exec(`
41
+ CREATE TABLE IF NOT EXISTS projects (
42
+ id TEXT PRIMARY KEY,
43
+ name TEXT NOT NULL,
44
+ path TEXT,
45
+ created_at INTEGER NOT NULL,
46
+ last_session INTEGER
47
+ );
48
+
49
+ CREATE TABLE IF NOT EXISTS sessions (
50
+ id TEXT PRIMARY KEY,
51
+ project_id TEXT NOT NULL REFERENCES projects(id),
52
+ started_at INTEGER NOT NULL,
53
+ ended_at INTEGER,
54
+ summary TEXT,
55
+ memories_injected INTEGER NOT NULL DEFAULT 0,
56
+ memories_stored INTEGER NOT NULL DEFAULT 0,
57
+ tool_failures INTEGER NOT NULL DEFAULT 0
58
+ );
59
+
60
+ CREATE INDEX IF NOT EXISTS idx_sessions_project
61
+ ON sessions(project_id, started_at DESC);
62
+
63
+ CREATE TABLE IF NOT EXISTS observations (
64
+ id TEXT PRIMARY KEY,
65
+ session_id TEXT NOT NULL REFERENCES sessions(id),
66
+ project_id TEXT NOT NULL,
67
+ tool_name TEXT,
68
+ content TEXT NOT NULL,
69
+ category TEXT,
70
+ created_at INTEGER NOT NULL,
71
+ promoted INTEGER NOT NULL DEFAULT 0
72
+ );
73
+
74
+ CREATE INDEX IF NOT EXISTS idx_obs_session ON observations(session_id);
75
+ CREATE INDEX IF NOT EXISTS idx_obs_project ON observations(project_id, created_at DESC);
76
+
77
+ CREATE TABLE IF NOT EXISTS memories (
78
+ id TEXT PRIMARY KEY,
79
+ project_id TEXT NOT NULL,
80
+ tier TEXT NOT NULL DEFAULT 'semantic',
81
+ category TEXT NOT NULL DEFAULT 'insight',
82
+ trust TEXT NOT NULL DEFAULT 'observed',
83
+ content TEXT NOT NULL,
84
+ context TEXT,
85
+ source TEXT NOT NULL DEFAULT 'manual',
86
+ embedding BLOB,
87
+ weight REAL NOT NULL DEFAULT 1.0,
88
+ used_count INTEGER NOT NULL DEFAULT 0,
89
+ last_used INTEGER,
90
+ created_at INTEGER NOT NULL,
91
+ session_id TEXT REFERENCES sessions(id),
92
+ flagged INTEGER NOT NULL DEFAULT 0,
93
+ flag_reason TEXT
94
+ );
95
+
96
+ CREATE INDEX IF NOT EXISTS idx_mem_project ON memories(project_id);
97
+ CREATE INDEX IF NOT EXISTS idx_mem_weight ON memories(project_id, weight DESC);
98
+ CREATE INDEX IF NOT EXISTS idx_mem_tier ON memories(project_id, tier);
99
+ CREATE INDEX IF NOT EXISTS idx_mem_trust ON memories(project_id, trust);
100
+ CREATE INDEX IF NOT EXISTS idx_mem_flagged ON memories(project_id, flagged)
101
+ WHERE flagged = 1;
102
+
103
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
104
+ content, context,
105
+ content='memories',
106
+ content_rowid='rowid',
107
+ tokenize='porter ascii'
108
+ );
109
+
110
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
111
+ INSERT INTO memories_fts(rowid, content, context)
112
+ VALUES (new.rowid, new.content, COALESCE(new.context, ''));
113
+ END;
114
+
115
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
116
+ INSERT INTO memories_fts(memories_fts, rowid, content, context)
117
+ VALUES ('delete', old.rowid, old.content, COALESCE(old.context, ''));
118
+ INSERT INTO memories_fts(rowid, content, context)
119
+ VALUES (new.rowid, new.content, COALESCE(new.context, ''));
120
+ END;
121
+
122
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
123
+ INSERT INTO memories_fts(memories_fts, rowid, content, context)
124
+ VALUES ('delete', old.rowid, old.content, COALESCE(old.context, ''));
125
+ END;
126
+ `);
127
+ return _db;
128
+ }
26
129
 
27
130
  // src/registry.ts
28
131
  function readRegistry() {
29
- if (!existsSync(REGISTRY_PATH))
132
+ if (!existsSync2(REGISTRY_PATH))
30
133
  return { projects: {} };
31
134
  try {
32
135
  return JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
@@ -36,8 +139,8 @@ function readRegistry() {
36
139
  }
37
140
  function writeRegistry(reg) {
38
141
  const dir = dirname(REGISTRY_PATH);
39
- if (!existsSync(dir))
40
- mkdirSync(dir, { recursive: true });
142
+ if (!existsSync2(dir))
143
+ mkdirSync2(dir, { recursive: true });
41
144
  writeFileSync(REGISTRY_PATH, JSON.stringify(reg, null, 2));
42
145
  }
43
146
  function registerProject(id, name, path) {
@@ -95,7 +198,7 @@ Models: ~/.apsolut/models/
95
198
  }
96
199
  async function runHook(name) {
97
200
  const hookPath = IS_DIST ? join2(__dirname2, "hooks", `${name}.js`) : join2(__dirname2, "hooks", `${name}.ts`);
98
- if (!existsSync2(hookPath)) {
201
+ if (!existsSync3(hookPath)) {
99
202
  process.stderr.write(`[apsolut-cortex] hook not found: ${hookPath}
100
203
  `);
101
204
  process.exit(0);
@@ -106,12 +209,12 @@ async function init() {
106
209
  console.log(`
107
210
  apsolut-cortex init
108
211
  `);
109
- if (!existsSync2(PROJECT_APSOLUT)) {
110
- mkdirSync2(PROJECT_APSOLUT, { recursive: true });
212
+ if (!existsSync3(PROJECT_APSOLUT)) {
213
+ mkdirSync3(PROJECT_APSOLUT, { recursive: true });
111
214
  }
112
215
  let projectId;
113
216
  let projectName;
114
- if (existsSync2(PROJECT_CONFIG)) {
217
+ if (existsSync3(PROJECT_CONFIG)) {
115
218
  const existing = JSON.parse(readFileSync2(PROJECT_CONFIG, "utf-8"));
116
219
  projectId = existing.id;
117
220
  projectName = existing.name;
@@ -134,7 +237,7 @@ apsolut-cortex init
134
237
  const mcpCommand = IS_DIST ? "node" : "bun";
135
238
  const mcpArgs = [mcpServerPath];
136
239
  let mcp = {};
137
- if (existsSync2(MCP_JSON)) {
240
+ if (existsSync3(MCP_JSON)) {
138
241
  try {
139
242
  mcp = JSON.parse(readFileSync2(MCP_JSON, "utf-8"));
140
243
  } catch {}
@@ -157,9 +260,9 @@ apsolut-cortex init
157
260
  };
158
261
  let settings = {};
159
262
  const settingsDir = dirname2(CLAUDE_SETTINGS);
160
- if (!existsSync2(settingsDir))
161
- mkdirSync2(settingsDir, { recursive: true });
162
- if (existsSync2(CLAUDE_SETTINGS)) {
263
+ if (!existsSync3(settingsDir))
264
+ mkdirSync3(settingsDir, { recursive: true });
265
+ if (existsSync3(CLAUDE_SETTINGS)) {
163
266
  try {
164
267
  settings = JSON.parse(readFileSync2(CLAUDE_SETTINGS, "utf-8"));
165
268
  } catch {}
@@ -178,7 +281,7 @@ apsolut-cortex init
178
281
  writeFileSync2(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
179
282
  console.log(added > 0 ? `✓ Registered ${added} hooks in ~/.claude/settings.json` : `✓ Hooks already registered`);
180
283
  const gitignore = join2(PROJECT_ROOT, ".gitignore");
181
- if (existsSync2(gitignore)) {
284
+ if (existsSync3(gitignore)) {
182
285
  const content = readFileSync2(gitignore, "utf-8");
183
286
  if (!content.includes(".apsolut/")) {
184
287
  writeFileSync2(gitignore, content + `
@@ -216,8 +319,7 @@ apsolut-cortex init
216
319
  console.log(BANNER);
217
320
  }
218
321
  async function status() {
219
- const { getDb } = await import(pathToFileURL(join2(__dirname2, "db.js")).href);
220
- if (!existsSync2(PROJECT_CONFIG)) {
322
+ if (!existsSync3(PROJECT_CONFIG)) {
221
323
  console.log("No project found. Run: apsolut-cortex init");
222
324
  process.exit(1);
223
325
  }
@@ -252,7 +354,7 @@ DB: ~/.apsolut/memory.db
252
354
  `);
253
355
  }
254
356
  function uninstall() {
255
- if (existsSync2(MCP_JSON)) {
357
+ if (existsSync3(MCP_JSON)) {
256
358
  try {
257
359
  const mcp = JSON.parse(readFileSync2(MCP_JSON, "utf-8"));
258
360
  if (mcp.mcpServers?.["apsolut-cortex"]) {
@@ -262,7 +364,7 @@ function uninstall() {
262
364
  }
263
365
  } catch {}
264
366
  }
265
- if (existsSync2(CLAUDE_SETTINGS)) {
367
+ if (existsSync3(CLAUDE_SETTINGS)) {
266
368
  try {
267
369
  const settings = JSON.parse(readFileSync2(CLAUDE_SETTINGS, "utf-8"));
268
370
  const hooks = settings.hooks;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apsolut-cortex",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Persistent memory for Claude Code projects — stores corrections, decisions, and patterns across sessions",
5
5
  "type": "module",
6
6
  "bin": {