@pikku/inspector 0.7.7 → 0.8.1
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 +35 -0
- package/dist/add-channel.d.ts +2 -2
- package/dist/add-channel.js +4 -2
- package/dist/add-functions.d.ts +2 -2
- package/dist/add-functions.js +2 -3
- package/dist/add-http-route.d.ts +2 -2
- package/dist/add-http-route.js +4 -2
- package/dist/add-mcp-prompt.d.ts +3 -0
- package/dist/add-mcp-prompt.js +61 -0
- package/dist/add-mcp-resource.d.ts +3 -0
- package/dist/add-mcp-resource.js +68 -0
- package/dist/add-mcp-tool.d.ts +3 -0
- package/dist/add-mcp-tool.js +64 -0
- package/dist/add-queue-worker.d.ts +3 -0
- package/dist/add-queue-worker.js +48 -0
- package/dist/add-schedule.d.ts +2 -2
- package/dist/add-schedule.js +8 -9
- package/dist/inspector.d.ts +2 -2
- package/dist/inspector.js +13 -3
- package/dist/types.d.ts +21 -1
- package/dist/utils.d.ts +5 -3
- package/dist/utils.js +40 -5
- package/dist/visit.d.ts +3 -3
- package/dist/visit.js +16 -8
- package/lcov.info +4655 -0
- package/package.json +2 -2
- package/run-tests.sh +0 -0
- package/src/add-channel.ts +19 -4
- package/src/add-functions.ts +4 -6
- package/src/add-http-route.ts +14 -4
- package/src/add-mcp-prompt.ts +104 -0
- package/src/add-mcp-resource.ts +116 -0
- package/src/add-mcp-tool.ts +107 -0
- package/src/add-queue-worker.ts +92 -0
- package/src/add-schedule.ts +26 -15
- package/src/inspector.ts +14 -2
- package/src/types.ts +22 -1
- package/src/utils.test.ts +484 -0
- package/src/utils.ts +60 -6
- package/src/visit.ts +23 -9
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"test:coverage": "bash run-tests.sh --coverage"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@pikku/core": "^0.
|
|
20
|
+
"@pikku/core": "^0.8.1",
|
|
21
21
|
"path-to-regexp": "^8.2.0",
|
|
22
22
|
"typescript": "^5.6"
|
|
23
23
|
},
|
package/run-tests.sh
CHANGED
|
File without changes
|
package/src/add-channel.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
import { getPropertyValue } from './get-property-value.js'
|
|
3
3
|
import { pathToRegexp } from 'path-to-regexp'
|
|
4
|
-
import { APIDocs } from '@pikku/core'
|
|
4
|
+
import { APIDocs, PikkuEventTypes } from '@pikku/core'
|
|
5
5
|
import {
|
|
6
6
|
extractFunctionName,
|
|
7
7
|
getPropertyAssignmentInitializer,
|
|
8
8
|
matchesFilters,
|
|
9
9
|
} from './utils.js'
|
|
10
10
|
import type { ChannelMessageMeta, ChannelMeta } from '@pikku/core/channel'
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
InspectorFilters,
|
|
13
|
+
InspectorState,
|
|
14
|
+
InspectorLogger,
|
|
15
|
+
} from './types.js'
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* Safely get the “initializer” expression of a property-like AST node:
|
|
@@ -363,7 +367,8 @@ export function addChannel(
|
|
|
363
367
|
node: ts.Node,
|
|
364
368
|
checker: ts.TypeChecker,
|
|
365
369
|
state: InspectorState,
|
|
366
|
-
filters: InspectorFilters
|
|
370
|
+
filters: InspectorFilters,
|
|
371
|
+
logger: InspectorLogger
|
|
367
372
|
) {
|
|
368
373
|
if (!ts.isCallExpression(node)) return
|
|
369
374
|
const { expression, arguments: args } = node
|
|
@@ -391,7 +396,17 @@ export function addChannel(
|
|
|
391
396
|
const tags = getPropertyValue(obj, 'tags') as string[] | undefined
|
|
392
397
|
const query = getPropertyValue(obj, 'query') as string[] | []
|
|
393
398
|
|
|
394
|
-
|
|
399
|
+
const filePath = node.getSourceFile().fileName
|
|
400
|
+
|
|
401
|
+
if (
|
|
402
|
+
!matchesFilters(
|
|
403
|
+
filters,
|
|
404
|
+
{ tags },
|
|
405
|
+
{ type: PikkuEventTypes.channel, name, filePath },
|
|
406
|
+
logger
|
|
407
|
+
)
|
|
408
|
+
)
|
|
409
|
+
return
|
|
395
410
|
|
|
396
411
|
const connect = getPropertyAssignmentInitializer(
|
|
397
412
|
obj,
|
package/src/add-functions.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import { InspectorState, InspectorFilters } from './types.js'
|
|
2
|
+
import { InspectorState, InspectorFilters, InspectorLogger } from './types.js'
|
|
3
3
|
import { TypesMap } from './types-map.js'
|
|
4
4
|
import {
|
|
5
5
|
extractFunctionName,
|
|
@@ -231,7 +231,8 @@ export function addFunctions(
|
|
|
231
231
|
node: ts.Node,
|
|
232
232
|
checker: ts.TypeChecker,
|
|
233
233
|
state: InspectorState,
|
|
234
|
-
filters: InspectorFilters
|
|
234
|
+
filters: InspectorFilters,
|
|
235
|
+
logger: InspectorLogger
|
|
235
236
|
) {
|
|
236
237
|
if (!ts.isCallExpression(node)) return
|
|
237
238
|
|
|
@@ -305,10 +306,7 @@ export function addFunctions(
|
|
|
305
306
|
services.services.push(original)
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
|
-
} else if (
|
|
309
|
-
ts.isIdentifier(firstParam.name) &&
|
|
310
|
-
!firstParam.name.text.startsWith('_')
|
|
311
|
-
) {
|
|
309
|
+
} else if (ts.isIdentifier(firstParam.name)) {
|
|
312
310
|
services.optimized = false
|
|
313
311
|
}
|
|
314
312
|
}
|
package/src/add-http-route.ts
CHANGED
|
@@ -2,13 +2,13 @@ import * as ts from 'typescript'
|
|
|
2
2
|
import { getPropertyValue } from './get-property-value.js'
|
|
3
3
|
import { pathToRegexp } from 'path-to-regexp'
|
|
4
4
|
import { HTTPMethod } from '@pikku/core/http'
|
|
5
|
-
import { APIDocs } from '@pikku/core'
|
|
5
|
+
import { APIDocs, PikkuEventTypes } from '@pikku/core'
|
|
6
6
|
import {
|
|
7
7
|
extractFunctionName,
|
|
8
8
|
getPropertyAssignmentInitializer,
|
|
9
9
|
matchesFilters,
|
|
10
10
|
} from './utils.js'
|
|
11
|
-
import { InspectorState, InspectorFilters } from './types.js'
|
|
11
|
+
import { InspectorState, InspectorFilters, InspectorLogger } from './types.js'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
@@ -43,7 +43,8 @@ export const addHTTPRoute = (
|
|
|
43
43
|
node: ts.Node,
|
|
44
44
|
checker: ts.TypeChecker,
|
|
45
45
|
state: InspectorState,
|
|
46
|
-
filters: InspectorFilters
|
|
46
|
+
filters: InspectorFilters,
|
|
47
|
+
logger: InspectorLogger
|
|
47
48
|
) => {
|
|
48
49
|
// only look at calls
|
|
49
50
|
if (!ts.isCallExpression(node)) return
|
|
@@ -69,7 +70,16 @@ export const addHTTPRoute = (
|
|
|
69
70
|
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
70
71
|
const query = (getPropertyValue(obj, 'query') as string[]) || []
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
const filePath = node.getSourceFile().fileName
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
!matchesFilters(
|
|
77
|
+
filters,
|
|
78
|
+
{ tags },
|
|
79
|
+
{ type: PikkuEventTypes.http, name: route, filePath },
|
|
80
|
+
logger
|
|
81
|
+
)
|
|
82
|
+
) {
|
|
73
83
|
return
|
|
74
84
|
}
|
|
75
85
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractFunctionName,
|
|
7
|
+
getPropertyAssignmentInitializer,
|
|
8
|
+
matchesFilters,
|
|
9
|
+
} from './utils.js'
|
|
10
|
+
|
|
11
|
+
export const addMCPPrompt = (
|
|
12
|
+
node: ts.Node,
|
|
13
|
+
checker: ts.TypeChecker,
|
|
14
|
+
state: InspectorState,
|
|
15
|
+
filters: InspectorFilters,
|
|
16
|
+
logger: InspectorLogger
|
|
17
|
+
) => {
|
|
18
|
+
if (!ts.isCallExpression(node)) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const args = node.arguments
|
|
23
|
+
const firstArg = args[0]
|
|
24
|
+
const expression = node.expression
|
|
25
|
+
|
|
26
|
+
// Check if the call is to addMCPPrompt
|
|
27
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPPrompt') {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!firstArg) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
36
|
+
const obj = firstArg
|
|
37
|
+
|
|
38
|
+
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
39
|
+
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
40
|
+
| string
|
|
41
|
+
| null
|
|
42
|
+
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
43
|
+
|
|
44
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
45
|
+
obj,
|
|
46
|
+
'func',
|
|
47
|
+
true,
|
|
48
|
+
checker
|
|
49
|
+
)
|
|
50
|
+
if (!funcInitializer) {
|
|
51
|
+
console.error(`• No valid 'func' property for MCP prompt '${nameValue}'.`)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const pikkuFuncName = extractFunctionName(
|
|
56
|
+
funcInitializer,
|
|
57
|
+
checker
|
|
58
|
+
).pikkuFuncName
|
|
59
|
+
|
|
60
|
+
if (!nameValue) {
|
|
61
|
+
console.error(`• MCP prompt is missing the required 'name' property.`)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!descriptionValue) {
|
|
66
|
+
console.error(`• MCP prompt '${nameValue}' is missing a description.`)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const filePath = node.getSourceFile().fileName
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
!matchesFilters(
|
|
74
|
+
filters,
|
|
75
|
+
{ tags },
|
|
76
|
+
{ type: PikkuEventTypes.mcp, name: nameValue, filePath },
|
|
77
|
+
logger
|
|
78
|
+
)
|
|
79
|
+
) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// lookup existing function metadata
|
|
84
|
+
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
85
|
+
if (!fnMeta) {
|
|
86
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
const inputSchema = fnMeta.inputs?.[0] || null
|
|
90
|
+
const outputSchema = fnMeta.outputs?.[0] || null
|
|
91
|
+
|
|
92
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
93
|
+
|
|
94
|
+
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
95
|
+
pikkuFuncName,
|
|
96
|
+
name: nameValue,
|
|
97
|
+
description: descriptionValue,
|
|
98
|
+
tags,
|
|
99
|
+
inputSchema,
|
|
100
|
+
outputSchema,
|
|
101
|
+
arguments: [], // Will be populated by CLI during serialization
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractFunctionName,
|
|
7
|
+
getPropertyAssignmentInitializer,
|
|
8
|
+
matchesFilters,
|
|
9
|
+
} from './utils.js'
|
|
10
|
+
|
|
11
|
+
export const addMCPResource = (
|
|
12
|
+
node: ts.Node,
|
|
13
|
+
checker: ts.TypeChecker,
|
|
14
|
+
state: InspectorState,
|
|
15
|
+
filters: InspectorFilters,
|
|
16
|
+
logger: InspectorLogger
|
|
17
|
+
) => {
|
|
18
|
+
if (!ts.isCallExpression(node)) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const args = node.arguments
|
|
23
|
+
const firstArg = args[0]
|
|
24
|
+
const expression = node.expression
|
|
25
|
+
|
|
26
|
+
// Check if the call is to addMCPResource
|
|
27
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPResource') {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!firstArg) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
36
|
+
const obj = firstArg
|
|
37
|
+
|
|
38
|
+
const uriValue = getPropertyValue(obj, 'uri') as string | null
|
|
39
|
+
const titleValue = getPropertyValue(obj, 'title') as string | null
|
|
40
|
+
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
41
|
+
| string
|
|
42
|
+
| null
|
|
43
|
+
const streamingValue = getPropertyValue(obj, 'streaming') as boolean | null
|
|
44
|
+
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
45
|
+
|
|
46
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
47
|
+
obj,
|
|
48
|
+
'func',
|
|
49
|
+
true,
|
|
50
|
+
checker
|
|
51
|
+
)
|
|
52
|
+
if (!funcInitializer) {
|
|
53
|
+
console.error(
|
|
54
|
+
`• No valid 'func' property for MCP resource '${uriValue}'.`
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const pikkuFuncName = extractFunctionName(
|
|
60
|
+
funcInitializer,
|
|
61
|
+
checker
|
|
62
|
+
).pikkuFuncName
|
|
63
|
+
|
|
64
|
+
if (!uriValue) {
|
|
65
|
+
console.error(`• MCP resource is missing the required 'uri' property.`)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!titleValue) {
|
|
70
|
+
console.error(
|
|
71
|
+
`• MCP resource '${uriValue}' is missing the required 'title' property.`
|
|
72
|
+
)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!descriptionValue) {
|
|
77
|
+
console.error(`• MCP resource '${uriValue}' is missing a description.`)
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const filePath = node.getSourceFile().fileName
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
!matchesFilters(
|
|
85
|
+
filters,
|
|
86
|
+
{ tags },
|
|
87
|
+
{ type: PikkuEventTypes.mcp, name: uriValue, filePath },
|
|
88
|
+
logger
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// lookup existing function metadata
|
|
95
|
+
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
96
|
+
if (!fnMeta) {
|
|
97
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`)
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
const inputSchema = fnMeta.inputs?.[0] || null
|
|
101
|
+
const outputSchema = fnMeta.outputs?.[0] || null
|
|
102
|
+
|
|
103
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
104
|
+
|
|
105
|
+
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
106
|
+
pikkuFuncName,
|
|
107
|
+
uri: uriValue,
|
|
108
|
+
title: titleValue,
|
|
109
|
+
description: descriptionValue,
|
|
110
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
111
|
+
tags,
|
|
112
|
+
inputSchema,
|
|
113
|
+
outputSchema,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractFunctionName,
|
|
7
|
+
getPropertyAssignmentInitializer,
|
|
8
|
+
matchesFilters,
|
|
9
|
+
} from './utils.js'
|
|
10
|
+
|
|
11
|
+
export const addMCPTool = (
|
|
12
|
+
node: ts.Node,
|
|
13
|
+
checker: ts.TypeChecker,
|
|
14
|
+
state: InspectorState,
|
|
15
|
+
filters: InspectorFilters,
|
|
16
|
+
logger: InspectorLogger
|
|
17
|
+
) => {
|
|
18
|
+
if (!ts.isCallExpression(node)) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const args = node.arguments
|
|
23
|
+
const firstArg = args[0]
|
|
24
|
+
const expression = node.expression
|
|
25
|
+
|
|
26
|
+
// Check if the call is to addMCPTool
|
|
27
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPTool') {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!firstArg) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
36
|
+
const obj = firstArg
|
|
37
|
+
|
|
38
|
+
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
39
|
+
const titleValue = getPropertyValue(obj, 'title') as string | null
|
|
40
|
+
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
41
|
+
| string
|
|
42
|
+
| null
|
|
43
|
+
const streamingValue = getPropertyValue(obj, 'streaming') as boolean | null
|
|
44
|
+
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
45
|
+
|
|
46
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
47
|
+
obj,
|
|
48
|
+
'func',
|
|
49
|
+
true,
|
|
50
|
+
checker
|
|
51
|
+
)
|
|
52
|
+
if (!funcInitializer) {
|
|
53
|
+
console.error(`• No valid 'func' property for MCP tool '${nameValue}'.`)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const pikkuFuncName = extractFunctionName(
|
|
58
|
+
funcInitializer,
|
|
59
|
+
checker
|
|
60
|
+
).pikkuFuncName
|
|
61
|
+
|
|
62
|
+
if (!nameValue) {
|
|
63
|
+
console.error(`• MCP tool is missing the required 'name' property.`)
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!descriptionValue) {
|
|
68
|
+
console.error(`• MCP tool '${nameValue}' is missing a description.`)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const filePath = node.getSourceFile().fileName
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
!matchesFilters(
|
|
76
|
+
filters,
|
|
77
|
+
{ tags },
|
|
78
|
+
{ type: PikkuEventTypes.mcp, name: nameValue, filePath },
|
|
79
|
+
logger
|
|
80
|
+
)
|
|
81
|
+
) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// lookup existing function metadata
|
|
86
|
+
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
87
|
+
if (!fnMeta) {
|
|
88
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`)
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
const inputSchema = fnMeta.inputs?.[0] || null
|
|
92
|
+
const outputSchema = fnMeta.outputs?.[0] || null
|
|
93
|
+
|
|
94
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
95
|
+
|
|
96
|
+
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
97
|
+
pikkuFuncName,
|
|
98
|
+
name: nameValue,
|
|
99
|
+
title: titleValue || undefined,
|
|
100
|
+
description: descriptionValue,
|
|
101
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
102
|
+
tags,
|
|
103
|
+
inputSchema,
|
|
104
|
+
outputSchema,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
+
import { APIDocs, PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractFunctionName,
|
|
7
|
+
getPropertyAssignmentInitializer,
|
|
8
|
+
matchesFilters,
|
|
9
|
+
} from './utils.js'
|
|
10
|
+
|
|
11
|
+
export const addQueueWorker = (
|
|
12
|
+
node: ts.Node,
|
|
13
|
+
checker: ts.TypeChecker,
|
|
14
|
+
state: InspectorState,
|
|
15
|
+
filters: InspectorFilters,
|
|
16
|
+
logger: InspectorLogger
|
|
17
|
+
) => {
|
|
18
|
+
if (!ts.isCallExpression(node)) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const args = node.arguments
|
|
23
|
+
const firstArg = args[0]
|
|
24
|
+
const expression = node.expression
|
|
25
|
+
|
|
26
|
+
// Check if the call is to addQueueWorker
|
|
27
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addQueueWorker') {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!firstArg) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
36
|
+
const obj = firstArg
|
|
37
|
+
|
|
38
|
+
const queueName = getPropertyValue(obj, 'queueName') as string | null
|
|
39
|
+
const docs = (getPropertyValue(obj, 'docs') as APIDocs) || undefined
|
|
40
|
+
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
41
|
+
|
|
42
|
+
// --- find the referenced function ---
|
|
43
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
44
|
+
obj,
|
|
45
|
+
'func',
|
|
46
|
+
true,
|
|
47
|
+
checker
|
|
48
|
+
)
|
|
49
|
+
if (!funcInitializer) {
|
|
50
|
+
console.error(
|
|
51
|
+
`• No valid 'func' property for queue processor '${queueName}'.`
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const pikkuFuncName = extractFunctionName(
|
|
57
|
+
funcInitializer,
|
|
58
|
+
checker
|
|
59
|
+
).pikkuFuncName
|
|
60
|
+
|
|
61
|
+
if (!queueName) {
|
|
62
|
+
console.error(
|
|
63
|
+
`• No 'queueName' provided for queue processor function '${pikkuFuncName}'.`
|
|
64
|
+
)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const filePath = node.getSourceFile().fileName
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
!matchesFilters(
|
|
72
|
+
filters,
|
|
73
|
+
{ tags },
|
|
74
|
+
{ type: PikkuEventTypes.queue, name: queueName, filePath },
|
|
75
|
+
logger
|
|
76
|
+
)
|
|
77
|
+
) {
|
|
78
|
+
console.info(
|
|
79
|
+
`• Skipping queue processor '${pikkuFuncName}' for queue '${queueName}' due to filter mismatch.`
|
|
80
|
+
)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
state.queueWorkers.files.add(node.getSourceFile().fileName)
|
|
85
|
+
state.queueWorkers.meta[queueName] = {
|
|
86
|
+
pikkuFuncName,
|
|
87
|
+
queueName,
|
|
88
|
+
docs,
|
|
89
|
+
tags,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/add-schedule.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
-
import { APIDocs } from '@pikku/core'
|
|
4
|
-
import { InspectorFilters, InspectorState } from './types.js'
|
|
5
|
-
import {
|
|
3
|
+
import { APIDocs, PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractFunctionName,
|
|
7
|
+
getPropertyAssignmentInitializer,
|
|
8
|
+
matchesFilters,
|
|
9
|
+
} from './utils.js'
|
|
6
10
|
|
|
7
11
|
export const addSchedule = (
|
|
8
12
|
node: ts.Node,
|
|
9
13
|
checker: ts.TypeChecker,
|
|
10
14
|
state: InspectorState,
|
|
11
|
-
filters: InspectorFilters
|
|
15
|
+
filters: InspectorFilters,
|
|
16
|
+
logger: InspectorLogger
|
|
12
17
|
) => {
|
|
13
18
|
if (!ts.isCallExpression(node)) {
|
|
14
19
|
return
|
|
@@ -35,22 +40,21 @@ export const addSchedule = (
|
|
|
35
40
|
const docs = (getPropertyValue(obj, 'docs') as APIDocs) || undefined
|
|
36
41
|
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
if (!funcProp || !ts.isIdentifier(funcProp.initializer)) {
|
|
43
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
44
|
+
obj,
|
|
45
|
+
'func',
|
|
46
|
+
true,
|
|
47
|
+
checker
|
|
48
|
+
)
|
|
49
|
+
if (!funcInitializer) {
|
|
47
50
|
console.error(
|
|
48
51
|
`• No valid 'func' property for scheduled task '${nameValue}'.`
|
|
49
52
|
)
|
|
50
53
|
return
|
|
51
54
|
}
|
|
55
|
+
|
|
52
56
|
const pikkuFuncName = extractFunctionName(
|
|
53
|
-
|
|
57
|
+
funcInitializer,
|
|
54
58
|
checker
|
|
55
59
|
).pikkuFuncName
|
|
56
60
|
|
|
@@ -58,8 +62,15 @@ export const addSchedule = (
|
|
|
58
62
|
return
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
const filePath = node.getSourceFile().fileName
|
|
66
|
+
|
|
61
67
|
if (
|
|
62
|
-
!matchesFilters(
|
|
68
|
+
!matchesFilters(
|
|
69
|
+
filters,
|
|
70
|
+
{ tags },
|
|
71
|
+
{ type: PikkuEventTypes.scheduler, name: nameValue, filePath },
|
|
72
|
+
logger
|
|
73
|
+
)
|
|
63
74
|
) {
|
|
64
75
|
return
|
|
65
76
|
}
|
package/src/inspector.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
InspectorState,
|
|
6
6
|
InspectorHTTPState,
|
|
7
7
|
InspectorFilters,
|
|
8
|
+
InspectorLogger,
|
|
8
9
|
} from './types.js'
|
|
9
10
|
|
|
10
11
|
export const normalizeHTTPTypes = (
|
|
@@ -14,6 +15,7 @@ export const normalizeHTTPTypes = (
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export const inspect = (
|
|
18
|
+
logger: InspectorLogger,
|
|
17
19
|
routeFiles: string[],
|
|
18
20
|
filters: InspectorFilters
|
|
19
21
|
): InspectorState => {
|
|
@@ -49,22 +51,32 @@ export const inspect = (
|
|
|
49
51
|
meta: {},
|
|
50
52
|
files: new Set(),
|
|
51
53
|
},
|
|
54
|
+
queueWorkers: {
|
|
55
|
+
meta: {},
|
|
56
|
+
files: new Set(),
|
|
57
|
+
},
|
|
52
58
|
rpc: {
|
|
53
59
|
meta: {},
|
|
54
60
|
},
|
|
61
|
+
mcpEndpoints: {
|
|
62
|
+
resourcesMeta: {},
|
|
63
|
+
toolsMeta: {},
|
|
64
|
+
promptsMeta: {},
|
|
65
|
+
files: new Set(),
|
|
66
|
+
},
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
// First sweep: add all functions
|
|
58
70
|
for (const sourceFile of sourceFiles) {
|
|
59
71
|
ts.forEachChild(sourceFile, (child) =>
|
|
60
|
-
visitSetup(checker, child, state, filters)
|
|
72
|
+
visitSetup(checker, child, state, filters, logger)
|
|
61
73
|
)
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
// Second sweep: add all transports
|
|
65
77
|
for (const sourceFile of sourceFiles) {
|
|
66
78
|
ts.forEachChild(sourceFile, (child) =>
|
|
67
|
-
visitRoutes(checker, child, state, filters)
|
|
79
|
+
visitRoutes(checker, child, state, filters, logger)
|
|
68
80
|
)
|
|
69
81
|
}
|
|
70
82
|
|