septum 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +105 -105
  3. package/bin/septum.ts +4 -4
  4. package/package.json +63 -63
  5. package/src/cli/commands/check.ts +161 -161
  6. package/src/cli/commands/hook.ts +216 -188
  7. package/src/cli/commands/ingest.ts +29 -29
  8. package/src/cli/commands/init.ts +213 -211
  9. package/src/cli/commands/locate.ts +61 -61
  10. package/src/cli/commands/query.ts +104 -64
  11. package/src/cli/commands/serve.ts +5 -5
  12. package/src/cli/commands/slice.ts +50 -48
  13. package/src/cli/commands/sync.ts +31 -31
  14. package/src/cli/index.ts +220 -210
  15. package/src/cli/templates/hooks.ts +75 -75
  16. package/src/cli/templates/rules.ts +50 -38
  17. package/src/cli/templates/skill.ts +65 -69
  18. package/src/core/boundary/evaluator.ts +429 -210
  19. package/src/core/config/loader.ts +117 -97
  20. package/src/core/config/schema.ts +39 -39
  21. package/src/core/database/client.ts +44 -44
  22. package/src/core/database/repositories/dependency.repository.ts +552 -349
  23. package/src/core/database/repositories/domain.repository.ts +275 -198
  24. package/src/core/database/repositories/file.repository.ts +117 -106
  25. package/src/core/database/repositories/meta.repository.ts +33 -33
  26. package/src/core/database/repositories/symbol.repository.ts +482 -443
  27. package/src/core/database/repository.ts +281 -260
  28. package/src/core/database/schema.ts +154 -153
  29. package/src/core/discovery/topology-detector.ts +486 -486
  30. package/src/core/ingestion/hasher.ts +5 -5
  31. package/src/core/ingestion/pipeline.ts +606 -535
  32. package/src/core/parser/boundary-tracker.ts +433 -288
  33. package/src/core/parser/extractors/base.ts +62 -62
  34. package/src/core/parser/extractors/blade.ts +158 -158
  35. package/src/core/parser/extractors/frontend.ts +147 -194
  36. package/src/core/parser/extractors/go.ts +408 -180
  37. package/src/core/parser/extractors/laravel-semantic.ts +1045 -901
  38. package/src/core/parser/extractors/mcp-cli-semantic.ts +328 -199
  39. package/src/core/parser/extractors/nestjs-semantic.ts +134 -119
  40. package/src/core/parser/extractors/php.ts +415 -153
  41. package/src/core/parser/extractors/python.ts +460 -228
  42. package/src/core/parser/extractors/registry.ts +70 -70
  43. package/src/core/parser/extractors/semantic-extractor.interface.ts +21 -21
  44. package/src/core/parser/extractors/typescript.ts +668 -181
  45. package/src/core/parser/tree-sitter.ts +41 -41
  46. package/src/core/parser/wasm-loader.ts +271 -0
  47. package/src/core/resolver/call-graph-tracer.ts +698 -668
  48. package/src/core/resolver/module-resolver.ts +479 -342
  49. package/src/core/resolver/path-resolver.ts +147 -147
  50. package/src/core/resolver/symbol-locator.ts +543 -543
  51. package/src/core/resolver/vertical-slice-tracer.ts +323 -285
  52. package/src/core/session/session-manager.ts +56 -56
  53. package/src/core/telemetry/telemetry.ts +86 -86
  54. package/src/core/topology/environment-detector.ts +109 -6
  55. package/src/index.ts +21 -21
  56. package/src/mcp/schemas.ts +695 -286
  57. package/src/mcp/server.ts +927 -716
  58. package/src/mcp/tools/check-boundary.ts +307 -152
  59. package/src/mcp/tools/get-domain-catalog.ts +155 -121
  60. package/src/mcp/tools/get-environment-topology.ts +3 -6
  61. package/src/mcp/tools/get-feature-context.ts +227 -116
  62. package/src/mcp/tools/get-symbol-hotspots.ts +54 -59
  63. package/src/mcp/tools/get-symbol-impact.ts +28 -26
  64. package/src/mcp/tools/get-symbol.ts +65 -63
  65. package/src/mcp/tools/locate-symbol.ts +169 -190
  66. package/src/mcp/tools/register-domain.ts +59 -64
  67. package/src/mcp/tools/register-feature.ts +91 -0
  68. package/src/mcp/tools/trace-vertical-slice.ts +74 -48
  69. package/src/types/index.ts +366 -315
  70. package/src/version.ts +3 -3
