@pikku/inspector 0.9.6-next.0 → 0.10.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/CHANGELOG.md +6 -0
- package/dist/add/add-channel.d.ts +5 -1
- package/dist/add/add-channel.js +51 -32
- package/dist/add/add-cli.d.ts +4 -0
- package/dist/add/add-cli.js +128 -23
- package/dist/add/add-file-extends-core-type.js +3 -2
- package/dist/add/add-file-with-factory.d.ts +2 -2
- package/dist/add/add-file-with-factory.js +34 -1
- package/dist/add/add-functions.js +52 -5
- package/dist/add/add-http-route.js +19 -12
- package/dist/add/add-mcp-prompt.js +20 -13
- package/dist/add/add-mcp-resource.js +24 -14
- package/dist/add/add-mcp-tool.js +23 -13
- package/dist/add/add-middleware.js +51 -12
- package/dist/add/add-permission.d.ts +1 -2
- package/dist/add/add-permission.js +275 -19
- package/dist/add/add-queue-worker.js +10 -12
- package/dist/add/add-schedule.js +9 -10
- package/dist/error-codes.d.ts +35 -0
- package/dist/error-codes.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/inspector.js +20 -1
- package/dist/types.d.ts +31 -3
- package/dist/utils/ensure-function-metadata.d.ts +6 -0
- package/dist/utils/ensure-function-metadata.js +18 -0
- package/dist/utils/extract-function-name.d.ts +2 -2
- package/dist/utils/extract-function-name.js +13 -8
- package/dist/utils/filter-inspector-state.d.ts +6 -0
- package/dist/utils/filter-inspector-state.js +382 -0
- package/dist/utils/filter-utils.d.ts +10 -0
- package/dist/utils/filter-utils.js +66 -2
- package/dist/utils/find-root-dir.d.ts +23 -0
- package/dist/utils/find-root-dir.js +55 -0
- package/dist/utils/get-files-and-methods.d.ts +2 -1
- package/dist/utils/get-files-and-methods.js +2 -1
- package/dist/utils/get-property-value.d.ts +9 -0
- package/dist/utils/get-property-value.js +20 -0
- package/dist/utils/middleware.d.ts +1 -1
- package/dist/utils/middleware.js +7 -7
- package/dist/utils/permissions.d.ts +43 -0
- package/dist/utils/permissions.js +178 -0
- package/dist/utils/post-process.d.ts +16 -0
- package/dist/utils/post-process.js +132 -0
- package/dist/utils/serialize-inspector-state.d.ts +179 -0
- package/dist/utils/serialize-inspector-state.js +170 -0
- package/dist/visit.js +3 -2
- package/package.json +4 -4
- package/src/add/add-channel.ts +92 -40
- package/src/add/add-cli.ts +188 -29
- package/src/add/add-file-extends-core-type.ts +5 -2
- package/src/add/add-file-with-factory.ts +45 -2
- package/src/add/add-functions.ts +60 -5
- package/src/add/add-http-route.ts +46 -21
- package/src/add/add-mcp-prompt.ts +42 -21
- package/src/add/add-mcp-prompt.ts.tmp +0 -0
- package/src/add/add-mcp-resource.ts +50 -24
- package/src/add/add-mcp-resource.ts.tmp +0 -0
- package/src/add/add-mcp-tool.ts +48 -21
- package/src/add/add-middleware.ts +74 -15
- package/src/add/add-permission.ts +364 -22
- package/src/add/add-queue-worker.ts +22 -25
- package/src/add/add-schedule.ts +19 -20
- package/src/error-codes.ts +43 -0
- package/src/index.ts +7 -0
- package/src/inspector.ts +22 -1
- package/src/types.ts +38 -3
- package/src/utils/ensure-function-metadata.ts +24 -0
- package/src/utils/extract-function-name.ts +20 -8
- package/src/utils/filter-inspector-state.test.ts +1433 -0
- package/src/utils/filter-inspector-state.ts +526 -0
- package/src/utils/filter-utils.test.ts +350 -1
- package/src/utils/filter-utils.ts +82 -2
- package/src/utils/find-root-dir.ts +68 -0
- package/src/utils/get-files-and-methods.ts +8 -0
- package/src/utils/get-property-value.ts +27 -0
- package/src/utils/middleware.ts +14 -7
- package/src/utils/permissions.test.ts +327 -0
- package/src/utils/permissions.ts +262 -0
- package/src/utils/post-process.ts +178 -0
- package/src/utils/serialize-inspector-state.ts +375 -0
- package/src/utils/test-data/inspector-state.json +1680 -0
- package/src/visit.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import { InspectorState, InspectorFilters, InspectorLogger } from '../types.js'
|
|
2
|
+
import { PikkuWiringTypes } from '@pikku/core'
|
|
3
|
+
import { aggregateRequiredServices } from './post-process.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Match a value against a pattern with wildcard support
|
|
7
|
+
* Supports "*" at the beginning, end, or both (e.g., "send*", "*Payment", "*process*")
|
|
8
|
+
*/
|
|
9
|
+
function matchesWildcard(value: string, pattern: string): boolean {
|
|
10
|
+
if (pattern === '*') return true
|
|
11
|
+
|
|
12
|
+
const startsWithWildcard = pattern.startsWith('*')
|
|
13
|
+
const endsWithWildcard = pattern.endsWith('*')
|
|
14
|
+
|
|
15
|
+
if (startsWithWildcard && endsWithWildcard) {
|
|
16
|
+
const middle = pattern.slice(1, -1)
|
|
17
|
+
if (middle === '') return true
|
|
18
|
+
return value.includes(middle)
|
|
19
|
+
} else if (startsWithWildcard) {
|
|
20
|
+
const suffix = pattern.slice(1)
|
|
21
|
+
return value.endsWith(suffix) && value.length > suffix.length
|
|
22
|
+
} else if (endsWithWildcard) {
|
|
23
|
+
const prefix = pattern.slice(0, -1)
|
|
24
|
+
return value.startsWith(prefix) && value.length > prefix.length
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return value === pattern
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if metadata matches the given filters
|
|
32
|
+
*/
|
|
33
|
+
function matchesFilters(
|
|
34
|
+
filters: InspectorFilters,
|
|
35
|
+
meta: {
|
|
36
|
+
type: PikkuWiringTypes
|
|
37
|
+
name: string
|
|
38
|
+
tags?: string[]
|
|
39
|
+
filePath?: string
|
|
40
|
+
httpRoute?: string
|
|
41
|
+
httpMethod?: string
|
|
42
|
+
},
|
|
43
|
+
logger: InspectorLogger
|
|
44
|
+
): boolean {
|
|
45
|
+
// If no filters, allow everything
|
|
46
|
+
if (Object.keys(filters).length === 0) return true
|
|
47
|
+
|
|
48
|
+
// If all filter arrays are empty, allow everything
|
|
49
|
+
if (
|
|
50
|
+
(!filters.names || filters.names.length === 0) &&
|
|
51
|
+
(!filters.tags || filters.tags.length === 0) &&
|
|
52
|
+
(!filters.types || filters.types.length === 0) &&
|
|
53
|
+
(!filters.directories || filters.directories.length === 0) &&
|
|
54
|
+
(!filters.httpRoutes || filters.httpRoutes.length === 0) &&
|
|
55
|
+
(!filters.httpMethods || filters.httpMethods.length === 0)
|
|
56
|
+
) {
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check type filter
|
|
61
|
+
if (filters.types && filters.types.length > 0) {
|
|
62
|
+
if (!filters.types.includes(meta.type)) {
|
|
63
|
+
logger.debug(`⒡ Filtered by type: ${meta.type}:${meta.name}`)
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check directory filter
|
|
69
|
+
if (filters.directories && filters.directories.length > 0 && meta.filePath) {
|
|
70
|
+
const matchesDirectory = filters.directories.some((dir) => {
|
|
71
|
+
const normalizedFilePath = meta.filePath!.replace(/\\/g, '/')
|
|
72
|
+
const normalizedDir = dir.replace(/\\/g, '/')
|
|
73
|
+
return normalizedFilePath.includes(normalizedDir)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
if (!matchesDirectory) {
|
|
77
|
+
logger.debug(`⒡ Filtered by directory: ${meta.type}:${meta.name}`)
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check tag filter
|
|
83
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
84
|
+
if (!meta.tags || !filters.tags.some((tag) => meta.tags!.includes(tag))) {
|
|
85
|
+
logger.debug(`⒡ Filtered by tags: ${meta.type}:${meta.name}`)
|
|
86
|
+
return false
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check name filter
|
|
91
|
+
if (filters.names && filters.names.length > 0) {
|
|
92
|
+
const nameMatches = filters.names.some((pattern) =>
|
|
93
|
+
matchesWildcard(meta.name, pattern)
|
|
94
|
+
)
|
|
95
|
+
if (!nameMatches) {
|
|
96
|
+
logger.debug(`⒡ Filtered by name: ${meta.type}:${meta.name}`)
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check HTTP route filter
|
|
102
|
+
if (filters.httpRoutes && filters.httpRoutes.length > 0 && meta.httpRoute) {
|
|
103
|
+
const routeMatches = filters.httpRoutes.some((pattern) =>
|
|
104
|
+
matchesWildcard(meta.httpRoute!, pattern)
|
|
105
|
+
)
|
|
106
|
+
if (!routeMatches) {
|
|
107
|
+
logger.debug(`⒡ Filtered by HTTP route: ${meta.httpRoute}`)
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check HTTP method filter
|
|
113
|
+
if (
|
|
114
|
+
filters.httpMethods &&
|
|
115
|
+
filters.httpMethods.length > 0 &&
|
|
116
|
+
meta.httpMethod
|
|
117
|
+
) {
|
|
118
|
+
const normalizedMethod = meta.httpMethod.toUpperCase()
|
|
119
|
+
if (!filters.httpMethods.includes(normalizedMethod)) {
|
|
120
|
+
logger.debug(`⒡ Filtered by HTTP method: ${meta.httpMethod}`)
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Extract wire names from middleware/permissions metadata
|
|
130
|
+
*/
|
|
131
|
+
function extractWireNames(obj: Record<string, any> | undefined): string[] {
|
|
132
|
+
if (!obj) return []
|
|
133
|
+
const names: string[] = []
|
|
134
|
+
for (const key of Object.keys(obj)) {
|
|
135
|
+
if (obj[key] && typeof obj[key] === 'object' && 'name' in obj[key]) {
|
|
136
|
+
names.push(obj[key].name)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return names
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Filters inspector state based on provided filters
|
|
144
|
+
* This is applied post-inspection to support the inspect-once, filter-many pattern
|
|
145
|
+
*/
|
|
146
|
+
export function filterInspectorState(
|
|
147
|
+
state: InspectorState | Omit<InspectorState, 'typesLookup'>,
|
|
148
|
+
filters: InspectorFilters,
|
|
149
|
+
logger: InspectorLogger
|
|
150
|
+
): typeof state {
|
|
151
|
+
// If no filters, return original state
|
|
152
|
+
if (
|
|
153
|
+
Object.keys(filters).length === 0 ||
|
|
154
|
+
((!filters.names || filters.names.length === 0) &&
|
|
155
|
+
(!filters.tags || filters.tags.length === 0) &&
|
|
156
|
+
(!filters.types || filters.types.length === 0) &&
|
|
157
|
+
(!filters.directories || filters.directories.length === 0) &&
|
|
158
|
+
(!filters.httpRoutes || filters.httpRoutes.length === 0) &&
|
|
159
|
+
(!filters.httpMethods || filters.httpMethods.length === 0))
|
|
160
|
+
) {
|
|
161
|
+
return state
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Create a shallow copy with new Maps/Sets to avoid mutating the original
|
|
165
|
+
const filteredState = {
|
|
166
|
+
...state,
|
|
167
|
+
serviceAggregation: {
|
|
168
|
+
...state.serviceAggregation,
|
|
169
|
+
requiredServices: new Set<string>(), // Reset requiredServices - will be recalculated
|
|
170
|
+
usedFunctions: new Set<string>(),
|
|
171
|
+
usedMiddleware: new Set<string>(),
|
|
172
|
+
usedPermissions: new Set<string>(),
|
|
173
|
+
},
|
|
174
|
+
http: {
|
|
175
|
+
...state.http,
|
|
176
|
+
meta: JSON.parse(JSON.stringify(state.http.meta)), // Deep clone metadata
|
|
177
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
178
|
+
},
|
|
179
|
+
channels: {
|
|
180
|
+
...state.channels,
|
|
181
|
+
meta: JSON.parse(JSON.stringify(state.channels.meta)),
|
|
182
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
183
|
+
},
|
|
184
|
+
scheduledTasks: {
|
|
185
|
+
...state.scheduledTasks,
|
|
186
|
+
meta: JSON.parse(JSON.stringify(state.scheduledTasks.meta)),
|
|
187
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
188
|
+
},
|
|
189
|
+
queueWorkers: {
|
|
190
|
+
...state.queueWorkers,
|
|
191
|
+
meta: JSON.parse(JSON.stringify(state.queueWorkers.meta)),
|
|
192
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
193
|
+
},
|
|
194
|
+
mcpEndpoints: {
|
|
195
|
+
...state.mcpEndpoints,
|
|
196
|
+
toolsMeta: JSON.parse(JSON.stringify(state.mcpEndpoints.toolsMeta)),
|
|
197
|
+
resourcesMeta: JSON.parse(
|
|
198
|
+
JSON.stringify(state.mcpEndpoints.resourcesMeta)
|
|
199
|
+
),
|
|
200
|
+
promptsMeta: JSON.parse(JSON.stringify(state.mcpEndpoints.promptsMeta)),
|
|
201
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
202
|
+
},
|
|
203
|
+
cli: {
|
|
204
|
+
...state.cli,
|
|
205
|
+
meta: JSON.parse(JSON.stringify(state.cli.meta)),
|
|
206
|
+
files: new Set<string>(), // Will be repopulated with filtered files
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Filter HTTP routes
|
|
211
|
+
for (const method of Object.keys(filteredState.http.meta)) {
|
|
212
|
+
const routes = filteredState.http.meta[method]
|
|
213
|
+
for (const route of Object.keys(routes)) {
|
|
214
|
+
const routeMeta = routes[route]
|
|
215
|
+
|
|
216
|
+
// Get function file path for directory filtering
|
|
217
|
+
const funcFile = filteredState.functions.files.get(
|
|
218
|
+
routeMeta.pikkuFuncName
|
|
219
|
+
)
|
|
220
|
+
const filePath = funcFile?.path
|
|
221
|
+
|
|
222
|
+
const matches = matchesFilters(
|
|
223
|
+
filters,
|
|
224
|
+
{
|
|
225
|
+
type: 'http' as PikkuWiringTypes,
|
|
226
|
+
name: routeMeta.pikkuFuncName, // Use function name, not route
|
|
227
|
+
tags: routeMeta.tags,
|
|
228
|
+
filePath,
|
|
229
|
+
httpRoute: routeMeta.route,
|
|
230
|
+
httpMethod: routeMeta.method,
|
|
231
|
+
},
|
|
232
|
+
logger
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if (!matches) {
|
|
236
|
+
delete routes[route]
|
|
237
|
+
} else {
|
|
238
|
+
// Track used functions/middleware/permissions
|
|
239
|
+
if (routeMeta.pikkuFuncName) {
|
|
240
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
241
|
+
routeMeta.pikkuFuncName
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
extractWireNames(routeMeta.middleware).forEach((name: string) =>
|
|
245
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
246
|
+
)
|
|
247
|
+
extractWireNames(routeMeta.permissions).forEach((name: string) =>
|
|
248
|
+
filteredState.serviceAggregation.usedPermissions.add(name)
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Repopulate http.files if any routes remain
|
|
255
|
+
const hasHttpRoutes = Object.values(
|
|
256
|
+
filteredState.http.meta as Record<string, any>
|
|
257
|
+
).some((routes) => Object.keys(routes).length > 0)
|
|
258
|
+
if (hasHttpRoutes) {
|
|
259
|
+
filteredState.http.files = new Set(state.http.files)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Filter channels
|
|
263
|
+
for (const name of Object.keys(filteredState.channels.meta)) {
|
|
264
|
+
const channelMeta = filteredState.channels.meta[name]
|
|
265
|
+
const matches = matchesFilters(
|
|
266
|
+
filters,
|
|
267
|
+
{
|
|
268
|
+
type: 'channel' as PikkuWiringTypes,
|
|
269
|
+
name,
|
|
270
|
+
tags: channelMeta.tags,
|
|
271
|
+
},
|
|
272
|
+
logger
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
if (!matches) {
|
|
276
|
+
delete filteredState.channels.meta[name]
|
|
277
|
+
} else {
|
|
278
|
+
if (channelMeta.pikkuFuncName) {
|
|
279
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
280
|
+
channelMeta.pikkuFuncName
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
extractWireNames(channelMeta.middleware).forEach((name: string) =>
|
|
284
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
285
|
+
)
|
|
286
|
+
extractWireNames(channelMeta.permissions).forEach((name: string) =>
|
|
287
|
+
filteredState.serviceAggregation.usedPermissions.add(name)
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Repopulate channels.files if any channels remain
|
|
293
|
+
if (Object.keys(filteredState.channels.meta).length > 0) {
|
|
294
|
+
filteredState.channels.files = new Set(state.channels.files)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Filter scheduled tasks
|
|
298
|
+
for (const name of Object.keys(filteredState.scheduledTasks.meta)) {
|
|
299
|
+
const taskMeta = filteredState.scheduledTasks.meta[name]
|
|
300
|
+
const matches = matchesFilters(
|
|
301
|
+
filters,
|
|
302
|
+
{
|
|
303
|
+
type: 'scheduler' as PikkuWiringTypes,
|
|
304
|
+
name,
|
|
305
|
+
tags: taskMeta.tags,
|
|
306
|
+
},
|
|
307
|
+
logger
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
if (!matches) {
|
|
311
|
+
delete filteredState.scheduledTasks.meta[name]
|
|
312
|
+
} else {
|
|
313
|
+
if (taskMeta.pikkuFuncName) {
|
|
314
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
315
|
+
taskMeta.pikkuFuncName
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
extractWireNames(taskMeta.middleware).forEach((name: string) =>
|
|
319
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Repopulate scheduledTasks.files if any tasks remain
|
|
325
|
+
if (Object.keys(filteredState.scheduledTasks.meta).length > 0) {
|
|
326
|
+
filteredState.scheduledTasks.files = new Set(state.scheduledTasks.files)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Filter queue workers
|
|
330
|
+
for (const name of Object.keys(filteredState.queueWorkers.meta)) {
|
|
331
|
+
const workerMeta = filteredState.queueWorkers.meta[name]
|
|
332
|
+
const matches = matchesFilters(
|
|
333
|
+
filters,
|
|
334
|
+
{
|
|
335
|
+
type: 'queue' as PikkuWiringTypes,
|
|
336
|
+
name,
|
|
337
|
+
tags: workerMeta.tags,
|
|
338
|
+
},
|
|
339
|
+
logger
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
if (!matches) {
|
|
343
|
+
delete filteredState.queueWorkers.meta[name]
|
|
344
|
+
} else {
|
|
345
|
+
if (workerMeta.pikkuFuncName) {
|
|
346
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
347
|
+
workerMeta.pikkuFuncName
|
|
348
|
+
)
|
|
349
|
+
}
|
|
350
|
+
extractWireNames(workerMeta.middleware).forEach((name: string) =>
|
|
351
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Repopulate queueWorkers.files if any workers remain
|
|
357
|
+
if (Object.keys(filteredState.queueWorkers.meta).length > 0) {
|
|
358
|
+
filteredState.queueWorkers.files = new Set(state.queueWorkers.files)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Filter MCP tools
|
|
362
|
+
for (const name of Object.keys(filteredState.mcpEndpoints.toolsMeta)) {
|
|
363
|
+
const toolMeta = filteredState.mcpEndpoints.toolsMeta[name]
|
|
364
|
+
const matches = matchesFilters(
|
|
365
|
+
filters,
|
|
366
|
+
{
|
|
367
|
+
type: 'mcp' as PikkuWiringTypes,
|
|
368
|
+
name,
|
|
369
|
+
tags: toolMeta.tags,
|
|
370
|
+
},
|
|
371
|
+
logger
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
if (!matches) {
|
|
375
|
+
delete filteredState.mcpEndpoints.toolsMeta[name]
|
|
376
|
+
} else {
|
|
377
|
+
if (toolMeta.pikkuFuncName) {
|
|
378
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
379
|
+
toolMeta.pikkuFuncName
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
extractWireNames(toolMeta.middleware).forEach((name: string) =>
|
|
383
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
384
|
+
)
|
|
385
|
+
extractWireNames(toolMeta.permissions).forEach((name: string) =>
|
|
386
|
+
filteredState.serviceAggregation.usedPermissions.add(name)
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Filter MCP resources
|
|
392
|
+
for (const name of Object.keys(filteredState.mcpEndpoints.resourcesMeta)) {
|
|
393
|
+
const resourceMeta = filteredState.mcpEndpoints.resourcesMeta[name]
|
|
394
|
+
const matches = matchesFilters(
|
|
395
|
+
filters,
|
|
396
|
+
{
|
|
397
|
+
type: 'mcp' as PikkuWiringTypes,
|
|
398
|
+
name,
|
|
399
|
+
tags: resourceMeta.tags,
|
|
400
|
+
},
|
|
401
|
+
logger
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
if (!matches) {
|
|
405
|
+
delete filteredState.mcpEndpoints.resourcesMeta[name]
|
|
406
|
+
} else {
|
|
407
|
+
if (resourceMeta.pikkuFuncName) {
|
|
408
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
409
|
+
resourceMeta.pikkuFuncName
|
|
410
|
+
)
|
|
411
|
+
}
|
|
412
|
+
extractWireNames(resourceMeta.middleware).forEach((name: string) =>
|
|
413
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
414
|
+
)
|
|
415
|
+
extractWireNames(resourceMeta.permissions).forEach((name: string) =>
|
|
416
|
+
filteredState.serviceAggregation.usedPermissions.add(name)
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Filter MCP prompts
|
|
422
|
+
for (const name of Object.keys(filteredState.mcpEndpoints.promptsMeta)) {
|
|
423
|
+
const promptMeta = filteredState.mcpEndpoints.promptsMeta[name]
|
|
424
|
+
const matches = matchesFilters(
|
|
425
|
+
filters,
|
|
426
|
+
{
|
|
427
|
+
type: 'mcp' as PikkuWiringTypes,
|
|
428
|
+
name,
|
|
429
|
+
tags: promptMeta.tags,
|
|
430
|
+
},
|
|
431
|
+
logger
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
if (!matches) {
|
|
435
|
+
delete filteredState.mcpEndpoints.promptsMeta[name]
|
|
436
|
+
} else {
|
|
437
|
+
if (promptMeta.pikkuFuncName) {
|
|
438
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
439
|
+
promptMeta.pikkuFuncName
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
extractWireNames(promptMeta.middleware).forEach((name: string) =>
|
|
443
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
444
|
+
)
|
|
445
|
+
extractWireNames(promptMeta.permissions).forEach((name: string) =>
|
|
446
|
+
filteredState.serviceAggregation.usedPermissions.add(name)
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Repopulate mcpEndpoints.files if any MCP endpoints remain
|
|
452
|
+
const hasMcpEndpoints =
|
|
453
|
+
Object.keys(filteredState.mcpEndpoints.toolsMeta).length > 0 ||
|
|
454
|
+
Object.keys(filteredState.mcpEndpoints.resourcesMeta).length > 0 ||
|
|
455
|
+
Object.keys(filteredState.mcpEndpoints.promptsMeta).length > 0
|
|
456
|
+
if (hasMcpEndpoints) {
|
|
457
|
+
filteredState.mcpEndpoints.files = new Set(state.mcpEndpoints.files)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Filter CLI programs (note: CLI filtering might be more complex with nested commands)
|
|
461
|
+
const referencedRenderers = new Set<string>()
|
|
462
|
+
|
|
463
|
+
for (const programName of Object.keys(filteredState.cli.meta.programs)) {
|
|
464
|
+
const programMeta = filteredState.cli.meta.programs[programName]
|
|
465
|
+
|
|
466
|
+
// Filter commands in the program
|
|
467
|
+
for (const commandName of Object.keys(programMeta.commands)) {
|
|
468
|
+
const commandMeta = programMeta.commands[commandName]
|
|
469
|
+
const matches = matchesFilters(
|
|
470
|
+
filters,
|
|
471
|
+
{
|
|
472
|
+
type: 'cli' as PikkuWiringTypes,
|
|
473
|
+
name: commandName,
|
|
474
|
+
tags: commandMeta.tags,
|
|
475
|
+
},
|
|
476
|
+
logger
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
if (!matches) {
|
|
480
|
+
delete programMeta.commands[commandName]
|
|
481
|
+
} else {
|
|
482
|
+
if (commandMeta.pikkuFuncName) {
|
|
483
|
+
filteredState.serviceAggregation.usedFunctions.add(
|
|
484
|
+
commandMeta.pikkuFuncName
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
extractWireNames(commandMeta.middleware).forEach((name: string) =>
|
|
488
|
+
filteredState.serviceAggregation.usedMiddleware.add(name)
|
|
489
|
+
)
|
|
490
|
+
// Track referenced renderers
|
|
491
|
+
if (commandMeta.defaultRenderName) {
|
|
492
|
+
referencedRenderers.add(commandMeta.defaultRenderName)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Remove program if it has no commands left
|
|
498
|
+
if (Object.keys(programMeta.commands).length === 0) {
|
|
499
|
+
delete filteredState.cli.meta.programs[programName]
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Filter out renderers that aren't referenced by any remaining commands
|
|
504
|
+
for (const rendererName of Object.keys(
|
|
505
|
+
filteredState.cli.meta.renderers || {}
|
|
506
|
+
)) {
|
|
507
|
+
if (!referencedRenderers.has(rendererName)) {
|
|
508
|
+
delete filteredState.cli.meta.renderers![rendererName]
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Repopulate cli.files if any CLI programs or referenced renderers remain
|
|
513
|
+
const hasCliPrograms = Object.keys(filteredState.cli.meta.programs).length > 0
|
|
514
|
+
const hasCliRenderers =
|
|
515
|
+
Object.keys(filteredState.cli.meta.renderers || {}).length > 0
|
|
516
|
+
if (hasCliPrograms || hasCliRenderers) {
|
|
517
|
+
filteredState.cli.files = new Set(state.cli.files)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Recalculate requiredServices based on filtered functions/middleware/permissions
|
|
521
|
+
// Need to cast to InspectorState temporarily for aggregateRequiredServices
|
|
522
|
+
const stateForAggregation = filteredState as InspectorState
|
|
523
|
+
aggregateRequiredServices(stateForAggregation)
|
|
524
|
+
|
|
525
|
+
return filteredState
|
|
526
|
+
}
|