@rangerchaz/aimem 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/LICENSE +21 -0
- package/README.md +380 -0
- package/dist/cli/commands/git.d.ts +6 -0
- package/dist/cli/commands/git.d.ts.map +1 -0
- package/dist/cli/commands/git.js +298 -0
- package/dist/cli/commands/git.js.map +1 -0
- package/dist/cli/commands/hook-session-end.d.ts +7 -0
- package/dist/cli/commands/hook-session-end.d.ts.map +1 -0
- package/dist/cli/commands/hook-session-end.js +109 -0
- package/dist/cli/commands/hook-session-end.js.map +1 -0
- package/dist/cli/commands/hook-session-start.d.ts +7 -0
- package/dist/cli/commands/hook-session-start.d.ts.map +1 -0
- package/dist/cli/commands/hook-session-start.js +116 -0
- package/dist/cli/commands/hook-session-start.js.map +1 -0
- package/dist/cli/commands/import.d.ts +14 -0
- package/dist/cli/commands/import.d.ts.map +1 -0
- package/dist/cli/commands/import.js +527 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +32 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mcp-serve.d.ts +2 -0
- package/dist/cli/commands/mcp-serve.d.ts.map +1 -0
- package/dist/cli/commands/mcp-serve.js +5 -0
- package/dist/cli/commands/mcp-serve.js.map +1 -0
- package/dist/cli/commands/query.d.ts +8 -0
- package/dist/cli/commands/query.d.ts.map +1 -0
- package/dist/cli/commands/query.js +83 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +10 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +504 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/start.d.ts +8 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +90 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +2 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +85 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +7 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +46 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/visualize.d.ts +8 -0
- package/dist/cli/commands/visualize.d.ts.map +1 -0
- package/dist/cli/commands/visualize.js +96 -0
- package/dist/cli/commands/visualize.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +114 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/db/index.d.ts +55 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +464 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +4 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +200 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/extractor/index.d.ts +27 -0
- package/dist/extractor/index.d.ts.map +1 -0
- package/dist/extractor/index.js +227 -0
- package/dist/extractor/index.js.map +1 -0
- package/dist/git/extractor.d.ts +30 -0
- package/dist/git/extractor.d.ts.map +1 -0
- package/dist/git/extractor.js +126 -0
- package/dist/git/extractor.js.map +1 -0
- package/dist/git/hooks.d.ts +36 -0
- package/dist/git/hooks.d.ts.map +1 -0
- package/dist/git/hooks.js +142 -0
- package/dist/git/hooks.js.map +1 -0
- package/dist/git/index.d.ts +69 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +250 -0
- package/dist/git/index.js.map +1 -0
- package/dist/indexer/index.d.ts +20 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +173 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/parsers/base.d.ts +19 -0
- package/dist/indexer/parsers/base.d.ts.map +1 -0
- package/dist/indexer/parsers/base.js +46 -0
- package/dist/indexer/parsers/base.js.map +1 -0
- package/dist/indexer/parsers/cpp.d.ts +3 -0
- package/dist/indexer/parsers/cpp.d.ts.map +1 -0
- package/dist/indexer/parsers/cpp.js +180 -0
- package/dist/indexer/parsers/cpp.js.map +1 -0
- package/dist/indexer/parsers/go.d.ts +3 -0
- package/dist/indexer/parsers/go.d.ts.map +1 -0
- package/dist/indexer/parsers/go.js +98 -0
- package/dist/indexer/parsers/go.js.map +1 -0
- package/dist/indexer/parsers/java.d.ts +3 -0
- package/dist/indexer/parsers/java.d.ts.map +1 -0
- package/dist/indexer/parsers/java.js +204 -0
- package/dist/indexer/parsers/java.js.map +1 -0
- package/dist/indexer/parsers/javascript.d.ts +3 -0
- package/dist/indexer/parsers/javascript.d.ts.map +1 -0
- package/dist/indexer/parsers/javascript.js +157 -0
- package/dist/indexer/parsers/javascript.js.map +1 -0
- package/dist/indexer/parsers/kotlin.d.ts +3 -0
- package/dist/indexer/parsers/kotlin.d.ts.map +1 -0
- package/dist/indexer/parsers/kotlin.js +182 -0
- package/dist/indexer/parsers/kotlin.js.map +1 -0
- package/dist/indexer/parsers/php.d.ts +3 -0
- package/dist/indexer/parsers/php.d.ts.map +1 -0
- package/dist/indexer/parsers/php.js +190 -0
- package/dist/indexer/parsers/php.js.map +1 -0
- package/dist/indexer/parsers/python.d.ts +3 -0
- package/dist/indexer/parsers/python.d.ts.map +1 -0
- package/dist/indexer/parsers/python.js +101 -0
- package/dist/indexer/parsers/python.js.map +1 -0
- package/dist/indexer/parsers/ruby.d.ts +3 -0
- package/dist/indexer/parsers/ruby.d.ts.map +1 -0
- package/dist/indexer/parsers/ruby.js +92 -0
- package/dist/indexer/parsers/ruby.js.map +1 -0
- package/dist/indexer/parsers/rust.d.ts +3 -0
- package/dist/indexer/parsers/rust.d.ts.map +1 -0
- package/dist/indexer/parsers/rust.js +190 -0
- package/dist/indexer/parsers/rust.js.map +1 -0
- package/dist/indexer/watcher-daemon.d.ts +2 -0
- package/dist/indexer/watcher-daemon.d.ts.map +1 -0
- package/dist/indexer/watcher-daemon.js +27 -0
- package/dist/indexer/watcher-daemon.js.map +1 -0
- package/dist/indexer/watcher.d.ts +7 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +77 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +241 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/proxy/interceptor-mockttp.d.ts +27 -0
- package/dist/proxy/interceptor-mockttp.d.ts.map +1 -0
- package/dist/proxy/interceptor-mockttp.js +274 -0
- package/dist/proxy/interceptor-mockttp.js.map +1 -0
- package/dist/proxy/proxy-daemon.d.ts +5 -0
- package/dist/proxy/proxy-daemon.d.ts.map +1 -0
- package/dist/proxy/proxy-daemon.js +26 -0
- package/dist/proxy/proxy-daemon.js.map +1 -0
- package/dist/query/index.d.ts +32 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +135 -0
- package/dist/query/index.js.map +1 -0
- package/dist/types/index.d.ts +89 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/visualize/index.d.ts +144 -0
- package/dist/visualize/index.d.ts.map +1 -0
- package/dist/visualize/index.js +707 -0
- package/dist/visualize/index.js.map +1 -0
- package/dist/visualize/server.d.ts +7 -0
- package/dist/visualize/server.d.ts.map +1 -0
- package/dist/visualize/server.js +77 -0
- package/dist/visualize/server.js.map +1 -0
- package/dist/visualize/template.d.ts +3 -0
- package/dist/visualize/template.d.ts.map +1 -0
- package/dist/visualize/template.js +3465 -0
- package/dist/visualize/template.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// Database schema for aimem
|
|
2
|
+
export const SCHEMA = `
|
|
3
|
+
-- Projects table
|
|
4
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
5
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6
|
+
path TEXT NOT NULL UNIQUE,
|
|
7
|
+
name TEXT NOT NULL,
|
|
8
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- Files table
|
|
12
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14
|
+
project_id INTEGER NOT NULL,
|
|
15
|
+
path TEXT NOT NULL,
|
|
16
|
+
hash TEXT NOT NULL,
|
|
17
|
+
last_indexed TEXT DEFAULT (datetime('now')),
|
|
18
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
|
19
|
+
UNIQUE(project_id, path)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- Structures table (functions, classes, methods, etc.)
|
|
23
|
+
CREATE TABLE IF NOT EXISTS structures (
|
|
24
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
+
file_id INTEGER NOT NULL,
|
|
26
|
+
type TEXT NOT NULL CHECK (type IN ('function', 'class', 'method', 'interface', 'type', 'variable', 'module')),
|
|
27
|
+
name TEXT NOT NULL,
|
|
28
|
+
line_start INTEGER NOT NULL,
|
|
29
|
+
line_end INTEGER NOT NULL,
|
|
30
|
+
signature TEXT,
|
|
31
|
+
raw_content TEXT NOT NULL,
|
|
32
|
+
metadata TEXT DEFAULT '{}',
|
|
33
|
+
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
-- Conversations table
|
|
37
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
39
|
+
project_id INTEGER,
|
|
40
|
+
timestamp TEXT DEFAULT (datetime('now')),
|
|
41
|
+
model TEXT,
|
|
42
|
+
tool TEXT,
|
|
43
|
+
summary TEXT,
|
|
44
|
+
raw_content TEXT NOT NULL,
|
|
45
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
-- Links table (graph edges)
|
|
49
|
+
CREATE TABLE IF NOT EXISTS links (
|
|
50
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
51
|
+
source_type TEXT NOT NULL CHECK (source_type IN ('file', 'structure', 'conversation', 'extraction')),
|
|
52
|
+
source_id INTEGER NOT NULL,
|
|
53
|
+
target_type TEXT NOT NULL CHECK (target_type IN ('file', 'structure', 'conversation', 'extraction')),
|
|
54
|
+
target_id INTEGER NOT NULL,
|
|
55
|
+
link_type TEXT NOT NULL CHECK (link_type IN ('decision', 'touched', 'rejected', 'calls', 'called_by', 'references')),
|
|
56
|
+
UNIQUE(source_type, source_id, target_type, target_id, link_type)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- Extractions table (decisions, patterns, rejections from conversations)
|
|
60
|
+
CREATE TABLE IF NOT EXISTS extractions (
|
|
61
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
62
|
+
conversation_id INTEGER NOT NULL,
|
|
63
|
+
type TEXT NOT NULL CHECK (type IN ('decision', 'pattern', 'rejection', 'question')),
|
|
64
|
+
content TEXT NOT NULL,
|
|
65
|
+
metadata TEXT DEFAULT '{}',
|
|
66
|
+
FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
-- Indexes for common queries
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_files_project ON files(project_id);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_files_path ON files(path);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_structures_file ON structures(file_id);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_structures_name ON structures(name);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_structures_type ON structures(type);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_project ON conversations(project_id);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_links_source ON links(source_type, source_id);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_links_target ON links(target_type, target_id);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_extractions_conversation ON extractions(conversation_id);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_extractions_type ON extractions(type);
|
|
80
|
+
|
|
81
|
+
-- Full-text search for structures
|
|
82
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS structures_fts USING fts5(
|
|
83
|
+
name,
|
|
84
|
+
signature,
|
|
85
|
+
raw_content,
|
|
86
|
+
content='structures',
|
|
87
|
+
content_rowid='id'
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
-- Triggers to keep FTS in sync
|
|
91
|
+
CREATE TRIGGER IF NOT EXISTS structures_ai AFTER INSERT ON structures BEGIN
|
|
92
|
+
INSERT INTO structures_fts(rowid, name, signature, raw_content)
|
|
93
|
+
VALUES (new.id, new.name, new.signature, new.raw_content);
|
|
94
|
+
END;
|
|
95
|
+
|
|
96
|
+
CREATE TRIGGER IF NOT EXISTS structures_ad AFTER DELETE ON structures BEGIN
|
|
97
|
+
INSERT INTO structures_fts(structures_fts, rowid, name, signature, raw_content)
|
|
98
|
+
VALUES ('delete', old.id, old.name, old.signature, old.raw_content);
|
|
99
|
+
END;
|
|
100
|
+
|
|
101
|
+
CREATE TRIGGER IF NOT EXISTS structures_au AFTER UPDATE ON structures BEGIN
|
|
102
|
+
INSERT INTO structures_fts(structures_fts, rowid, name, signature, raw_content)
|
|
103
|
+
VALUES ('delete', old.id, old.name, old.signature, old.raw_content);
|
|
104
|
+
INSERT INTO structures_fts(rowid, name, signature, raw_content)
|
|
105
|
+
VALUES (new.id, new.name, new.signature, new.raw_content);
|
|
106
|
+
END;
|
|
107
|
+
|
|
108
|
+
-- Full-text search for conversations
|
|
109
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
110
|
+
summary,
|
|
111
|
+
raw_content,
|
|
112
|
+
content='conversations',
|
|
113
|
+
content_rowid='id'
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
CREATE TRIGGER IF NOT EXISTS conversations_ai AFTER INSERT ON conversations BEGIN
|
|
117
|
+
INSERT INTO conversations_fts(rowid, summary, raw_content)
|
|
118
|
+
VALUES (new.id, new.summary, new.raw_content);
|
|
119
|
+
END;
|
|
120
|
+
|
|
121
|
+
CREATE TRIGGER IF NOT EXISTS conversations_ad AFTER DELETE ON conversations BEGIN
|
|
122
|
+
INSERT INTO conversations_fts(conversations_fts, rowid, summary, raw_content)
|
|
123
|
+
VALUES ('delete', old.id, old.summary, old.raw_content);
|
|
124
|
+
END;
|
|
125
|
+
|
|
126
|
+
CREATE TRIGGER IF NOT EXISTS conversations_au AFTER UPDATE ON conversations BEGIN
|
|
127
|
+
INSERT INTO conversations_fts(conversations_fts, rowid, summary, raw_content)
|
|
128
|
+
VALUES ('delete', old.id, old.summary, old.raw_content);
|
|
129
|
+
INSERT INTO conversations_fts(rowid, summary, raw_content)
|
|
130
|
+
VALUES (new.id, new.summary, new.raw_content);
|
|
131
|
+
END;
|
|
132
|
+
|
|
133
|
+
-- Git commits table
|
|
134
|
+
CREATE TABLE IF NOT EXISTS commits (
|
|
135
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
136
|
+
project_id INTEGER NOT NULL,
|
|
137
|
+
hash TEXT NOT NULL,
|
|
138
|
+
short_hash TEXT,
|
|
139
|
+
author_name TEXT,
|
|
140
|
+
author_email TEXT,
|
|
141
|
+
timestamp TEXT NOT NULL,
|
|
142
|
+
subject TEXT NOT NULL,
|
|
143
|
+
body TEXT,
|
|
144
|
+
parent_hashes TEXT,
|
|
145
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
|
146
|
+
UNIQUE(project_id, hash)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
CREATE INDEX IF NOT EXISTS idx_commits_project ON commits(project_id);
|
|
150
|
+
CREATE INDEX IF NOT EXISTS idx_commits_hash ON commits(hash);
|
|
151
|
+
CREATE INDEX IF NOT EXISTS idx_commits_timestamp ON commits(timestamp);
|
|
152
|
+
|
|
153
|
+
-- Full-text search for commits
|
|
154
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS commits_fts USING fts5(
|
|
155
|
+
subject,
|
|
156
|
+
body,
|
|
157
|
+
content='commits',
|
|
158
|
+
content_rowid='id'
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
CREATE TRIGGER IF NOT EXISTS commits_ai AFTER INSERT ON commits BEGIN
|
|
162
|
+
INSERT INTO commits_fts(rowid, subject, body)
|
|
163
|
+
VALUES (new.id, new.subject, new.body);
|
|
164
|
+
END;
|
|
165
|
+
|
|
166
|
+
CREATE TRIGGER IF NOT EXISTS commits_ad AFTER DELETE ON commits BEGIN
|
|
167
|
+
INSERT INTO commits_fts(commits_fts, rowid, subject, body)
|
|
168
|
+
VALUES ('delete', old.id, old.subject, old.body);
|
|
169
|
+
END;
|
|
170
|
+
|
|
171
|
+
CREATE TRIGGER IF NOT EXISTS commits_au AFTER UPDATE ON commits BEGIN
|
|
172
|
+
INSERT INTO commits_fts(commits_fts, rowid, subject, body)
|
|
173
|
+
VALUES ('delete', old.id, old.subject, old.body);
|
|
174
|
+
INSERT INTO commits_fts(rowid, subject, body)
|
|
175
|
+
VALUES (new.id, new.subject, new.body);
|
|
176
|
+
END;
|
|
177
|
+
`;
|
|
178
|
+
// Migrations for existing databases
|
|
179
|
+
export const MIGRATIONS = [
|
|
180
|
+
// Migration 1: Add git authorship columns to structures
|
|
181
|
+
`ALTER TABLE structures ADD COLUMN last_author TEXT;`,
|
|
182
|
+
`ALTER TABLE structures ADD COLUMN last_author_email TEXT;`,
|
|
183
|
+
`ALTER TABLE structures ADD COLUMN last_commit_hash TEXT;`,
|
|
184
|
+
];
|
|
185
|
+
// Links between commits and other entities use a separate table to avoid schema migration issues
|
|
186
|
+
export const COMMIT_LINKS_SCHEMA = `
|
|
187
|
+
CREATE TABLE IF NOT EXISTS commit_links (
|
|
188
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
189
|
+
commit_id INTEGER NOT NULL,
|
|
190
|
+
target_type TEXT NOT NULL CHECK (target_type IN ('structure', 'file', 'extraction', 'conversation')),
|
|
191
|
+
target_id INTEGER NOT NULL,
|
|
192
|
+
link_type TEXT NOT NULL CHECK (link_type IN ('modified', 'committed_in', 'introduced')),
|
|
193
|
+
FOREIGN KEY (commit_id) REFERENCES commits(id) ON DELETE CASCADE,
|
|
194
|
+
UNIQUE(commit_id, target_type, target_id, link_type)
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
CREATE INDEX IF NOT EXISTS idx_commit_links_commit ON commit_links(commit_id);
|
|
198
|
+
CREATE INDEX IF NOT EXISTS idx_commit_links_target ON commit_links(target_type, target_id);
|
|
199
|
+
`;
|
|
200
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAE5B,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KrB,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,wDAAwD;IACxD,qDAAqD;IACrD,2DAA2D;IAC3D,0DAA0D;CAC3D,CAAC;AAEF,iGAAiG;AACjG,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;CAalC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface TranscriptMessage {
|
|
2
|
+
type: string;
|
|
3
|
+
role?: string;
|
|
4
|
+
content?: string | {
|
|
5
|
+
type: string;
|
|
6
|
+
text?: string;
|
|
7
|
+
}[];
|
|
8
|
+
tool_name?: string;
|
|
9
|
+
tool_input?: Record<string, unknown>;
|
|
10
|
+
tool_result?: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface ExtractedItem {
|
|
13
|
+
type: 'decision' | 'rejection' | 'pattern' | 'question';
|
|
14
|
+
content: string;
|
|
15
|
+
mentionedEntities: string[];
|
|
16
|
+
metadata: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extract decisions, rejections, and patterns from conversation messages.
|
|
20
|
+
* Uses pattern matching - no LLM required.
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractDecisions(messages: TranscriptMessage[]): ExtractedItem[];
|
|
23
|
+
/**
|
|
24
|
+
* Generate a summary of the conversation for storage
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateSummary(messages: TranscriptMessage[]): string;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extractor/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,aAAa,EAAE,CA2E/E;AA2JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAiBrE"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// Decision and pattern extraction from conversation transcripts
|
|
2
|
+
/**
|
|
3
|
+
* Extract decisions, rejections, and patterns from conversation messages.
|
|
4
|
+
* Uses pattern matching - no LLM required.
|
|
5
|
+
*/
|
|
6
|
+
export function extractDecisions(messages) {
|
|
7
|
+
const extractions = [];
|
|
8
|
+
// Decision patterns - phrases that indicate a choice was made
|
|
9
|
+
const decisionPatterns = [
|
|
10
|
+
/(?:we should|let's|I'll|I will|going to|decided to|will use|using|chose|choosing|the best approach is|recommend using)\s+(.+?)(?:\.|$)/gi,
|
|
11
|
+
/(?:the approach|the solution|the fix|the implementation|the strategy)\s+(?:is|will be|should be)\s+(.+?)(?:\.|$)/gi,
|
|
12
|
+
/(?:because|since|the reason is|this is because)\s+(.+?)(?:\.|$)/gi,
|
|
13
|
+
/(?:I've implemented|I've added|I've created|I've updated)\s+(.+?)(?:\.|$)/gi,
|
|
14
|
+
];
|
|
15
|
+
// Rejection patterns - phrases that indicate something was ruled out
|
|
16
|
+
const rejectionPatterns = [
|
|
17
|
+
/(?:instead of|rather than|not using|won't use|shouldn't use|avoid using|don't use)\s+(.+?)(?:\.|$)/gi,
|
|
18
|
+
/(?:rejected|ruled out|decided against|not recommended|wouldn't work)\s+(.+?)(?:\.|$)/gi,
|
|
19
|
+
/(?:the problem with|the issue with|doesn't work because)\s+(.+?)(?:\.|$)/gi,
|
|
20
|
+
];
|
|
21
|
+
// Entity patterns for linking to code structures
|
|
22
|
+
const classPattern = /\b([A-Z][a-zA-Z0-9]*(?:Service|Controller|Model|Helper|Manager|Handler|Factory|Builder|Provider|Middleware|Client|Server|Worker|Job|Task|Command|Query|Event|Listener|Observer|Strategy|Adapter|Decorator|Proxy|Repository|Gateway|Validator|Serializer|Parser|Formatter|Renderer|Component|Module|Plugin|Extension)?)\b/g;
|
|
23
|
+
const functionPattern = /\b([a-z_][a-z0-9_]*)\s*\(/g;
|
|
24
|
+
const methodPattern = /(?:def|function|const|let|var)\s+([a-z_][a-z0-9_]*)/g;
|
|
25
|
+
const filePattern = /(?:in|from|file|at)\s+[`"']?([a-zA-Z0-9_/.-]+\.[a-z]+)[`"']?/gi;
|
|
26
|
+
for (const msg of messages) {
|
|
27
|
+
if (msg.role !== 'assistant')
|
|
28
|
+
continue;
|
|
29
|
+
const content = getMessageContent(msg);
|
|
30
|
+
if (!content)
|
|
31
|
+
continue;
|
|
32
|
+
// Extract decisions
|
|
33
|
+
for (const pattern of decisionPatterns) {
|
|
34
|
+
pattern.lastIndex = 0; // Reset regex state
|
|
35
|
+
let match;
|
|
36
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
37
|
+
const sentence = getSentenceAround(content, match.index);
|
|
38
|
+
if (isValidExtraction(sentence)) {
|
|
39
|
+
const entities = extractEntities(sentence, classPattern, functionPattern, methodPattern);
|
|
40
|
+
extractions.push({
|
|
41
|
+
type: 'decision',
|
|
42
|
+
content: cleanSentence(sentence),
|
|
43
|
+
mentionedEntities: entities,
|
|
44
|
+
metadata: {
|
|
45
|
+
patternType: 'decision',
|
|
46
|
+
originalMatch: match[0].slice(0, 100)
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Extract rejections
|
|
53
|
+
for (const pattern of rejectionPatterns) {
|
|
54
|
+
pattern.lastIndex = 0;
|
|
55
|
+
let match;
|
|
56
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
57
|
+
const sentence = getSentenceAround(content, match.index);
|
|
58
|
+
if (isValidExtraction(sentence)) {
|
|
59
|
+
const entities = extractEntities(sentence, classPattern, functionPattern, methodPattern);
|
|
60
|
+
extractions.push({
|
|
61
|
+
type: 'rejection',
|
|
62
|
+
content: cleanSentence(sentence),
|
|
63
|
+
mentionedEntities: entities,
|
|
64
|
+
metadata: {
|
|
65
|
+
patternType: 'rejection',
|
|
66
|
+
originalMatch: match[0].slice(0, 100)
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Deduplicate and return
|
|
74
|
+
return deduplicateExtractions(extractions);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get text content from a message, handling different content formats
|
|
78
|
+
*/
|
|
79
|
+
function getMessageContent(msg) {
|
|
80
|
+
if (typeof msg.content === 'string') {
|
|
81
|
+
return msg.content;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(msg.content)) {
|
|
84
|
+
return msg.content
|
|
85
|
+
.map(c => c.text)
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
.join('\n');
|
|
88
|
+
}
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the sentence containing the match index
|
|
93
|
+
*/
|
|
94
|
+
function getSentenceAround(text, index) {
|
|
95
|
+
// Find sentence boundaries (., !, ?, or newlines)
|
|
96
|
+
const sentenceEnders = /[.!?]\s|\n\n/g;
|
|
97
|
+
let start = 0;
|
|
98
|
+
let end = text.length;
|
|
99
|
+
// Find start of sentence
|
|
100
|
+
const beforeText = text.slice(0, index);
|
|
101
|
+
const lastEnder = beforeText.search(/[.!?]\s[^.!?]*$/);
|
|
102
|
+
if (lastEnder !== -1) {
|
|
103
|
+
start = lastEnder + 2;
|
|
104
|
+
}
|
|
105
|
+
const lastNewline = beforeText.lastIndexOf('\n\n');
|
|
106
|
+
if (lastNewline > start) {
|
|
107
|
+
start = lastNewline + 2;
|
|
108
|
+
}
|
|
109
|
+
// Find end of sentence
|
|
110
|
+
const afterText = text.slice(index);
|
|
111
|
+
const nextEnderMatch = afterText.match(/[.!?](?:\s|$)/);
|
|
112
|
+
if (nextEnderMatch && nextEnderMatch.index !== undefined) {
|
|
113
|
+
end = index + nextEnderMatch.index + 1;
|
|
114
|
+
}
|
|
115
|
+
const nextNewline = afterText.indexOf('\n\n');
|
|
116
|
+
if (nextNewline !== -1 && index + nextNewline < end) {
|
|
117
|
+
end = index + nextNewline;
|
|
118
|
+
}
|
|
119
|
+
return text.slice(start, end).trim();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if extraction is valid (not too short, not too long, not code)
|
|
123
|
+
*/
|
|
124
|
+
function isValidExtraction(sentence) {
|
|
125
|
+
// Too short or too long
|
|
126
|
+
if (sentence.length < 30 || sentence.length > 500) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
// Looks like code (too many special characters)
|
|
130
|
+
const codeIndicators = sentence.match(/[{}()\[\];=<>]/g);
|
|
131
|
+
if (codeIndicators && codeIndicators.length > 5) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
// Is a code block
|
|
135
|
+
if (sentence.includes('```') || sentence.startsWith(' ') || sentence.startsWith('\t')) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
// Is just a list item number or bullet
|
|
139
|
+
if (/^[\d\-*•]\s/.test(sentence) && sentence.length < 50) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Clean up a sentence for storage
|
|
146
|
+
*/
|
|
147
|
+
function cleanSentence(sentence) {
|
|
148
|
+
return sentence
|
|
149
|
+
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
150
|
+
.replace(/^[-*•]\s*/, '') // Remove list markers
|
|
151
|
+
.replace(/^\d+\.\s*/, '') // Remove numbered list markers
|
|
152
|
+
.trim();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Extract entity names from text using patterns
|
|
156
|
+
*/
|
|
157
|
+
function extractEntities(text, ...patterns) {
|
|
158
|
+
const entities = new Set();
|
|
159
|
+
for (const pattern of patterns) {
|
|
160
|
+
const p = new RegExp(pattern.source, pattern.flags);
|
|
161
|
+
let match;
|
|
162
|
+
while ((match = p.exec(text)) !== null) {
|
|
163
|
+
const entity = match[1];
|
|
164
|
+
// Filter out common false positives
|
|
165
|
+
if (entity && entity.length > 2 && !isCommonWord(entity)) {
|
|
166
|
+
entities.add(entity);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return [...entities];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if a word is too common to be a meaningful entity
|
|
174
|
+
*/
|
|
175
|
+
function isCommonWord(word) {
|
|
176
|
+
const commonWords = new Set([
|
|
177
|
+
'the', 'this', 'that', 'these', 'those', 'then', 'than',
|
|
178
|
+
'will', 'would', 'should', 'could', 'can', 'may', 'might',
|
|
179
|
+
'have', 'has', 'had', 'get', 'set', 'let', 'var', 'const',
|
|
180
|
+
'function', 'class', 'def', 'return', 'true', 'false', 'null',
|
|
181
|
+
'undefined', 'new', 'for', 'while', 'if', 'else', 'try', 'catch',
|
|
182
|
+
'import', 'export', 'from', 'require', 'module', 'use', 'using',
|
|
183
|
+
'not', 'and', 'but', 'with', 'was', 'were', 'are', 'been',
|
|
184
|
+
'being', 'does', 'done', 'doing', 'did', 'make', 'made', 'making',
|
|
185
|
+
'String', 'Number', 'Boolean', 'Array', 'Object', 'Date', 'Error',
|
|
186
|
+
'Promise', 'Map', 'Set', 'JSON', 'Math', 'console', 'process',
|
|
187
|
+
]);
|
|
188
|
+
return commonWords.has(word) || commonWords.has(word.toLowerCase());
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Remove duplicate or very similar extractions
|
|
192
|
+
*/
|
|
193
|
+
function deduplicateExtractions(extractions) {
|
|
194
|
+
const seen = new Set();
|
|
195
|
+
const result = [];
|
|
196
|
+
for (const ext of extractions) {
|
|
197
|
+
// Create a normalized key for comparison
|
|
198
|
+
const key = ext.content
|
|
199
|
+
.toLowerCase()
|
|
200
|
+
.replace(/\s+/g, ' ')
|
|
201
|
+
.slice(0, 80);
|
|
202
|
+
if (!seen.has(key)) {
|
|
203
|
+
seen.add(key);
|
|
204
|
+
result.push(ext);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate a summary of the conversation for storage
|
|
211
|
+
*/
|
|
212
|
+
export function generateSummary(messages) {
|
|
213
|
+
const userMessages = messages
|
|
214
|
+
.filter(m => m.role === 'user')
|
|
215
|
+
.map(m => getMessageContent(m))
|
|
216
|
+
.filter(c => c.length > 0);
|
|
217
|
+
if (userMessages.length === 0) {
|
|
218
|
+
return 'Empty conversation';
|
|
219
|
+
}
|
|
220
|
+
// Use first user message as base for summary
|
|
221
|
+
const firstMessage = userMessages[0].slice(0, 200);
|
|
222
|
+
const topicHint = userMessages.length > 1
|
|
223
|
+
? ` (${userMessages.length} exchanges)`
|
|
224
|
+
: '';
|
|
225
|
+
return `${firstMessage}${topicHint}`;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extractor/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract decisions and context from git commit messages
|
|
3
|
+
*/
|
|
4
|
+
import type { GitCommit } from './index.js';
|
|
5
|
+
export interface ConventionalCommit {
|
|
6
|
+
type: string;
|
|
7
|
+
scope: string | null;
|
|
8
|
+
breaking: boolean;
|
|
9
|
+
description: string;
|
|
10
|
+
body: string | null;
|
|
11
|
+
footers: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface CommitExtraction {
|
|
14
|
+
type: 'decision' | 'pattern' | 'rejection';
|
|
15
|
+
content: string;
|
|
16
|
+
source: 'commit';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse a conventional commit message
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseConventionalCommit(subject: string, body?: string): ConventionalCommit | null;
|
|
22
|
+
/**
|
|
23
|
+
* Extract decisions from a commit message
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractFromCommit(commit: GitCommit): CommitExtraction[];
|
|
26
|
+
/**
|
|
27
|
+
* Check if a commit message contains decision-related content
|
|
28
|
+
*/
|
|
29
|
+
export declare function hasDecisionContent(commit: GitCommit): boolean;
|
|
30
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/git/extractor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,CAAC;CAClB;AA2BD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA0BjG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EAAE,CAmDvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAoB7D"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract decisions and context from git commit messages
|
|
3
|
+
*/
|
|
4
|
+
// Conventional commit regex: type(scope)!: description
|
|
5
|
+
const CONVENTIONAL_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
|
|
6
|
+
// Patterns that indicate decisions in commit messages
|
|
7
|
+
const DECISION_PATTERNS = [
|
|
8
|
+
/\bdecid(?:e|ed|ing)\s+to\b/i,
|
|
9
|
+
/\bchoos(?:e|ing)\s+to\b/i,
|
|
10
|
+
/\bswitch(?:ed|ing)?\s+(?:to|from)\b/i,
|
|
11
|
+
/\bmigrat(?:e|ed|ing)\s+(?:to|from)\b/i,
|
|
12
|
+
/\breplace(?:d|ing)?\s+.+\s+with\b/i,
|
|
13
|
+
/\buse\s+.+\s+instead\s+of\b/i,
|
|
14
|
+
/\badopt(?:ed|ing)?\b/i,
|
|
15
|
+
/\bimplement(?:ed|ing)?\s+.+\s+using\b/i,
|
|
16
|
+
];
|
|
17
|
+
// Patterns that indicate rejections
|
|
18
|
+
const REJECTION_PATTERNS = [
|
|
19
|
+
/\bremov(?:e|ed|ing)\s+.+\s+(?:because|due\s+to)\b/i,
|
|
20
|
+
/\bdeprecate(?:d|ing)?\b/i,
|
|
21
|
+
/\brevert(?:ed|ing)?\b/i,
|
|
22
|
+
/\bdon't\s+use\b/i,
|
|
23
|
+
/\bavoid(?:ed|ing)?\b/i,
|
|
24
|
+
/\bstop(?:ped|ping)?\s+using\b/i,
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Parse a conventional commit message
|
|
28
|
+
*/
|
|
29
|
+
export function parseConventionalCommit(subject, body) {
|
|
30
|
+
const match = subject.match(CONVENTIONAL_REGEX);
|
|
31
|
+
if (!match)
|
|
32
|
+
return null;
|
|
33
|
+
const [, type, scope, breaking, description] = match;
|
|
34
|
+
const footers = {};
|
|
35
|
+
// Parse footers from body (lines matching "Key: Value" or "Key #value")
|
|
36
|
+
if (body) {
|
|
37
|
+
const lines = body.split('\n');
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
const footerMatch = line.match(/^([\w-]+)(?::\s*|\s+#)(.+)$/);
|
|
40
|
+
if (footerMatch) {
|
|
41
|
+
footers[footerMatch[1].toLowerCase()] = footerMatch[2];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
type: type.toLowerCase(),
|
|
47
|
+
scope: scope || null,
|
|
48
|
+
breaking: !!breaking || 'breaking-change' in footers || 'breaking change' in footers,
|
|
49
|
+
description,
|
|
50
|
+
body: body || null,
|
|
51
|
+
footers,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract decisions from a commit message
|
|
56
|
+
*/
|
|
57
|
+
export function extractFromCommit(commit) {
|
|
58
|
+
const extractions = [];
|
|
59
|
+
const fullMessage = `${commit.subject}\n${commit.body || ''}`;
|
|
60
|
+
// Check for decision patterns
|
|
61
|
+
for (const pattern of DECISION_PATTERNS) {
|
|
62
|
+
if (pattern.test(fullMessage)) {
|
|
63
|
+
extractions.push({
|
|
64
|
+
type: 'decision',
|
|
65
|
+
content: `[${commit.shortHash}] ${commit.subject}`,
|
|
66
|
+
source: 'commit',
|
|
67
|
+
});
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Check for rejection patterns
|
|
72
|
+
for (const pattern of REJECTION_PATTERNS) {
|
|
73
|
+
if (pattern.test(fullMessage)) {
|
|
74
|
+
extractions.push({
|
|
75
|
+
type: 'rejection',
|
|
76
|
+
content: `[${commit.shortHash}] ${commit.subject}`,
|
|
77
|
+
source: 'commit',
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Check for conventional commits with specific types
|
|
83
|
+
const conventional = parseConventionalCommit(commit.subject, commit.body);
|
|
84
|
+
if (conventional) {
|
|
85
|
+
// feat and refactor often represent decisions
|
|
86
|
+
if (['feat', 'refactor'].includes(conventional.type) && extractions.length === 0) {
|
|
87
|
+
extractions.push({
|
|
88
|
+
type: 'decision',
|
|
89
|
+
content: `[${commit.shortHash}] ${conventional.type}${conventional.scope ? `(${conventional.scope})` : ''}: ${conventional.description}`,
|
|
90
|
+
source: 'commit',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Breaking changes are important decisions
|
|
94
|
+
if (conventional.breaking && !extractions.some(e => e.content.includes('BREAKING'))) {
|
|
95
|
+
extractions.push({
|
|
96
|
+
type: 'decision',
|
|
97
|
+
content: `[${commit.shortHash}] BREAKING: ${conventional.description}`,
|
|
98
|
+
source: 'commit',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return extractions;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if a commit message contains decision-related content
|
|
106
|
+
*/
|
|
107
|
+
export function hasDecisionContent(commit) {
|
|
108
|
+
const fullMessage = `${commit.subject}\n${commit.body || ''}`;
|
|
109
|
+
// Check decision patterns
|
|
110
|
+
for (const pattern of DECISION_PATTERNS) {
|
|
111
|
+
if (pattern.test(fullMessage))
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
// Check rejection patterns
|
|
115
|
+
for (const pattern of REJECTION_PATTERNS) {
|
|
116
|
+
if (pattern.test(fullMessage))
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// Check for conventional commit with meaningful type
|
|
120
|
+
const conventional = parseConventionalCommit(commit.subject);
|
|
121
|
+
if (conventional && ['feat', 'refactor', 'fix'].includes(conventional.type)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/git/extractor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH,uDAAuD;AACvD,MAAM,kBAAkB,GAAG,qCAAqC,CAAC;AAEjE,sDAAsD;AACtD,MAAM,iBAAiB,GAAG;IACxB,6BAA6B;IAC7B,0BAA0B;IAC1B,sCAAsC;IACtC,uCAAuC;IACvC,oCAAoC;IACpC,8BAA8B;IAC9B,uBAAuB;IACvB,wCAAwC;CACzC,CAAC;AAEF,oCAAoC;AACpC,MAAM,kBAAkB,GAAG;IACzB,oDAAoD;IACpD,0BAA0B;IAC1B,wBAAwB;IACxB,kBAAkB;IAClB,uBAAuB;IACvB,gCAAgC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,IAAa;IACpE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC;IACrD,MAAM,OAAO,GAA2B,EAAE,CAAC;IAE3C,wEAAwE;IACxE,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC9D,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;QACxB,KAAK,EAAE,KAAK,IAAI,IAAI;QACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,iBAAiB,IAAI,OAAO,IAAI,iBAAiB,IAAI,OAAO;QACpF,WAAW;QACX,IAAI,EAAE,IAAI,IAAI,IAAI;QAClB,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IAE9D,8BAA8B;IAC9B,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,IAAI,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,OAAO,EAAE;gBAClD,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;YACH,MAAM;QACR,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,IAAI,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,OAAO,EAAE;gBAClD,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;YACH,MAAM;QACR,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,MAAM,YAAY,GAAG,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1E,IAAI,YAAY,EAAE,CAAC;QACjB,8CAA8C;QAC9C,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjF,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,IAAI,MAAM,CAAC,SAAS,KAAK,YAAY,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE;gBACxI,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;QACL,CAAC;QAED,2CAA2C;QAC3C,IAAI,YAAY,CAAC,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YACpF,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,IAAI,MAAM,CAAC,SAAS,eAAe,YAAY,CAAC,WAAW,EAAE;gBACtE,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IAE9D,0BAA0B;IAC1B,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IAED,2BAA2B;IAC3B,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IAED,qDAAqD;IACrD,MAAM,YAAY,GAAG,uBAAuB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7D,IAAI,YAAY,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|