@@ -1,260 +1,281 @@
1
- import type { Database } from "bun:sqlite";
2
- import type {
3
- ArchetypeKind,
4
- DomainCatalogResponse,
5
- DomainConfig,
6
- DomainRecord,
7
- ExtractedDependency,
8
- ExtractedSymbol,
9
- FileRecord,
10
- GetSymbolDetailsResponse,
11
- GetSymbolImpactResponse,
12
- InboundCaller,
13
- SymbolKind,
14
- SymbolRecord,
15
- VerticalSliceRecord,
16
- } from "../../types/index.ts";
17
-
18
- export type {
19
- ArchetypeKind,
20
- DomainCatalogResponse,
21
- DomainConfig,
22
- DomainRecord,
23
- ExtractedDependency,
24
- ExtractedSymbol,
25
- FileRecord,
26
- GetSymbolDetailsResponse,
27
- GetSymbolImpactResponse,
28
- InboundCaller,
29
- SymbolKind,
30
- SymbolRecord,
31
- VerticalSliceRecord,
32
- } from "../../types/index.ts";
33
- import { DependencyRepository } from "./repositories/dependency.repository.ts";
34
- import { DomainRepository } from "./repositories/domain.repository.ts";
35
- import { EnvironmentRepository } from "./repositories/environment.repository.ts";
36
- import { FileRepository } from "./repositories/file.repository.ts";
37
- import { MetaRepository } from "./repositories/meta.repository.ts";
38
- import { SymbolRepository } from "./repositories/symbol.repository.ts";
39
-
40
- export type DatabaseRepository = SeptumRepository;
41
-
42
- export class SeptumRepository {
43
- public readonly domains: DomainRepository;
44
- public readonly files: FileRepository;
45
- public readonly symbols: SymbolRepository;
46
- public readonly dependencies: DependencyRepository;
47
- public readonly meta: MetaRepository;
48
- public readonly environment: EnvironmentRepository;
49
-
50
- constructor(private db: Database) {
51
- this.domains = new DomainRepository(db);
52
- this.files = new FileRepository(db);
53
- this.symbols = new SymbolRepository(db);
54
- this.dependencies = new DependencyRepository(db);
55
- this.meta = new MetaRepository(db);
56
- this.environment = new EnvironmentRepository(db);
57
- }
58
-
59
- public runInTransaction<T>(fn: () => T): T {
60
- return this.db.transaction(fn)();
61
- }
62
-
63
- // --- Domain Methods ---
64
- public upsertDomain(name: string, config: DomainConfig): number {
65
- return this.domains.upsertDomain(name, config);
66
- }
67
-
68
- public getDomainByName(name: string): DomainRecord | null {
69
- return this.domains.getDomainByName(name);
70
- }
71
-
72
- public getAllDomains(): DomainRecord[] {
73
- return this.domains.getAllDomains();
74
- }
75
-
76
- // --- File Methods ---
77
- public getFileByPath(path: string): FileRecord | null {
78
- return this.files.getFileByPath(path);
79
- }
80
-
81
- public countFiles(): number {
82
- return this.files.countFiles();
83
- }
84
-
85
- public getFilesByDomain(domainId: number): FileRecord[] {
86
- return this.files.getFilesByDomain(domainId);
87
- }
88
-
89
- public upsertFile(
90
- domainId: number,
91
- path: string,
92
- archetype: ArchetypeKind,
93
- contentHash: string,
94
- lineCount: number,
95
- mtimeMs: number = 0,
96
- sizeBytes: number = 0
97
- ): number {
98
- return this.files.upsertFile(
99
- domainId,
100
- path,
101
- archetype,
102
- contentHash,
103
- lineCount,
104
- mtimeMs,
105
- sizeBytes
106
- );
107
- }
108
-
109
- public updateFileMetadataOnly(id: number, mtimeMs: number, sizeBytes: number): void {
110
- this.files.updateFileMetadataOnly(id, mtimeMs, sizeBytes);
111
- }
112
-
113
- public deleteFilesNotInPaths(domainId: number, validPaths: string[]): number {
114
- return this.files.deleteFilesNotInPaths(domainId, validPaths);
115
- }
116
-
117
- public deleteFile(path: string): void {
118
- this.files.deleteFile(path);
119
- }
120
-
121
- public getDomainCatalog(
122
- domainName: string,
123
- archetypeFilter?: string
124
- ): DomainCatalogResponse | null {
125
- return this.domains.getDomainCatalog(domainName, archetypeFilter);
126
- }
127
-
128
- // --- Symbol Methods ---
129
- public replaceFileSymbols(fileId: number, symbols: ExtractedSymbol[]): void {
130
- this.symbols.replaceFileSymbols(fileId, symbols);
131
- }
132
-
133
- public getSymbolsByFileId(fileId: number): SymbolRecord[] {
134
- return this.symbols.getSymbolsByFileId(fileId);
135
- }
136
-
137
- public findSymbolsByName(name: string): Array<SymbolRecord & { file_path: string }> {
138
- return this.symbols.findSymbolsByName(name);
139
- }
140
-
141
- public findContainers(
142
- containerName: string
143
- ): Array<{ file: FileRecord; symbol?: SymbolRecord }> {
144
- return this.symbols.findContainers(containerName);
145
- }
146
-
147
- public getAllSymbolsWithFiles(): Array<SymbolRecord & { file_path: string }> {
148
- return this.symbols.getAllSymbolsWithFiles();
149
- }
150
-
151
- // --- Dependency & Slice Methods ---
152
- public replaceFileDependencies(fileId: number, deps: ExtractedDependency[]): void {
153
- this.dependencies.replaceFileDependencies(fileId, deps);
154
- }
155
-
156
- public upsertVerticalSlice(
157
- slice: Omit<VerticalSliceRecord, "id" | "created_at">
158
- ): void {
159
- this.dependencies.upsertVerticalSlice(slice);
160
- }
161
-
162
- public findVerticalSlices(searchTerm: string): VerticalSliceRecord[] {
163
- return this.dependencies.findVerticalSlices(searchTerm);
164
- }
165
-
166
- public getAllVerticalSlices(): VerticalSliceRecord[] {
167
- return this.dependencies.getAllVerticalSlices();
168
- }
169
-
170
- public clearVerticalSlices(domainId?: number): void {
171
- this.dependencies.clearVerticalSlices(domainId);
172
- }
173
-
174
- public getAllDependenciesWithDomains(): Array<{
175
- source_file: string;
176
- source_domain: string;
177
- line_number: number;
178
- target: string;
179
- statement: string;
180
- is_external: boolean;
181
- }> {
182
- return this.dependencies.getAllDependenciesWithDomains();
183
- }
184
-
185
- public findSymbolWithDomain(
186
- symbolName: string
187
- ): {
188
- symbol_name: string;
189
- kind: string;
190
- file_path: string;
191
- domain_name: string;
192
- } | null {
193
- return this.symbols.findSymbolWithDomain(symbolName);
194
- }
195
-
196
- public findSymbolWithMembers(symbolName: string): {
197
- symbol_name: string;
198
- kind: string;
199
- signature: string;
200
- file_path: string;
201
- domain_name: string;
202
- methods: string[];
203
- properties: string[];
204
- } | null {
205
- return this.symbols.findSymbolWithMembers(symbolName);
206
- }
207
-
208
- public getFileWithDomain(filePath: string): {
209
- file_id: number;
210
- file_path: string;
211
- domain_name: string;
212
- } | null {
213
- return this.symbols.getFileWithDomain(filePath);
214
- }
215
-
216
- public getHotspotSymbols(options: {
217
- minLines?: number;
218
- minNesting?: number;
219
- kind?: SymbolKind;
220
- domain?: string;
221
- limit?: number;
222
- sortBy?: "lines" | "nesting" | "risk_score";
223
- } = {}): Array<SymbolRecord & { file_path: string; domain_name: string; risk_score: number }> {
224
- return this.symbols.getHotspotSymbols(options);
225
- }
226
-
227
- public getSymbolDetails(
228
- symbolQuery: string,
229
- options: { domain?: string; includeDependencies?: boolean } = {}
230
- ): GetSymbolDetailsResponse | null {
231
- return this.symbols.getSymbolDetails(symbolQuery, options);
232
- }
233
-
234
- public getSymbolImpact(symbolName: string): GetSymbolImpactResponse {
235
- return this.dependencies.getSymbolImpact(symbolName);
236
- }
237
-
238
- public getFileInboundImpact(filePath: string): {
239
- direct_dependents_count: number;
240
- top_consumers: string[];
241
- symbols_count: number;
242
- risk_level: "low" | "medium" | "high";
243
- } {
244
- return this.dependencies.getFileInboundImpact(filePath);
245
- }
246
-
247
- // --- Metadata Methods ---
248
- public getMeta(key: string): string | null {
249
- return this.meta.getMeta(key);
250
- }
251
-
252
- public setMeta(key: string, value: string): void {
253
- this.meta.setMeta(key, value);
254
- }
255
-
256
- public getAllMeta(): Record<string, string> {
257
- return this.meta.getAllMeta();
258
- }
259
- }
260
-
1
+ import type { Database } from "bun:sqlite";
2
+ import type {
3
+ ArchetypeKind,
4
+ DomainCatalogResponse,
5
+ DomainConfig,
6
+ DomainRecord,
7
+ ExtractedDependency,
8
+ ExtractedSymbol,
9
+ FileRecord,
10
+ GetSymbolDetailsResponse,
11
+ GetSymbolImpactResponse,
12
+ InboundCaller,
13
+ SymbolKind,
14
+ SymbolRecord,
15
+ VerticalSliceRecord,
16
+ } from "../../types/index.ts";
17
+
18
+ export type {
19
+ ArchetypeKind,
20
+ DomainCatalogResponse,
21
+ DomainConfig,
22
+ DomainRecord,
23
+ ExtractedDependency,
24
+ ExtractedSymbol,
25
+ FileRecord,
26
+ GetSymbolDetailsResponse,
27
+ GetSymbolImpactResponse,
28
+ InboundCaller,
29
+ SymbolKind,
30
+ SymbolRecord,
31
+ VerticalSliceRecord,
32
+ } from "../../types/index.ts";
33
+ import { DependencyRepository } from "./repositories/dependency.repository.ts";
34
+ import { DomainRepository } from "./repositories/domain.repository.ts";
35
+ import { EnvironmentRepository } from "./repositories/environment.repository.ts";
36
+ import { FileRepository } from "./repositories/file.repository.ts";
37
+ import { MetaRepository } from "./repositories/meta.repository.ts";
38
+ import { SymbolRepository } from "./repositories/symbol.repository.ts";
39
+
40
+ export type DatabaseRepository = SeptumRepository;
41
+
42
+ export class SeptumRepository {
43
+ public readonly domains: DomainRepository;
44
+ public readonly files: FileRepository;
45
+ public readonly symbols: SymbolRepository;
46
+ public readonly dependencies: DependencyRepository;
47
+ public readonly meta: MetaRepository;
48
+ public readonly environment: EnvironmentRepository;
49
+
50
+ constructor(private db: Database) {
51
+ this.domains = new DomainRepository(db);
52
+ this.files = new FileRepository(db);
53
+ this.symbols = new SymbolRepository(db);
54
+ this.dependencies = new DependencyRepository(db);
55
+ this.meta = new MetaRepository(db);
56
+ this.environment = new EnvironmentRepository(db);
57
+ }
58
+
59
+ public runInTransaction<T>(fn: () => T): T {
60
+ return this.db.transaction(fn)();
61
+ }
62
+
63
+ // --- Domain Methods ---
64
+ public upsertDomain(name: string, config: DomainConfig): number {
65
+ return this.domains.upsertDomain(name, config);
66
+ }
67
+
68
+ public getDomainByName(name: string): DomainRecord | null {
69
+ return this.domains.getDomainByName(name);
70
+ }
71
+
72
+ public getAllDomains(): DomainRecord[] {
73
+ return this.domains.getAllDomains();
74
+ }
75
+
76
+ // --- File Methods ---
77
+ public getFileByPath(path: string): FileRecord | null {
78
+ return this.files.getFileByPath(path);
79
+ }
80
+
81
+ public countFiles(): number {
82
+ return this.files.countFiles();
83
+ }
84
+
85
+ public getFilesByDomain(domainId: number): FileRecord[] {
86
+ return this.files.getFilesByDomain(domainId);
87
+ }
88
+
89
+ public getAllFiles(): FileRecord[] {
90
+ return this.files.getAllFiles();
91
+ }
92
+
93
+ public upsertFile(
94
+ domainId: number,
95
+ path: string,
96
+ archetype: ArchetypeKind,
97
+ contentHash: string,
98
+ lineCount: number,
99
+ mtimeMs: number = 0,
100
+ sizeBytes: number = 0
101
+ ): number {
102
+ return this.files.upsertFile(
103
+ domainId,
104
+ path,
105
+ archetype,
106
+ contentHash,
107
+ lineCount,
108
+ mtimeMs,
109
+ sizeBytes
110
+ );
111
+ }
112
+
113
+ public updateFileMetadataOnly(id: number, mtimeMs: number, sizeBytes: number): void {
114
+ this.files.updateFileMetadataOnly(id, mtimeMs, sizeBytes);
115
+ }
116
+
117
+ public deleteFilesNotInPaths(domainId: number, validPaths: string[]): number {
118
+ return this.files.deleteFilesNotInPaths(domainId, validPaths);
119
+ }
120
+
121
+ public deleteFile(path: string): void {
122
+ this.files.deleteFile(path);
123
+ }
124
+
125
+ public deleteFileByPath(path: string): void {
126
+ this.files.deleteFileByPath(path);
127
+ }
128
+
129
+ public getDomainCatalog(
130
+ domainName: string,
131
+ archetypeFilter?: string,
132
+ options?: { detailLevel?: "compact" | "full"; fileFilter?: string }
133
+ ): DomainCatalogResponse | null {
134
+ return this.domains.getDomainCatalog(domainName, archetypeFilter, options);
135
+ }
136
+
137
+ // --- Symbol Methods ---
138
+ public replaceFileSymbols(fileId: number, symbols: ExtractedSymbol[]): void {
139
+ this.symbols.replaceFileSymbols(fileId, symbols);
140
+ }
141
+
142
+ public getSymbolsByFileId(fileId: number): SymbolRecord[] {
143
+ return this.symbols.getSymbolsByFileId(fileId);
144
+ }
145
+
146
+ public findSymbolsByName(name: string): Array<SymbolRecord & { file_path: string }> {
147
+ return this.symbols.findSymbolsByName(name);
148
+ }
149
+
150
+ public findContainers(
151
+ containerName: string
152
+ ): Array<{ file: FileRecord; symbol?: SymbolRecord }> {
153
+ return this.symbols.findContainers(containerName);
154
+ }
155
+
156
+ public getAllSymbolsWithFiles(): Array<SymbolRecord & { file_path: string }> {
157
+ return this.symbols.getAllSymbolsWithFiles();
158
+ }
159
+
160
+ // --- Dependency & Slice Methods ---
161
+ public replaceFileDependencies(fileId: number, deps: ExtractedDependency[]): void {
162
+ this.dependencies.replaceFileDependencies(fileId, deps);
163
+ }
164
+
165
+ public upsertVerticalSlice(
166
+ slice: Omit<VerticalSliceRecord, "id" | "created_at">
167
+ ): void {
168
+ this.dependencies.upsertVerticalSlice(slice);
169
+ }
170
+
171
+ public findVerticalSlices(searchTerm: string): VerticalSliceRecord[] {
172
+ return this.dependencies.findVerticalSlices(searchTerm);
173
+ }
174
+
175
+ public getAllVerticalSlices(): VerticalSliceRecord[] {
176
+ return this.dependencies.getAllVerticalSlices();
177
+ }
178
+
179
+ public countVerticalSlices(): number {
180
+ return this.dependencies.countVerticalSlices();
181
+ }
182
+
183
+ public clearVerticalSlices(domainId?: number): void {
184
+ this.dependencies.clearVerticalSlices(domainId);
185
+ }
186
+
187
+ public getDomainFileConnections(domainId?: number) {
188
+ return this.dependencies.getDomainFileConnections(domainId);
189
+ }
190
+
191
+ public getFileConnections(filePath: string) {
192
+ return this.dependencies.getFileConnections(filePath);
193
+ }
194
+
195
+ public getAllDependenciesWithDomains(): Array<{
196
+ source_file: string;
197
+ source_domain: string;
198
+ line_number: number;
199
+ target: string;
200
+ statement: string;
201
+ is_external: boolean;
202
+ }> {
203
+ return this.dependencies.getAllDependenciesWithDomains();
204
+ }
205
+
206
+ public findSymbolWithDomain(
207
+ symbolName: string
208
+ ): {
209
+ symbol_name: string;
210
+ kind: string;
211
+ file_path: string;
212
+ domain_name: string;
213
+ } | null {
214
+ return this.symbols.findSymbolWithDomain(symbolName);
215
+ }
216
+
217
+ public findSymbolWithMembers(symbolName: string): {
218
+ symbol_name: string;
219
+ kind: string;
220
+ signature: string;
221
+ file_path: string;
222
+ domain_name: string;
223
+ methods: string[];
224
+ properties: string[];
225
+ } | null {
226
+ return this.symbols.findSymbolWithMembers(symbolName);
227
+ }
228
+
229
+ public getFileWithDomain(filePath: string): {
230
+ file_id: number;
231
+ file_path: string;
232
+ domain_name: string;
233
+ } | null {
234
+ return this.symbols.getFileWithDomain(filePath);
235
+ }
236
+
237
+ public getHotspotSymbols(options: {
238
+ minLines?: number;
239
+ minNesting?: number;
240
+ kind?: SymbolKind;
241
+ domain?: string;
242
+ limit?: number;
243
+ sortBy?: "lines" | "nesting" | "risk_score";
244
+ } = {}): Array<SymbolRecord & { file_path: string; domain_name: string; risk_score: number }> {
245
+ return this.symbols.getHotspotSymbols(options);
246
+ }
247
+
248
+ public getSymbolDetails(
249
+ symbolQuery: string,
250
+ options: { domain?: string; includeDependencies?: boolean } = {}
251
+ ): GetSymbolDetailsResponse | null {
252
+ return this.symbols.getSymbolDetails(symbolQuery, options);
253
+ }
254
+
255
+ public getSymbolImpact(symbolName: string): GetSymbolImpactResponse {
256
+ return this.dependencies.getSymbolImpact(symbolName);
257
+ }
258
+
259
+ public getFileInboundImpact(filePath: string): {
260
+ direct_dependents_count: number;
261
+ top_consumers: string[];
262
+ symbols_count: number;
263
+ risk_level: "low" | "medium" | "high";
264
+ } {
265
+ return this.dependencies.getFileInboundImpact(filePath);
266
+ }
267
+
268
+ // --- Metadata Methods ---
269
+ public getMeta(key: string): string | null {
270
+ return this.meta.getMeta(key);
271
+ }
272
+
273
+ public setMeta(key: string, value: string): void {
274
+ this.meta.setMeta(key, value);
275
+ }
276
+
277
+ public getAllMeta(): Record<string, string> {
278
+ return this.meta.getAllMeta();
279
+ }
280
+ }
281
+