@pikku/inspector 0.11.2 → 0.12.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 +11 -1
- package/OPTIMIZATION-PLAN.md +195 -0
- package/dist/add/add-ai-agent.d.ts +2 -0
- package/dist/add/add-ai-agent.js +314 -0
- package/dist/add/add-channel.js +69 -61
- package/dist/add/add-cli.js +36 -18
- package/dist/add/add-file-with-factory.js +2 -0
- package/dist/add/add-functions.js +250 -75
- package/dist/add/add-http-route.d.ts +19 -10
- package/dist/add/add-http-route.js +152 -66
- package/dist/add/add-http-routes.d.ts +5 -0
- package/dist/add/add-http-routes.js +159 -0
- package/dist/add/add-keyed-wiring.d.ts +12 -0
- package/dist/add/add-keyed-wiring.js +97 -0
- package/dist/add/add-mcp-prompt.js +14 -9
- package/dist/add/add-mcp-resource.js +14 -9
- package/dist/add/add-middleware.d.ts +1 -4
- package/dist/add/add-middleware.js +364 -79
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +152 -40
- package/dist/add/add-queue-worker.js +18 -12
- package/dist/add/add-rpc-invocations.js +14 -0
- package/dist/add/add-schedule.js +11 -5
- package/dist/add/add-secret.d.ts +3 -0
- package/dist/add/add-secret.js +82 -0
- package/dist/add/add-trigger.d.ts +2 -0
- package/dist/add/add-trigger.js +87 -0
- package/dist/add/add-variable.d.ts +1 -0
- package/dist/add/add-variable.js +8 -0
- package/dist/add/add-workflow-graph.d.ts +3 -2
- package/dist/add/add-workflow-graph.js +143 -406
- package/dist/add/add-workflow.js +6 -4
- package/dist/error-codes.d.ts +14 -1
- package/dist/error-codes.js +19 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +5 -4
- package/dist/inspector.d.ts +1 -1
- package/dist/inspector.js +91 -14
- package/dist/schema-generator.d.ts +1 -0
- package/dist/schema-generator.js +1 -0
- package/dist/types-map.js +10 -1
- package/dist/types.d.ts +163 -39
- package/dist/utils/compute-required-schemas.d.ts +4 -0
- package/dist/utils/compute-required-schemas.js +41 -0
- package/dist/utils/contract-hashes.d.ts +35 -0
- package/dist/utils/contract-hashes.js +202 -0
- package/dist/utils/custom-types-generator.d.ts +9 -0
- package/dist/utils/custom-types-generator.js +71 -0
- package/dist/utils/detect-schema-vendor.d.ts +22 -0
- package/dist/utils/detect-schema-vendor.js +76 -0
- package/dist/utils/ensure-function-metadata.d.ts +5 -2
- package/dist/utils/ensure-function-metadata.js +220 -6
- package/dist/utils/extract-function-name.d.ts +5 -16
- package/dist/utils/extract-function-name.js +86 -291
- package/dist/utils/extract-services.d.ts +2 -1
- package/dist/utils/extract-services.js +25 -1
- package/dist/utils/filter-inspector-state.js +107 -23
- package/dist/utils/get-property-value.d.ts +6 -1
- package/dist/utils/get-property-value.js +28 -3
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/utils/middleware.d.ts +7 -30
- package/dist/utils/middleware.js +80 -66
- package/dist/utils/permissions.d.ts +2 -2
- package/dist/utils/permissions.js +10 -10
- package/dist/utils/post-process.d.ts +9 -10
- package/dist/utils/post-process.js +231 -24
- package/dist/utils/resolve-external-package.d.ts +12 -0
- package/dist/utils/resolve-external-package.js +34 -0
- package/dist/utils/resolve-function-types.d.ts +6 -0
- package/dist/utils/resolve-function-types.js +29 -0
- package/dist/utils/resolve-identifier.d.ts +10 -0
- package/dist/utils/resolve-identifier.js +36 -0
- package/dist/utils/resolve-versions.d.ts +2 -0
- package/dist/utils/resolve-versions.js +78 -0
- package/dist/utils/schema-generator.d.ts +9 -0
- package/dist/utils/schema-generator.js +209 -0
- package/dist/utils/serialize-inspector-state.d.ts +59 -22
- package/dist/utils/serialize-inspector-state.js +92 -20
- package/dist/utils/serialize-mcp-json.d.ts +2 -0
- package/dist/utils/serialize-mcp-json.js +99 -0
- package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
- package/dist/utils/serialize-middleware-groups-meta.js +28 -0
- package/dist/utils/serialize-openapi-json.d.ts +85 -0
- package/dist/utils/serialize-openapi-json.js +151 -0
- package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
- package/dist/utils/serialize-permissions-groups-meta.js +31 -0
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
- package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
- package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
- package/dist/utils/workflow/graph/index.d.ts +2 -0
- package/dist/utils/workflow/graph/index.js +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
- package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
- package/dist/visit.js +11 -6
- package/package.json +14 -4
- package/src/add/add-ai-agent.ts +468 -0
- package/src/add/add-channel.ts +82 -79
- package/src/add/add-cli.ts +49 -20
- package/src/add/add-file-with-factory.ts +2 -0
- package/src/add/add-functions.ts +330 -86
- package/src/add/add-http-route.ts +245 -88
- package/src/add/add-http-routes.ts +228 -0
- package/src/add/add-keyed-wiring.ts +151 -0
- package/src/add/add-mcp-prompt.ts +26 -15
- package/src/add/add-mcp-resource.ts +27 -15
- package/src/add/add-middleware.ts +482 -80
- package/src/add/add-permission.ts +199 -40
- package/src/add/add-queue-worker.ts +24 -19
- package/src/add/add-rpc-invocations.ts +17 -0
- package/src/add/add-schedule.ts +16 -11
- package/src/add/add-secret.ts +140 -0
- package/src/add/add-trigger.ts +154 -0
- package/src/add/add-variable.ts +9 -0
- package/src/add/add-workflow-graph.ts +180 -522
- package/src/add/add-workflow.ts +5 -4
- package/src/error-codes.ts +24 -1
- package/src/index.ts +22 -13
- package/src/inspector.ts +129 -17
- package/src/schema-generator.ts +1 -0
- package/src/types-map.ts +12 -1
- package/src/types.ts +175 -58
- package/src/utils/compute-required-schemas.ts +49 -0
- package/src/utils/contract-hashes.test.ts +528 -0
- package/src/utils/contract-hashes.ts +290 -0
- package/src/utils/custom-types-generator.ts +88 -0
- package/src/utils/detect-schema-vendor.ts +90 -0
- package/src/utils/ensure-function-metadata.ts +324 -7
- package/src/utils/extract-function-name.ts +101 -351
- package/src/utils/extract-services.ts +35 -2
- package/src/utils/filter-inspector-state.test.ts +34 -20
- package/src/utils/filter-inspector-state.ts +140 -31
- package/src/utils/get-property-value.ts +42 -4
- package/src/utils/hash.ts +26 -0
- package/src/utils/middleware.test.ts +204 -0
- package/src/utils/middleware.ts +129 -67
- package/src/utils/permissions.test.ts +35 -12
- package/src/utils/permissions.ts +10 -10
- package/src/utils/post-process.ts +283 -43
- package/src/utils/resolve-external-package.ts +42 -0
- package/src/utils/resolve-function-types.ts +42 -0
- package/src/utils/resolve-identifier.ts +46 -0
- package/src/utils/resolve-versions.test.ts +249 -0
- package/src/utils/resolve-versions.ts +105 -0
- package/src/utils/schema-generator.ts +329 -0
- package/src/utils/serialize-inspector-state.ts +163 -40
- package/src/utils/serialize-mcp-json.ts +145 -0
- package/src/utils/serialize-middleware-groups-meta.ts +33 -0
- package/src/utils/serialize-openapi-json.ts +277 -0
- package/src/utils/serialize-permissions-groups-meta.ts +35 -0
- package/src/utils/test-data/inspector-state.json +69 -66
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +24 -4
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
- package/src/utils/workflow/graph/index.ts +5 -0
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
- package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
- package/src/visit.ts +12 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add/add-forge-credential.d.ts +0 -8
- package/dist/add/add-forge-credential.js +0 -77
- package/dist/add/add-forge-node.d.ts +0 -7
- package/dist/add/add-forge-node.js +0 -77
- package/dist/add/add-mcp-tool.d.ts +0 -2
- package/dist/add/add-mcp-tool.js +0 -81
- package/dist/utils/extract-service-metadata.d.ts +0 -19
- package/dist/utils/extract-service-metadata.js +0 -244
- package/dist/utils/write-service-metadata.d.ts +0 -13
- package/dist/utils/write-service-metadata.js +0 -37
- package/src/add/add-forge-credential.ts +0 -119
- package/src/add/add-forge-node.ts +0 -132
- package/src/add/add-mcp-tool.ts +0 -141
- package/src/utils/extract-service-metadata.ts +0 -353
- package/src/utils/write-service-metadata.ts +0 -51
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
|
-
import { ErrorCode } from '../error-codes.js';
|
|
4
|
-
/**
|
|
5
|
-
* Inspector for wireForgeCredential calls.
|
|
6
|
-
* Extracts metadata for Forge package credential declarations.
|
|
7
|
-
* Note: wireForgeCredential is metadata-only - no runtime behavior.
|
|
8
|
-
* Schema is stored as the variable name reference; actual Zod→JSON Schema conversion happens at CLI build time.
|
|
9
|
-
*/
|
|
10
|
-
export const addForgeCredential = (logger, node, _checker, state, _options) => {
|
|
11
|
-
if (!ts.isCallExpression(node)) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const args = node.arguments;
|
|
15
|
-
const firstArg = args[0];
|
|
16
|
-
const expression = node.expression;
|
|
17
|
-
// Check if the call is to wireForgeCredential
|
|
18
|
-
if (!ts.isIdentifier(expression) ||
|
|
19
|
-
expression.text !== 'wireForgeCredential') {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
if (!firstArg) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
26
|
-
const obj = firstArg;
|
|
27
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
28
|
-
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
29
|
-
const descriptionValue = getPropertyValue(obj, 'description');
|
|
30
|
-
const secretIdValue = getPropertyValue(obj, 'secretId');
|
|
31
|
-
// Get schema variable name for later runtime import
|
|
32
|
-
let schemaVariableName = null;
|
|
33
|
-
for (const prop of obj.properties) {
|
|
34
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
35
|
-
ts.isIdentifier(prop.name) &&
|
|
36
|
-
prop.name.text === 'schema') {
|
|
37
|
-
if (ts.isIdentifier(prop.initializer)) {
|
|
38
|
-
schemaVariableName = prop.initializer.text;
|
|
39
|
-
}
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
// Validate required fields
|
|
44
|
-
if (!nameValue) {
|
|
45
|
-
logger.critical(ErrorCode.MISSING_NAME, "Forge credential is missing the required 'name' property.");
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (!displayNameValue) {
|
|
49
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'displayName' property.`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (!secretIdValue) {
|
|
53
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'secretId' property.`);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (!schemaVariableName) {
|
|
57
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'schema' property or schema is not a variable reference.`);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const sourceFile = node.getSourceFile().fileName;
|
|
61
|
-
state.forgeCredentials.files.add(sourceFile);
|
|
62
|
-
// Register the zod schema in the central zodLookup for deferred conversion
|
|
63
|
-
const schemaLookupName = `ForgeCredential_${nameValue}`;
|
|
64
|
-
state.zodLookup.set(schemaLookupName, {
|
|
65
|
-
variableName: schemaVariableName,
|
|
66
|
-
sourceFile,
|
|
67
|
-
});
|
|
68
|
-
// Store metadata - schema conversion happens later in schema-generator
|
|
69
|
-
state.forgeCredentials.meta[nameValue] = {
|
|
70
|
-
name: nameValue,
|
|
71
|
-
displayName: displayNameValue,
|
|
72
|
-
description: descriptionValue || undefined,
|
|
73
|
-
secretId: secretIdValue,
|
|
74
|
-
schema: schemaLookupName,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
|
-
import { ErrorCode } from '../error-codes.js';
|
|
4
|
-
/**
|
|
5
|
-
* Inspector for wireForgeNode calls.
|
|
6
|
-
* Extracts metadata for Forge workflow builder nodes.
|
|
7
|
-
* Note: wireForgeNode is metadata-only - no runtime behavior.
|
|
8
|
-
*/
|
|
9
|
-
export const addForgeNode = (logger, node, checker, state, _options) => {
|
|
10
|
-
if (!ts.isCallExpression(node)) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const args = node.arguments;
|
|
14
|
-
const firstArg = args[0];
|
|
15
|
-
const expression = node.expression;
|
|
16
|
-
// Check if the call is to wireForgeNode
|
|
17
|
-
if (!ts.isIdentifier(expression) || expression.text !== 'wireForgeNode') {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (!firstArg) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
24
|
-
const obj = firstArg;
|
|
25
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
26
|
-
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
27
|
-
const categoryValue = getPropertyValue(obj, 'category');
|
|
28
|
-
const typeValue = getPropertyValue(obj, 'type');
|
|
29
|
-
const rpcValue = getPropertyValue(obj, 'rpc');
|
|
30
|
-
const errorOutputValue = getPropertyValue(obj, 'errorOutput');
|
|
31
|
-
const { tags, description } = getCommonWireMetaData(obj, 'Forge node', nameValue, logger);
|
|
32
|
-
// Validate required fields
|
|
33
|
-
if (!nameValue) {
|
|
34
|
-
logger.critical(ErrorCode.MISSING_NAME, "Forge node is missing the required 'name' property.");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!displayNameValue) {
|
|
38
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'displayName' property.`);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!categoryValue) {
|
|
42
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'category' property.`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (!typeValue) {
|
|
46
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'type' property.`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (!['trigger', 'action', 'end'].includes(typeValue)) {
|
|
50
|
-
logger.critical(ErrorCode.INVALID_VALUE, `Forge node '${nameValue}' has invalid type '${typeValue}'. Must be 'trigger', 'action', or 'end'.`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (!rpcValue) {
|
|
54
|
-
logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'rpc' property.`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
// Get function metadata for input/output schemas
|
|
58
|
-
const fnMeta = state.functions.meta[rpcValue];
|
|
59
|
-
const inputSchemaName = fnMeta?.inputs?.[0] || null;
|
|
60
|
-
const outputSchemaName = fnMeta?.outputs?.[0] || null;
|
|
61
|
-
// Note: Category validation against forge.node.categories config
|
|
62
|
-
// is done at CLI build time, not during inspection
|
|
63
|
-
state.forgeNodes.files.add(node.getSourceFile().fileName);
|
|
64
|
-
state.forgeNodes.meta[nameValue] = {
|
|
65
|
-
name: nameValue,
|
|
66
|
-
displayName: displayNameValue,
|
|
67
|
-
category: categoryValue,
|
|
68
|
-
type: typeValue,
|
|
69
|
-
rpc: rpcValue,
|
|
70
|
-
description,
|
|
71
|
-
errorOutput: errorOutputValue ?? false,
|
|
72
|
-
inputSchemaName,
|
|
73
|
-
outputSchemaName,
|
|
74
|
-
tags,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
};
|
package/dist/add/add-mcp-tool.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
|
-
import { extractWireNames } from '../utils/post-process.js';
|
|
4
|
-
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
5
|
-
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
6
|
-
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
7
|
-
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
-
import { resolvePermissions } from '../utils/permissions.js';
|
|
9
|
-
import { ErrorCode } from '../error-codes.js';
|
|
10
|
-
export const addMCPTool = (logger, node, checker, state, options) => {
|
|
11
|
-
if (!ts.isCallExpression(node)) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const args = node.arguments;
|
|
15
|
-
const firstArg = args[0];
|
|
16
|
-
const expression = node.expression;
|
|
17
|
-
// Check if the call is to wireMCPTool
|
|
18
|
-
if (!ts.isIdentifier(expression) || expression.text !== 'wireMCPTool') {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (!firstArg) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
25
|
-
const obj = firstArg;
|
|
26
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
27
|
-
const titleValue = getPropertyValue(obj, 'title');
|
|
28
|
-
const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'MCP tool', nameValue, logger);
|
|
29
|
-
const streamingValue = getPropertyValue(obj, 'streaming');
|
|
30
|
-
if (streamingValue === true) {
|
|
31
|
-
logger.warn(`MCP tool '${nameValue}' has streaming enabled, but streaming is not yet supported.`);
|
|
32
|
-
}
|
|
33
|
-
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
34
|
-
if (!funcInitializer) {
|
|
35
|
-
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for MCP tool '${nameValue}'.`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const pikkuFuncName = extractFunctionName(funcInitializer, checker, state.rootDir).pikkuFuncName;
|
|
39
|
-
// Ensure function metadata exists (creates stub for inline functions)
|
|
40
|
-
ensureFunctionMetadata(state, pikkuFuncName, nameValue || undefined);
|
|
41
|
-
if (!nameValue) {
|
|
42
|
-
logger.critical(ErrorCode.MISSING_NAME, "MCP tool is missing the required 'name' property.");
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (!description) {
|
|
46
|
-
logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP tool '${nameValue}' is missing a description.`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
// lookup existing function metadata
|
|
50
|
-
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
51
|
-
if (!fnMeta) {
|
|
52
|
-
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${pikkuFuncName}'.`);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
56
|
-
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
57
|
-
// --- resolve middleware ---
|
|
58
|
-
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
59
|
-
// --- resolve permissions ---
|
|
60
|
-
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
61
|
-
// --- track used functions/middleware/permissions for service aggregation ---
|
|
62
|
-
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
63
|
-
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
64
|
-
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
65
|
-
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
66
|
-
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
67
|
-
pikkuFuncName,
|
|
68
|
-
name: nameValue,
|
|
69
|
-
title: titleValue || undefined,
|
|
70
|
-
description,
|
|
71
|
-
summary,
|
|
72
|
-
errors,
|
|
73
|
-
...(streamingValue !== null && { streaming: streamingValue }),
|
|
74
|
-
tags,
|
|
75
|
-
inputSchema,
|
|
76
|
-
outputSchema,
|
|
77
|
-
middleware,
|
|
78
|
-
permissions,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
export interface ServiceMetadata {
|
|
3
|
-
name: string;
|
|
4
|
-
summary: string;
|
|
5
|
-
description: string;
|
|
6
|
-
package: string;
|
|
7
|
-
path: string;
|
|
8
|
-
version: string;
|
|
9
|
-
interface: string;
|
|
10
|
-
expandedProperties: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Extract metadata for a service from its TypeScript declaration
|
|
14
|
-
*/
|
|
15
|
-
export declare function extractServiceMetadata(serviceName: string, type: ts.Type, checker: ts.TypeChecker, rootDir: string): ServiceMetadata | null;
|
|
16
|
-
/**
|
|
17
|
-
* Extract metadata for all services in a type
|
|
18
|
-
*/
|
|
19
|
-
export declare function extractAllServiceMetadata(servicesType: ts.Type, checker: ts.TypeChecker, rootDir: string): ServiceMetadata[];
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
/**
|
|
5
|
-
* Extract JSDoc comment information from a TypeScript node
|
|
6
|
-
*/
|
|
7
|
-
function extractJSDoc(node) {
|
|
8
|
-
const jsDocTags = ts.getJSDocTags(node);
|
|
9
|
-
const jsDocComments = ts.getJSDocCommentsAndTags(node);
|
|
10
|
-
let summary = '';
|
|
11
|
-
let description = '';
|
|
12
|
-
const summaryTag = jsDocTags.find((tag) => tag.tagName.text === 'summary');
|
|
13
|
-
if (summaryTag && summaryTag.comment) {
|
|
14
|
-
summary =
|
|
15
|
-
typeof summaryTag.comment === 'string'
|
|
16
|
-
? summaryTag.comment
|
|
17
|
-
: summaryTag.comment.map((c) => c.text).join('');
|
|
18
|
-
}
|
|
19
|
-
for (const comment of jsDocComments) {
|
|
20
|
-
if (ts.isJSDoc(comment) && comment.comment) {
|
|
21
|
-
const commentText = typeof comment.comment === 'string'
|
|
22
|
-
? comment.comment
|
|
23
|
-
: comment.comment.map((c) => c.text).join('');
|
|
24
|
-
if (!summary && commentText) {
|
|
25
|
-
const lines = commentText
|
|
26
|
-
.split('\n')
|
|
27
|
-
.map((l) => l.trim())
|
|
28
|
-
.filter(Boolean);
|
|
29
|
-
if (lines.length > 0) {
|
|
30
|
-
summary = lines[0];
|
|
31
|
-
if (lines.length > 1) {
|
|
32
|
-
description = lines.slice(1).join('\n').trim();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
description = commentText;
|
|
38
|
-
}
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return { summary, description };
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Serialize a TypeScript type to a string representation
|
|
46
|
-
*/
|
|
47
|
-
function serializeTypeToString(node, sourceFile, checker) {
|
|
48
|
-
const nodeSourceFile = node.getSourceFile();
|
|
49
|
-
if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
|
|
50
|
-
return node.getText(nodeSourceFile);
|
|
51
|
-
}
|
|
52
|
-
if (ts.isClassDeclaration(node)) {
|
|
53
|
-
return serializePublicClassMembers(node, nodeSourceFile, checker);
|
|
54
|
-
}
|
|
55
|
-
const type = checker.getTypeAtLocation(node);
|
|
56
|
-
return checker.typeToString(type, node, ts.TypeFormatFlags.NoTruncation);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Extract public members from a class and serialize them
|
|
60
|
-
*/
|
|
61
|
-
function serializePublicClassMembers(classNode, sourceFile, checker) {
|
|
62
|
-
const className = classNode.name?.text || 'UnnamedClass';
|
|
63
|
-
const publicMembers = [];
|
|
64
|
-
for (const member of classNode.members) {
|
|
65
|
-
const modifiers = ts.canHaveModifiers(member)
|
|
66
|
-
? ts.getModifiers(member)
|
|
67
|
-
: undefined;
|
|
68
|
-
const isPublic = !modifiers?.some((mod) => mod.kind === ts.SyntaxKind.PrivateKeyword ||
|
|
69
|
-
mod.kind === ts.SyntaxKind.ProtectedKeyword);
|
|
70
|
-
if (!isPublic)
|
|
71
|
-
continue;
|
|
72
|
-
if (ts.isMethodDeclaration(member) ||
|
|
73
|
-
ts.isPropertyDeclaration(member) ||
|
|
74
|
-
ts.isConstructorDeclaration(member)) {
|
|
75
|
-
const memberSignature = getMemberSignature(member, sourceFile, checker);
|
|
76
|
-
if (memberSignature) {
|
|
77
|
-
publicMembers.push(memberSignature);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return `class ${className} {\n ${publicMembers.join('\n ')}\n}`;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Extract a clean signature for a class member (without implementation)
|
|
85
|
-
*/
|
|
86
|
-
function getMemberSignature(member, sourceFile, checker) {
|
|
87
|
-
if (ts.isPropertyDeclaration(member)) {
|
|
88
|
-
const name = member.name.getText(sourceFile);
|
|
89
|
-
const type = member.type ? member.type.getText(sourceFile) : 'any';
|
|
90
|
-
const optional = member.questionToken ? '?' : '';
|
|
91
|
-
return `${name}${optional}: ${type};`;
|
|
92
|
-
}
|
|
93
|
-
if (ts.isMethodDeclaration(member)) {
|
|
94
|
-
const name = member.name.getText(sourceFile);
|
|
95
|
-
const typeParams = member.typeParameters
|
|
96
|
-
? `<${member.typeParameters.map((tp) => tp.getText(sourceFile)).join(', ')}>`
|
|
97
|
-
: '';
|
|
98
|
-
const params = member.parameters
|
|
99
|
-
.map((p) => p.getText(sourceFile))
|
|
100
|
-
.join(', ');
|
|
101
|
-
const returnType = member.type ? member.type.getText(sourceFile) : 'void';
|
|
102
|
-
const optional = member.questionToken ? '?' : '';
|
|
103
|
-
return `${name}${optional}${typeParams}(${params}): ${returnType};`;
|
|
104
|
-
}
|
|
105
|
-
if (ts.isConstructorDeclaration(member)) {
|
|
106
|
-
const params = member.parameters
|
|
107
|
-
.map((p) => p.getText(sourceFile))
|
|
108
|
-
.join(', ');
|
|
109
|
-
return `constructor(${params});`;
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Find the nearest package.json and extract package name and version
|
|
115
|
-
*/
|
|
116
|
-
function getPackageInfo(filePath) {
|
|
117
|
-
let currentDir = path.dirname(filePath);
|
|
118
|
-
const root = path.parse(currentDir).root;
|
|
119
|
-
while (currentDir !== root) {
|
|
120
|
-
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
121
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
122
|
-
try {
|
|
123
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
124
|
-
return {
|
|
125
|
-
packageName: packageJson.name || 'unknown',
|
|
126
|
-
version: packageJson.version || '0.0.0',
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
// If we can't parse the package.json, continue searching
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
currentDir = path.dirname(currentDir);
|
|
134
|
-
}
|
|
135
|
-
return { packageName: 'unknown', version: '0.0.0' };
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Expand a type to show all its properties including inherited ones
|
|
139
|
-
* Returns a Record mapping property names to their type strings
|
|
140
|
-
*/
|
|
141
|
-
function expandInterfaceProperties(type, checker, maxDepth = 2, currentDepth = 0, visited = new Set()) {
|
|
142
|
-
const result = {};
|
|
143
|
-
if (visited.has(type) || currentDepth >= maxDepth) {
|
|
144
|
-
return result;
|
|
145
|
-
}
|
|
146
|
-
visited.add(type);
|
|
147
|
-
const properties = type.getProperties();
|
|
148
|
-
for (const prop of properties) {
|
|
149
|
-
const propName = prop.getName();
|
|
150
|
-
const propDecl = prop.valueDeclaration || prop.declarations?.[0];
|
|
151
|
-
if (!propDecl)
|
|
152
|
-
continue;
|
|
153
|
-
try {
|
|
154
|
-
const propType = checker.getTypeOfSymbolAtLocation(prop, propDecl);
|
|
155
|
-
const isOptional = !!(prop.flags & ts.SymbolFlags.Optional);
|
|
156
|
-
let typeString = checker.typeToString(propType, propDecl, ts.TypeFormatFlags.NoTruncation |
|
|
157
|
-
ts.TypeFormatFlags.UseFullyQualifiedType);
|
|
158
|
-
if (isOptional && !typeString.includes('undefined')) {
|
|
159
|
-
typeString = `${typeString} | undefined`;
|
|
160
|
-
}
|
|
161
|
-
result[propName] = typeString;
|
|
162
|
-
}
|
|
163
|
-
catch (err) {
|
|
164
|
-
result[propName] = 'any';
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Extract metadata for a service from its TypeScript declaration
|
|
171
|
-
*/
|
|
172
|
-
export function extractServiceMetadata(serviceName, type, checker, rootDir) {
|
|
173
|
-
const property = type.getProperty(serviceName);
|
|
174
|
-
if (!property) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
const declaration = property.valueDeclaration || property.declarations?.[0];
|
|
178
|
-
if (!declaration) {
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
const sourceFile = declaration.getSourceFile();
|
|
182
|
-
const filePath = sourceFile.fileName;
|
|
183
|
-
const serviceType = checker.getTypeOfSymbolAtLocation(property, declaration);
|
|
184
|
-
let typeDeclaration = null;
|
|
185
|
-
if (serviceType.symbol) {
|
|
186
|
-
const typeDecl = serviceType.symbol.valueDeclaration ||
|
|
187
|
-
serviceType.symbol.declarations?.[0];
|
|
188
|
-
if (typeDecl &&
|
|
189
|
-
(ts.isInterfaceDeclaration(typeDecl) ||
|
|
190
|
-
ts.isClassDeclaration(typeDecl) ||
|
|
191
|
-
ts.isTypeAliasDeclaration(typeDecl))) {
|
|
192
|
-
typeDeclaration = typeDecl;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
let summary = '';
|
|
196
|
-
let description = '';
|
|
197
|
-
if (typeDeclaration) {
|
|
198
|
-
const jsDoc = extractJSDoc(typeDeclaration);
|
|
199
|
-
summary = jsDoc.summary;
|
|
200
|
-
description = jsDoc.description;
|
|
201
|
-
}
|
|
202
|
-
else if (ts.isPropertySignature(declaration) ||
|
|
203
|
-
ts.isPropertyDeclaration(declaration)) {
|
|
204
|
-
const jsDoc = extractJSDoc(declaration);
|
|
205
|
-
summary = jsDoc.summary;
|
|
206
|
-
description = jsDoc.description;
|
|
207
|
-
}
|
|
208
|
-
let interfaceString = '';
|
|
209
|
-
if (typeDeclaration) {
|
|
210
|
-
interfaceString = serializeTypeToString(typeDeclaration, sourceFile, checker);
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
interfaceString = checker.typeToString(serviceType, declaration, ts.TypeFormatFlags.NoTruncation);
|
|
214
|
-
}
|
|
215
|
-
const { packageName, version } = getPackageInfo(filePath);
|
|
216
|
-
const relativePath = path.relative(rootDir, filePath);
|
|
217
|
-
const expandedProperties = expandInterfaceProperties(serviceType, checker);
|
|
218
|
-
return {
|
|
219
|
-
name: serviceName,
|
|
220
|
-
summary,
|
|
221
|
-
description,
|
|
222
|
-
package: packageName,
|
|
223
|
-
path: relativePath,
|
|
224
|
-
version,
|
|
225
|
-
interface: interfaceString,
|
|
226
|
-
expandedProperties,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Extract metadata for all services in a type
|
|
231
|
-
*/
|
|
232
|
-
export function extractAllServiceMetadata(servicesType, checker, rootDir) {
|
|
233
|
-
const metadata = [];
|
|
234
|
-
const serviceNames = servicesType
|
|
235
|
-
.getProperties()
|
|
236
|
-
.map((prop) => prop.getName());
|
|
237
|
-
for (const serviceName of serviceNames) {
|
|
238
|
-
const serviceMeta = extractServiceMetadata(serviceName, servicesType, checker, rootDir);
|
|
239
|
-
if (serviceMeta) {
|
|
240
|
-
metadata.push(serviceMeta);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return metadata;
|
|
244
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ServiceMetadata } from './extract-service-metadata.js';
|
|
2
|
-
/**
|
|
3
|
-
* Write service metadata to a JSON file in .pikku/services directory
|
|
4
|
-
*/
|
|
5
|
-
export declare function writeServiceMetadata(serviceMeta: ServiceMetadata, outDir: string): void;
|
|
6
|
-
/**
|
|
7
|
-
* Write all service metadata files
|
|
8
|
-
*/
|
|
9
|
-
export declare function writeAllServiceMetadata(servicesMetadata: ServiceMetadata[], outDir: string): void;
|
|
10
|
-
/**
|
|
11
|
-
* Clean up services directory (remove old service JSON files)
|
|
12
|
-
*/
|
|
13
|
-
export declare function cleanServicesDirectory(outDir: string): void;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
/**
|
|
4
|
-
* Write service metadata to a JSON file in .pikku/services directory
|
|
5
|
-
*/
|
|
6
|
-
export function writeServiceMetadata(serviceMeta, outDir) {
|
|
7
|
-
const servicesDir = path.join(outDir, 'services');
|
|
8
|
-
if (!fs.existsSync(servicesDir)) {
|
|
9
|
-
fs.mkdirSync(servicesDir, { recursive: true });
|
|
10
|
-
}
|
|
11
|
-
const fileName = `${serviceMeta.name}.gen.json`;
|
|
12
|
-
const filePath = path.join(servicesDir, fileName);
|
|
13
|
-
const jsonContent = JSON.stringify(serviceMeta, null, 2);
|
|
14
|
-
fs.writeFileSync(filePath, jsonContent, 'utf-8');
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Write all service metadata files
|
|
18
|
-
*/
|
|
19
|
-
export function writeAllServiceMetadata(servicesMetadata, outDir) {
|
|
20
|
-
for (const serviceMeta of servicesMetadata) {
|
|
21
|
-
writeServiceMetadata(serviceMeta, outDir);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Clean up services directory (remove old service JSON files)
|
|
26
|
-
*/
|
|
27
|
-
export function cleanServicesDirectory(outDir) {
|
|
28
|
-
const servicesDir = path.join(outDir, 'services');
|
|
29
|
-
if (fs.existsSync(servicesDir)) {
|
|
30
|
-
const files = fs.readdirSync(servicesDir);
|
|
31
|
-
for (const file of files) {
|
|
32
|
-
if (file.endsWith('.gen.json')) {
|
|
33
|
-
fs.unlinkSync(path.join(servicesDir, file));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import { getPropertyValue } from '../utils/get-property-value.js'
|
|
3
|
-
import { AddWiring } from '../types.js'
|
|
4
|
-
import { ErrorCode } from '../error-codes.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Inspector for wireForgeCredential calls.
|
|
8
|
-
* Extracts metadata for Forge package credential declarations.
|
|
9
|
-
* Note: wireForgeCredential is metadata-only - no runtime behavior.
|
|
10
|
-
* Schema is stored as the variable name reference; actual Zod→JSON Schema conversion happens at CLI build time.
|
|
11
|
-
*/
|
|
12
|
-
export const addForgeCredential: AddWiring = (
|
|
13
|
-
logger,
|
|
14
|
-
node,
|
|
15
|
-
_checker,
|
|
16
|
-
state,
|
|
17
|
-
_options
|
|
18
|
-
) => {
|
|
19
|
-
if (!ts.isCallExpression(node)) {
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const args = node.arguments
|
|
24
|
-
const firstArg = args[0]
|
|
25
|
-
const expression = node.expression
|
|
26
|
-
|
|
27
|
-
// Check if the call is to wireForgeCredential
|
|
28
|
-
if (
|
|
29
|
-
!ts.isIdentifier(expression) ||
|
|
30
|
-
expression.text !== 'wireForgeCredential'
|
|
31
|
-
) {
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!firstArg) {
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
40
|
-
const obj = firstArg
|
|
41
|
-
|
|
42
|
-
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
43
|
-
const displayNameValue = getPropertyValue(obj, 'displayName') as
|
|
44
|
-
| string
|
|
45
|
-
| null
|
|
46
|
-
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
47
|
-
| string
|
|
48
|
-
| null
|
|
49
|
-
const secretIdValue = getPropertyValue(obj, 'secretId') as string | null
|
|
50
|
-
|
|
51
|
-
// Get schema variable name for later runtime import
|
|
52
|
-
let schemaVariableName: string | null = null
|
|
53
|
-
for (const prop of obj.properties) {
|
|
54
|
-
if (
|
|
55
|
-
ts.isPropertyAssignment(prop) &&
|
|
56
|
-
ts.isIdentifier(prop.name) &&
|
|
57
|
-
prop.name.text === 'schema'
|
|
58
|
-
) {
|
|
59
|
-
if (ts.isIdentifier(prop.initializer)) {
|
|
60
|
-
schemaVariableName = prop.initializer.text
|
|
61
|
-
}
|
|
62
|
-
break
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Validate required fields
|
|
67
|
-
if (!nameValue) {
|
|
68
|
-
logger.critical(
|
|
69
|
-
ErrorCode.MISSING_NAME,
|
|
70
|
-
"Forge credential is missing the required 'name' property."
|
|
71
|
-
)
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!displayNameValue) {
|
|
76
|
-
logger.critical(
|
|
77
|
-
ErrorCode.MISSING_NAME,
|
|
78
|
-
`Forge credential '${nameValue}' is missing the required 'displayName' property.`
|
|
79
|
-
)
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!secretIdValue) {
|
|
84
|
-
logger.critical(
|
|
85
|
-
ErrorCode.MISSING_NAME,
|
|
86
|
-
`Forge credential '${nameValue}' is missing the required 'secretId' property.`
|
|
87
|
-
)
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!schemaVariableName) {
|
|
92
|
-
logger.critical(
|
|
93
|
-
ErrorCode.MISSING_NAME,
|
|
94
|
-
`Forge credential '${nameValue}' is missing the required 'schema' property or schema is not a variable reference.`
|
|
95
|
-
)
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const sourceFile = node.getSourceFile().fileName
|
|
100
|
-
|
|
101
|
-
state.forgeCredentials.files.add(sourceFile)
|
|
102
|
-
|
|
103
|
-
// Register the zod schema in the central zodLookup for deferred conversion
|
|
104
|
-
const schemaLookupName = `ForgeCredential_${nameValue}`
|
|
105
|
-
state.zodLookup.set(schemaLookupName, {
|
|
106
|
-
variableName: schemaVariableName,
|
|
107
|
-
sourceFile,
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
// Store metadata - schema conversion happens later in schema-generator
|
|
111
|
-
state.forgeCredentials.meta[nameValue] = {
|
|
112
|
-
name: nameValue,
|
|
113
|
-
displayName: displayNameValue,
|
|
114
|
-
description: descriptionValue || undefined,
|
|
115
|
-
secretId: secretIdValue,
|
|
116
|
-
schema: schemaLookupName,
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|