@pikku/inspector 0.12.42 → 0.12.44
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 +266 -0
- package/dist/add/add-addon-bans.js +1 -0
- package/dist/add/add-ai-agent.d.ts +3 -1
- package/dist/add/add-ai-agent.js +82 -0
- package/dist/add/add-credential.js +5 -1
- package/dist/add/add-functions.js +10 -9
- package/dist/add/add-gateway.js +3 -0
- package/dist/add/add-http-route.js +2 -2
- package/dist/add/add-keyed-wiring.js +2 -0
- package/dist/add/add-mcp-prompt.js +0 -1
- package/dist/add/add-mcp-resource.js +0 -1
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +3 -177
- package/dist/add/add-queue-worker.js +3 -0
- package/dist/add/add-schedule.js +3 -0
- package/dist/add/add-scope.d.ts +2 -0
- package/dist/add/add-scope.js +146 -0
- package/dist/add/add-trigger.js +3 -0
- package/dist/add/add-wire-remote-addon.d.ts +10 -0
- package/dist/add/add-wire-remote-addon.js +66 -0
- package/dist/add/add-workflow-graph.js +32 -3
- package/dist/add/add-workflow.js +9 -4
- package/dist/error-codes.d.ts +3 -0
- package/dist/error-codes.js +4 -0
- package/dist/inspector.js +11 -5
- package/dist/types.d.ts +19 -13
- package/dist/utils/custom-types-generator.js +2 -1
- package/dist/utils/ensure-function-metadata.d.ts +15 -0
- package/dist/utils/ensure-function-metadata.js +24 -0
- package/dist/utils/filter-inspector-state.js +9 -0
- package/dist/utils/get-property-value.d.ts +7 -2
- package/dist/utils/get-property-value.js +48 -1
- package/dist/utils/load-addon-functions-meta.js +81 -6
- package/dist/utils/permissions.d.ts +1 -21
- package/dist/utils/permissions.js +17 -108
- package/dist/utils/post-process.d.ts +30 -1
- package/dist/utils/post-process.js +150 -72
- package/dist/utils/schema-generator.js +19 -4
- package/dist/utils/serialize-inspector-state.d.ts +13 -8
- package/dist/utils/serialize-inspector-state.js +12 -6
- package/dist/utils/serialize-permissions-groups-meta.d.ts +0 -2
- package/dist/utils/serialize-permissions-groups-meta.js +0 -26
- package/dist/utils/workflow/derive-workflow-plan.js +9 -3
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +373 -91
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +274 -100
- package/dist/utils/workflow/dsl/patterns.d.ts +4 -0
- package/dist/utils/workflow/dsl/patterns.js +11 -0
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +76 -5
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +7 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +11 -2
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +4 -0
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +8 -4
- package/dist/visit.js +4 -0
- package/package.json +3 -3
- package/run-tests.sh +1 -1
- package/src/add/add-addon-bans.ts +1 -0
- package/src/add/add-ai-agent.test.ts +87 -0
- package/src/add/add-ai-agent.ts +122 -0
- package/src/add/add-credential.ts +8 -0
- package/src/add/add-functions.ts +10 -12
- package/src/add/add-gateway.ts +11 -0
- package/src/add/add-http-route.ts +2 -8
- package/src/add/add-keyed-wiring.ts +2 -0
- package/src/add/add-mcp-prompt.ts +0 -1
- package/src/add/add-mcp-resource.ts +0 -1
- package/src/add/add-permission.ts +4 -242
- package/src/add/add-queue-worker.ts +11 -0
- package/src/add/add-schedule.ts +11 -0
- package/src/add/add-scope.test.ts +346 -0
- package/src/add/add-scope.ts +225 -0
- package/src/add/add-trigger.ts +11 -0
- package/src/add/add-wire-remote-addon.ts +77 -0
- package/src/add/add-workflow-edge-cases.test.ts +201 -0
- package/src/add/add-workflow-fanout.test.ts +60 -0
- package/src/add/add-workflow-graph-input.test.ts +94 -0
- package/src/add/add-workflow-graph-notes.test.ts +74 -0
- package/src/add/add-workflow-graph.ts +35 -3
- package/src/add/add-workflow-on-error.test.ts +118 -0
- package/src/add/add-workflow-return-switch.test.ts +121 -0
- package/src/add/add-workflow-silent-drops.test.ts +163 -0
- package/src/add/add-workflow-sleep-expression.test.ts +97 -0
- package/src/add/add-workflow.ts +9 -4
- package/src/add/config-value-metadata.test.ts +169 -0
- package/src/add/inline-wiring-function.test.ts +104 -0
- package/src/add/validate-workflow-graph-addons.test.ts +102 -0
- package/src/error-codes.ts +5 -0
- package/src/inspector.ts +14 -4
- package/src/types.ts +16 -17
- package/src/utils/custom-types-generator.test.ts +26 -1
- package/src/utils/custom-types-generator.ts +2 -1
- package/src/utils/ensure-function-metadata.ts +42 -0
- package/src/utils/filter-inspector-state.test.ts +0 -2
- package/src/utils/filter-inspector-state.ts +9 -0
- package/src/utils/get-property-value.test.ts +141 -0
- package/src/utils/get-property-value.ts +62 -1
- package/src/utils/load-addon-functions-meta.test.ts +157 -0
- package/src/utils/load-addon-functions-meta.ts +94 -6
- package/src/utils/load-addon-scopes.test.ts +138 -0
- package/src/utils/permissions.test.ts +7 -232
- package/src/utils/permissions.ts +20 -160
- package/src/utils/post-process.test.ts +269 -4
- package/src/utils/post-process.ts +216 -95
- package/src/utils/schema-generator.test.ts +164 -0
- package/src/utils/schema-generator.ts +26 -3
- package/src/utils/serialize-inspector-state.ts +22 -25
- package/src/utils/serialize-permissions-groups-meta.ts +0 -28
- package/src/utils/workflow/derive-workflow-plan.test.ts +41 -3
- package/src/utils/workflow/derive-workflow-plan.ts +11 -4
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +480 -119
- package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +71 -0
- package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +99 -0
- package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +161 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +121 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +116 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +145 -0
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +311 -105
- package/src/utils/workflow/dsl/patterns.ts +18 -0
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +82 -10
- package/src/utils/workflow/graph/fanout-node-identity.test.ts +105 -0
- package/src/utils/workflow/graph/finalize-workflows.test.ts +50 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +13 -2
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +6 -0
- package/src/utils/workflow/graph/workflow-graph.types.ts +11 -2
- package/src/visit.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
import type { SerializedWorkflowGraph } from './workflow-graph.types.js';
|
|
1
2
|
import type { InspectorState } from '../../../types.js';
|
|
2
3
|
export declare function finalizeWorkflows(state: InspectorState): void;
|
|
4
|
+
/**
|
|
5
|
+
* Hash of graph topology only. `notes` (node- and graph-level) is deliberately
|
|
6
|
+
* excluded so editing documentation never changes the hash / marks the workflow
|
|
7
|
+
* as a new version.
|
|
8
|
+
*/
|
|
9
|
+
export declare function computeGraphHash(graph: SerializedWorkflowGraph): string;
|
|
@@ -80,11 +80,20 @@ function computeStepHashes(graph, functionsMeta) {
|
|
|
80
80
|
node.stepHash = hashString(`${node.nodeId}:${meta?.contractHash ?? ''}`, 12);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Hash of graph topology only. `notes` (node- and graph-level) is deliberately
|
|
85
|
+
* excluded so editing documentation never changes the hash / marks the workflow
|
|
86
|
+
* as a new version.
|
|
87
|
+
*/
|
|
88
|
+
export function computeGraphHash(graph) {
|
|
89
|
+
const nodesForHash = Object.fromEntries(Object.entries(graph.nodes).map(([nodeId, node]) => {
|
|
90
|
+
const { notes: _notes, ...rest } = node;
|
|
91
|
+
return [nodeId, rest];
|
|
92
|
+
}));
|
|
84
93
|
return hashString(canonicalJSON({
|
|
85
94
|
source: graph.source,
|
|
86
95
|
context: graph.context,
|
|
87
|
-
nodes:
|
|
96
|
+
nodes: nodesForHash,
|
|
88
97
|
entryNodeIds: graph.entryNodeIds,
|
|
89
98
|
}), 12);
|
|
90
99
|
}
|
|
@@ -14,10 +14,12 @@ export declare function serializeWorkflowGraph(definition: {
|
|
|
14
14
|
input?: (ref: any) => Record<string, unknown>;
|
|
15
15
|
next?: string | string[] | Record<string, string | string[]>;
|
|
16
16
|
onError?: string | string[];
|
|
17
|
+
notes?: string;
|
|
17
18
|
}>;
|
|
18
19
|
}, options?: {
|
|
19
20
|
description?: string;
|
|
20
21
|
tags?: string[];
|
|
22
|
+
notes?: string[];
|
|
21
23
|
}): SerializedWorkflowGraph;
|
|
22
24
|
/**
|
|
23
25
|
* Deserialize a workflow graph from JSON to runtime format
|
|
@@ -108,6 +108,9 @@ export function serializeWorkflowGraph(definition, options) {
|
|
|
108
108
|
next: serializeNext(node.next),
|
|
109
109
|
onError: node.onError,
|
|
110
110
|
};
|
|
111
|
+
if (node.notes !== undefined) {
|
|
112
|
+
funcNode.notes = node.notes;
|
|
113
|
+
}
|
|
111
114
|
nodes[nodeId] = funcNode;
|
|
112
115
|
// Entry nodes have no incoming edges
|
|
113
116
|
if (!hasIncomingEdge.has(nodeId)) {
|
|
@@ -120,6 +123,7 @@ export function serializeWorkflowGraph(definition, options) {
|
|
|
120
123
|
source: 'graph',
|
|
121
124
|
description: options?.description,
|
|
122
125
|
tags: options?.tags,
|
|
126
|
+
notes: options?.notes,
|
|
123
127
|
nodes,
|
|
124
128
|
entryNodeIds,
|
|
125
129
|
};
|
|
@@ -51,22 +51,22 @@ export type SerializedNext = string | string[] | {
|
|
|
51
51
|
conditions: BranchCondition[];
|
|
52
52
|
/** Default target if no conditions match */
|
|
53
53
|
default?: string | string[];
|
|
54
|
-
}
|
|
54
|
+
} | Record<string, string | string[]>;
|
|
55
55
|
/**
|
|
56
56
|
* Node execution options
|
|
57
57
|
*/
|
|
58
58
|
export interface NodeOptions {
|
|
59
59
|
/** Number of retry attempts on failure */
|
|
60
60
|
retries?: number;
|
|
61
|
-
/** Delay between retries (e.g., '1s', '5s') */
|
|
62
|
-
retryDelay?: string;
|
|
61
|
+
/** Delay between retries (e.g., '1s', '5s', or a number of milliseconds) */
|
|
62
|
+
retryDelay?: string | number;
|
|
63
63
|
/** Timeout for node execution (e.g., '30s', '5m') */
|
|
64
64
|
timeout?: string;
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
67
|
* Flow node types for control flow (no RPC call)
|
|
68
68
|
*/
|
|
69
|
-
export type FlowType = 'sleep' | 'branch' | 'parallel' | 'fanout' | 'inline' | 'switch' | 'filter' | 'arrayPredicate' | 'return' | 'cancel' | 'set';
|
|
69
|
+
export type FlowType = 'sleep' | 'suspend' | 'approval' | 'branch' | 'parallel' | 'fanout' | 'inline' | 'switch' | 'filter' | 'arrayPredicate' | 'return' | 'cancel' | 'set';
|
|
70
70
|
import type { ContextVariable, WorkflowContext, WorkflowPlannedStep } from '@pikku/core/workflow';
|
|
71
71
|
export type { ContextVariable, WorkflowContext };
|
|
72
72
|
/**
|
|
@@ -83,6 +83,8 @@ interface BaseNode {
|
|
|
83
83
|
onError?: string | string[];
|
|
84
84
|
/** Execution options */
|
|
85
85
|
options?: NodeOptions;
|
|
86
|
+
/** Free-text node documentation. Non-semantic — excluded from graphHash. */
|
|
87
|
+
notes?: string;
|
|
86
88
|
}
|
|
87
89
|
/**
|
|
88
90
|
* Function node - calls an RPC
|
|
@@ -154,6 +156,8 @@ export interface SerializedWorkflowGraph {
|
|
|
154
156
|
context?: WorkflowContext;
|
|
155
157
|
/** Serialized nodes */
|
|
156
158
|
nodes: Record<string, SerializedGraphNode>;
|
|
159
|
+
/** Graph-level free-text notes (e.g. imported sticky notes). Non-semantic — excluded from graphHash. */
|
|
160
|
+
notes?: string[];
|
|
157
161
|
/** Entry node(s) - first nodes to execute */
|
|
158
162
|
entryNodeIds: string[];
|
|
159
163
|
/** Hash of graph topology (nodes, edges, input mappings) */
|
package/dist/visit.js
CHANGED
|
@@ -15,12 +15,14 @@ import { addChannel } from './add/add-channel.js';
|
|
|
15
15
|
import { addGateway } from './add/add-gateway.js';
|
|
16
16
|
import { addRPCInvocations } from './add/add-rpc-invocations.js';
|
|
17
17
|
import { addWireAddon } from './add/add-wire-addon.js';
|
|
18
|
+
import { addWireRemoteAddon } from './add/add-wire-remote-addon.js';
|
|
18
19
|
import { addMiddleware } from './add/add-middleware.js';
|
|
19
20
|
import { addPermission } from './add/add-permission.js';
|
|
20
21
|
import { addCLI, addCLIRenderers } from './add/add-cli.js';
|
|
21
22
|
import { addAuth } from './add/add-auth.js';
|
|
22
23
|
import { addSecret } from './add/add-secret.js';
|
|
23
24
|
import { addCredential } from './add/add-credential.js';
|
|
25
|
+
import { addScope } from './add/add-scope.js';
|
|
24
26
|
import { addVariable } from './add/add-variable.js';
|
|
25
27
|
import { addWorkflowGraph } from './add/add-workflow-graph.js';
|
|
26
28
|
import { addAIAgent } from './add/add-ai-agent.js';
|
|
@@ -36,6 +38,7 @@ export const visitSetup = (logger, checker, node, state, options) => {
|
|
|
36
38
|
addFileWithFactory(node, checker, state.serverLifecycleFactories, 'ServerLifecycle');
|
|
37
39
|
addRPCInvocations(node, state, logger);
|
|
38
40
|
addWireAddon(node, state, logger);
|
|
41
|
+
addWireRemoteAddon(node, state, logger);
|
|
39
42
|
addMiddleware(logger, node, checker, state, options);
|
|
40
43
|
addPermission(logger, node, checker, state, options);
|
|
41
44
|
addApprovalDescription(logger, node, checker, state, options);
|
|
@@ -64,6 +67,7 @@ export const visitRoutes = (logger, checker, node, state, options) => {
|
|
|
64
67
|
addAuth(logger, node, checker, state, nextOptions);
|
|
65
68
|
addSecret(logger, node, checker, state, nextOptions);
|
|
66
69
|
addCredential(logger, node, checker, state, nextOptions);
|
|
70
|
+
addScope(logger, node, checker, state, nextOptions);
|
|
67
71
|
addVariable(logger, node, checker, state, nextOptions);
|
|
68
72
|
addHTTPRoute(logger, node, checker, state, nextOptions);
|
|
69
73
|
addHTTPRoutes(logger, node, checker, state, nextOptions);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.44",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"type": "module",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"zod-to-ts": "^2.1.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@pikku/core": "^0.12.
|
|
47
|
+
"@pikku/core": "^0.12.65"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@pikku/core": "^0.12.
|
|
50
|
+
"@pikku/core": "^0.12.65",
|
|
51
51
|
"@types/node": "^24.11.0"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
package/run-tests.sh
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import * as ts from 'typescript'
|
|
4
|
+
|
|
5
|
+
import { resolveWorkflowReferences } from './add-ai-agent.js'
|
|
6
|
+
import type { InspectorLogger } from '../types.js'
|
|
7
|
+
|
|
8
|
+
function createSourceFile(code: string): ts.SourceFile {
|
|
9
|
+
return ts.createSourceFile('test.ts', code, ts.ScriptTarget.ESNext, true)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getObjectLiteral(
|
|
13
|
+
sourceFile: ts.SourceFile
|
|
14
|
+
): ts.ObjectLiteralExpression {
|
|
15
|
+
let result: ts.ObjectLiteralExpression | undefined
|
|
16
|
+
ts.forEachChild(sourceFile, function visit(node) {
|
|
17
|
+
if (ts.isObjectLiteralExpression(node) && !result) {
|
|
18
|
+
result = node
|
|
19
|
+
}
|
|
20
|
+
ts.forEachChild(node, visit)
|
|
21
|
+
})
|
|
22
|
+
if (!result) throw new Error('No object literal found')
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createLogger(): {
|
|
27
|
+
logger: InspectorLogger
|
|
28
|
+
criticals: Array<{ code: unknown; message: string }>
|
|
29
|
+
} {
|
|
30
|
+
const criticals: Array<{ code: unknown; message: string }> = []
|
|
31
|
+
const logger = {
|
|
32
|
+
info: () => {},
|
|
33
|
+
error: () => {},
|
|
34
|
+
warn: () => {},
|
|
35
|
+
debug: () => {},
|
|
36
|
+
diagnostic: () => {},
|
|
37
|
+
critical: (code: unknown, message: string) =>
|
|
38
|
+
criticals.push({ code, message }),
|
|
39
|
+
hasCriticalErrors: () => criticals.length > 0,
|
|
40
|
+
} as unknown as InspectorLogger
|
|
41
|
+
return { logger, criticals }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('resolveWorkflowReferences', () => {
|
|
45
|
+
test('returns null when no workflows property exists', () => {
|
|
46
|
+
const obj = getObjectLiteral(createSourceFile('const x = { name: "a" }'))
|
|
47
|
+
const { logger } = createLogger()
|
|
48
|
+
assert.strictEqual(
|
|
49
|
+
resolveWorkflowReferences(obj, {} as any, 'a', logger),
|
|
50
|
+
null
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('returns null for an empty workflows array', () => {
|
|
55
|
+
const obj = getObjectLiteral(
|
|
56
|
+
createSourceFile('const x = { workflows: [] }')
|
|
57
|
+
)
|
|
58
|
+
const { logger } = createLogger()
|
|
59
|
+
assert.strictEqual(
|
|
60
|
+
resolveWorkflowReferences(obj, {} as any, 'a', logger),
|
|
61
|
+
null
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('resolves ref() and workflow() string-literal references', () => {
|
|
66
|
+
const obj = getObjectLiteral(
|
|
67
|
+
createSourceFile(
|
|
68
|
+
`const x = { workflows: [ref('buildReport'), workflow('country_capitals')] }`
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
const { logger, criticals } = createLogger()
|
|
72
|
+
const result = resolveWorkflowReferences(obj, {} as any, 'planner', logger)
|
|
73
|
+
assert.deepStrictEqual(result, ['buildReport', 'country_capitals'])
|
|
74
|
+
assert.strictEqual(criticals.length, 0)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('flags a raw string literal as a critical error', () => {
|
|
78
|
+
const obj = getObjectLiteral(
|
|
79
|
+
createSourceFile(`const x = { workflows: ['buildReport'] }`)
|
|
80
|
+
)
|
|
81
|
+
const { logger, criticals } = createLogger()
|
|
82
|
+
const result = resolveWorkflowReferences(obj, {} as any, 'planner', logger)
|
|
83
|
+
assert.strictEqual(result, null)
|
|
84
|
+
assert.strictEqual(criticals.length, 1)
|
|
85
|
+
assert.match(criticals[0].message, /string literal/)
|
|
86
|
+
})
|
|
87
|
+
})
|
package/src/add/add-ai-agent.ts
CHANGED
|
@@ -142,6 +142,114 @@ function resolveAgentReferences(
|
|
|
142
142
|
return resolved.length > 0 ? resolved : null
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
export function resolveWorkflowReferences(
|
|
146
|
+
obj: ts.ObjectLiteralExpression,
|
|
147
|
+
checker: ts.TypeChecker,
|
|
148
|
+
agentName: string,
|
|
149
|
+
logger: InspectorLogger
|
|
150
|
+
): string[] | null {
|
|
151
|
+
const property = obj.properties.find(
|
|
152
|
+
(p) =>
|
|
153
|
+
ts.isPropertyAssignment(p) &&
|
|
154
|
+
ts.isIdentifier(p.name) &&
|
|
155
|
+
p.name.text === 'workflows'
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if (!property || !ts.isPropertyAssignment(property)) {
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const initializer = property.initializer
|
|
163
|
+
if (!ts.isArrayLiteralExpression(initializer)) {
|
|
164
|
+
return null
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const resolved: string[] = []
|
|
168
|
+
|
|
169
|
+
for (const element of initializer.elements) {
|
|
170
|
+
if (ts.isStringLiteral(element)) {
|
|
171
|
+
logger.critical(
|
|
172
|
+
ErrorCode.INVALID_VALUE,
|
|
173
|
+
`AI agent '${agentName}' workflows array contains a string literal '${element.text}'. ` +
|
|
174
|
+
`Use a workflow reference instead (e.g., ref('<workflowName>') or import the pikkuWorkflowGraph variable).`
|
|
175
|
+
)
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (ts.isCallExpression(element) && ts.isIdentifier(element.expression)) {
|
|
180
|
+
const calleeName = element.expression.text
|
|
181
|
+
if (calleeName === 'ref' || calleeName === 'workflow') {
|
|
182
|
+
const [firstArg] = element.arguments
|
|
183
|
+
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
184
|
+
resolved.push(firstArg.text)
|
|
185
|
+
continue
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (ts.isIdentifier(element)) {
|
|
191
|
+
const name = resolveIdentifierToWorkflowName(element, checker)
|
|
192
|
+
if (name) {
|
|
193
|
+
resolved.push(name)
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
logger.critical(
|
|
198
|
+
ErrorCode.INVALID_VALUE,
|
|
199
|
+
`AI agent '${agentName}' workflows array contains identifier '${element.text}' ` +
|
|
200
|
+
`that could not be resolved to a pikkuWorkflowGraph.`
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return resolved.length > 0 ? resolved : null
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function resolveIdentifierToWorkflowName(
|
|
209
|
+
identifier: ts.Identifier,
|
|
210
|
+
checker: ts.TypeChecker
|
|
211
|
+
): string | null {
|
|
212
|
+
const symbol = checker.getSymbolAtLocation(identifier)
|
|
213
|
+
if (!symbol) return null
|
|
214
|
+
|
|
215
|
+
let resolved = symbol
|
|
216
|
+
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
217
|
+
resolved = checker.getAliasedSymbol(resolved) ?? resolved
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const decl = resolved.valueDeclaration ?? resolved.declarations?.[0]
|
|
221
|
+
if (!decl) return null
|
|
222
|
+
|
|
223
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
224
|
+
if (
|
|
225
|
+
ts.isCallExpression(decl.initializer) &&
|
|
226
|
+
ts.isIdentifier(decl.initializer.expression) &&
|
|
227
|
+
(decl.initializer.expression.text === 'pikkuWorkflowGraph' ||
|
|
228
|
+
decl.initializer.expression.text === 'pikkuWorkflow' ||
|
|
229
|
+
decl.initializer.expression.text === 'pikkuWorkflowComplex')
|
|
230
|
+
) {
|
|
231
|
+
const firstArg = decl.initializer.arguments[0]
|
|
232
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
233
|
+
for (const prop of firstArg.properties) {
|
|
234
|
+
if (
|
|
235
|
+
ts.isPropertyAssignment(prop) &&
|
|
236
|
+
ts.isIdentifier(prop.name) &&
|
|
237
|
+
prop.name.text === 'name' &&
|
|
238
|
+
ts.isStringLiteral(prop.initializer)
|
|
239
|
+
) {
|
|
240
|
+
return prop.initializer.text
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (ts.isIdentifier(decl.name)) {
|
|
245
|
+
return decl.name.text
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return null
|
|
251
|
+
}
|
|
252
|
+
|
|
145
253
|
function resolveIdentifierToRpcName(
|
|
146
254
|
identifier: ts.Identifier,
|
|
147
255
|
checker: ts.TypeChecker
|
|
@@ -293,6 +401,19 @@ export const addAIAgent: AddWiring = (
|
|
|
293
401
|
logger
|
|
294
402
|
)
|
|
295
403
|
|
|
404
|
+
const workflowsValue = resolveWorkflowReferences(
|
|
405
|
+
obj,
|
|
406
|
+
checker,
|
|
407
|
+
nameValue || '',
|
|
408
|
+
logger
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
if (workflowsValue) {
|
|
412
|
+
for (const workflowName of workflowsValue) {
|
|
413
|
+
state.workflows.invokedWorkflows.add(workflowName)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
296
417
|
if (!nameValue) {
|
|
297
418
|
logger.critical(
|
|
298
419
|
ErrorCode.MISSING_NAME,
|
|
@@ -460,6 +581,7 @@ export const addAIAgent: AddWiring = (
|
|
|
460
581
|
}),
|
|
461
582
|
...(toolsValue !== null && { tools: toolsValue }),
|
|
462
583
|
...(agentsValue !== null && { agents: agentsValue }),
|
|
584
|
+
...(workflowsValue !== null && { workflows: workflowsValue }),
|
|
463
585
|
tags,
|
|
464
586
|
inputSchema,
|
|
465
587
|
outputSchema,
|
|
@@ -2,6 +2,7 @@ import * as ts from 'typescript'
|
|
|
2
2
|
import {
|
|
3
3
|
getPropertyValue,
|
|
4
4
|
getArrayPropertyValue,
|
|
5
|
+
getRecordPropertyValue,
|
|
5
6
|
assertStringLiteralProperty,
|
|
6
7
|
} from '../utils/get-property-value.js'
|
|
7
8
|
import type { AddWiring } from '../types.js'
|
|
@@ -44,6 +45,7 @@ export const addCredential: AddWiring = (
|
|
|
44
45
|
| string
|
|
45
46
|
| null
|
|
46
47
|
const typeValue = getPropertyValue(obj, 'type') as string | null
|
|
48
|
+
const docsUrlValue = getPropertyValue(obj, 'docsUrl') as string | null
|
|
47
49
|
|
|
48
50
|
if (!nameValue) {
|
|
49
51
|
logger.critical(
|
|
@@ -133,6 +135,10 @@ export const addCredential: AddWiring = (
|
|
|
133
135
|
const tokenUrl = getPropertyValue(oauth2Obj, 'tokenUrl') as string | null
|
|
134
136
|
const scopes = getArrayPropertyValue(oauth2Obj, 'scopes')
|
|
135
137
|
const pkce = getPropertyValue(oauth2Obj, 'pkce') as boolean | null
|
|
138
|
+
const additionalParams = getRecordPropertyValue(
|
|
139
|
+
oauth2Obj,
|
|
140
|
+
'additionalParams'
|
|
141
|
+
)
|
|
136
142
|
|
|
137
143
|
if (appCredentialSecretId && authorizationUrl && tokenUrl && scopes) {
|
|
138
144
|
oauth2 = {
|
|
@@ -142,6 +148,7 @@ export const addCredential: AddWiring = (
|
|
|
142
148
|
tokenUrl,
|
|
143
149
|
scopes,
|
|
144
150
|
pkce: pkce || undefined,
|
|
151
|
+
additionalParams: additionalParams || undefined,
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
}
|
|
@@ -173,6 +180,7 @@ export const addCredential: AddWiring = (
|
|
|
173
180
|
displayName: displayNameValue,
|
|
174
181
|
description: descriptionValue || undefined,
|
|
175
182
|
type: typeValue as 'singleton' | 'wire',
|
|
183
|
+
docsUrl: docsUrlValue || undefined,
|
|
176
184
|
schema: schemaLookupName,
|
|
177
185
|
oauth2,
|
|
178
186
|
sourceFile,
|
package/src/add/add-functions.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { FunctionServicesMeta } from '@pikku/core'
|
|
|
12
12
|
import { formatVersionedId, parseVersionedId } from '@pikku/core'
|
|
13
13
|
import {
|
|
14
14
|
getPropertyValue,
|
|
15
|
+
getArrayPropertyValue,
|
|
15
16
|
getCommonWireMetaData,
|
|
16
17
|
} from '../utils/get-property-value.js'
|
|
17
18
|
import { canonicalJSON, hashString } from '../utils/hash.js'
|
|
@@ -426,6 +427,7 @@ export const addFunctions: AddWiring = (
|
|
|
426
427
|
let workflowQueued: boolean | undefined
|
|
427
428
|
let workflowRetries: number | undefined
|
|
428
429
|
let workflowTimeout: string | undefined
|
|
430
|
+
let scopes: string[] | undefined
|
|
429
431
|
let version: number | undefined
|
|
430
432
|
let objectNode: ts.ObjectLiteralExpression | undefined
|
|
431
433
|
let nodeDisplayName: string | null = null
|
|
@@ -530,6 +532,7 @@ export const addFunctions: AddWiring = (
|
|
|
530
532
|
workflowTimeout = getPropertyValue(firstArg, 'workflowTimeout') as
|
|
531
533
|
| string
|
|
532
534
|
| undefined
|
|
535
|
+
scopes = getArrayPropertyValue(firstArg, 'scopes') ?? undefined
|
|
533
536
|
|
|
534
537
|
// Extract approvalDescription identifier reference
|
|
535
538
|
for (const prop of firstArg.properties) {
|
|
@@ -1029,17 +1032,6 @@ export const addFunctions: AddWiring = (
|
|
|
1029
1032
|
if (newMiddleware.length > 0) {
|
|
1030
1033
|
middleware = [...(middleware || []), ...newMiddleware]
|
|
1031
1034
|
}
|
|
1032
|
-
const existingPermissionTags = new Set(
|
|
1033
|
-
(permissions || [])
|
|
1034
|
-
.filter((p) => p.type === 'tag')
|
|
1035
|
-
.map((p) => (p as any).tag)
|
|
1036
|
-
)
|
|
1037
|
-
const newPermissions = tagEntries.filter(
|
|
1038
|
-
(e) => !existingPermissionTags.has(e.tag)
|
|
1039
|
-
)
|
|
1040
|
-
if (newPermissions.length > 0) {
|
|
1041
|
-
permissions = [...(permissions || []), ...newPermissions]
|
|
1042
|
-
}
|
|
1043
1035
|
}
|
|
1044
1036
|
|
|
1045
1037
|
const implementationHash = computeImplementationHash({
|
|
@@ -1094,6 +1086,7 @@ export const addFunctions: AddWiring = (
|
|
|
1094
1086
|
workflowQueued: workflowQueued === true ? true : undefined,
|
|
1095
1087
|
workflowRetries: workflowRetries ?? undefined,
|
|
1096
1088
|
workflowTimeout: workflowTimeout ?? undefined,
|
|
1089
|
+
scopes: scopes ?? undefined,
|
|
1097
1090
|
implementationHash,
|
|
1098
1091
|
version,
|
|
1099
1092
|
title,
|
|
@@ -1147,7 +1140,6 @@ export const addFunctions: AddWiring = (
|
|
|
1147
1140
|
inputSchema: inputNames[0] ?? null,
|
|
1148
1141
|
outputSchema: outputNames[0] ?? null,
|
|
1149
1142
|
middleware,
|
|
1150
|
-
permissions,
|
|
1151
1143
|
}
|
|
1152
1144
|
state.serviceAggregation.usedFunctions.add(pikkuFuncId)
|
|
1153
1145
|
extractWireNames(middleware).forEach((n) =>
|
|
@@ -1192,6 +1184,12 @@ export const addFunctions: AddWiring = (
|
|
|
1192
1184
|
|
|
1193
1185
|
if (remote) {
|
|
1194
1186
|
state.rpc.invokedFunctions.add(pikkuFuncId)
|
|
1187
|
+
// The consumer-facing surface a wireRemoteAddon imports (mirrors exposedMeta)
|
|
1188
|
+
state.rpc.remoteMeta[name] = pikkuFuncId
|
|
1189
|
+
state.rpc.remoteFiles.set(name, {
|
|
1190
|
+
path: node.getSourceFile().fileName,
|
|
1191
|
+
exportedName,
|
|
1192
|
+
})
|
|
1195
1193
|
}
|
|
1196
1194
|
|
|
1197
1195
|
if (expose) {
|
package/src/add/add-gateway.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
makeContextBasedId,
|
|
10
10
|
} from '../utils/extract-function-name.js'
|
|
11
11
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
12
|
+
import { ensureInlineWiringFunction } from '../utils/ensure-function-metadata.js'
|
|
12
13
|
import { resolveMiddleware } from '../utils/middleware.js'
|
|
13
14
|
import { extractWireNames } from '../utils/post-process.js'
|
|
14
15
|
import { resolveAddonName } from '../utils/resolve-addon-package.js'
|
|
@@ -83,6 +84,16 @@ export const addGateway: AddWiring = (
|
|
|
83
84
|
return
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
// Register metadata for a func inlined into the wiring (see helper).
|
|
88
|
+
ensureInlineWiringFunction(
|
|
89
|
+
state,
|
|
90
|
+
pikkuFuncId,
|
|
91
|
+
nameValue,
|
|
92
|
+
funcInitializer,
|
|
93
|
+
checker,
|
|
94
|
+
extracted.isHelper
|
|
95
|
+
)
|
|
96
|
+
|
|
86
97
|
const middleware = resolveMiddleware(state, obj, tags, checker)
|
|
87
98
|
|
|
88
99
|
state.serviceAggregation.usedFunctions.add(pikkuFuncId)
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
InspectorState,
|
|
20
20
|
} from '../types.js'
|
|
21
21
|
import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js'
|
|
22
|
-
import {
|
|
22
|
+
import { resolvePermissions } from '../utils/permissions.js'
|
|
23
23
|
import { extractWireNames } from '../utils/post-process.js'
|
|
24
24
|
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
|
|
25
25
|
import { resolveFunctionMeta } from '../utils/resolve-function-meta.js'
|
|
@@ -381,13 +381,7 @@ export function registerHTTPRoute({
|
|
|
381
381
|
)
|
|
382
382
|
|
|
383
383
|
// Resolve permissions
|
|
384
|
-
const permissions =
|
|
385
|
-
state,
|
|
386
|
-
fullRoute,
|
|
387
|
-
obj,
|
|
388
|
-
tags,
|
|
389
|
-
checker
|
|
390
|
-
)
|
|
384
|
+
const permissions = resolvePermissions(state, obj, tags, checker)
|
|
391
385
|
|
|
392
386
|
state.serviceAggregation.usedFunctions.add(funcName)
|
|
393
387
|
if (refAddonTarget) {
|
|
@@ -56,6 +56,7 @@ export const createAddKeyedWiring = (config: KeyedWiringConfig): AddWiring => {
|
|
|
56
56
|
const rotationPeriodValue = getPropertyValue(obj, 'rotationPeriod') as
|
|
57
57
|
| string
|
|
58
58
|
| null
|
|
59
|
+
const docsUrlValue = getPropertyValue(obj, 'docsUrl') as string | null
|
|
59
60
|
const idValue = getPropertyValue(obj, config.idField) as string | null
|
|
60
61
|
|
|
61
62
|
let schemaVariableName: string | null = null
|
|
@@ -165,6 +166,7 @@ export const createAddKeyedWiring = (config: KeyedWiringConfig): AddWiring => {
|
|
|
165
166
|
displayName: displayNameValue,
|
|
166
167
|
description: descriptionValue || undefined,
|
|
167
168
|
rotationPeriod: rotationPeriodValue || undefined,
|
|
169
|
+
docsUrl: docsUrlValue || undefined,
|
|
168
170
|
[config.idField]: idValue,
|
|
169
171
|
schema: schemaLookupName,
|
|
170
172
|
sourceFile,
|