continuum-ai-mcp 1.0.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/README.md +274 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +125 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/database/Database.d.ts +4 -0
- package/dist/database/Database.d.ts.map +1 -0
- package/dist/database/Database.js +83 -0
- package/dist/database/Database.js.map +1 -0
- package/dist/database/schema.sql +121 -0
- package/dist/knowledge/KnowledgeEngine.d.ts +63 -0
- package/dist/knowledge/KnowledgeEngine.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeEngine.js +190 -0
- package/dist/knowledge/KnowledgeEngine.js.map +1 -0
- package/dist/languages/LanguageRegistry.d.ts +38 -0
- package/dist/languages/LanguageRegistry.d.ts.map +1 -0
- package/dist/languages/LanguageRegistry.js +233 -0
- package/dist/languages/LanguageRegistry.js.map +1 -0
- package/dist/languages/definitions/cpp.d.ts +2 -0
- package/dist/languages/definitions/cpp.d.ts.map +1 -0
- package/dist/languages/definitions/cpp.js +25 -0
- package/dist/languages/definitions/cpp.js.map +1 -0
- package/dist/languages/definitions/csharp.d.ts +2 -0
- package/dist/languages/definitions/csharp.d.ts.map +1 -0
- package/dist/languages/definitions/csharp.js +40 -0
- package/dist/languages/definitions/csharp.js.map +1 -0
- package/dist/languages/definitions/go.d.ts +2 -0
- package/dist/languages/definitions/go.d.ts.map +1 -0
- package/dist/languages/definitions/go.js +21 -0
- package/dist/languages/definitions/go.js.map +1 -0
- package/dist/languages/definitions/java.d.ts +2 -0
- package/dist/languages/definitions/java.d.ts.map +1 -0
- package/dist/languages/definitions/java.js +32 -0
- package/dist/languages/definitions/java.js.map +1 -0
- package/dist/languages/definitions/javascript.d.ts +2 -0
- package/dist/languages/definitions/javascript.d.ts.map +1 -0
- package/dist/languages/definitions/javascript.js +26 -0
- package/dist/languages/definitions/javascript.js.map +1 -0
- package/dist/languages/definitions/kotlin.d.ts +2 -0
- package/dist/languages/definitions/kotlin.d.ts.map +1 -0
- package/dist/languages/definitions/kotlin.js +36 -0
- package/dist/languages/definitions/kotlin.js.map +1 -0
- package/dist/languages/definitions/markdown.d.ts +2 -0
- package/dist/languages/definitions/markdown.d.ts.map +1 -0
- package/dist/languages/definitions/markdown.js +18 -0
- package/dist/languages/definitions/markdown.js.map +1 -0
- package/dist/languages/definitions/php.d.ts +2 -0
- package/dist/languages/definitions/php.d.ts.map +1 -0
- package/dist/languages/definitions/php.js +27 -0
- package/dist/languages/definitions/php.js.map +1 -0
- package/dist/languages/definitions/python.d.ts +2 -0
- package/dist/languages/definitions/python.d.ts.map +1 -0
- package/dist/languages/definitions/python.js +17 -0
- package/dist/languages/definitions/python.js.map +1 -0
- package/dist/languages/definitions/ruby.d.ts +2 -0
- package/dist/languages/definitions/ruby.d.ts.map +1 -0
- package/dist/languages/definitions/ruby.js +16 -0
- package/dist/languages/definitions/ruby.js.map +1 -0
- package/dist/languages/definitions/rust.d.ts +2 -0
- package/dist/languages/definitions/rust.d.ts.map +1 -0
- package/dist/languages/definitions/rust.js +28 -0
- package/dist/languages/definitions/rust.js.map +1 -0
- package/dist/languages/definitions/sql.d.ts +2 -0
- package/dist/languages/definitions/sql.d.ts.map +1 -0
- package/dist/languages/definitions/sql.js +36 -0
- package/dist/languages/definitions/sql.js.map +1 -0
- package/dist/languages/definitions/swift.d.ts +2 -0
- package/dist/languages/definitions/swift.d.ts.map +1 -0
- package/dist/languages/definitions/swift.js +40 -0
- package/dist/languages/definitions/swift.js.map +1 -0
- package/dist/languages/definitions/typescript.d.ts +2 -0
- package/dist/languages/definitions/typescript.d.ts.map +1 -0
- package/dist/languages/definitions/typescript.js +40 -0
- package/dist/languages/definitions/typescript.js.map +1 -0
- package/dist/mcp/McpServer.d.ts +2 -0
- package/dist/mcp/McpServer.d.ts.map +1 -0
- package/dist/mcp/McpServer.js +262 -0
- package/dist/mcp/McpServer.js.map +1 -0
- package/dist/parser/IncrementalParser.d.ts +25 -0
- package/dist/parser/IncrementalParser.d.ts.map +1 -0
- package/dist/parser/IncrementalParser.js +195 -0
- package/dist/parser/IncrementalParser.js.map +1 -0
- package/dist/schema/ISchemaAdapter.d.ts +20 -0
- package/dist/schema/ISchemaAdapter.d.ts.map +1 -0
- package/dist/schema/ISchemaAdapter.js +3 -0
- package/dist/schema/ISchemaAdapter.js.map +1 -0
- package/dist/schema/MssqlAdapter.d.ts +6 -0
- package/dist/schema/MssqlAdapter.d.ts.map +1 -0
- package/dist/schema/MssqlAdapter.js +139 -0
- package/dist/schema/MssqlAdapter.js.map +1 -0
- package/dist/schema/MySqlAdapter.d.ts +6 -0
- package/dist/schema/MySqlAdapter.d.ts.map +1 -0
- package/dist/schema/MySqlAdapter.js +77 -0
- package/dist/schema/MySqlAdapter.js.map +1 -0
- package/dist/schema/PostgresAdapter.d.ts +6 -0
- package/dist/schema/PostgresAdapter.d.ts.map +1 -0
- package/dist/schema/PostgresAdapter.js +78 -0
- package/dist/schema/PostgresAdapter.js.map +1 -0
- package/dist/schema/SchemaReader.d.ts +17 -0
- package/dist/schema/SchemaReader.d.ts.map +1 -0
- package/dist/schema/SchemaReader.js +82 -0
- package/dist/schema/SchemaReader.js.map +1 -0
- package/dist/session/SessionEngine.d.ts +40 -0
- package/dist/session/SessionEngine.d.ts.map +1 -0
- package/dist/session/SessionEngine.js +131 -0
- package/dist/session/SessionEngine.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +54 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/watcher/FileWatcher.d.ts +19 -0
- package/dist/watcher/FileWatcher.d.ts.map +1 -0
- package/dist/watcher/FileWatcher.js +146 -0
- package/dist/watcher/FileWatcher.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,139 @@
|
|
|
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.MssqlAdapter = void 0;
|
|
37
|
+
const sql = __importStar(require("mssql"));
|
|
38
|
+
const logger_1 = require("../utils/logger");
|
|
39
|
+
const config = {
|
|
40
|
+
server: process.env.MSSQL_HOST || 'localhost',
|
|
41
|
+
port: parseInt(process.env.MSSQL_PORT || '1433'),
|
|
42
|
+
database: process.env.MSSQL_DATABASE || '',
|
|
43
|
+
user: process.env.MSSQL_USER || '',
|
|
44
|
+
password: process.env.MSSQL_PASSWORD || '',
|
|
45
|
+
options: {
|
|
46
|
+
trustServerCertificate: true,
|
|
47
|
+
encrypt: false,
|
|
48
|
+
},
|
|
49
|
+
connectionTimeout: 8000,
|
|
50
|
+
requestTimeout: 8000,
|
|
51
|
+
pool: {
|
|
52
|
+
max: 5,
|
|
53
|
+
min: 0,
|
|
54
|
+
idleTimeoutMillis: 30000,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
let pool = null;
|
|
58
|
+
async function getPool() {
|
|
59
|
+
if (!pool || !pool.connected) {
|
|
60
|
+
pool = await new sql.ConnectionPool(config).connect();
|
|
61
|
+
logger_1.logger.info('MSSQL connection pool established');
|
|
62
|
+
}
|
|
63
|
+
return pool;
|
|
64
|
+
}
|
|
65
|
+
class MssqlAdapter {
|
|
66
|
+
async getSchema(tableName) {
|
|
67
|
+
try {
|
|
68
|
+
const p = await getPool();
|
|
69
|
+
const columnsResult = await p
|
|
70
|
+
.request()
|
|
71
|
+
.input('table', sql.VarChar, tableName)
|
|
72
|
+
.query(`
|
|
73
|
+
SELECT
|
|
74
|
+
c.COLUMN_NAME AS column_name,
|
|
75
|
+
c.DATA_TYPE AS data_type,
|
|
76
|
+
c.IS_NULLABLE AS is_nullable,
|
|
77
|
+
c.CHARACTER_MAXIMUM_LENGTH AS max_length,
|
|
78
|
+
CASE WHEN pk.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END AS is_primary_key,
|
|
79
|
+
fk_col.TABLE_NAME AS foreign_key_table,
|
|
80
|
+
fk_col.COLUMN_NAME AS foreign_key_column
|
|
81
|
+
FROM INFORMATION_SCHEMA.COLUMNS c
|
|
82
|
+
LEFT JOIN (
|
|
83
|
+
SELECT ku.COLUMN_NAME
|
|
84
|
+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
|
85
|
+
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
|
|
86
|
+
ON tc.CONSTRAINT_NAME = ku.CONSTRAINT_NAME
|
|
87
|
+
WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.TABLE_NAME = @table
|
|
88
|
+
) pk ON c.COLUMN_NAME = pk.COLUMN_NAME
|
|
89
|
+
LEFT JOIN (
|
|
90
|
+
SELECT kcu.COLUMN_NAME, ccu.TABLE_NAME, ccu.COLUMN_NAME AS FK_COLUMN
|
|
91
|
+
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
|
92
|
+
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON rc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
|
|
93
|
+
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
|
|
94
|
+
ON rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
|
|
95
|
+
WHERE kcu.TABLE_NAME = @table
|
|
96
|
+
) fk_col ON c.COLUMN_NAME = fk_col.COLUMN_NAME
|
|
97
|
+
WHERE c.TABLE_NAME = @table
|
|
98
|
+
ORDER BY c.ORDINAL_POSITION
|
|
99
|
+
`);
|
|
100
|
+
if (columnsResult.recordset.length === 0)
|
|
101
|
+
return null;
|
|
102
|
+
const indexResult = await p
|
|
103
|
+
.request()
|
|
104
|
+
.input('table', sql.VarChar, tableName)
|
|
105
|
+
.query(`
|
|
106
|
+
SELECT i.name AS index_name
|
|
107
|
+
FROM sys.indexes i
|
|
108
|
+
JOIN sys.tables t ON i.object_id = t.object_id
|
|
109
|
+
WHERE t.name = @table AND i.name IS NOT NULL
|
|
110
|
+
`);
|
|
111
|
+
return {
|
|
112
|
+
table_name: tableName,
|
|
113
|
+
columns: columnsResult.recordset,
|
|
114
|
+
indexes: indexResult.recordset.map((r) => r.index_name),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
logger_1.logger.error({ err, tableName }, 'MSSQL getSchema failed');
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async listTables() {
|
|
123
|
+
try {
|
|
124
|
+
const p = await getPool();
|
|
125
|
+
const result = await p.request().query(`
|
|
126
|
+
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
|
|
127
|
+
WHERE TABLE_TYPE = 'BASE TABLE'
|
|
128
|
+
ORDER BY TABLE_NAME
|
|
129
|
+
`);
|
|
130
|
+
return result.recordset.map((r) => r.TABLE_NAME);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
logger_1.logger.error({ err }, 'MSSQL listTables failed');
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.MssqlAdapter = MssqlAdapter;
|
|
139
|
+
//# sourceMappingURL=MssqlAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MssqlAdapter.js","sourceRoot":"","sources":["../../src/schema/MssqlAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ISchemaAdapter, TableSchema } from './ISchemaAdapter';
|
|
2
|
+
export declare class MySqlAdapter implements ISchemaAdapter {
|
|
3
|
+
getSchema(tableName: string): Promise<TableSchema | null>;
|
|
4
|
+
listTables(): Promise<string[]>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=MySqlAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySqlAdapter.d.ts","sourceRoot":"","sources":["../../src/schema/MySqlAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAe/D,qBAAa,YAAa,YAAW,cAAc;IAC3C,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAgDzD,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CActC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MySqlAdapter = void 0;
|
|
7
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
8
|
+
const logger_1 = require("../utils/logger");
|
|
9
|
+
const pool = promise_1.default.createPool({
|
|
10
|
+
host: process.env.MYSQL_HOST || 'localhost',
|
|
11
|
+
port: parseInt(process.env.MYSQL_PORT || '3306'),
|
|
12
|
+
database: process.env.MYSQL_DATABASE || '',
|
|
13
|
+
user: process.env.MYSQL_USER || '',
|
|
14
|
+
password: process.env.MYSQL_PASSWORD || '',
|
|
15
|
+
waitForConnections: true,
|
|
16
|
+
connectionLimit: 5,
|
|
17
|
+
queueLimit: 0,
|
|
18
|
+
connectTimeout: 8000,
|
|
19
|
+
});
|
|
20
|
+
class MySqlAdapter {
|
|
21
|
+
async getSchema(tableName) {
|
|
22
|
+
const conn = await pool.getConnection();
|
|
23
|
+
try {
|
|
24
|
+
const [cols] = await conn.query(`
|
|
25
|
+
SELECT
|
|
26
|
+
c.COLUMN_NAME AS column_name,
|
|
27
|
+
c.DATA_TYPE AS data_type,
|
|
28
|
+
c.IS_NULLABLE AS is_nullable,
|
|
29
|
+
c.CHARACTER_MAXIMUM_LENGTH AS max_length,
|
|
30
|
+
IF(c.COLUMN_KEY = 'PRI', 1, 0) AS is_primary_key,
|
|
31
|
+
kcu.REFERENCED_TABLE_NAME AS foreign_key_table,
|
|
32
|
+
kcu.REFERENCED_COLUMN_NAME AS foreign_key_column
|
|
33
|
+
FROM information_schema.COLUMNS c
|
|
34
|
+
LEFT JOIN information_schema.KEY_COLUMN_USAGE kcu
|
|
35
|
+
ON c.TABLE_NAME = kcu.TABLE_NAME
|
|
36
|
+
AND c.COLUMN_NAME = kcu.COLUMN_NAME
|
|
37
|
+
AND c.TABLE_SCHEMA = kcu.TABLE_SCHEMA
|
|
38
|
+
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
39
|
+
WHERE c.TABLE_NAME = ?
|
|
40
|
+
AND c.TABLE_SCHEMA = DATABASE()
|
|
41
|
+
ORDER BY c.ORDINAL_POSITION
|
|
42
|
+
`, [tableName]);
|
|
43
|
+
if (cols.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
const [idxs] = await conn.query(`SHOW INDEX FROM \`${tableName}\``, []);
|
|
46
|
+
const uniqueIndexNames = [...new Set(idxs.map((r) => r['Key_name']))];
|
|
47
|
+
return {
|
|
48
|
+
table_name: tableName,
|
|
49
|
+
columns: cols,
|
|
50
|
+
indexes: uniqueIndexNames,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
logger_1.logger.error({ err, tableName }, 'MySQL getSchema failed');
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
conn.release();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async listTables() {
|
|
62
|
+
const conn = await pool.getConnection();
|
|
63
|
+
try {
|
|
64
|
+
const [rows] = await conn.query(`SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'`);
|
|
65
|
+
return rows.map((r) => Object.values(r)[0]);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
logger_1.logger.error({ err }, 'MySQL listTables failed');
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
conn.release();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.MySqlAdapter = MySqlAdapter;
|
|
77
|
+
//# sourceMappingURL=MySqlAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySqlAdapter.js","sourceRoot":"","sources":["../../src/schema/MySqlAdapter.ts"],"names":[],"mappings":";;;;;;AAAA,6DAAmC;AAEnC,4CAAyC;AAEzC,MAAM,IAAI,GAAG,iBAAK,CAAC,UAAU,CAAC;IAC5B,IAAI,EAAgB,OAAO,CAAC,GAAG,CAAC,UAAU,IAAQ,WAAW;IAC7D,IAAI,EAAgB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC;IAC9D,QAAQ,EAAY,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;IACpD,IAAI,EAAgB,OAAO,CAAC,GAAG,CAAC,UAAU,IAAQ,EAAE;IACpD,QAAQ,EAAY,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;IACpD,kBAAkB,EAAE,IAAI;IACxB,eAAe,EAAK,CAAC;IACrB,UAAU,EAAU,CAAC;IACrB,cAAc,EAAM,IAAI;CACzB,CAAC,CAAC;AAEH,MAAa,YAAY;IACvB,KAAK,CAAC,SAAS,CAAC,SAAiB;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B;;;;;;;;;;;;;;;;;;SAkBC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;YAEF,IAAK,IAAkB,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAElD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,qBAAqB,SAAS,IAAI,EAClC,EAAE,CACH,CAAC;YAEF,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAE,IAA8B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAW,CAAC,CAAC,CAAC,CAAC;YAE3G,OAAO;gBACL,UAAU,EAAE,SAAS;gBACrB,OAAO,EAAE,IAA8B;gBACvC,OAAO,EAAE,gBAAgB;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,wBAAwB,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,kDAAkD,CACnD,CAAC;YACF,OAAQ,IAA8B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,yBAAyB,CAAC,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AA/DD,oCA+DC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ISchemaAdapter, TableSchema } from './ISchemaAdapter';
|
|
2
|
+
export declare class PostgresAdapter implements ISchemaAdapter {
|
|
3
|
+
getSchema(tableName: string): Promise<TableSchema | null>;
|
|
4
|
+
listTables(): Promise<string[]>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=PostgresAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresAdapter.d.ts","sourceRoot":"","sources":["../../src/schema/PostgresAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAc/D,qBAAa,eAAgB,YAAW,cAAc;IAC9C,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAgDzD,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAgBtC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresAdapter = void 0;
|
|
4
|
+
const pg_1 = require("pg");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
const pool = new pg_1.Pool({
|
|
7
|
+
host: process.env.PG_HOST || 'localhost',
|
|
8
|
+
port: parseInt(process.env.PG_PORT || '5432'),
|
|
9
|
+
database: process.env.PG_DATABASE || '',
|
|
10
|
+
user: process.env.PG_USER || '',
|
|
11
|
+
password: process.env.PG_PASSWORD || '',
|
|
12
|
+
max: 5,
|
|
13
|
+
idleTimeoutMillis: 30000,
|
|
14
|
+
connectionTimeoutMillis: 8000,
|
|
15
|
+
});
|
|
16
|
+
class PostgresAdapter {
|
|
17
|
+
async getSchema(tableName) {
|
|
18
|
+
const client = await pool.connect();
|
|
19
|
+
try {
|
|
20
|
+
const colsRes = await client.query(`
|
|
21
|
+
SELECT
|
|
22
|
+
c.column_name,
|
|
23
|
+
c.data_type,
|
|
24
|
+
c.is_nullable,
|
|
25
|
+
c.character_maximum_length AS max_length,
|
|
26
|
+
(tc.constraint_type = 'PRIMARY KEY') AS is_primary_key,
|
|
27
|
+
ccu.table_name AS foreign_key_table,
|
|
28
|
+
ccu.column_name AS foreign_key_column
|
|
29
|
+
FROM information_schema.columns c
|
|
30
|
+
LEFT JOIN information_schema.key_column_usage kcu
|
|
31
|
+
ON c.table_name = kcu.table_name AND c.column_name = kcu.column_name
|
|
32
|
+
LEFT JOIN information_schema.table_constraints tc
|
|
33
|
+
ON kcu.constraint_name = tc.constraint_name
|
|
34
|
+
LEFT JOIN information_schema.referential_constraints rc
|
|
35
|
+
ON kcu.constraint_name = rc.constraint_name
|
|
36
|
+
LEFT JOIN information_schema.constraint_column_usage ccu
|
|
37
|
+
ON rc.unique_constraint_name = ccu.constraint_name
|
|
38
|
+
WHERE c.table_name = $1
|
|
39
|
+
ORDER BY c.ordinal_position
|
|
40
|
+
`, [tableName]);
|
|
41
|
+
if (colsRes.rows.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const idxRes = await client.query(`SELECT indexname AS index_name FROM pg_indexes WHERE tablename = $1`, [tableName]);
|
|
44
|
+
return {
|
|
45
|
+
table_name: tableName,
|
|
46
|
+
columns: colsRes.rows,
|
|
47
|
+
indexes: idxRes.rows.map((r) => r.index_name),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
logger_1.logger.error({ err, tableName }, 'Postgres getSchema failed');
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
client.release();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async listTables() {
|
|
59
|
+
const client = await pool.connect();
|
|
60
|
+
try {
|
|
61
|
+
const res = await client.query(`
|
|
62
|
+
SELECT table_name FROM information_schema.tables
|
|
63
|
+
WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
|
|
64
|
+
ORDER BY table_name
|
|
65
|
+
`);
|
|
66
|
+
return res.rows.map((r) => r.table_name);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
logger_1.logger.error({ err }, 'Postgres listTables failed');
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
client.release();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.PostgresAdapter = PostgresAdapter;
|
|
78
|
+
//# sourceMappingURL=PostgresAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresAdapter.js","sourceRoot":"","sources":["../../src/schema/PostgresAdapter.ts"],"names":[],"mappings":";;;AAAA,2BAA0B;AAE1B,4CAAyC;AAEzC,MAAM,IAAI,GAAG,IAAI,SAAI,CAAC;IACpB,IAAI,EAAM,OAAO,CAAC,GAAG,CAAC,OAAO,IAAQ,WAAW;IAChD,IAAI,EAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC;IACjD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE;IACvC,IAAI,EAAM,OAAO,CAAC,GAAG,CAAC,OAAO,IAAQ,EAAE;IACvC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE;IACvC,GAAG,EAAO,CAAC;IACX,iBAAiB,EAAE,KAAK;IACxB,uBAAuB,EAAE,IAAI;CAC9B,CAAC,CAAC;AAEH,MAAa,eAAe;IAC1B,KAAK,CAAC,SAAS,CAAC,SAAiB;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,KAAK,CAChC;;;;;;;;;;;;;;;;;;;;SAoBC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;YAEF,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAE3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B,qEAAqE,EACrE,CAAC,SAAS,CAAC,CACZ,CAAC;YAEF,OAAO;gBACL,UAAU,EAAE,SAAS;gBACrB,OAAO,EAAE,OAAO,CAAC,IAAI;gBACrB,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAyB,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;aACtE,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,2BAA2B,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;;;;OAI9B,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAyB,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,4BAA4B,CAAC,CAAC;YACpD,OAAO,EAAE,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;CACF;AAjED,0CAiEC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TableSchema } from './ISchemaAdapter';
|
|
2
|
+
/**
|
|
3
|
+
* DB-agnostic Schema Reader (Strategy pattern).
|
|
4
|
+
*
|
|
5
|
+
* Wraps any ISchemaAdapter (MSSQL | Postgres | MySQL) with a SQLite cache
|
|
6
|
+
* so repeated tool calls don't hammer the database.
|
|
7
|
+
*
|
|
8
|
+
* Select adapter via DB_TYPE env var: 'mssql' | 'postgres' | 'mysql'
|
|
9
|
+
*/
|
|
10
|
+
export declare class SchemaReader {
|
|
11
|
+
private adapter;
|
|
12
|
+
constructor();
|
|
13
|
+
isEnabled(): boolean;
|
|
14
|
+
getSchema(tableName: string): Promise<TableSchema | null>;
|
|
15
|
+
listTables(): Promise<string[]>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=SchemaReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaReader.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaReader.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/D;;;;;;;GAOG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAA+B;;IA4B9C,SAAS,IAAI,OAAO;IAId,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAoCzD,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAItC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaReader = void 0;
|
|
4
|
+
const Database_1 = require("../database/Database");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
const CACHE_TTL_SECONDS = 3600; // 1 hour
|
|
7
|
+
/**
|
|
8
|
+
* DB-agnostic Schema Reader (Strategy pattern).
|
|
9
|
+
*
|
|
10
|
+
* Wraps any ISchemaAdapter (MSSQL | Postgres | MySQL) with a SQLite cache
|
|
11
|
+
* so repeated tool calls don't hammer the database.
|
|
12
|
+
*
|
|
13
|
+
* Select adapter via DB_TYPE env var: 'mssql' | 'postgres' | 'mysql'
|
|
14
|
+
*/
|
|
15
|
+
class SchemaReader {
|
|
16
|
+
adapter = null;
|
|
17
|
+
constructor() {
|
|
18
|
+
const dbType = process.env.DB_TYPE?.toLowerCase();
|
|
19
|
+
if (!dbType) {
|
|
20
|
+
logger_1.logger.info('No DB_TYPE set - get_schema tool will be disabled');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Lazy-require adapters so unused DB drivers don't crash on import
|
|
24
|
+
try {
|
|
25
|
+
if (dbType === 'mssql') {
|
|
26
|
+
const { MssqlAdapter } = require('./MssqlAdapter');
|
|
27
|
+
this.adapter = new MssqlAdapter();
|
|
28
|
+
}
|
|
29
|
+
else if (dbType === 'postgres' || dbType === 'postgresql') {
|
|
30
|
+
const { PostgresAdapter } = require('./PostgresAdapter');
|
|
31
|
+
this.adapter = new PostgresAdapter();
|
|
32
|
+
}
|
|
33
|
+
else if (dbType === 'mysql') {
|
|
34
|
+
const { MySqlAdapter } = require('./MySqlAdapter');
|
|
35
|
+
this.adapter = new MySqlAdapter();
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
logger_1.logger.warn({ dbType }, 'Unknown DB_TYPE - supported: mssql | postgres | mysql');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
logger_1.logger.error({ err, dbType }, 'Failed to initialise schema adapter');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
isEnabled() {
|
|
46
|
+
return this.adapter !== null;
|
|
47
|
+
}
|
|
48
|
+
async getSchema(tableName) {
|
|
49
|
+
if (!this.adapter)
|
|
50
|
+
return null;
|
|
51
|
+
const db = (0, Database_1.getDb)();
|
|
52
|
+
// Serve from cache if fresh
|
|
53
|
+
const cached = db
|
|
54
|
+
.prepare(`SELECT schema_json, cached_at FROM schema_cache
|
|
55
|
+
WHERE table_name = ? AND cached_at > unixepoch() - ?`)
|
|
56
|
+
.get(tableName, CACHE_TTL_SECONDS);
|
|
57
|
+
if (cached) {
|
|
58
|
+
logger_1.logger.debug({ tableName }, 'Schema cache hit');
|
|
59
|
+
return JSON.parse(cached.schema_json);
|
|
60
|
+
}
|
|
61
|
+
const tableSchema = await this.adapter.getSchema(tableName);
|
|
62
|
+
if (!tableSchema)
|
|
63
|
+
return null;
|
|
64
|
+
// Cache it
|
|
65
|
+
db.prepare(`
|
|
66
|
+
INSERT INTO schema_cache (table_name, schema_json, cached_at)
|
|
67
|
+
VALUES (?, ?, unixepoch())
|
|
68
|
+
ON CONFLICT(table_name) DO UPDATE SET
|
|
69
|
+
schema_json = excluded.schema_json,
|
|
70
|
+
cached_at = excluded.cached_at
|
|
71
|
+
`).run(tableName, JSON.stringify(tableSchema));
|
|
72
|
+
logger_1.logger.info({ tableName }, 'Schema fetched and cached');
|
|
73
|
+
return tableSchema;
|
|
74
|
+
}
|
|
75
|
+
async listTables() {
|
|
76
|
+
if (!this.adapter)
|
|
77
|
+
return [];
|
|
78
|
+
return this.adapter.listTables();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.SchemaReader = SchemaReader;
|
|
82
|
+
//# sourceMappingURL=SchemaReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaReader.js","sourceRoot":"","sources":["../../src/schema/SchemaReader.ts"],"names":[],"mappings":";;;AAAA,mDAA6C;AAE7C,4CAAyC;AAEzC,MAAM,iBAAiB,GAAG,IAAI,CAAC,CAAC,SAAS;AAEzC;;;;;;;GAOG;AACH,MAAa,YAAY;IACf,OAAO,GAA0B,IAAI,CAAC;IAE9C;QACE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,eAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,IAAI,CAAC;YACH,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAoC,CAAC;gBACtF,IAAI,CAAC,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;YACpC,CAAC;iBAAM,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;gBAC5D,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAuC,CAAC;gBAC/F,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;YACvC,CAAC;iBAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC9B,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAoC,CAAC;gBACtF,IAAI,CAAC,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,eAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,uDAAuD,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,qCAAqC,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,SAAiB;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE/B,MAAM,EAAE,GAAG,IAAA,gBAAK,GAAE,CAAC;QAEnB,4BAA4B;QAC5B,MAAM,MAAM,GAAG,EAAE;aACd,OAAO,CACN;8DACsD,CACvD;aACA,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAEtB,CAAC;QAEd,IAAI,MAAM,EAAE,CAAC;YACX,eAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,kBAAkB,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAgB,CAAC;QACvD,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAE9B,WAAW;QACX,EAAE,CAAC,OAAO,CAAC;;;;;;KAMV,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QAE/C,eAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,2BAA2B,CAAC,CAAC;QACxD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IACnC,CAAC;CACF;AAzED,oCAyEC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface TaskState {
|
|
2
|
+
goal: string;
|
|
3
|
+
decisions: string[];
|
|
4
|
+
next_steps: string[];
|
|
5
|
+
open_questions: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface TouchedFile {
|
|
8
|
+
path: string;
|
|
9
|
+
action: string;
|
|
10
|
+
touched_at: number;
|
|
11
|
+
}
|
|
12
|
+
export interface SessionState {
|
|
13
|
+
session_id: string;
|
|
14
|
+
goal: string | null;
|
|
15
|
+
started_at: number;
|
|
16
|
+
compaction_count: number;
|
|
17
|
+
touched_files: TouchedFile[];
|
|
18
|
+
latest_task: TaskState | null;
|
|
19
|
+
}
|
|
20
|
+
export declare class SessionEngine {
|
|
21
|
+
private readonly sessionId;
|
|
22
|
+
private readonly startTime;
|
|
23
|
+
constructor();
|
|
24
|
+
private initSession;
|
|
25
|
+
getSessionId(): string;
|
|
26
|
+
getUptimeSeconds(): number;
|
|
27
|
+
/**
|
|
28
|
+
* Record a file being touched. Action 'opened' is separate from watcher events.
|
|
29
|
+
* Skips duplicate entries within 5 seconds (debounce for rapid saves).
|
|
30
|
+
*/
|
|
31
|
+
recordFileTouch(filePath: string, action: 'opened' | 'modified' | 'created' | 'deleted'): void;
|
|
32
|
+
/** Save structured task state. Returns the task ID. */
|
|
33
|
+
saveTask(task: TaskState): number;
|
|
34
|
+
/** Full session state — the primary recovery payload after compaction. */
|
|
35
|
+
getSession(): SessionState;
|
|
36
|
+
/** Distinct files touched this session — useful for impact analysis. */
|
|
37
|
+
getTouchedFiles(): TouchedFile[];
|
|
38
|
+
recordCompaction(): void;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=SessionEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionEngine.d.ts","sourceRoot":"","sources":["../../src/session/SessionEngine.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,WAAW,EAAE,SAAS,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;;IAOnC,OAAO,CAAC,WAAW;IAWnB,YAAY,IAAI,MAAM;IAItB,gBAAgB,IAAI,MAAM;IAI1B;;;OAGG;IACH,eAAe,CACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GACpD,IAAI;IAwBP,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM;IAwBjC,0EAA0E;IAC1E,UAAU,IAAI,YAAY;IAwD1B,wEAAwE;IACxE,eAAe,IAAI,WAAW,EAAE;IAahC,gBAAgB,IAAI,IAAI;CASzB"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionEngine = void 0;
|
|
4
|
+
const Database_1 = require("../database/Database");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const logger_1 = require("../utils/logger");
|
|
7
|
+
class SessionEngine {
|
|
8
|
+
sessionId;
|
|
9
|
+
startTime;
|
|
10
|
+
constructor() {
|
|
11
|
+
this.startTime = Math.floor(Date.now() / 1000);
|
|
12
|
+
this.sessionId = this.initSession();
|
|
13
|
+
}
|
|
14
|
+
initSession() {
|
|
15
|
+
const db = (0, Database_1.getDb)();
|
|
16
|
+
const id = (0, crypto_1.randomUUID)();
|
|
17
|
+
db.prepare(`
|
|
18
|
+
INSERT INTO sessions (id, started_at, updated_at)
|
|
19
|
+
VALUES (?, unixepoch(), unixepoch())
|
|
20
|
+
`).run(id);
|
|
21
|
+
logger_1.logger.info({ sessionId: id }, 'Session started');
|
|
22
|
+
return id;
|
|
23
|
+
}
|
|
24
|
+
getSessionId() {
|
|
25
|
+
return this.sessionId;
|
|
26
|
+
}
|
|
27
|
+
getUptimeSeconds() {
|
|
28
|
+
return Math.floor(Date.now() / 1000) - this.startTime;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Record a file being touched. Action 'opened' is separate from watcher events.
|
|
32
|
+
* Skips duplicate entries within 5 seconds (debounce for rapid saves).
|
|
33
|
+
*/
|
|
34
|
+
recordFileTouch(filePath, action) {
|
|
35
|
+
const db = (0, Database_1.getDb)();
|
|
36
|
+
// Debounce: skip if same file+action recorded in last 5 seconds
|
|
37
|
+
const recent = db
|
|
38
|
+
.prepare(`
|
|
39
|
+
SELECT id FROM touched_files
|
|
40
|
+
WHERE session_id = ? AND path = ? AND action = ?
|
|
41
|
+
AND touched_at > unixepoch() - 5
|
|
42
|
+
`)
|
|
43
|
+
.get(this.sessionId, filePath, action);
|
|
44
|
+
if (recent)
|
|
45
|
+
return;
|
|
46
|
+
db.prepare(`
|
|
47
|
+
INSERT INTO touched_files (session_id, path, action, touched_at)
|
|
48
|
+
VALUES (?, ?, ?, unixepoch())
|
|
49
|
+
`).run(this.sessionId, filePath, action);
|
|
50
|
+
db.prepare(`
|
|
51
|
+
UPDATE sessions SET updated_at = unixepoch() WHERE id = ?
|
|
52
|
+
`).run(this.sessionId);
|
|
53
|
+
}
|
|
54
|
+
/** Save structured task state. Returns the task ID. */
|
|
55
|
+
saveTask(task) {
|
|
56
|
+
const db = (0, Database_1.getDb)();
|
|
57
|
+
const result = db
|
|
58
|
+
.prepare(`
|
|
59
|
+
INSERT INTO tasks (session_id, goal, decisions, next_steps, open_questions, saved_at)
|
|
60
|
+
VALUES (?, ?, ?, ?, ?, unixepoch())
|
|
61
|
+
`)
|
|
62
|
+
.run(this.sessionId, task.goal, JSON.stringify(task.decisions), JSON.stringify(task.next_steps), JSON.stringify(task.open_questions));
|
|
63
|
+
db.prepare(`UPDATE sessions SET goal = ?, updated_at = unixepoch() WHERE id = ?`).run(task.goal, this.sessionId);
|
|
64
|
+
logger_1.logger.info({ sessionId: this.sessionId, taskId: result.lastInsertRowid }, 'Task saved');
|
|
65
|
+
return Number(result.lastInsertRowid);
|
|
66
|
+
}
|
|
67
|
+
/** Full session state — the primary recovery payload after compaction. */
|
|
68
|
+
getSession() {
|
|
69
|
+
const db = (0, Database_1.getDb)();
|
|
70
|
+
const session = db
|
|
71
|
+
.prepare('SELECT * FROM sessions WHERE id = ?')
|
|
72
|
+
.get(this.sessionId);
|
|
73
|
+
const touched = db
|
|
74
|
+
.prepare(`
|
|
75
|
+
SELECT path, action, MAX(touched_at) as touched_at
|
|
76
|
+
FROM touched_files
|
|
77
|
+
WHERE session_id = ?
|
|
78
|
+
GROUP BY path
|
|
79
|
+
ORDER BY touched_at DESC
|
|
80
|
+
LIMIT 100
|
|
81
|
+
`)
|
|
82
|
+
.all(this.sessionId);
|
|
83
|
+
const latestTask = db
|
|
84
|
+
.prepare(`
|
|
85
|
+
SELECT * FROM tasks
|
|
86
|
+
WHERE session_id = ?
|
|
87
|
+
ORDER BY saved_at DESC
|
|
88
|
+
LIMIT 1
|
|
89
|
+
`)
|
|
90
|
+
.get(this.sessionId);
|
|
91
|
+
return {
|
|
92
|
+
session_id: session.id,
|
|
93
|
+
goal: session.goal,
|
|
94
|
+
started_at: session.started_at,
|
|
95
|
+
compaction_count: session.compaction_count,
|
|
96
|
+
touched_files: touched,
|
|
97
|
+
latest_task: latestTask
|
|
98
|
+
? {
|
|
99
|
+
goal: latestTask.goal,
|
|
100
|
+
decisions: JSON.parse(latestTask.decisions || '[]'),
|
|
101
|
+
next_steps: JSON.parse(latestTask.next_steps || '[]'),
|
|
102
|
+
open_questions: JSON.parse(latestTask.open_questions || '[]'),
|
|
103
|
+
}
|
|
104
|
+
: null,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Distinct files touched this session — useful for impact analysis. */
|
|
108
|
+
getTouchedFiles() {
|
|
109
|
+
const db = (0, Database_1.getDb)();
|
|
110
|
+
return db
|
|
111
|
+
.prepare(`
|
|
112
|
+
SELECT path, action, MAX(touched_at) as touched_at
|
|
113
|
+
FROM touched_files
|
|
114
|
+
WHERE session_id = ?
|
|
115
|
+
GROUP BY path
|
|
116
|
+
ORDER BY touched_at DESC
|
|
117
|
+
`)
|
|
118
|
+
.all(this.sessionId);
|
|
119
|
+
}
|
|
120
|
+
recordCompaction() {
|
|
121
|
+
const db = (0, Database_1.getDb)();
|
|
122
|
+
db.prepare(`
|
|
123
|
+
UPDATE sessions
|
|
124
|
+
SET compaction_count = compaction_count + 1, updated_at = unixepoch()
|
|
125
|
+
WHERE id = ?
|
|
126
|
+
`).run(this.sessionId);
|
|
127
|
+
logger_1.logger.info({ sessionId: this.sessionId }, 'Context compaction recorded');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.SessionEngine = SessionEngine;
|
|
131
|
+
//# sourceMappingURL=SessionEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionEngine.js","sourceRoot":"","sources":["../../src/session/SessionEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAaxB,eAAO,MAAM,MAAM,6BAOlB,CAAC"}
|