engramx 0.5.3 → 1.0.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.
@@ -0,0 +1,54 @@
1
+ // src/generators/aider-context.ts
2
+ import { mkdirSync, writeFileSync } from "fs";
3
+ import { join, dirname } from "path";
4
+ var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
5
+ function buildSection(heading, lines) {
6
+ if (lines.length === 0) return "";
7
+ return [`## ${heading}`, "", ...lines, ""].join("\n");
8
+ }
9
+ async function generateAiderContext(projectRoot) {
10
+ const { getStore } = await import("./core-77MHT3QV.js");
11
+ const store = await getStore(projectRoot);
12
+ try {
13
+ const allNodes = store.getAllNodes();
14
+ const now = Date.now();
15
+ const cutoff = now - THIRTY_DAYS_MS;
16
+ const godNodes = store.getGodNodes(10);
17
+ const architectureLines = godNodes.map(
18
+ ({ node, degree }) => `- \`${node.label}\` (${node.kind}, ${degree} connections) \u2014 ${node.sourceFile}`
19
+ );
20
+ const hotFileLines = allNodes.filter(
21
+ (n) => n.kind === "pattern" && n.metadata.type === "hot_file"
22
+ ).slice(0, 10).map((n) => `- ${n.label}`);
23
+ const issueLines = allNodes.filter((n) => n.kind === "mistake").sort((a, b) => b.queryCount - a.queryCount).slice(0, 5).map((n) => `- ${n.label}`);
24
+ const decisionLines = allNodes.filter((n) => n.kind === "decision" && n.lastVerified >= cutoff).sort((a, b) => b.lastVerified - a.lastVerified).map((n) => `- ${n.label}`);
25
+ const patternLines = allNodes.filter(
26
+ (n) => n.kind === "pattern" && n.confidenceScore >= 0.8 && n.metadata.type !== "hot_file"
27
+ ).map((n) => `- ${n.label}`);
28
+ const sections = [
29
+ buildSection("Architecture", architectureLines),
30
+ buildSection("Hot Files", hotFileLines),
31
+ buildSection("Known Issues", issueLines),
32
+ buildSection("Decisions", decisionLines),
33
+ buildSection("Key Patterns", patternLines)
34
+ ].filter((s) => s.length > 0);
35
+ const header = [
36
+ "# engram context",
37
+ "",
38
+ "> Auto-generated by engram. Do not edit manually.",
39
+ "> Regenerate: `engram gen-aider -p .`",
40
+ ""
41
+ ].join("\n");
42
+ const content = header + sections.join("\n");
43
+ const outPath = join(projectRoot, ".aider-context.md");
44
+ mkdirSync(dirname(outPath), { recursive: true });
45
+ writeFileSync(outPath, content, "utf-8");
46
+ const nodeCount = architectureLines.length + hotFileLines.length + issueLines.length + decisionLines.length + patternLines.length;
47
+ return { filePath: outPath, sections: sections.length, nodes: nodeCount };
48
+ } finally {
49
+ store.close();
50
+ }
51
+ }
52
+ export {
53
+ generateAiderContext
54
+ };
@@ -1,3 +1,7 @@
1
+ import {
2
+ runMigrations
3
+ } from "./chunk-SBHGK5WA.js";
4
+
1
5
  // src/core.ts
2
6
  import { join as join4, resolve as resolve2, relative as relative2 } from "path";
3
7
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2, unlinkSync, statSync as statSync2 } from "fs";
@@ -86,6 +90,7 @@ var GraphStore = class _GraphStore {
86
90
  } catch {
87
91
  }
88
92
  }
93
+ runMigrations(this.db, this.dbPath);
89
94
  }
