@pikku/inspector 0.7.7 → 0.8.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 +8 -0
- package/dist/add-channel.js +2 -1
- package/dist/add-http-route.js +2 -1
- package/dist/add-mcp-prompt.d.ts +3 -0
- package/dist/add-mcp-prompt.js +60 -0
- package/dist/add-mcp-resource.d.ts +3 -0
- package/dist/add-mcp-resource.js +67 -0
- package/dist/add-mcp-tool.d.ts +3 -0
- package/dist/add-mcp-tool.js +63 -0
- package/dist/add-queue-worker.d.ts +3 -0
- package/dist/add-queue-worker.js +47 -0
- package/dist/add-schedule.js +6 -8
- package/dist/inspector.js +10 -0
- package/dist/types.d.ts +13 -1
- package/dist/utils.d.ts +2 -1
- package/dist/visit.js +8 -0
- package/package.json +2 -2
- package/src/add-channel.ts +5 -2
- package/src/add-http-route.ts +8 -2
- package/src/add-mcp-prompt.ts +100 -0
- package/src/add-mcp-resource.ts +112 -0
- package/src/add-mcp-tool.ts +103 -0
- package/src/add-queue-worker.ts +88 -0
- package/src/add-schedule.ts +20 -13
- package/src/inspector.ts +10 -0
- package/src/types.ts +13 -1
- package/src/utils.ts +5 -1
- package/src/visit.ts +8 -0
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @pikku/inspector
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Major Features
|
|
6
|
+
|
|
7
|
+
- **Model Context Protocol (MCP) Analysis**: Added comprehensive MCP endpoint analysis
|
|
8
|
+
- **Queue Worker Analysis**: Added queue analysis
|
|
9
|
+
- **Enhanced Service Analysis**: Added service destructuring analysis for better code generation and type safety
|
|
10
|
+
|
|
3
11
|
## 0.7.7
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/add-channel.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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 { PikkuEventTypes } from '@pikku/core';
|
|
4
5
|
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
6
|
/**
|
|
6
7
|
* Safely get the “initializer” expression of a property-like AST node:
|
|
@@ -291,7 +292,7 @@ export function addChannel(node, checker, state, filters) {
|
|
|
291
292
|
const docs = getPropertyValue(obj, 'docs');
|
|
292
293
|
const tags = getPropertyValue(obj, 'tags');
|
|
293
294
|
const query = getPropertyValue(obj, 'query');
|
|
294
|
-
if (!matchesFilters(filters, { tags }, { type:
|
|
295
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.channel, name }))
|
|
295
296
|
return;
|
|
296
297
|
const connect = getPropertyAssignmentInitializer(obj, 'onConnect', false, checker);
|
|
297
298
|
const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', false, checker);
|
package/dist/add-http-route.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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 { PikkuEventTypes } from '@pikku/core';
|
|
4
5
|
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
6
|
/**
|
|
6
7
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
@@ -44,7 +45,7 @@ export const addHTTPRoute = (node, checker, state, filters) => {
|
|
|
44
45
|
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
45
46
|
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
46
47
|
const query = getPropertyValue(obj, 'query') || [];
|
|
47
|
-
if (!matchesFilters(filters, { tags }, { type:
|
|
48
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.http, name: route })) {
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
// --- find the referenced function ---
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
|
+
export const addMCPPrompt = (node, checker, state, filters) => {
|
|
6
|
+
if (!ts.isCallExpression(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const args = node.arguments;
|
|
10
|
+
const firstArg = args[0];
|
|
11
|
+
const expression = node.expression;
|
|
12
|
+
// Check if the call is to addMCPPrompt
|
|
13
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPPrompt') {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!firstArg) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
20
|
+
const obj = firstArg;
|
|
21
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
22
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
23
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
24
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
25
|
+
if (!funcInitializer) {
|
|
26
|
+
console.error(`• No valid 'func' property for MCP prompt '${nameValue}'.`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
30
|
+
if (!nameValue) {
|
|
31
|
+
console.error(`• MCP prompt is missing the required 'name' property.`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!descriptionValue) {
|
|
35
|
+
console.error(`• MCP prompt '${nameValue}' is missing a description.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: nameValue })) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// lookup existing function metadata
|
|
42
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
43
|
+
if (!fnMeta) {
|
|
44
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
48
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
49
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
50
|
+
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
51
|
+
pikkuFuncName,
|
|
52
|
+
name: nameValue,
|
|
53
|
+
description: descriptionValue,
|
|
54
|
+
tags,
|
|
55
|
+
inputSchema,
|
|
56
|
+
outputSchema,
|
|
57
|
+
arguments: [], // Will be populated by CLI during serialization
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
|
+
export const addMCPResource = (node, checker, state, filters) => {
|
|
6
|
+
if (!ts.isCallExpression(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const args = node.arguments;
|
|
10
|
+
const firstArg = args[0];
|
|
11
|
+
const expression = node.expression;
|
|
12
|
+
// Check if the call is to addMCPResource
|
|
13
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPResource') {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!firstArg) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
20
|
+
const obj = firstArg;
|
|
21
|
+
const uriValue = getPropertyValue(obj, 'uri');
|
|
22
|
+
const titleValue = getPropertyValue(obj, 'title');
|
|
23
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
24
|
+
const streamingValue = getPropertyValue(obj, 'streaming');
|
|
25
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
26
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
27
|
+
if (!funcInitializer) {
|
|
28
|
+
console.error(`• No valid 'func' property for MCP resource '${uriValue}'.`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
32
|
+
if (!uriValue) {
|
|
33
|
+
console.error(`• MCP resource is missing the required 'uri' property.`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!titleValue) {
|
|
37
|
+
console.error(`• MCP resource '${uriValue}' is missing the required 'title' property.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!descriptionValue) {
|
|
41
|
+
console.error(`• MCP resource '${uriValue}' is missing a description.`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: uriValue })) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// lookup existing function metadata
|
|
48
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
49
|
+
if (!fnMeta) {
|
|
50
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
54
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
55
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
56
|
+
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
57
|
+
pikkuFuncName,
|
|
58
|
+
uri: uriValue,
|
|
59
|
+
title: titleValue,
|
|
60
|
+
description: descriptionValue,
|
|
61
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
62
|
+
tags,
|
|
63
|
+
inputSchema,
|
|
64
|
+
outputSchema,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
|
+
export const addMCPTool = (node, checker, state, filters) => {
|
|
6
|
+
if (!ts.isCallExpression(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const args = node.arguments;
|
|
10
|
+
const firstArg = args[0];
|
|
11
|
+
const expression = node.expression;
|
|
12
|
+
// Check if the call is to addMCPTool
|
|
13
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPTool') {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!firstArg) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
20
|
+
const obj = firstArg;
|
|
21
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
22
|
+
const titleValue = getPropertyValue(obj, 'title');
|
|
23
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
24
|
+
const streamingValue = getPropertyValue(obj, 'streaming');
|
|
25
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
26
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
27
|
+
if (!funcInitializer) {
|
|
28
|
+
console.error(`• No valid 'func' property for MCP tool '${nameValue}'.`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
32
|
+
if (!nameValue) {
|
|
33
|
+
console.error(`• MCP tool is missing the required 'name' property.`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!descriptionValue) {
|
|
37
|
+
console.error(`• MCP tool '${nameValue}' is missing a description.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: nameValue })) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// lookup existing function metadata
|
|
44
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
45
|
+
if (!fnMeta) {
|
|
46
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
50
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
51
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
52
|
+
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
53
|
+
pikkuFuncName,
|
|
54
|
+
name: nameValue,
|
|
55
|
+
title: titleValue || undefined,
|
|
56
|
+
description: descriptionValue,
|
|
57
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
58
|
+
tags,
|
|
59
|
+
inputSchema,
|
|
60
|
+
outputSchema,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
|
+
export const addQueueWorker = (node, checker, state, filters) => {
|
|
6
|
+
if (!ts.isCallExpression(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const args = node.arguments;
|
|
10
|
+
const firstArg = args[0];
|
|
11
|
+
const expression = node.expression;
|
|
12
|
+
// Check if the call is to addQueueWorker
|
|
13
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addQueueWorker') {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!firstArg) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
20
|
+
const obj = firstArg;
|
|
21
|
+
const queueName = getPropertyValue(obj, 'queueName');
|
|
22
|
+
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
23
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
24
|
+
// --- find the referenced function ---
|
|
25
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
26
|
+
if (!funcInitializer) {
|
|
27
|
+
console.error(`• No valid 'func' property for queue processor '${queueName}'.`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
31
|
+
if (!queueName) {
|
|
32
|
+
console.error(`• No 'queueName' provided for queue processor function '${pikkuFuncName}'.`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.queue, name: queueName })) {
|
|
36
|
+
console.info(`• Skipping queue processor '${pikkuFuncName}' for queue '${queueName}' due to filter mismatch.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
state.queueWorkers.files.add(node.getSourceFile().fileName);
|
|
40
|
+
state.queueWorkers.meta[queueName] = {
|
|
41
|
+
pikkuFuncName,
|
|
42
|
+
queueName,
|
|
43
|
+
docs,
|
|
44
|
+
tags,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
package/dist/add-schedule.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
-
import {
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
4
5
|
export const addSchedule = (node, checker, state, filters) => {
|
|
5
6
|
if (!ts.isCallExpression(node)) {
|
|
6
7
|
return;
|
|
@@ -21,19 +22,16 @@ export const addSchedule = (node, checker, state, filters) => {
|
|
|
21
22
|
const scheduleValue = getPropertyValue(obj, 'schedule');
|
|
22
23
|
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
23
24
|
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
ts.isIdentifier(p.name) &&
|
|
27
|
-
p.name.text === 'func');
|
|
28
|
-
if (!funcProp || !ts.isIdentifier(funcProp.initializer)) {
|
|
25
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
26
|
+
if (!funcInitializer) {
|
|
29
27
|
console.error(`• No valid 'func' property for scheduled task '${nameValue}'.`);
|
|
30
28
|
return;
|
|
31
29
|
}
|
|
32
|
-
const pikkuFuncName = extractFunctionName(
|
|
30
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
33
31
|
if (!nameValue || !scheduleValue) {
|
|
34
32
|
return;
|
|
35
33
|
}
|
|
36
|
-
if (!matchesFilters(filters, { tags }, { type:
|
|
34
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.scheduled, name: nameValue })) {
|
|
37
35
|
return;
|
|
38
36
|
}
|
|
39
37
|
state.scheduledTasks.files.add(node.getSourceFile().fileName);
|
package/dist/inspector.js
CHANGED
|
@@ -36,9 +36,19 @@ export const inspect = (routeFiles, filters) => {
|
|
|
36
36
|
meta: {},
|
|
37
37
|
files: new Set(),
|
|
38
38
|
},
|
|
39
|
+
queueWorkers: {
|
|
40
|
+
meta: {},
|
|
41
|
+
files: new Set(),
|
|
42
|
+
},
|
|
39
43
|
rpc: {
|
|
40
44
|
meta: {},
|
|
41
45
|
},
|
|
46
|
+
mcpEndpoints: {
|
|
47
|
+
resourcesMeta: {},
|
|
48
|
+
toolsMeta: {},
|
|
49
|
+
promptsMeta: {},
|
|
50
|
+
files: new Set(),
|
|
51
|
+
},
|
|
42
52
|
};
|
|
43
53
|
// First sweep: add all functions
|
|
44
54
|
for (const sourceFile of sourceFiles) {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ChannelsMeta } from '@pikku/core/channel';
|
|
2
2
|
import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
3
3
|
import { ScheduledTasksMeta } from '@pikku/core/scheduler';
|
|
4
|
+
import { queueWorkersMeta } from '@pikku/core/queue';
|
|
5
|
+
import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core';
|
|
4
6
|
import { TypesMap } from './types-map.js';
|
|
5
7
|
import { FunctionsMeta } from '@pikku/core';
|
|
6
|
-
import { RPCMeta } from '
|
|
8
|
+
import { RPCMeta } from '@pikku/core/rpc';
|
|
7
9
|
export type PathToNameAndType = Map<string, {
|
|
8
10
|
variable: string;
|
|
9
11
|
type: string | null;
|
|
@@ -48,7 +50,17 @@ export interface InspectorState {
|
|
|
48
50
|
meta: ScheduledTasksMeta;
|
|
49
51
|
files: Set<string>;
|
|
50
52
|
};
|
|
53
|
+
queueWorkers: {
|
|
54
|
+
meta: queueWorkersMeta;
|
|
55
|
+
files: Set<string>;
|
|
56
|
+
};
|
|
51
57
|
rpc: {
|
|
52
58
|
meta: Record<string, RPCMeta>;
|
|
53
59
|
};
|
|
60
|
+
mcpEndpoints: {
|
|
61
|
+
resourcesMeta: MCPResourceMeta;
|
|
62
|
+
toolsMeta: MCPToolMeta;
|
|
63
|
+
promptsMeta: MCPPromptMeta;
|
|
64
|
+
files: Set<string>;
|
|
65
|
+
};
|
|
54
66
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { InspectorFilters } from './types.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
3
4
|
type ExtractedFunctionName = {
|
|
4
5
|
pikkuFuncName: string;
|
|
5
6
|
name: string;
|
|
@@ -27,7 +28,7 @@ export declare function getPropertyAssignmentInitializer(obj: ts.ObjectLiteralEx
|
|
|
27
28
|
export declare const matchesFilters: (filters: InspectorFilters, params: {
|
|
28
29
|
tags?: string[];
|
|
29
30
|
}, meta: {
|
|
30
|
-
type:
|
|
31
|
+
type: PikkuEventTypes;
|
|
31
32
|
name: string;
|
|
32
33
|
}) => boolean;
|
|
33
34
|
export {};
|
package/dist/visit.js
CHANGED
|
@@ -3,6 +3,10 @@ import { addFileWithFactory } from './add-file-with-factory.js';
|
|
|
3
3
|
import { addFileExtendsCoreType } from './add-file-extends-core-type.js';
|
|
4
4
|
import { addHTTPRoute } from './add-http-route.js';
|
|
5
5
|
import { addSchedule } from './add-schedule.js';
|
|
6
|
+
import { addQueueWorker } from './add-queue-worker.js';
|
|
7
|
+
import { addMCPResource } from './add-mcp-resource.js';
|
|
8
|
+
import { addMCPTool } from './add-mcp-tool.js';
|
|
9
|
+
import { addMCPPrompt } from './add-mcp-prompt.js';
|
|
6
10
|
import { addFunctions } from './add-functions.js';
|
|
7
11
|
import { addChannel } from './add-channel.js';
|
|
8
12
|
export const visitSetup = (checker, node, state, filters) => {
|
|
@@ -18,6 +22,10 @@ export const visitSetup = (checker, node, state, filters) => {
|
|
|
18
22
|
export const visitRoutes = (checker, node, state, filters) => {
|
|
19
23
|
addHTTPRoute(node, checker, state, filters);
|
|
20
24
|
addSchedule(node, checker, state, filters);
|
|
25
|
+
addQueueWorker(node, checker, state, filters);
|
|
21
26
|
addChannel(node, checker, state, filters);
|
|
27
|
+
addMCPResource(node, checker, state, filters);
|
|
28
|
+
addMCPTool(node, checker, state, filters);
|
|
29
|
+
addMCPPrompt(node, checker, state, filters);
|
|
22
30
|
ts.forEachChild(node, (child) => visitRoutes(checker, child, state, filters));
|
|
23
31
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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.0",
|
|
21
21
|
"path-to-regexp": "^8.2.0",
|
|
22
22
|
"typescript": "^5.6"
|
|
23
23
|
},
|
package/src/add-channel.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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,
|
|
@@ -391,7 +391,10 @@ export function addChannel(
|
|
|
391
391
|
const tags = getPropertyValue(obj, 'tags') as string[] | undefined
|
|
392
392
|
const query = getPropertyValue(obj, 'query') as string[] | []
|
|
393
393
|
|
|
394
|
-
if (
|
|
394
|
+
if (
|
|
395
|
+
!matchesFilters(filters, { tags }, { type: PikkuEventTypes.channel, name })
|
|
396
|
+
)
|
|
397
|
+
return
|
|
395
398
|
|
|
396
399
|
const connect = getPropertyAssignmentInitializer(
|
|
397
400
|
obj,
|
package/src/add-http-route.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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,
|
|
@@ -69,7 +69,13 @@ export const addHTTPRoute = (
|
|
|
69
69
|
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
70
70
|
const query = (getPropertyValue(obj, 'query') as string[]) || []
|
|
71
71
|
|
|
72
|
-
if (
|
|
72
|
+
if (
|
|
73
|
+
!matchesFilters(
|
|
74
|
+
filters,
|
|
75
|
+
{ tags },
|
|
76
|
+
{ type: PikkuEventTypes.http, name: route }
|
|
77
|
+
)
|
|
78
|
+
) {
|
|
73
79
|
return
|
|
74
80
|
}
|
|
75
81
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { getPropertyValue } from './get-property-value.js'
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core'
|
|
4
|
+
import { InspectorFilters, InspectorState } 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
|
+
) => {
|
|
17
|
+
if (!ts.isCallExpression(node)) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const args = node.arguments
|
|
22
|
+
const firstArg = args[0]
|
|
23
|
+
const expression = node.expression
|
|
24
|
+
|
|
25
|
+
// Check if the call is to addMCPPrompt
|
|
26
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addMCPPrompt') {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!firstArg) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
35
|
+
const obj = firstArg
|
|
36
|
+
|
|
37
|
+
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
38
|
+
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
39
|
+
| string
|
|
40
|
+
| null
|
|
41
|
+
const tags = (getPropertyValue(obj, 'tags') as string[]) || undefined
|
|
42
|
+
|
|
43
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
44
|
+
obj,
|
|
45
|
+
'func',
|
|
46
|
+
true,
|
|
47
|
+
checker
|
|
48
|
+
)
|
|
49
|
+
if (!funcInitializer) {
|
|
50
|
+
console.error(`• No valid 'func' property for MCP prompt '${nameValue}'.`)
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const pikkuFuncName = extractFunctionName(
|
|
55
|
+
funcInitializer,
|
|
56
|
+
checker
|
|
57
|
+
).pikkuFuncName
|
|
58
|
+
|
|
59
|
+
if (!nameValue) {
|
|
60
|
+
console.error(`• MCP prompt is missing the required 'name' property.`)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!descriptionValue) {
|
|
65
|
+
console.error(`• MCP prompt '${nameValue}' is missing a description.`)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
!matchesFilters(
|
|
71
|
+
filters,
|
|
72
|
+
{ tags },
|
|
73
|
+
{ type: PikkuEventTypes.mcp, name: nameValue }
|
|
74
|
+
)
|
|
75
|
+
) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// lookup existing function metadata
|
|
80
|
+
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
81
|
+
if (!fnMeta) {
|
|
82
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
const inputSchema = fnMeta.inputs?.[0] || null
|
|
86
|
+
const outputSchema = fnMeta.outputs?.[0] || null
|
|
87
|
+
|
|
88
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
89
|
+
|
|
90
|
+
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
91
|
+
pikkuFuncName,
|
|
92
|
+
name: nameValue,
|
|
93
|
+
description: descriptionValue,
|
|
94
|
+
tags,
|
|
95
|
+
inputSchema,
|
|
96
|
+
outputSchema,
|
|
97
|
+
arguments: [], // Will be populated by CLI during serialization
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|