@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @pikku/inspector
|
|
2
2
|
|
|
3
|
+
## 0.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 44e3ff4: feat: enhance CLI filtering with type and directory filters
|
|
8
|
+
|
|
9
|
+
- Add --types filter to filter by PikkuEventTypes (http, channel, queue, scheduler, rpc, mcp)
|
|
10
|
+
- Add --directories filter to filter by file paths/directories
|
|
11
|
+
- All filters (tags, types, directories) now work together with AND logic
|
|
12
|
+
- Add comprehensive logging interface to inspector package
|
|
13
|
+
- Add comprehensive test suite for matchesFilters function
|
|
14
|
+
- Support cross-platform path handling
|
|
15
|
+
|
|
16
|
+
- 7c592b8: feat: support for required services and improved service configuration
|
|
17
|
+
|
|
18
|
+
This release includes several enhancements to service management and configuration:
|
|
19
|
+
|
|
20
|
+
- Added support for required services configuration
|
|
21
|
+
- Improved service discovery and registration
|
|
22
|
+
- Added typed RPC clients for service communication
|
|
23
|
+
- Updated middleware to run per function
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [3261090]
|
|
26
|
+
- Updated dependencies [7c592b8]
|
|
27
|
+
- Updated dependencies [30a082f]
|
|
28
|
+
- @pikku/core@0.8.1
|
|
29
|
+
|
|
30
|
+
## 0.8.0
|
|
31
|
+
|
|
32
|
+
### Major Features
|
|
33
|
+
|
|
34
|
+
- **Model Context Protocol (MCP) Analysis**: Added comprehensive MCP endpoint analysis
|
|
35
|
+
- **Queue Worker Analysis**: Added queue analysis
|
|
36
|
+
- **Enhanced Service Analysis**: Added service destructuring analysis for better code generation and type safety
|
|
37
|
+
|
|
3
38
|
## 0.7.7
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
package/dist/add-channel.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import type { ChannelMeta } from '@pikku/core/channel';
|
|
3
|
-
import type { InspectorFilters, InspectorState } from './types.js';
|
|
3
|
+
import type { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Build out the nested message-routes by looking up each handler
|
|
6
6
|
* in state.functions.meta instead of re-inferring it here.
|
|
@@ -10,4 +10,4 @@ export declare function addMessagesRoutes(obj: ts.ObjectLiteralExpression, state
|
|
|
10
10
|
* Inspect addChannel calls, look up all handlers in state.functions.meta,
|
|
11
11
|
* and emit one entry into state.channels.meta.
|
|
12
12
|
*/
|
|
13
|
-
export declare function addChannel(node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters): void;
|
|
13
|
+
export declare function addChannel(node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger): void;
|
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:
|
|
@@ -266,7 +267,7 @@ export function addMessagesRoutes(obj, state, checker) {
|
|
|
266
267
|
* Inspect addChannel calls, look up all handlers in state.functions.meta,
|
|
267
268
|
* and emit one entry into state.channels.meta.
|
|
268
269
|
*/
|
|
269
|
-
export function addChannel(node, checker, state, filters) {
|
|
270
|
+
export function addChannel(node, checker, state, filters, logger) {
|
|
270
271
|
if (!ts.isCallExpression(node))
|
|
271
272
|
return;
|
|
272
273
|
const { expression, arguments: args } = node;
|
|
@@ -291,7 +292,8 @@ 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
|
-
|
|
295
|
+
const filePath = node.getSourceFile().fileName;
|
|
296
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.channel, name, filePath }, logger))
|
|
295
297
|
return;
|
|
296
298
|
const connect = getPropertyAssignmentInitializer(obj, 'onConnect', false, checker);
|
|
297
299
|
const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', false, checker);
|
package/dist/add-functions.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorState, InspectorFilters } from './types.js';
|
|
2
|
+
import { InspectorState, InspectorFilters, InspectorLogger } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Inspect pikkuFunc calls, extract input/output and first-arg destructuring,
|
|
5
5
|
* then push into state.functions.meta.
|
|
6
6
|
*/
|
|
7
|
-
export declare function addFunctions(node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters): void;
|
|
7
|
+
export declare function addFunctions(node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger): void;
|
package/dist/add-functions.js
CHANGED
|
@@ -171,7 +171,7 @@ function unwrapPromise(checker, type) {
|
|
|
171
171
|
* Inspect pikkuFunc calls, extract input/output and first-arg destructuring,
|
|
172
172
|
* then push into state.functions.meta.
|
|
173
173
|
*/
|
|
174
|
-
export function addFunctions(node, checker, state, filters) {
|
|
174
|
+
export function addFunctions(node, checker, state, filters, logger) {
|
|
175
175
|
if (!ts.isCallExpression(node))
|
|
176
176
|
return;
|
|
177
177
|
const { expression, arguments: args, typeArguments } = node;
|
|
@@ -226,8 +226,7 @@ export function addFunctions(node, checker, state, filters) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
|
-
else if (ts.isIdentifier(firstParam.name)
|
|
230
|
-
!firstParam.name.text.startsWith('_')) {
|
|
229
|
+
else if (ts.isIdentifier(firstParam.name)) {
|
|
231
230
|
services.optimized = false;
|
|
232
231
|
}
|
|
233
232
|
}
|
package/dist/add-http-route.d.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
|
/**
|
|
4
4
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
5
5
|
* query and params. Returns undefined (we only mutate metaTypes).
|
|
@@ -13,4 +13,4 @@ export declare const getInputTypes: (metaTypes: Map<string, {
|
|
|
13
13
|
* Simplified addHTTPRoute: re-uses function metadata from state.functions.meta
|
|
14
14
|
* instead of re-inferring types here.
|
|
15
15
|
*/
|
|
16
|
-
export declare const addHTTPRoute: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters) => void;
|
|
16
|
+
export declare const addHTTPRoute: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
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,
|
|
@@ -22,7 +23,7 @@ export const getInputTypes = (metaTypes, methodType, inputType, queryValues, par
|
|
|
22
23
|
* Simplified addHTTPRoute: re-uses function metadata from state.functions.meta
|
|
23
24
|
* instead of re-inferring types here.
|
|
24
25
|
*/
|
|
25
|
-
export const addHTTPRoute = (node, checker, state, filters) => {
|
|
26
|
+
export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
26
27
|
// only look at calls
|
|
27
28
|
if (!ts.isCallExpression(node))
|
|
28
29
|
return;
|
|
@@ -44,7 +45,8 @@ 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
|
-
|
|
48
|
+
const filePath = node.getSourceFile().fileName;
|
|
49
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.http, name: route, filePath }, logger)) {
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
50
52
|
// --- find the referenced function ---
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
3
|
+
export declare const addMCPPrompt: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
|
@@ -0,0 +1,61 @@
|
|
|
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, logger) => {
|
|
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
|
+
const filePath = node.getSourceFile().fileName;
|
|
39
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// lookup existing function metadata
|
|
43
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
44
|
+
if (!fnMeta) {
|
|
45
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
49
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
50
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
51
|
+
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
52
|
+
pikkuFuncName,
|
|
53
|
+
name: nameValue,
|
|
54
|
+
description: descriptionValue,
|
|
55
|
+
tags,
|
|
56
|
+
inputSchema,
|
|
57
|
+
outputSchema,
|
|
58
|
+
arguments: [], // Will be populated by CLI during serialization
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
3
|
+
export declare const addMCPResource: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
|
@@ -0,0 +1,68 @@
|
|
|
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, logger) => {
|
|
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
|
+
const filePath = node.getSourceFile().fileName;
|
|
45
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: uriValue, filePath }, logger)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// lookup existing function metadata
|
|
49
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
50
|
+
if (!fnMeta) {
|
|
51
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
55
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
56
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
57
|
+
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
58
|
+
pikkuFuncName,
|
|
59
|
+
uri: uriValue,
|
|
60
|
+
title: titleValue,
|
|
61
|
+
description: descriptionValue,
|
|
62
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
63
|
+
tags,
|
|
64
|
+
inputSchema,
|
|
65
|
+
outputSchema,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
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, logger) => {
|
|
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
|
+
const filePath = node.getSourceFile().fileName;
|
|
41
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// lookup existing function metadata
|
|
45
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
46
|
+
if (!fnMeta) {
|
|
47
|
+
console.error(`• No function metadata found for '${pikkuFuncName}'.`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
51
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
52
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
53
|
+
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
54
|
+
pikkuFuncName,
|
|
55
|
+
name: nameValue,
|
|
56
|
+
title: titleValue || undefined,
|
|
57
|
+
description: descriptionValue,
|
|
58
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
59
|
+
tags,
|
|
60
|
+
inputSchema,
|
|
61
|
+
outputSchema,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
3
|
+
export declare const addQueueWorker: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
|
@@ -0,0 +1,48 @@
|
|
|
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, logger) => {
|
|
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
|
+
const filePath = node.getSourceFile().fileName;
|
|
36
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.queue, name: queueName, filePath }, logger)) {
|
|
37
|
+
console.info(`• Skipping queue processor '${pikkuFuncName}' for queue '${queueName}' due to filter mismatch.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
state.queueWorkers.files.add(node.getSourceFile().fileName);
|
|
41
|
+
state.queueWorkers.meta[queueName] = {
|
|
42
|
+
pikkuFuncName,
|
|
43
|
+
queueName,
|
|
44
|
+
docs,
|
|
45
|
+
tags,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
package/dist/add-schedule.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorFilters, InspectorState } from './types.js';
|
|
3
|
-
export declare const addSchedule: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters) => void;
|
|
2
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
3
|
+
export declare const addSchedule: (node: ts.Node, checker: ts.TypeChecker, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
package/dist/add-schedule.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { getPropertyValue } from './get-property-value.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
4
|
+
import { extractFunctionName, getPropertyAssignmentInitializer, matchesFilters, } from './utils.js';
|
|
5
|
+
export const addSchedule = (node, checker, state, filters, logger) => {
|
|
5
6
|
if (!ts.isCallExpression(node)) {
|
|
6
7
|
return;
|
|
7
8
|
}
|
|
@@ -21,19 +22,17 @@ 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
|
-
|
|
34
|
+
const filePath = node.getSourceFile().fileName;
|
|
35
|
+
if (!matchesFilters(filters, { tags }, { type: PikkuEventTypes.scheduler, name: nameValue, filePath }, logger)) {
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
state.scheduledTasks.files.add(node.getSourceFile().fileName);
|
package/dist/inspector.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { InspectorState, InspectorHTTPState, InspectorFilters } from './types.js';
|
|
1
|
+
import { InspectorState, InspectorHTTPState, InspectorFilters, InspectorLogger } from './types.js';
|
|
2
2
|
export declare const normalizeHTTPTypes: (httpState: InspectorHTTPState) => InspectorHTTPState;
|
|
3
|
-
export declare const inspect: (routeFiles: string[], filters: InspectorFilters) => InspectorState;
|
|
3
|
+
export declare const inspect: (logger: InspectorLogger, routeFiles: string[], filters: InspectorFilters) => InspectorState;
|
package/dist/inspector.js
CHANGED
|
@@ -4,7 +4,7 @@ import { TypesMap } from './types-map.js';
|
|
|
4
4
|
export const normalizeHTTPTypes = (httpState) => {
|
|
5
5
|
return httpState;
|
|
6
6
|
};
|
|
7
|
-
export const inspect = (routeFiles, filters) => {
|
|
7
|
+
export const inspect = (logger, routeFiles, filters) => {
|
|
8
8
|
const program = ts.createProgram(routeFiles, {
|
|
9
9
|
target: ts.ScriptTarget.ESNext,
|
|
10
10
|
module: ts.ModuleKind.CommonJS,
|
|
@@ -36,17 +36,27 @@ 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) {
|
|
45
|
-
ts.forEachChild(sourceFile, (child) => visitSetup(checker, child, state, filters));
|
|
55
|
+
ts.forEachChild(sourceFile, (child) => visitSetup(checker, child, state, filters, logger));
|
|
46
56
|
}
|
|
47
57
|
// Second sweep: add all transports
|
|
48
58
|
for (const sourceFile of sourceFiles) {
|
|
49
|
-
ts.forEachChild(sourceFile, (child) => visitRoutes(checker, child, state, filters));
|
|
59
|
+
ts.forEachChild(sourceFile, (child) => visitRoutes(checker, child, state, filters, logger));
|
|
50
60
|
}
|
|
51
61
|
// Normalise the typesMap
|
|
52
62
|
state.http = normalizeHTTPTypes(state.http);
|
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;
|
|
@@ -33,7 +35,15 @@ export interface InspectorChannelState {
|
|
|
33
35
|
}
|
|
34
36
|
export type InspectorFilters = {
|
|
35
37
|
tags?: string[];
|
|
38
|
+
types?: string[];
|
|
39
|
+
directories?: string[];
|
|
36
40
|
};
|
|
41
|
+
export interface InspectorLogger {
|
|
42
|
+
info: (message: string) => void;
|
|
43
|
+
error: (message: string) => void;
|
|
44
|
+
warn: (message: string) => void;
|
|
45
|
+
debug: (message: string) => void;
|
|
46
|
+
}
|
|
37
47
|
export interface InspectorState {
|
|
38
48
|
singletonServicesTypeImportMap: PathToNameAndType;
|
|
39
49
|
sessionServicesTypeImportMap: PathToNameAndType;
|
|
@@ -48,7 +58,17 @@ export interface InspectorState {
|
|
|
48
58
|
meta: ScheduledTasksMeta;
|
|
49
59
|
files: Set<string>;
|
|
50
60
|
};
|
|
61
|
+
queueWorkers: {
|
|
62
|
+
meta: queueWorkersMeta;
|
|
63
|
+
files: Set<string>;
|
|
64
|
+
};
|
|
51
65
|
rpc: {
|
|
52
66
|
meta: Record<string, RPCMeta>;
|
|
53
67
|
};
|
|
68
|
+
mcpEndpoints: {
|
|
69
|
+
resourcesMeta: MCPResourceMeta;
|
|
70
|
+
toolsMeta: MCPToolMeta;
|
|
71
|
+
promptsMeta: MCPPromptMeta;
|
|
72
|
+
files: Set<string>;
|
|
73
|
+
};
|
|
54
74
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorFilters } from './types.js';
|
|
2
|
+
import { InspectorFilters, InspectorLogger } from './types.js';
|
|
3
|
+
import { PikkuEventTypes } from '@pikku/core';
|
|
3
4
|
type ExtractedFunctionName = {
|
|
4
5
|
pikkuFuncName: string;
|
|
5
6
|
name: string;
|
|
@@ -27,7 +28,8 @@ 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
|
+
filePath?: string;
|
|
34
|
+
}, logger: InspectorLogger) => boolean;
|
|
33
35
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -660,13 +660,48 @@ export function getPropertyAssignmentInitializer(obj, propName, followShorthand
|
|
|
660
660
|
}
|
|
661
661
|
return undefined;
|
|
662
662
|
}
|
|
663
|
-
export const matchesFilters = (filters, params, meta) => {
|
|
664
|
-
|
|
663
|
+
export const matchesFilters = (filters, params, meta, logger) => {
|
|
664
|
+
// If no filters are provided, allow everything
|
|
665
|
+
if (Object.keys(filters).length === 0) {
|
|
665
666
|
return true;
|
|
666
667
|
}
|
|
667
|
-
|
|
668
|
+
// If all filter arrays are empty, allow everything
|
|
669
|
+
if ((!filters.tags || filters.tags.length === 0) &&
|
|
670
|
+
(!filters.types || filters.types.length === 0) &&
|
|
671
|
+
(!filters.directories || filters.directories.length === 0)) {
|
|
668
672
|
return true;
|
|
669
673
|
}
|
|
670
|
-
|
|
671
|
-
|
|
674
|
+
// Check type filter
|
|
675
|
+
if (filters.types && filters.types.length > 0) {
|
|
676
|
+
if (!filters.types.includes(meta.type)) {
|
|
677
|
+
logger.debug(`⒡ Filtered by type: ${meta.type}:${meta.name}`);
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
// Check directory filter
|
|
682
|
+
if (filters.directories && filters.directories.length > 0) {
|
|
683
|
+
if (!meta.filePath) {
|
|
684
|
+
logger.debug(`⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`);
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
const matchesDirectory = filters.directories.some((dir) => {
|
|
688
|
+
// Normalize paths for comparison
|
|
689
|
+
const normalizedFilePath = meta.filePath.replace(/\\/g, '/');
|
|
690
|
+
const normalizedDir = dir.replace(/\\/g, '/');
|
|
691
|
+
return normalizedFilePath.includes(normalizedDir);
|
|
692
|
+
});
|
|
693
|
+
if (!matchesDirectory) {
|
|
694
|
+
logger.debug(`⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`);
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// Check tag filter
|
|
699
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
700
|
+
if (!params.tags ||
|
|
701
|
+
!filters.tags.some((tag) => params.tags.includes(tag))) {
|
|
702
|
+
logger.debug(`⒡ Filtered by tags: ${meta.type}:${meta.name}`);
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return true;
|
|
672
707
|
};
|
package/dist/visit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorFilters, InspectorState } from './types.js';
|
|
3
|
-
export declare const visitSetup: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters) => void;
|
|
4
|
-
export declare const visitRoutes: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters) => void;
|
|
2
|
+
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
|
|
3
|
+
export declare const visitSetup: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|
|
4
|
+
export declare const visitRoutes: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
|