90
95
  save() {
91
96
  const data = this.db.export();
@@ -0,0 +1,88 @@
1
+ // src/tuner/config.ts
2
+ import { existsSync, readFileSync, writeFileSync } from "fs";
3
+ import { join } from "path";
4
+ var DEFAULTS = {
5
+ confidenceThreshold: 0.7,
6
+ totalTokenBudget: 600,
7
+ providers: {}
8
+ };
9
+ function readConfig(projectRoot) {
10
+ const configPath = join(projectRoot, ".engram", "config.json");
11
+ if (!existsSync(configPath)) return DEFAULTS;
12
+ try {
13
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
14
+ return {
15
+ ...DEFAULTS,
16
+ ...raw,
17
+ providers: { ...DEFAULTS.providers, ...raw.providers ?? {} }
18
+ };
19
+ } catch {
20
+ return DEFAULTS;
21
+ }
22
+ }
23
+ function writeConfig(projectRoot, config) {
24
+ const configPath = join(projectRoot, ".engram", "config.json");
25
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
26
+ }
27
+
28
+ // src/intelligence/hook-log.ts
29
+ import {
30
+ appendFileSync,
31
+ existsSync as existsSync2,
32
+ renameSync,
33
+ statSync,
34
+ readFileSync as readFileSync2
35
+ } from "fs";
36
+ import { join as join2 } from "path";
37
+ var HOOK_LOG_MAX_BYTES = 10 * 1024 * 1024;
38
+ var LOG_FILENAME = "hook-log.jsonl";
39
+ var LOG_ROTATED_FILENAME = "hook-log.jsonl.1";
40
+ function logHookEvent(projectRoot, entry) {
41
+ if (!projectRoot) return;
42
+ try {
43
+ const logPath = join2(projectRoot, ".engram", LOG_FILENAME);
44
+ rotateIfNeeded(projectRoot);
45
+ const line = JSON.stringify({
46
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
47
+ ...entry
48
+ }) + "\n";
49
+ appendFileSync(logPath, line);
50
+ } catch {
51
+ }
52
+ }
53
+ function rotateIfNeeded(projectRoot) {
54
+ try {
55
+ const logPath = join2(projectRoot, ".engram", LOG_FILENAME);
56
+ if (!existsSync2(logPath)) return;
57
+ const size = statSync(logPath).size;
58
+ if (size < HOOK_LOG_MAX_BYTES) return;
59
+ const rotatedPath = join2(projectRoot, ".engram", LOG_ROTATED_FILENAME);
60
+ renameSync(logPath, rotatedPath);
61
+ } catch {
62
+ }
63
+ }
64
+ function readHookLog(projectRoot) {
65
+ try {
66
+ const logPath = join2(projectRoot, ".engram", LOG_FILENAME);
67
+ if (!existsSync2(logPath)) return [];
68
+ const raw = readFileSync2(logPath, "utf-8");
69
+ const entries = [];
70
+ for (const line of raw.split("\n")) {
71
+ if (!line.trim()) continue;
72
+ try {
73
+ entries.push(JSON.parse(line));
74
+ } catch {
75
+ }
76
+ }
77
+ return entries;
78
+ } catch {
79
+ return [];
80
+ }
81
+ }
82
+
83
+ export {
84
+ readConfig,
85
+ writeConfig,
86
+ logHookEvent,
87
+ readHookLog
88
+ };
@@ -310,7 +310,7 @@ function writeToFile(filePath, summary) {
310
310
  writeFileSync2(filePath, newContent);
311
311
  }
312
312
  async function autogen(projectRoot, target, task) {
313
- const { getStore } = await import("./core-UXIP2GDR.js");
313
+ const { getStore } = await import("./core-77MHT3QV.js");
314
314
  const store = await getStore(projectRoot);
315
315
  try {
316
316
  let view = VIEWS.general;
@@ -0,0 +1,104 @@
1
+ // src/db/migrate.ts
2
+ import { existsSync, copyFileSync } from "fs";
3
+ var CURRENT_SCHEMA_VERSION = 6;
4
+ var MIGRATIONS = {
5
+ // v0.1.0: Initial schema
6
+ 1: `
7
+ CREATE TABLE IF NOT EXISTS nodes (
8
+ id TEXT PRIMARY KEY,
9
+ label TEXT NOT NULL,
10
+ kind TEXT NOT NULL,
11
+ source_file TEXT NOT NULL DEFAULT '',
12
+ source_location TEXT,
13
+ confidence TEXT NOT NULL DEFAULT 'EXTRACTED',
14
+ confidence_score REAL NOT NULL DEFAULT 1.0,
15
+ last_verified INTEGER NOT NULL DEFAULT 0,
16
+ query_count INTEGER NOT NULL DEFAULT 0,
17
+ metadata TEXT NOT NULL DEFAULT '{}'
18
+ );
19
+ CREATE TABLE IF NOT EXISTS edges (
20
+ source TEXT NOT NULL,
21
+ target TEXT NOT NULL,
22
+ relation TEXT NOT NULL,
23
+ confidence TEXT NOT NULL DEFAULT 'EXTRACTED',
24
+ confidence_score REAL NOT NULL DEFAULT 1.0,
25
+ source_file TEXT NOT NULL DEFAULT '',
26
+ source_location TEXT,
27
+ last_verified INTEGER NOT NULL DEFAULT 0,
28
+ metadata TEXT NOT NULL DEFAULT '{}',
29
+ PRIMARY KEY (source, target, relation)
30
+ );
31
+ CREATE TABLE IF NOT EXISTS stats (
32
+ key TEXT PRIMARY KEY,
33
+ value TEXT NOT NULL
34
+ );`,
35
+ // v0.2.0: Mistake memory — uses existing nodes table, no schema change
36
+ 2: `SELECT 1;`,
37
+ // v0.2.0: Skills miner — uses concept nodes with metadata.subkind, no schema change
38
+ 3: `SELECT 1;`,
39
+ // v0.3.0: Hook log — stored in JSONL file, not SQLite
40
+ 4: `SELECT 1;`,
41
+ // v0.5.0: Provider cache
42
+ 5: `
43
+ CREATE TABLE IF NOT EXISTS provider_cache (
44
+ provider TEXT NOT NULL,
45
+ file_path TEXT NOT NULL,
46
+ content TEXT NOT NULL,
47
+ query_used TEXT NOT NULL DEFAULT '',
48
+ cached_at INTEGER NOT NULL,
49
+ ttl INTEGER NOT NULL DEFAULT 3600,
50
+ PRIMARY KEY (provider, file_path)
51
+ );`,
52
+ // v1.0.0: Config table for auto-tuning
53
+ 6: `
54
+ CREATE TABLE IF NOT EXISTS engram_config (
55
+ key TEXT PRIMARY KEY,
56
+ value TEXT NOT NULL,
57
+ updated_at INTEGER NOT NULL
58
+ );`
59
+ };
60
+ function getSchemaVersion(db) {
61
+ try {
62
+ const result = db.exec("SELECT version FROM schema_version LIMIT 1");
63
+ if (result.length > 0 && result[0].values.length > 0) {
64
+ return result[0].values[0][0];
65
+ }
66
+ } catch {
67
+ }
68
+ return 0;
69
+ }
70
+ function runMigrations(db, dbPath) {
71
+ const fromVersion = getSchemaVersion(db);
72
+ if (fromVersion >= CURRENT_SCHEMA_VERSION) {
73
+ return { fromVersion, toVersion: fromVersion, migrationsRun: 0, backedUp: false };
74
+ }
75
+ let backedUp = false;
76
+ if (existsSync(dbPath) && fromVersion > 0) {
77
+ const backupPath = `${dbPath}.bak-v${fromVersion}`;
78
+ try {
79
+ copyFileSync(dbPath, backupPath);
80
+ backedUp = true;
81
+ } catch {
82
+ }
83
+ }
84
+ db.exec(
85
+ `CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL)`
86
+ );
87
+ let migrationsRun = 0;
88
+ for (let v = fromVersion + 1; v <= CURRENT_SCHEMA_VERSION; v++) {
89
+ const sql = MIGRATIONS[v];
90
+ if (sql) {
91
+ db.exec(sql);
92
+ migrationsRun++;
93
+ }
94
+ }
95
+ db.exec(`DELETE FROM schema_version`);
96
+ db.run(`INSERT INTO schema_version (version) VALUES (?)`, [CURRENT_SCHEMA_VERSION]);
97
+ return { fromVersion, toVersion: CURRENT_SCHEMA_VERSION, migrationsRun, backedUp };
98
+ }
99
+
100
+ export {
101
+ CURRENT_SCHEMA_VERSION,
102
+ getSchemaVersion,
103
+ runMigrations
104
+ };