@pikku/inspector 0.12.8 → 0.12.10
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 +27 -0
- package/dist/add/add-functions.js +5 -3
- package/dist/add/add-mcp-prompt.js +4 -0
- package/dist/add/add-mcp-resource.js +4 -0
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/add/add-workflow.js +11 -11
- package/dist/utils/extract-function-name.d.ts +1 -0
- package/dist/utils/extract-function-name.js +27 -32
- package/dist/utils/extract-node-value.js +10 -1
- package/dist/utils/filter-inspector-state.js +7 -3
- package/dist/utils/resolve-versions.js +30 -0
- package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +5 -4
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +47 -28
- package/dist/utils/workflow/dsl/patterns.d.ts +5 -1
- package/dist/utils/workflow/dsl/patterns.js +2 -2
- package/dist/utils/workflow/dsl/validation.d.ts +4 -2
- package/dist/utils/workflow/dsl/validation.js +16 -8
- package/package.json +2 -2
- package/src/add/add-functions.ts +9 -6
- package/src/add/add-mcp-prompt.ts +5 -0
- package/src/add/add-mcp-resource.ts +5 -0
- package/src/add/add-workflow.ts +12 -12
- package/src/utils/extract-function-name.ts +36 -37
- package/src/utils/extract-node-value.test.ts +67 -0
- package/src/utils/extract-node-value.ts +10 -1
- package/src/utils/filter-inspector-state.ts +7 -3
- package/src/utils/resolve-versions.test.ts +141 -0
- package/src/utils/resolve-versions.ts +37 -0
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +58 -32
- package/src/utils/workflow/dsl/patterns.ts +2 -2
- package/src/utils/workflow/dsl/validation.ts +21 -9
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -2,6 +2,7 @@ import * as ts from 'typescript'
|
|
|
2
2
|
import type {
|
|
3
3
|
WorkflowStepMeta,
|
|
4
4
|
RpcStepMeta,
|
|
5
|
+
InlineStepMeta,
|
|
5
6
|
BranchStepMeta,
|
|
6
7
|
ParallelGroupStepMeta,
|
|
7
8
|
FanoutStepMeta,
|
|
@@ -32,6 +33,7 @@ import {
|
|
|
32
33
|
extractForOfVariable,
|
|
33
34
|
isArrayType,
|
|
34
35
|
getSourceText,
|
|
36
|
+
extractSourcePath,
|
|
35
37
|
} from './patterns.js'
|
|
36
38
|
import type { ValidationError } from './validation.js'
|
|
37
39
|
import {
|
|
@@ -63,25 +65,7 @@ interface ExtractionContext {
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
function extractSourcePath(expr: ts.Expression): string | null {
|
|
69
|
-
if (ts.isIdentifier(expr)) {
|
|
70
|
-
return expr.text
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (ts.isPropertyAccessExpression(expr)) {
|
|
74
|
-
const base = extractSourcePath(expr.expression)
|
|
75
|
-
if (base) {
|
|
76
|
-
return `${base}.${expr.name.text}`
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return null
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Result of simple workflow extraction
|
|
68
|
+
* Result of DSL workflow extraction
|
|
85
69
|
*/
|
|
86
70
|
export interface ExtractionResult {
|
|
87
71
|
status: 'ok' | 'error'
|
|
@@ -89,15 +73,15 @@ export interface ExtractionResult {
|
|
|
89
73
|
/** Workflow context (top-level variables) */
|
|
90
74
|
context?: WorkflowContext
|
|
91
75
|
reason?: string
|
|
92
|
-
simple?: boolean
|
|
93
76
|
}
|
|
94
77
|
|
|
95
78
|
/**
|
|
96
|
-
* Extract
|
|
79
|
+
* Extract DSL workflow metadata from a function declaration
|
|
97
80
|
*/
|
|
98
81
|
export function extractDSLWorkflow(
|
|
99
82
|
funcNode: ts.Node,
|
|
100
|
-
checker: ts.TypeChecker
|
|
83
|
+
checker: ts.TypeChecker,
|
|
84
|
+
options?: { allowInline?: boolean }
|
|
101
85
|
): ExtractionResult {
|
|
102
86
|
try {
|
|
103
87
|
// Find the async arrow function
|
|
@@ -106,7 +90,6 @@ export function extractDSLWorkflow(
|
|
|
106
90
|
return {
|
|
107
91
|
status: 'error',
|
|
108
92
|
reason: 'Could not find async arrow function in workflow definition',
|
|
109
|
-
simple: false,
|
|
110
93
|
}
|
|
111
94
|
}
|
|
112
95
|
|
|
@@ -116,7 +99,6 @@ export function extractDSLWorkflow(
|
|
|
116
99
|
return {
|
|
117
100
|
status: 'error',
|
|
118
101
|
reason: 'Could not determine input parameter name',
|
|
119
|
-
simple: false,
|
|
120
102
|
}
|
|
121
103
|
}
|
|
122
104
|
|
|
@@ -134,12 +116,13 @@ export function extractDSLWorkflow(
|
|
|
134
116
|
}
|
|
135
117
|
|
|
136
118
|
// Validate no disallowed patterns
|
|
137
|
-
const patternErrors = validateNoDisallowedPatterns(arrowFunc.body
|
|
119
|
+
const patternErrors = validateNoDisallowedPatterns(arrowFunc.body, {
|
|
120
|
+
allowInline: options?.allowInline,
|
|
121
|
+
})
|
|
138
122
|
if (patternErrors.length > 0) {
|
|
139
123
|
return {
|
|
140
124
|
status: 'error',
|
|
141
125
|
reason: formatValidationErrors(patternErrors),
|
|
142
|
-
simple: false,
|
|
143
126
|
}
|
|
144
127
|
}
|
|
145
128
|
|
|
@@ -149,7 +132,6 @@ export function extractDSLWorkflow(
|
|
|
149
132
|
return {
|
|
150
133
|
status: 'error',
|
|
151
134
|
reason: formatValidationErrors(awaitErrors),
|
|
152
|
-
simple: false,
|
|
153
135
|
}
|
|
154
136
|
}
|
|
155
137
|
|
|
@@ -161,7 +143,6 @@ export function extractDSLWorkflow(
|
|
|
161
143
|
return {
|
|
162
144
|
status: 'error',
|
|
163
145
|
reason: formatValidationErrors(context.errors),
|
|
164
|
-
simple: false,
|
|
165
146
|
}
|
|
166
147
|
}
|
|
167
148
|
|
|
@@ -179,13 +160,11 @@ export function extractDSLWorkflow(
|
|
|
179
160
|
steps,
|
|
180
161
|
context:
|
|
181
162
|
Object.keys(workflowContext).length > 0 ? workflowContext : undefined,
|
|
182
|
-
simple: true,
|
|
183
163
|
}
|
|
184
164
|
} catch (error) {
|
|
185
165
|
return {
|
|
186
166
|
status: 'error',
|
|
187
167
|
reason: error instanceof Error ? error.message : String(error),
|
|
188
|
-
simple: false,
|
|
189
168
|
}
|
|
190
169
|
}
|
|
191
170
|
}
|
|
@@ -375,7 +354,9 @@ function extractVariableDeclaration(
|
|
|
375
354
|
if (ts.isAwaitExpression(init) && ts.isCallExpression(init.expression)) {
|
|
376
355
|
const call = init.expression
|
|
377
356
|
if (isWorkflowDoCall(call, context.checker)) {
|
|
378
|
-
const step =
|
|
357
|
+
const step = isInlineDoCall(call)
|
|
358
|
+
? extractInlineStep(call, context)
|
|
359
|
+
: extractRpcStep(call, context, varName)
|
|
379
360
|
if (step) {
|
|
380
361
|
// Track output variable
|
|
381
362
|
const type = context.checker.getTypeAtLocation(decl)
|
|
@@ -481,7 +462,9 @@ function extractExpressionStatement(
|
|
|
481
462
|
const call = expr.expression
|
|
482
463
|
|
|
483
464
|
if (isWorkflowDoCall(call, context.checker)) {
|
|
484
|
-
const step =
|
|
465
|
+
const step = isInlineDoCall(call)
|
|
466
|
+
? extractInlineStep(call, context)
|
|
467
|
+
: extractRpcStep(call, context, outputVar)
|
|
485
468
|
|
|
486
469
|
// Track output variable if this is an assignment
|
|
487
470
|
if (outputVar && step) {
|
|
@@ -559,6 +542,49 @@ function extractRpcStep(
|
|
|
559
542
|
}
|
|
560
543
|
}
|
|
561
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Extract inline step from workflow.do() call with a function argument
|
|
547
|
+
*/
|
|
548
|
+
function extractInlineStep(
|
|
549
|
+
call: ts.CallExpression,
|
|
550
|
+
context: ExtractionContext
|
|
551
|
+
): InlineStepMeta | null {
|
|
552
|
+
const args = call.arguments
|
|
553
|
+
if (args.length < 2) return null
|
|
554
|
+
|
|
555
|
+
try {
|
|
556
|
+
const stepName = extractStringLiteral(args[0], context.checker)
|
|
557
|
+
const optionsArg = args.length >= 3 ? args[args.length - 1] : undefined
|
|
558
|
+
const options =
|
|
559
|
+
optionsArg && ts.isObjectLiteralExpression(optionsArg)
|
|
560
|
+
? extractStepOptions(optionsArg, context)
|
|
561
|
+
: undefined
|
|
562
|
+
|
|
563
|
+
return {
|
|
564
|
+
type: 'inline',
|
|
565
|
+
stepName,
|
|
566
|
+
options,
|
|
567
|
+
}
|
|
568
|
+
} catch (error) {
|
|
569
|
+
context.errors.push({
|
|
570
|
+
message: `Failed to extract inline step: ${error instanceof Error ? error.message : String(error)}`,
|
|
571
|
+
node: call,
|
|
572
|
+
})
|
|
573
|
+
return null
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Check if the second argument of a workflow.do() call is a function
|
|
579
|
+
*/
|
|
580
|
+
function isInlineDoCall(call: ts.CallExpression): boolean {
|
|
581
|
+
const secondArg = call.arguments[1]
|
|
582
|
+
return (
|
|
583
|
+
!!secondArg &&
|
|
584
|
+
(ts.isArrowFunction(secondArg) || ts.isFunctionExpression(secondArg))
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
|
|
562
588
|
/**
|
|
563
589
|
* Extract step options from options object
|
|
564
590
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Pattern detection helpers for
|
|
4
|
+
* Pattern detection helpers for DSL workflow extraction
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -209,7 +209,7 @@ export function isSequentialFanout(node: ts.ForOfStatement): boolean {
|
|
|
209
209
|
/**
|
|
210
210
|
* Extract full source path from an expression (e.g., data.memberEmails)
|
|
211
211
|
*/
|
|
212
|
-
function extractSourcePath(expr: ts.Expression): string | null {
|
|
212
|
+
export function extractSourcePath(expr: ts.Expression): string | null {
|
|
213
213
|
if (ts.isIdentifier(expr)) {
|
|
214
214
|
return expr.text
|
|
215
215
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Validation rules for
|
|
4
|
+
* Validation rules for DSL workflows
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export interface ValidationError {
|
|
@@ -22,7 +22,10 @@ export interface ValidationError {
|
|
|
22
22
|
* - ThrowStatement (for WorkflowCancelledException)
|
|
23
23
|
* - Block (containers)
|
|
24
24
|
*/
|
|
25
|
-
export function validateNoDisallowedPatterns(
|
|
25
|
+
export function validateNoDisallowedPatterns(
|
|
26
|
+
node: ts.Node,
|
|
27
|
+
options?: { allowInline?: boolean }
|
|
28
|
+
): ValidationError[] {
|
|
26
29
|
const errors: ValidationError[] = []
|
|
27
30
|
|
|
28
31
|
function visitBlock(block: ts.Block) {
|
|
@@ -42,7 +45,7 @@ export function validateNoDisallowedPatterns(node: ts.Node): ValidationError[] {
|
|
|
42
45
|
// Unknown/disallowed statement type
|
|
43
46
|
const nodeType = ts.SyntaxKind[statement.kind]
|
|
44
47
|
errors.push({
|
|
45
|
-
message: `Statement type '${nodeType}' is not allowed in
|
|
48
|
+
message: `Statement type '${nodeType}' is not allowed in DSL workflows. Allowed: const/let, if/else, switch/case, for..of, return, throw, and workflow calls. If this should be supported, please report the node type: ${nodeType}`,
|
|
46
49
|
node: statement,
|
|
47
50
|
})
|
|
48
51
|
}
|
|
@@ -53,7 +56,7 @@ export function validateNoDisallowedPatterns(node: ts.Node): ValidationError[] {
|
|
|
53
56
|
// Disallow while and do-while
|
|
54
57
|
if (ts.isWhileStatement(node) || ts.isDoStatement(node)) {
|
|
55
58
|
errors.push({
|
|
56
|
-
message: 'while and do-while loops are not allowed in
|
|
59
|
+
message: 'while and do-while loops are not allowed in DSL workflows',
|
|
57
60
|
node,
|
|
58
61
|
})
|
|
59
62
|
return
|
|
@@ -63,14 +66,14 @@ export function validateNoDisallowedPatterns(node: ts.Node): ValidationError[] {
|
|
|
63
66
|
if (ts.isForInStatement(node) || ts.isForStatement(node)) {
|
|
64
67
|
errors.push({
|
|
65
68
|
message:
|
|
66
|
-
'for and for-in loops are not allowed in
|
|
69
|
+
'for and for-in loops are not allowed in DSL workflows. Use for-of instead.',
|
|
67
70
|
node,
|
|
68
71
|
})
|
|
69
72
|
return
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
// Check for inline workflow.do
|
|
73
|
-
if (ts.isCallExpression(node)) {
|
|
76
|
+
if (!options?.allowInline && ts.isCallExpression(node)) {
|
|
74
77
|
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
75
78
|
const propAccess = node.expression
|
|
76
79
|
if (
|
|
@@ -86,7 +89,7 @@ export function validateNoDisallowedPatterns(node: ts.Node): ValidationError[] {
|
|
|
86
89
|
) {
|
|
87
90
|
errors.push({
|
|
88
91
|
message:
|
|
89
|
-
'Inline workflow.do with function argument is not allowed in
|
|
92
|
+
'Inline workflow.do with function argument is not allowed in DSL workflows. Use pikkuWorkflowComplexFunc instead.',
|
|
90
93
|
node,
|
|
91
94
|
})
|
|
92
95
|
return
|
|
@@ -129,11 +132,20 @@ export function validateAwaitedCalls(node: ts.Node): ValidationError[] {
|
|
|
129
132
|
ts.isIdentifier(propAccess.expression) &&
|
|
130
133
|
propAccess.expression.text === 'Promise'
|
|
131
134
|
) {
|
|
132
|
-
// console.log('[DEBUG] Found Promise.all, setting insidePromiseAll=true')
|
|
133
|
-
// Visit children with insidePromiseAll = true
|
|
134
135
|
ts.forEachChild(node, (child) => visit(child, parentIsAwait, true))
|
|
135
136
|
return
|
|
136
137
|
}
|
|
138
|
+
// .push() on an array — workflow.do() inside is collecting promises
|
|
139
|
+
if (propAccess.name.text === 'push') {
|
|
140
|
+
ts.forEachChild(node, (child) => visit(child, parentIsAwait, true))
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Array literal — workflow.do() inside is collecting promises
|
|
146
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
147
|
+
ts.forEachChild(node, (child) => visit(child, parentIsAwait, true))
|
|
148
|
+
return
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
// Now check for workflow calls
|