septum 0.1.3 → 0.1.5
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 -21
- package/README.md +105 -102
- package/bin/septum.ts +4 -4
- package/package.json +63 -63
- package/src/cli/commands/check.ts +161 -161
- package/src/cli/commands/hook.ts +188 -188
- package/src/cli/commands/ingest.ts +29 -29
- package/src/cli/commands/init.ts +211 -211
- package/src/cli/commands/locate.ts +61 -61
- package/src/cli/commands/query.ts +64 -64
- package/src/cli/commands/serve.ts +5 -5
- package/src/cli/commands/slice.ts +48 -90
- package/src/cli/commands/sync.ts +31 -31
- package/src/cli/commands/topology.ts +119 -0
- package/src/cli/index.ts +210 -199
- package/src/cli/templates/hooks.ts +75 -75
- package/src/cli/templates/rules.ts +38 -38
- package/src/cli/templates/skill.ts +69 -69
- package/src/core/boundary/evaluator.ts +232 -210
- package/src/core/config/loader.ts +97 -97
- package/src/core/config/schema.ts +39 -39
- package/src/core/database/client.ts +44 -44
- package/src/core/database/repositories/dependency.repository.ts +366 -349
- package/src/core/database/repositories/domain.repository.ts +218 -198
- package/src/core/database/repositories/environment.repository.ts +207 -0
- package/src/core/database/repositories/file.repository.ts +116 -106
- package/src/core/database/repositories/meta.repository.ts +33 -33
- package/src/core/database/repositories/symbol.repository.ts +443 -424
- package/src/core/database/repository.ts +264 -255
- package/src/core/database/schema.ts +34 -1
- package/src/core/discovery/topology-detector.ts +486 -486
- package/src/core/ingestion/hasher.ts +5 -5
- package/src/core/ingestion/pipeline.ts +584 -535
- package/src/core/parser/behavioral-analyzer.ts +119 -0
- package/src/core/parser/boundary-tracker.ts +288 -128
- package/src/core/parser/extractors/base.ts +62 -61
- package/src/core/parser/extractors/frontend.ts +194 -194
- package/src/core/parser/extractors/go.ts +229 -176
- package/src/core/parser/extractors/laravel-semantic.ts +1039 -585
- package/src/core/parser/extractors/mcp-cli-semantic.ts +199 -199
- package/src/core/parser/extractors/nestjs-semantic.ts +119 -119
- package/src/core/parser/extractors/php.ts +153 -149
- package/src/core/parser/extractors/python.ts +228 -226
- package/src/core/parser/extractors/registry.ts +70 -70
- package/src/core/parser/extractors/semantic-extractor.interface.ts +21 -21
- package/src/core/parser/extractors/typescript.ts +181 -177
- package/src/core/parser/schema/providers/laravel-migration-provider.ts +215 -0
- package/src/core/parser/schema/providers/prisma-schema-provider.ts +89 -0
- package/src/core/parser/schema/schema-provider-registry.ts +43 -0
- package/src/core/parser/schema/schema-provider.interface.ts +33 -0
- package/src/core/parser/tree-sitter.ts +41 -41
- package/src/core/resolver/call-graph-tracer.ts +666 -668
- package/src/core/resolver/module-resolver.ts +408 -342
- package/src/core/resolver/symbol-locator.ts +543 -543
- package/src/core/resolver/vertical-slice-tracer.ts +301 -252
- package/src/core/session/session-manager.ts +56 -56
- package/src/core/telemetry/telemetry.ts +86 -86
- package/src/core/topology/environment-detector.ts +860 -0
- package/src/core/topology/types.ts +83 -0
- package/src/index.ts +21 -18
- package/src/mcp/schemas.ts +578 -238
- package/src/mcp/server.ts +875 -656
- package/src/mcp/tools/check-boundary.ts +171 -152
- package/src/mcp/tools/get-domain-catalog.ts +145 -121
- package/src/mcp/tools/get-environment-topology.ts +141 -0
- package/src/mcp/tools/get-feature-context.ts +212 -116
- package/src/mcp/tools/get-symbol-hotspots.ts +60 -49
- package/src/mcp/tools/get-symbol-impact.ts +28 -26
- package/src/mcp/tools/get-symbol.ts +65 -63
- package/src/mcp/tools/locate-symbol.ts +171 -190
- package/src/mcp/tools/register-domain.ts +68 -64
- package/src/mcp/tools/register-feature.ts +100 -0
- package/src/mcp/tools/trace-vertical-slice.ts +74 -103
- package/src/types/index.ts +335 -299
package/src/mcp/schemas.ts
CHANGED
|
@@ -1,238 +1,578 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
function withAliases(raw: unknown, aliases: Record<string, string>): unknown {
|
|
4
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
5
|
-
const obj = { ...(raw as Record<string, unknown>) };
|
|
6
|
-
for (const [alias, target] of Object.entries(aliases)) {
|
|
7
|
-
if (obj[alias] !== undefined && obj[target] === undefined) {
|
|
8
|
-
obj[target] = obj[alias];
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
return obj;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
})
|
|
172
|
-
);
|
|
173
|
-
export type
|
|
174
|
-
|
|
175
|
-
export const
|
|
176
|
-
|
|
177
|
-
z.object({
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
function withAliases(raw: unknown, aliases: Record<string, string>): unknown {
|
|
4
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
5
|
+
const obj = { ...(raw as Record<string, unknown>) };
|
|
6
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
7
|
+
if (obj[alias] !== undefined && obj[target] === undefined) {
|
|
8
|
+
obj[target] = obj[alias];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return obj;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function extractSingleStringFallback(
|
|
15
|
+
raw: unknown,
|
|
16
|
+
targetField: string,
|
|
17
|
+
ignoredKeys: string[] = ["workspace_path", "workspacePath", "workspace", "project_root", "projectRoot"]
|
|
18
|
+
): unknown {
|
|
19
|
+
if (typeof raw === "string") {
|
|
20
|
+
return { [targetField]: raw };
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(raw) && raw.length === 1 && typeof raw[0] === "string") {
|
|
23
|
+
return { [targetField]: raw[0] };
|
|
24
|
+
}
|
|
25
|
+
if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
|
|
26
|
+
const obj = { ...(raw as Record<string, unknown>) };
|
|
27
|
+
if (obj[targetField] !== undefined && typeof obj[targetField] === "string" && (obj[targetField] as string).trim() !== "") {
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
const nonIgnoredEntries = Object.entries(obj).filter(
|
|
31
|
+
([key, val]) => !ignoredKeys.includes(key) && typeof val === "string" && (val as string).trim() !== ""
|
|
32
|
+
);
|
|
33
|
+
if (nonIgnoredEntries.length === 1) {
|
|
34
|
+
obj[targetField] = nonIgnoredEntries[0][1];
|
|
35
|
+
}
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function normalizeFeatureContextArgs(raw: unknown): unknown {
|
|
42
|
+
const coerced = extractSingleStringFallback(raw, "feature_key");
|
|
43
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
44
|
+
const obj = { ...(coerced as Record<string, unknown>) };
|
|
45
|
+
|
|
46
|
+
const aliases: Record<string, string> = {
|
|
47
|
+
feature: "feature_key",
|
|
48
|
+
featureKey: "feature_key",
|
|
49
|
+
feature_name: "feature_key",
|
|
50
|
+
featureName: "feature_key",
|
|
51
|
+
feat: "feature_key",
|
|
52
|
+
name: "feature_key",
|
|
53
|
+
key: "feature_key",
|
|
54
|
+
task: "feature_key",
|
|
55
|
+
task_name: "feature_key",
|
|
56
|
+
target: "feature_key",
|
|
57
|
+
context: "feature_key",
|
|
58
|
+
slug: "feature_key",
|
|
59
|
+
workspace: "workspace_path",
|
|
60
|
+
workspacePath: "workspace_path",
|
|
61
|
+
project_root: "workspace_path",
|
|
62
|
+
projectRoot: "workspace_path",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
66
|
+
if (obj[alias] !== undefined && obj[target] === undefined) {
|
|
67
|
+
obj[target] = obj[alias];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Populate feature as backward-compatible alias
|
|
72
|
+
if (obj.feature_key !== undefined && obj.feature === undefined) {
|
|
73
|
+
obj.feature = obj.feature_key;
|
|
74
|
+
} else if (obj.feature !== undefined && obj.feature_key === undefined) {
|
|
75
|
+
obj.feature_key = obj.feature;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return obj;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizeBoundaryArgs(raw: unknown): unknown {
|
|
82
|
+
if (Array.isArray(raw) && raw.length > 1 && raw.every((item) => typeof item === "string")) {
|
|
83
|
+
raw = { file_paths: raw };
|
|
84
|
+
}
|
|
85
|
+
const coerced = extractSingleStringFallback(raw, "file_path");
|
|
86
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
87
|
+
const obj = { ...(coerced as Record<string, unknown>) };
|
|
88
|
+
const aliases: Record<string, string> = {
|
|
89
|
+
filePath: "file_path",
|
|
90
|
+
file: "file_path",
|
|
91
|
+
path: "file_path",
|
|
92
|
+
from_file: "file_path",
|
|
93
|
+
fromFile: "file_path",
|
|
94
|
+
source_file: "file_path",
|
|
95
|
+
sourceFile: "file_path",
|
|
96
|
+
filePaths: "file_paths",
|
|
97
|
+
files: "file_paths",
|
|
98
|
+
paths: "file_paths",
|
|
99
|
+
proposedImports: "proposed_imports",
|
|
100
|
+
imports: "proposed_imports",
|
|
101
|
+
featureKey: "feature_key",
|
|
102
|
+
feature: "feature_key",
|
|
103
|
+
feature_name: "feature_key",
|
|
104
|
+
featureName: "feature_key",
|
|
105
|
+
name: "feature_key",
|
|
106
|
+
key: "feature_key",
|
|
107
|
+
};
|
|
108
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
109
|
+
if (obj[alias] !== undefined && obj[target] === undefined) {
|
|
110
|
+
obj[target] = obj[alias];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (obj.feature_key !== undefined && obj.feature === undefined) {
|
|
115
|
+
obj.feature = obj.feature_key;
|
|
116
|
+
} else if (obj.feature !== undefined && obj.feature_key === undefined) {
|
|
117
|
+
obj.feature_key = obj.feature;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (obj.to_file || obj.toFile) {
|
|
121
|
+
const rawTo = obj.to_file ?? obj.toFile;
|
|
122
|
+
const toFiles = Array.isArray(rawTo) ? rawTo.map(String) : [String(rawTo)];
|
|
123
|
+
if (!obj.proposed_imports) {
|
|
124
|
+
obj.proposed_imports = toFiles;
|
|
125
|
+
} else if (Array.isArray(obj.proposed_imports)) {
|
|
126
|
+
obj.proposed_imports = [...obj.proposed_imports, ...toFiles];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (Array.isArray(obj.file_path) && !obj.file_paths) {
|
|
130
|
+
obj.file_paths = obj.file_path;
|
|
131
|
+
delete obj.file_path;
|
|
132
|
+
}
|
|
133
|
+
if (typeof obj.file_paths === "string" && !obj.file_path) {
|
|
134
|
+
obj.file_path = obj.file_paths;
|
|
135
|
+
delete obj.file_paths;
|
|
136
|
+
}
|
|
137
|
+
return obj;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function normalizeDomainCatalogArgs(raw: unknown): unknown {
|
|
141
|
+
const coerced = extractSingleStringFallback(raw, "domain");
|
|
142
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
143
|
+
const obj = withAliases(coerced, {
|
|
144
|
+
domain_name: "domain",
|
|
145
|
+
domainName: "domain",
|
|
146
|
+
name: "domain",
|
|
147
|
+
archetype_filter: "archetype",
|
|
148
|
+
archetypeFilter: "archetype",
|
|
149
|
+
type: "archetype",
|
|
150
|
+
workspace: "workspace_path",
|
|
151
|
+
workspacePath: "workspace_path",
|
|
152
|
+
project_root: "workspace_path",
|
|
153
|
+
target_path: "workspace_path",
|
|
154
|
+
path: "workspace_path",
|
|
155
|
+
}) as Record<string, unknown>;
|
|
156
|
+
if (obj.domain !== undefined && obj.name === undefined) {
|
|
157
|
+
obj.name = obj.domain;
|
|
158
|
+
} else if (obj.name !== undefined && obj.domain === undefined) {
|
|
159
|
+
obj.domain = obj.name;
|
|
160
|
+
}
|
|
161
|
+
return obj;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const GetDomainCatalogSchema = z.preprocess(
|
|
165
|
+
normalizeDomainCatalogArgs,
|
|
166
|
+
z.object({
|
|
167
|
+
domain: z.string().optional(),
|
|
168
|
+
name: z.string().optional(),
|
|
169
|
+
archetype: z.string().optional(),
|
|
170
|
+
workspace_path: z.string().optional(),
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
export type GetDomainCatalogArgs = z.infer<typeof GetDomainCatalogSchema>;
|
|
174
|
+
|
|
175
|
+
export const GetFeatureContextSchema = z.preprocess(
|
|
176
|
+
normalizeFeatureContextArgs,
|
|
177
|
+
z.object({
|
|
178
|
+
feature_key: z.string().optional(),
|
|
179
|
+
feature: z.string().optional(),
|
|
180
|
+
workspace_path: z.string().optional(),
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
export type GetFeatureContextArgs = z.infer<typeof GetFeatureContextSchema>;
|
|
184
|
+
|
|
185
|
+
export function normalizeLocateSymbolArgs(raw: unknown): unknown {
|
|
186
|
+
const coerced = extractSingleStringFallback(raw, "query");
|
|
187
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
188
|
+
const obj = withAliases(coerced, {
|
|
189
|
+
symbol: "query",
|
|
190
|
+
name: "query",
|
|
191
|
+
symbol_name: "query",
|
|
192
|
+
symbolName: "query",
|
|
193
|
+
target: "query",
|
|
194
|
+
domain_name: "domain",
|
|
195
|
+
domainName: "domain",
|
|
196
|
+
max: "limit",
|
|
197
|
+
workspace: "workspace_path",
|
|
198
|
+
workspacePath: "workspace_path",
|
|
199
|
+
project_root: "workspace_path",
|
|
200
|
+
target_path: "workspace_path",
|
|
201
|
+
path: "workspace_path",
|
|
202
|
+
}) as Record<string, unknown>;
|
|
203
|
+
if (obj.query !== undefined && obj.symbol === undefined) {
|
|
204
|
+
obj.symbol = obj.query;
|
|
205
|
+
} else if (obj.symbol !== undefined && obj.query === undefined) {
|
|
206
|
+
obj.query = obj.symbol;
|
|
207
|
+
}
|
|
208
|
+
return obj;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const LocateSymbolSchema = z.preprocess(
|
|
212
|
+
normalizeLocateSymbolArgs,
|
|
213
|
+
z.object({
|
|
214
|
+
query: z.string().min(1, "query is required"),
|
|
215
|
+
symbol: z.string().optional(),
|
|
216
|
+
domain: z.string().optional(),
|
|
217
|
+
limit: z.number().int().positive().optional().default(10),
|
|
218
|
+
workspace_path: z.string().optional(),
|
|
219
|
+
})
|
|
220
|
+
);
|
|
221
|
+
export type LocateSymbolArgs = z.infer<typeof LocateSymbolSchema>;
|
|
222
|
+
|
|
223
|
+
export function normalizeGetSymbolArgs(raw: unknown): unknown {
|
|
224
|
+
const coerced = extractSingleStringFallback(raw, "symbol");
|
|
225
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
226
|
+
const obj = withAliases(coerced, {
|
|
227
|
+
query: "symbol",
|
|
228
|
+
name: "symbol",
|
|
229
|
+
symbol_name: "symbol",
|
|
230
|
+
symbolName: "symbol",
|
|
231
|
+
target: "symbol",
|
|
232
|
+
domain_name: "domain",
|
|
233
|
+
domainName: "domain",
|
|
234
|
+
includeDependencies: "include_dependencies",
|
|
235
|
+
include_deps: "include_dependencies",
|
|
236
|
+
includeDeps: "include_dependencies",
|
|
237
|
+
dependencies: "include_dependencies",
|
|
238
|
+
deps: "include_dependencies",
|
|
239
|
+
}) as Record<string, unknown>;
|
|
240
|
+
if (obj.symbol !== undefined && obj.query === undefined) {
|
|
241
|
+
obj.query = obj.symbol;
|
|
242
|
+
} else if (obj.query !== undefined && obj.symbol === undefined) {
|
|
243
|
+
obj.symbol = obj.query;
|
|
244
|
+
}
|
|
245
|
+
return obj;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export const GetSymbolSchema = z.preprocess(
|
|
249
|
+
normalizeGetSymbolArgs,
|
|
250
|
+
z.object({
|
|
251
|
+
symbol: z.string().min(1, "symbol is required"),
|
|
252
|
+
query: z.string().optional(),
|
|
253
|
+
domain: z.string().optional(),
|
|
254
|
+
include_dependencies: z.boolean().optional().default(true),
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
export type GetSymbolArgs = z.infer<typeof GetSymbolSchema>;
|
|
258
|
+
|
|
259
|
+
export function normalizeGetSymbolImpactArgs(raw: unknown): unknown {
|
|
260
|
+
const coerced = extractSingleStringFallback(raw, "symbol");
|
|
261
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
262
|
+
const obj = withAliases(coerced, {
|
|
263
|
+
query: "symbol",
|
|
264
|
+
name: "symbol",
|
|
265
|
+
symbol_name: "symbol",
|
|
266
|
+
symbolName: "symbol",
|
|
267
|
+
file_path: "symbol",
|
|
268
|
+
filePath: "symbol",
|
|
269
|
+
file: "symbol",
|
|
270
|
+
path: "symbol",
|
|
271
|
+
target: "symbol",
|
|
272
|
+
}) as Record<string, unknown>;
|
|
273
|
+
if (obj.symbol !== undefined && obj.query === undefined) {
|
|
274
|
+
obj.query = obj.symbol;
|
|
275
|
+
} else if (obj.query !== undefined && obj.symbol === undefined) {
|
|
276
|
+
obj.symbol = obj.query;
|
|
277
|
+
}
|
|
278
|
+
return obj;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const GetSymbolImpactSchema = z.preprocess(
|
|
282
|
+
normalizeGetSymbolImpactArgs,
|
|
283
|
+
z.object({
|
|
284
|
+
symbol: z.string().min(1, "symbol is required"),
|
|
285
|
+
query: z.string().optional(),
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
export type GetSymbolImpactArgs = z.infer<typeof GetSymbolImpactSchema>;
|
|
289
|
+
|
|
290
|
+
export function normalizeTraceVerticalSliceArgs(raw: unknown): unknown {
|
|
291
|
+
const coerced = extractSingleStringFallback(raw, "query");
|
|
292
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
293
|
+
const obj = withAliases(coerced, {
|
|
294
|
+
route: "query",
|
|
295
|
+
uri: "query",
|
|
296
|
+
route_uri: "query",
|
|
297
|
+
routeUri: "query",
|
|
298
|
+
entry_file: "query",
|
|
299
|
+
entryFile: "query",
|
|
300
|
+
file_path: "query",
|
|
301
|
+
filePath: "query",
|
|
302
|
+
file: "query",
|
|
303
|
+
path: "query",
|
|
304
|
+
symbol: "query",
|
|
305
|
+
name: "query",
|
|
306
|
+
feature: "query",
|
|
307
|
+
feature_key: "query",
|
|
308
|
+
featureKey: "query",
|
|
309
|
+
maxDepth: "max_depth",
|
|
310
|
+
depth: "max_depth",
|
|
311
|
+
}) as Record<string, unknown>;
|
|
312
|
+
if (obj.query !== undefined && obj.symbol === undefined) {
|
|
313
|
+
obj.symbol = obj.query;
|
|
314
|
+
} else if (obj.symbol !== undefined && obj.query === undefined) {
|
|
315
|
+
obj.query = obj.symbol;
|
|
316
|
+
}
|
|
317
|
+
return obj;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export const TraceVerticalSliceSchema = z.preprocess(
|
|
321
|
+
normalizeTraceVerticalSliceArgs,
|
|
322
|
+
z.object({
|
|
323
|
+
query: z.string().min(1, "query is required"),
|
|
324
|
+
symbol: z.string().optional(),
|
|
325
|
+
max_depth: z.number().int().positive().optional().default(5),
|
|
326
|
+
})
|
|
327
|
+
);
|
|
328
|
+
export type TraceVerticalSliceArgs = z.infer<typeof TraceVerticalSliceSchema>;
|
|
329
|
+
|
|
330
|
+
export const CheckBoundarySchema = z.preprocess(
|
|
331
|
+
normalizeBoundaryArgs,
|
|
332
|
+
z.object({
|
|
333
|
+
file_path: z.string().optional(),
|
|
334
|
+
file_paths: z.array(z.string()).optional(),
|
|
335
|
+
proposed_imports: z.array(z.string()).default([]),
|
|
336
|
+
feature_key: z.string().optional(),
|
|
337
|
+
})
|
|
338
|
+
);
|
|
339
|
+
export type CheckBoundaryArgs = z.infer<typeof CheckBoundarySchema>;
|
|
340
|
+
|
|
341
|
+
export const GetSymbolHotspotsSchema = z.preprocess(
|
|
342
|
+
(args) =>
|
|
343
|
+
withAliases(args, {
|
|
344
|
+
domain_name: "domain",
|
|
345
|
+
domainName: "domain",
|
|
346
|
+
max: "limit",
|
|
347
|
+
nesting: "min_nesting",
|
|
348
|
+
minNesting: "min_nesting",
|
|
349
|
+
lines: "min_lines",
|
|
350
|
+
minLines: "min_lines",
|
|
351
|
+
sortBy: "sort_by",
|
|
352
|
+
}),
|
|
353
|
+
z.object({
|
|
354
|
+
min_lines: z.number().int().nonnegative().optional(),
|
|
355
|
+
min_nesting: z.number().int().positive().optional(),
|
|
356
|
+
kind: z.string().optional(),
|
|
357
|
+
domain: z.string().optional(),
|
|
358
|
+
limit: z.number().int().positive().optional().default(10),
|
|
359
|
+
sort_by: z.enum(["lines", "nesting", "risk_score"]).optional(),
|
|
360
|
+
})
|
|
361
|
+
);
|
|
362
|
+
export type GetSymbolHotspotsArgs = z.infer<typeof GetSymbolHotspotsSchema>;
|
|
363
|
+
|
|
364
|
+
export function normalizeRegisterDomainArgs(raw: unknown): unknown {
|
|
365
|
+
const coerced = extractSingleStringFallback(raw, "domain", [
|
|
366
|
+
"root",
|
|
367
|
+
"root_path",
|
|
368
|
+
"rootPath",
|
|
369
|
+
"path",
|
|
370
|
+
"root_dir",
|
|
371
|
+
"workspace_path",
|
|
372
|
+
"workspacePath",
|
|
373
|
+
"workspace",
|
|
374
|
+
"project_root",
|
|
375
|
+
"projectRoot",
|
|
376
|
+
]);
|
|
377
|
+
if (typeof coerced !== "object" || coerced === null || Array.isArray(coerced)) return coerced;
|
|
378
|
+
const obj = withAliases(coerced, {
|
|
379
|
+
name: "domain",
|
|
380
|
+
domain_name: "domain",
|
|
381
|
+
domainName: "domain",
|
|
382
|
+
root_path: "root",
|
|
383
|
+
rootPath: "root",
|
|
384
|
+
path: "root",
|
|
385
|
+
allowedDependencies: "allowed_dependencies",
|
|
386
|
+
allowed: "allowed_dependencies",
|
|
387
|
+
forbiddenDependencies: "forbidden_dependencies",
|
|
388
|
+
forbidden: "forbidden_dependencies",
|
|
389
|
+
archetype: "archetypes",
|
|
390
|
+
ingestNow: "ingest_now",
|
|
391
|
+
}) as Record<string, unknown>;
|
|
392
|
+
if (obj.domain !== undefined && obj.name === undefined) {
|
|
393
|
+
obj.name = obj.domain;
|
|
394
|
+
} else if (obj.name !== undefined && obj.domain === undefined) {
|
|
395
|
+
obj.domain = obj.name;
|
|
396
|
+
}
|
|
397
|
+
return obj;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export const RegisterDomainSchema = z.preprocess(
|
|
401
|
+
normalizeRegisterDomainArgs,
|
|
402
|
+
z.object({
|
|
403
|
+
domain: z.string().min(1, "Domain name/identifier is required"),
|
|
404
|
+
name: z.string().optional(),
|
|
405
|
+
root: z.string().min(1, "Domain root path is required"),
|
|
406
|
+
description: z.string().optional(),
|
|
407
|
+
allowed_dependencies: z.array(z.string()).optional(),
|
|
408
|
+
forbidden_dependencies: z.array(z.string()).optional(),
|
|
409
|
+
archetypes: z.record(z.string()).optional(),
|
|
410
|
+
ingest_now: z.boolean().optional().default(false),
|
|
411
|
+
})
|
|
412
|
+
);
|
|
413
|
+
export type RegisterDomainArgs = z.infer<typeof RegisterDomainSchema>;
|
|
414
|
+
|
|
415
|
+
export function normalizeRegisterFeatureArgs(raw: unknown): unknown {
|
|
416
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
417
|
+
const obj = { ...(raw as Record<string, unknown>) };
|
|
418
|
+
|
|
419
|
+
const aliases: Record<string, string> = {
|
|
420
|
+
feature: "feature_key",
|
|
421
|
+
featureKey: "feature_key",
|
|
422
|
+
feature_name: "feature_key",
|
|
423
|
+
featureName: "feature_key",
|
|
424
|
+
feat: "feature_key",
|
|
425
|
+
name: "feature_key",
|
|
426
|
+
key: "feature_key",
|
|
427
|
+
domain_name: "domain",
|
|
428
|
+
domainName: "domain",
|
|
429
|
+
touchpoints: "allowed_touchpoints",
|
|
430
|
+
allowedTouchpoints: "allowed_touchpoints",
|
|
431
|
+
touchpoint: "allowed_touchpoints",
|
|
432
|
+
files: "allowed_touchpoints",
|
|
433
|
+
allowed_files: "allowed_touchpoints",
|
|
434
|
+
reuseSymbols: "reuse_symbols",
|
|
435
|
+
reuse: "reuse_symbols",
|
|
436
|
+
symbols: "reuse_symbols",
|
|
437
|
+
inputContract: "input_contract",
|
|
438
|
+
outputContract: "output_contract",
|
|
439
|
+
persistToConfig: "persist_to_config",
|
|
440
|
+
persist: "persist_to_config",
|
|
441
|
+
workspace: "workspace_path",
|
|
442
|
+
workspacePath: "workspace_path",
|
|
443
|
+
project_root: "workspace_path",
|
|
444
|
+
projectRoot: "workspace_path",
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
448
|
+
if (obj[alias] !== undefined && obj[target] === undefined) {
|
|
449
|
+
obj[target] = obj[alias];
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Symmetrical contract: feature_key <-> feature
|
|
454
|
+
if (obj.feature_key !== undefined && obj.feature === undefined) {
|
|
455
|
+
obj.feature = obj.feature_key;
|
|
456
|
+
} else if (obj.feature !== undefined && obj.feature_key === undefined) {
|
|
457
|
+
obj.feature_key = obj.feature;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Symmetrical contract: domain <-> domain_name
|
|
461
|
+
if (obj.domain !== undefined && obj.domain_name === undefined) {
|
|
462
|
+
obj.domain_name = obj.domain;
|
|
463
|
+
} else if (obj.domain_name !== undefined && obj.domain === undefined) {
|
|
464
|
+
obj.domain = obj.domain_name;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Array coercion for allowed_touchpoints
|
|
468
|
+
if (typeof obj.allowed_touchpoints === "string") {
|
|
469
|
+
obj.allowed_touchpoints = [obj.allowed_touchpoints];
|
|
470
|
+
} else if (!Array.isArray(obj.allowed_touchpoints) && obj.allowed_touchpoints !== undefined) {
|
|
471
|
+
obj.allowed_touchpoints = [];
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Array coercion for reuse_symbols
|
|
475
|
+
if (typeof obj.reuse_symbols === "string") {
|
|
476
|
+
obj.reuse_symbols = [obj.reuse_symbols];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return obj;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export const RegisterFeatureSchema = z.preprocess(
|
|
483
|
+
normalizeRegisterFeatureArgs,
|
|
484
|
+
z.object({
|
|
485
|
+
feature_key: z.string().min(1, "Feature key is required"),
|
|
486
|
+
feature: z.string().optional(),
|
|
487
|
+
domain: z.string().min(1, "Domain name is required"),
|
|
488
|
+
domain_name: z.string().optional(),
|
|
489
|
+
description: z.string().optional(),
|
|
490
|
+
allowed_touchpoints: z.array(z.string()).default([]),
|
|
491
|
+
reuse_symbols: z.array(z.string()).optional(),
|
|
492
|
+
input_contract: z.record(z.unknown()).optional(),
|
|
493
|
+
output_contract: z.record(z.unknown()).optional(),
|
|
494
|
+
persist_to_config: z.boolean().optional().default(false),
|
|
495
|
+
workspace_path: z.string().optional(),
|
|
496
|
+
})
|
|
497
|
+
);
|
|
498
|
+
export type RegisterFeatureArgs = z.infer<typeof RegisterFeatureSchema>;
|
|
499
|
+
|
|
500
|
+
export const AutoDiscoverDomainsSchema = z.preprocess(
|
|
501
|
+
(args) =>
|
|
502
|
+
withAliases(args, {
|
|
503
|
+
save: "persist",
|
|
504
|
+
}),
|
|
505
|
+
z.object({
|
|
506
|
+
persist: z.boolean().optional().default(true),
|
|
507
|
+
})
|
|
508
|
+
);
|
|
509
|
+
export type AutoDiscoverDomainsArgs = z.infer<typeof AutoDiscoverDomainsSchema>;
|
|
510
|
+
|
|
511
|
+
function normalizeTopologyArgs(raw: unknown): unknown {
|
|
512
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
513
|
+
const obj = { ...(raw as Record<string, unknown>) };
|
|
514
|
+
if (obj.resolve_node !== undefined && obj.resolveNode === undefined) {
|
|
515
|
+
obj.resolveNode = obj.resolve_node;
|
|
516
|
+
}
|
|
517
|
+
if (obj.resolve_layer !== undefined && obj.resolve === undefined) {
|
|
518
|
+
obj.resolve = obj.resolve_layer;
|
|
519
|
+
}
|
|
520
|
+
if (obj.resolveLayer !== undefined && obj.resolve === undefined) {
|
|
521
|
+
obj.resolve = obj.resolveLayer;
|
|
522
|
+
}
|
|
523
|
+
if (typeof obj.resolveNode === "object" && obj.resolveNode !== null) {
|
|
524
|
+
obj.resolveNode = withAliases(obj.resolveNode, {
|
|
525
|
+
canonicalTag: "canonical_tag",
|
|
526
|
+
domainOrIp: "domain_or_ip",
|
|
527
|
+
connectedTo: "connected_to",
|
|
528
|
+
nodeId: "id",
|
|
529
|
+
node_id: "id",
|
|
530
|
+
nodeName: "name",
|
|
531
|
+
node_name: "name",
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
return obj;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export const GetEnvironmentTopologySchema = z.preprocess(
|
|
538
|
+
(args) => normalizeTopologyArgs(args),
|
|
539
|
+
z.object({
|
|
540
|
+
resolve: z
|
|
541
|
+
.object({
|
|
542
|
+
layer: z.enum(["edge", "gateway", "host", "runtime", "storage", "telemetry"]),
|
|
543
|
+
platform: z.string().min(1, "platform name cannot be empty"),
|
|
544
|
+
constraints: z.array(z.string()).optional(),
|
|
545
|
+
})
|
|
546
|
+
.optional(),
|
|
547
|
+
resolveNode: z
|
|
548
|
+
.object({
|
|
549
|
+
id: z.string().min(1, "Node id cannot be empty"),
|
|
550
|
+
layer: z.enum(["edge", "gateway", "host", "runtime", "storage", "telemetry"]),
|
|
551
|
+
name: z.string().min(1, "Node name cannot be empty"),
|
|
552
|
+
platform: z.string().min(1, "Platform cannot be empty"),
|
|
553
|
+
canonical_tag: z
|
|
554
|
+
.enum([
|
|
555
|
+
"shared_hosting",
|
|
556
|
+
"vps",
|
|
557
|
+
"docker",
|
|
558
|
+
"serverless",
|
|
559
|
+
"kubernetes",
|
|
560
|
+
"managed_db",
|
|
561
|
+
"cdn_edge",
|
|
562
|
+
"paas",
|
|
563
|
+
"static_cdn",
|
|
564
|
+
"unspecified",
|
|
565
|
+
])
|
|
566
|
+
.optional(),
|
|
567
|
+
domain_or_ip: z.string().optional(),
|
|
568
|
+
role: z.string().optional(),
|
|
569
|
+
constraints: z.array(z.string()).optional(),
|
|
570
|
+
connected_to: z.array(z.string()).optional(),
|
|
571
|
+
})
|
|
572
|
+
.optional(),
|
|
573
|
+
refresh: z.boolean().optional().default(false),
|
|
574
|
+
})
|
|
575
|
+
);
|
|
576
|
+
export type GetEnvironmentTopologyArgs = z.infer<typeof GetEnvironmentTopologySchema>;
|
|
577
|
+
|
|
578
|
+
|