codemaxxing 0.1.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 +209 -0
- package/dist/agent.d.ts +65 -0
- package/dist/agent.js +269 -0
- package/dist/config.d.ts +41 -0
- package/dist/config.js +174 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +659 -0
- package/dist/tools/files.d.ts +9 -0
- package/dist/tools/files.js +227 -0
- package/dist/utils/context.d.ts +13 -0
- package/dist/utils/context.js +135 -0
- package/dist/utils/git.d.ts +27 -0
- package/dist/utils/git.js +113 -0
- package/dist/utils/repomap.d.ts +18 -0
- package/dist/utils/repomap.js +195 -0
- package/dist/utils/sessions.d.ts +51 -0
- package/dist/utils/sessions.js +174 -0
- package/dist/utils/treesitter.d.ts +20 -0
- package/dist/utils/treesitter.js +710 -0
- package/package.json +51 -0
- package/src/agent.ts +322 -0
- package/src/config.ts +211 -0
- package/src/index.tsx +858 -0
- package/src/tools/files.ts +247 -0
- package/src/utils/context.ts +146 -0
- package/src/utils/git.ts +117 -0
- package/src/utils/repomap.ts +220 -0
- package/src/utils/sessions.ts +222 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import { join, extname, relative } from "path";
|
|
3
|
+
const IGNORE_DIRS = new Set([
|
|
4
|
+
"node_modules", ".git", "dist", ".next", "__pycache__", ".pytest_cache",
|
|
5
|
+
"target", "build", "out", ".cache", ".parcel-cache", ".nuxt", ".svelte-kit",
|
|
6
|
+
"vendor", "venv", ".venv", "env", ".env", "coverage", ".nyc_output",
|
|
7
|
+
]);
|
|
8
|
+
const IGNORE_FILES = new Set([
|
|
9
|
+
".DS_Store", "package-lock.json", "yarn.lock", "pnpm-lock.yaml",
|
|
10
|
+
]);
|
|
11
|
+
const MAX_FILE_SIZE = 100 * 1024;
|
|
12
|
+
const MAX_MAP_SIZE = 15 * 1024;
|
|
13
|
+
const LANGS = {
|
|
14
|
+
javascript: {
|
|
15
|
+
patterns: [
|
|
16
|
+
{ kind: "fn", regex: /^(?:export\s+)?(?:export\s+default\s+)?(?:async\s+)?function\s+(\w+)\s*\(/, format: (m) => `function ${m[1]}(...)` },
|
|
17
|
+
{ kind: "arrow", regex: /^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/, format: (m) => `const ${m[1]} = (...)` },
|
|
18
|
+
{ kind: "cls", regex: /^(?:export\s+)?(?:export\s+default\s+)?class\s+(\w+)/, format: (m) => `class ${m[1]}` },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
typescript: {
|
|
22
|
+
patterns: [
|
|
23
|
+
{ kind: "fn", regex: /^(?:export\s+)?(?:export\s+default\s+)?(?:async\s+)?function\s+(\w+)/, format: (m) => `function ${m[1]}(...)` },
|
|
24
|
+
{ kind: "arrow", regex: /^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/, format: (m) => `const ${m[1]} = (...)` },
|
|
25
|
+
{ kind: "cls", regex: /^(?:export\s+)?(?:export\s+default\s+)?class\s+(\w+)/, format: (m) => `class ${m[1]}` },
|
|
26
|
+
{ kind: "iface", regex: /^(?:export\s+)?interface\s+(\w+)/, format: (m) => `interface ${m[1]}` },
|
|
27
|
+
{ kind: "type", regex: /^(?:export\s+)?type\s+(\w+)\s*[=<]/, format: (m) => `type ${m[1]}` },
|
|
28
|
+
{ kind: "enum", regex: /^(?:export\s+)?enum\s+(\w+)/, format: (m) => `enum ${m[1]}` },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
python: {
|
|
32
|
+
patterns: [
|
|
33
|
+
{ kind: "fn", regex: /^def\s+(\w+)\s*\(/, format: (m) => `def ${m[1]}(...)` },
|
|
34
|
+
{ kind: "method", regex: /^\s{2,}def\s+(\w+)\s*\(/, format: (m) => ` def ${m[1]}(...)` },
|
|
35
|
+
{ kind: "cls", regex: /^class\s+(\w+)/, format: (m) => `class ${m[1]}` },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
go: {
|
|
39
|
+
patterns: [
|
|
40
|
+
{ kind: "fn", regex: /^func\s+(\w+)\s*\(/, format: (m) => `func ${m[1]}(...)` },
|
|
41
|
+
{ kind: "method", regex: /^func\s+\((\w+)\s+\*?(\w+)\)\s+(\w+)\s*\(/, format: (m) => `func (${m[2]}) ${m[3]}(...)` },
|
|
42
|
+
{ kind: "struct", regex: /^type\s+(\w+)\s+struct/, format: (m) => `type ${m[1]} struct` },
|
|
43
|
+
{ kind: "iface", regex: /^type\s+(\w+)\s+interface/, format: (m) => `type ${m[1]} interface` },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
rust: {
|
|
47
|
+
patterns: [
|
|
48
|
+
{ kind: "fn", regex: /^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/, format: (m) => `fn ${m[1]}(...)` },
|
|
49
|
+
{ kind: "struct", regex: /^(?:pub\s+)?struct\s+(\w+)/, format: (m) => `struct ${m[1]}` },
|
|
50
|
+
{ kind: "enum", regex: /^(?:pub\s+)?enum\s+(\w+)/, format: (m) => `enum ${m[1]}` },
|
|
51
|
+
{ kind: "trait", regex: /^(?:pub\s+)?trait\s+(\w+)/, format: (m) => `trait ${m[1]}` },
|
|
52
|
+
{ kind: "impl", regex: /^impl(?:<[^>]*>)?\s+(?:(\w+)\s+for\s+)?(\w+)/, format: (m) => m[1] ? `impl ${m[1]} for ${m[2]}` : `impl ${m[2]}` },
|
|
53
|
+
{ kind: "mod", regex: /^(?:pub\s+)?mod\s+(\w+)/, format: (m) => `mod ${m[1]}` },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Get language from extension
|
|
59
|
+
*/
|
|
60
|
+
function getLang(ext) {
|
|
61
|
+
const map = {
|
|
62
|
+
".js": "javascript", ".jsx": "javascript", ".mjs": "javascript", ".cjs": "javascript",
|
|
63
|
+
".ts": "typescript", ".tsx": "typescript",
|
|
64
|
+
".py": "python",
|
|
65
|
+
".go": "go",
|
|
66
|
+
".rs": "rust",
|
|
67
|
+
};
|
|
68
|
+
return map[ext.toLowerCase()] || null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Extract signatures from file content
|
|
72
|
+
*/
|
|
73
|
+
function extractSignatures(content, lang) {
|
|
74
|
+
const sigs = [];
|
|
75
|
+
const langDef = LANGS[lang];
|
|
76
|
+
if (!langDef)
|
|
77
|
+
return sigs;
|
|
78
|
+
const lines = content.split("\n");
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
for (const line of lines) {
|
|
81
|
+
for (const pattern of langDef.patterns) {
|
|
82
|
+
const match = line.match(pattern.regex);
|
|
83
|
+
if (match) {
|
|
84
|
+
const sig = pattern.format(match);
|
|
85
|
+
if (!seen.has(sig)) {
|
|
86
|
+
seen.add(sig);
|
|
87
|
+
sigs.push(sig);
|
|
88
|
+
}
|
|
89
|
+
break; // Only match one pattern per line
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return sigs;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Scan directory for supported files
|
|
97
|
+
*/
|
|
98
|
+
function getFiles(cwd) {
|
|
99
|
+
const files = [];
|
|
100
|
+
function walk(dir, depth) {
|
|
101
|
+
if (depth > 5)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
for (const entry of readdirSync(dir)) {
|
|
105
|
+
if (IGNORE_FILES.has(entry) || entry.startsWith("."))
|
|
106
|
+
continue;
|
|
107
|
+
if (IGNORE_DIRS.has(entry))
|
|
108
|
+
continue;
|
|
109
|
+
const full = join(dir, entry);
|
|
110
|
+
const stat = statSync(full);
|
|
111
|
+
if (stat.isDirectory()) {
|
|
112
|
+
walk(full, depth + 1);
|
|
113
|
+
}
|
|
114
|
+
else if (stat.isFile() && stat.size < MAX_FILE_SIZE) {
|
|
115
|
+
if (getLang(extname(entry)))
|
|
116
|
+
files.push(full);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch { /* skip */ }
|
|
121
|
+
}
|
|
122
|
+
walk(cwd, 0);
|
|
123
|
+
return files;
|
|
124
|
+
}
|
|
125
|
+
// ── Cache ──
|
|
126
|
+
let cachedMap = "";
|
|
127
|
+
let cachedCwd = "";
|
|
128
|
+
let cachedTime = 0;
|
|
129
|
+
const CACHE_TTL = 60_000;
|
|
130
|
+
/**
|
|
131
|
+
* Build the repo map — cached for 1 min
|
|
132
|
+
*/
|
|
133
|
+
export async function buildRepoMap(cwd) {
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
if (cachedMap && cachedCwd === cwd && now - cachedTime < CACHE_TTL) {
|
|
136
|
+
return cachedMap;
|
|
137
|
+
}
|
|
138
|
+
const files = getFiles(cwd);
|
|
139
|
+
const lines = [];
|
|
140
|
+
for (const file of files) {
|
|
141
|
+
const ext = extname(file);
|
|
142
|
+
const lang = getLang(ext);
|
|
143
|
+
if (!lang)
|
|
144
|
+
continue;
|
|
145
|
+
try {
|
|
146
|
+
const content = readFileSync(file, "utf-8");
|
|
147
|
+
const sigs = extractSignatures(content, lang);
|
|
148
|
+
if (sigs.length > 0) {
|
|
149
|
+
const relPath = relative(cwd, file);
|
|
150
|
+
lines.push(`${relPath}:`);
|
|
151
|
+
for (const sig of sigs) {
|
|
152
|
+
lines.push(` ${sig}`);
|
|
153
|
+
}
|
|
154
|
+
lines.push("");
|
|
155
|
+
// Size guard
|
|
156
|
+
if (lines.join("\n").length > MAX_MAP_SIZE) {
|
|
157
|
+
lines.push(`... (truncated)`);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch { /* skip */ }
|
|
163
|
+
}
|
|
164
|
+
const map = lines.length > 0 ? lines.join("\n") : "(no signatures found)";
|
|
165
|
+
cachedMap = map;
|
|
166
|
+
cachedCwd = cwd;
|
|
167
|
+
cachedTime = now;
|
|
168
|
+
return map;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get cached map without rebuilding
|
|
172
|
+
*/
|
|
173
|
+
export function getCachedMap() {
|
|
174
|
+
return cachedMap;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Clear the cache
|
|
178
|
+
*/
|
|
179
|
+
export function clearMapCache() {
|
|
180
|
+
cachedMap = "";
|
|
181
|
+
cachedCwd = "";
|
|
182
|
+
cachedTime = 0;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if file is supported
|
|
186
|
+
*/
|
|
187
|
+
export function isSupportedFile(filePath) {
|
|
188
|
+
return !!getLang(extname(filePath).toLowerCase());
|
|
189
|
+
}
|
|
190
|
+
export function getSupportedExtensions() {
|
|
191
|
+
return [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".py", ".go", ".rs"];
|
|
192
|
+
}
|
|
193
|
+
export function getLanguageForExt(ext) {
|
|
194
|
+
return getLang(ext);
|
|
195
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
2
|
+
/**
|
|
3
|
+
* Create a new session
|
|
4
|
+
*/
|
|
5
|
+
export declare function createSession(cwd: string, model: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Save a message to a session
|
|
8
|
+
*/
|
|
9
|
+
export declare function saveMessage(sessionId: string, message: ChatCompletionMessageParam): void;
|
|
10
|
+
/**
|
|
11
|
+
* Update token estimate for a session
|
|
12
|
+
*/
|
|
13
|
+
export declare function updateTokenEstimate(sessionId: string, tokens: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* List recent sessions
|
|
16
|
+
*/
|
|
17
|
+
export interface SessionInfo {
|
|
18
|
+
id: string;
|
|
19
|
+
cwd: string;
|
|
20
|
+
model: string;
|
|
21
|
+
created_at: string;
|
|
22
|
+
updated_at: string;
|
|
23
|
+
message_count: number;
|
|
24
|
+
token_estimate: number;
|
|
25
|
+
summary: string | null;
|
|
26
|
+
}
|
|
27
|
+
export declare function listSessions(limit?: number): SessionInfo[];
|
|
28
|
+
/**
|
|
29
|
+
* Load all messages for a session
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadMessages(sessionId: string): ChatCompletionMessageParam[];
|
|
32
|
+
/**
|
|
33
|
+
* Get a specific session
|
|
34
|
+
*/
|
|
35
|
+
export declare function getSession(sessionId: string): SessionInfo | null;
|
|
36
|
+
/**
|
|
37
|
+
* Delete a session and its messages
|
|
38
|
+
*/
|
|
39
|
+
export declare function deleteSession(sessionId: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Update session summary (for context compression)
|
|
42
|
+
*/
|
|
43
|
+
export declare function updateSummary(sessionId: string, summary: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get the most recent session for a given cwd
|
|
46
|
+
*/
|
|
47
|
+
export declare function getLastSession(cwd: string): SessionInfo | null;
|
|
48
|
+
/**
|
|
49
|
+
* Close the database connection
|
|
50
|
+
*/
|
|
51
|
+
export declare function closeDb(): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { existsSync, mkdirSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
const CONFIG_DIR = join(homedir(), ".codemaxxing");
|
|
6
|
+
const DB_PATH = join(CONFIG_DIR, "sessions.db");
|
|
7
|
+
let db = null;
|
|
8
|
+
/**
|
|
9
|
+
* Initialize the database and create tables if needed
|
|
10
|
+
*/
|
|
11
|
+
function getDb() {
|
|
12
|
+
if (db)
|
|
13
|
+
return db;
|
|
14
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
15
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
db = new Database(DB_PATH);
|
|
18
|
+
// Enable WAL mode for better concurrent performance
|
|
19
|
+
db.pragma("journal_mode = WAL");
|
|
20
|
+
// Create tables
|
|
21
|
+
db.exec(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
23
|
+
id TEXT PRIMARY KEY,
|
|
24
|
+
cwd TEXT NOT NULL,
|
|
25
|
+
model TEXT NOT NULL,
|
|
26
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
27
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
28
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
token_estimate INTEGER NOT NULL DEFAULT 0,
|
|
30
|
+
summary TEXT
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
34
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
35
|
+
session_id TEXT NOT NULL,
|
|
36
|
+
role TEXT NOT NULL,
|
|
37
|
+
content TEXT,
|
|
38
|
+
tool_calls TEXT,
|
|
39
|
+
tool_call_id TEXT,
|
|
40
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
41
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
45
|
+
`);
|
|
46
|
+
return db;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a short session ID (8 chars)
|
|
50
|
+
*/
|
|
51
|
+
function generateId() {
|
|
52
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
53
|
+
let id = "";
|
|
54
|
+
for (let i = 0; i < 8; i++) {
|
|
55
|
+
id += chars[Math.floor(Math.random() * chars.length)];
|
|
56
|
+
}
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a new session
|
|
61
|
+
*/
|
|
62
|
+
export function createSession(cwd, model) {
|
|
63
|
+
const db = getDb();
|
|
64
|
+
const id = generateId();
|
|
65
|
+
db.prepare(`
|
|
66
|
+
INSERT INTO sessions (id, cwd, model) VALUES (?, ?, ?)
|
|
67
|
+
`).run(id, cwd, model);
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Save a message to a session
|
|
72
|
+
*/
|
|
73
|
+
export function saveMessage(sessionId, message) {
|
|
74
|
+
const db = getDb();
|
|
75
|
+
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
|
|
76
|
+
const toolCalls = "tool_calls" in message && message.tool_calls
|
|
77
|
+
? JSON.stringify(message.tool_calls)
|
|
78
|
+
: null;
|
|
79
|
+
const toolCallId = "tool_call_id" in message ? message.tool_call_id : null;
|
|
80
|
+
db.prepare(`
|
|
81
|
+
INSERT INTO messages (session_id, role, content, tool_calls, tool_call_id)
|
|
82
|
+
VALUES (?, ?, ?, ?, ?)
|
|
83
|
+
`).run(sessionId, message.role, content, toolCalls, toolCallId);
|
|
84
|
+
// Update session metadata
|
|
85
|
+
const stats = db.prepare(`
|
|
86
|
+
SELECT COUNT(*) as count FROM messages WHERE session_id = ?
|
|
87
|
+
`).get(sessionId);
|
|
88
|
+
db.prepare(`
|
|
89
|
+
UPDATE sessions SET updated_at = datetime('now'), message_count = ? WHERE id = ?
|
|
90
|
+
`).run(stats.count, sessionId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Update token estimate for a session
|
|
94
|
+
*/
|
|
95
|
+
export function updateTokenEstimate(sessionId, tokens) {
|
|
96
|
+
const db = getDb();
|
|
97
|
+
db.prepare(`
|
|
98
|
+
UPDATE sessions SET token_estimate = ? WHERE id = ?
|
|
99
|
+
`).run(tokens, sessionId);
|
|
100
|
+
}
|
|
101
|
+
export function listSessions(limit = 10) {
|
|
102
|
+
const db = getDb();
|
|
103
|
+
return db.prepare(`
|
|
104
|
+
SELECT * FROM sessions ORDER BY updated_at DESC LIMIT ?
|
|
105
|
+
`).all(limit);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Load all messages for a session
|
|
109
|
+
*/
|
|
110
|
+
export function loadMessages(sessionId) {
|
|
111
|
+
const db = getDb();
|
|
112
|
+
const rows = db.prepare(`
|
|
113
|
+
SELECT role, content, tool_calls, tool_call_id FROM messages
|
|
114
|
+
WHERE session_id = ? ORDER BY id ASC
|
|
115
|
+
`).all(sessionId);
|
|
116
|
+
return rows.map((row) => {
|
|
117
|
+
const msg = { role: row.role, content: row.content };
|
|
118
|
+
if (row.tool_calls) {
|
|
119
|
+
try {
|
|
120
|
+
msg.tool_calls = JSON.parse(row.tool_calls);
|
|
121
|
+
}
|
|
122
|
+
catch { /* ignore */ }
|
|
123
|
+
}
|
|
124
|
+
if (row.tool_call_id) {
|
|
125
|
+
msg.tool_call_id = row.tool_call_id;
|
|
126
|
+
}
|
|
127
|
+
return msg;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get a specific session
|
|
132
|
+
*/
|
|
133
|
+
export function getSession(sessionId) {
|
|
134
|
+
const db = getDb();
|
|
135
|
+
return db.prepare(`
|
|
136
|
+
SELECT * FROM sessions WHERE id = ?
|
|
137
|
+
`).get(sessionId) || null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Delete a session and its messages
|
|
141
|
+
*/
|
|
142
|
+
export function deleteSession(sessionId) {
|
|
143
|
+
const db = getDb();
|
|
144
|
+
db.prepare(`DELETE FROM messages WHERE session_id = ?`).run(sessionId);
|
|
145
|
+
const result = db.prepare(`DELETE FROM sessions WHERE id = ?`).run(sessionId);
|
|
146
|
+
return result.changes > 0;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Update session summary (for context compression)
|
|
150
|
+
*/
|
|
151
|
+
export function updateSummary(sessionId, summary) {
|
|
152
|
+
const db = getDb();
|
|
153
|
+
db.prepare(`
|
|
154
|
+
UPDATE sessions SET summary = ? WHERE id = ?
|
|
155
|
+
`).run(summary, sessionId);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the most recent session for a given cwd
|
|
159
|
+
*/
|
|
160
|
+
export function getLastSession(cwd) {
|
|
161
|
+
const db = getDb();
|
|
162
|
+
return db.prepare(`
|
|
163
|
+
SELECT * FROM sessions WHERE cwd = ? ORDER BY updated_at DESC LIMIT 1
|
|
164
|
+
`).get(cwd) || null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Close the database connection
|
|
168
|
+
*/
|
|
169
|
+
export function closeDb() {
|
|
170
|
+
if (db) {
|
|
171
|
+
db.close();
|
|
172
|
+
db = null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface Signature {
|
|
2
|
+
kind: "function" | "class" | "method" | "interface" | "type" | "enum" | "struct" | "trait" | "impl" | "variable" | "const" | "module" | "package" | "export";
|
|
3
|
+
name: string;
|
|
4
|
+
detail: string;
|
|
5
|
+
startLine: number;
|
|
6
|
+
endLine: number;
|
|
7
|
+
children?: Signature[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get the language name for a file extension
|
|
11
|
+
*/
|
|
12
|
+
export declare function getLanguageForExt(ext: string): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Get all supported extensions
|
|
15
|
+
*/
|
|
16
|
+
export declare function getSupportedExtensions(): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Parse a file and extract signatures using tree-sitter queries
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractSignatures(source: string, langName: string): Promise<Signature[]>;
|