@wootsup/mcp 0.1.0 → 0.4.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 +157 -83
- package/README.md +31 -27
- package/SECURITY.md +15 -6
- package/dist/auth/keychain.d.ts +27 -1
- package/dist/auth/keychain.js +48 -2
- package/dist/auth/keychain.js.map +1 -1
- package/dist/catalog/build-catalog.d.ts +31 -0
- package/dist/catalog/build-catalog.js +68 -0
- package/dist/catalog/build-catalog.js.map +1 -0
- package/dist/cli-hint.d.ts +22 -0
- package/dist/cli-hint.js +55 -0
- package/dist/cli-hint.js.map +1 -0
- package/dist/index.js +129 -22
- package/dist/index.js.map +1 -1
- package/dist/install-skill.js +1 -1
- package/dist/modules/apimapper/auto-layout.d.ts +21 -0
- package/dist/modules/apimapper/auto-layout.js +54 -0
- package/dist/modules/apimapper/auto-layout.js.map +1 -0
- package/dist/modules/apimapper/cache.js +25 -17
- package/dist/modules/apimapper/cache.js.map +1 -1
- package/dist/modules/apimapper/client.d.ts +115 -4
- package/dist/modules/apimapper/client.js +699 -304
- package/dist/modules/apimapper/client.js.map +1 -1
- package/dist/modules/apimapper/connections-format.d.ts +31 -1
- package/dist/modules/apimapper/connections-format.js +97 -5
- package/dist/modules/apimapper/connections-format.js.map +1 -1
- package/dist/modules/apimapper/connections.d.ts +9 -7
- package/dist/modules/apimapper/connections.js +449 -127
- package/dist/modules/apimapper/connections.js.map +1 -1
- package/dist/modules/apimapper/credential-sanitizer.d.ts +5 -0
- package/dist/modules/apimapper/credential-sanitizer.js +60 -1
- package/dist/modules/apimapper/credential-sanitizer.js.map +1 -1
- package/dist/modules/apimapper/credentials.js +105 -61
- package/dist/modules/apimapper/credentials.js.map +1 -1
- package/dist/modules/apimapper/diagnose.js +21 -2
- package/dist/modules/apimapper/diagnose.js.map +1 -1
- package/dist/modules/apimapper/elicitation.d.ts +29 -0
- package/dist/modules/apimapper/elicitation.js +62 -0
- package/dist/modules/apimapper/elicitation.js.map +1 -1
- package/dist/modules/apimapper/example-extract.d.ts +13 -0
- package/dist/modules/apimapper/example-extract.js +111 -0
- package/dist/modules/apimapper/example-extract.js.map +1 -0
- package/dist/modules/apimapper/filter-operators.d.ts +24 -0
- package/dist/modules/apimapper/filter-operators.js +103 -0
- package/dist/modules/apimapper/filter-operators.js.map +1 -0
- package/dist/modules/apimapper/flows-format.js +92 -22
- package/dist/modules/apimapper/flows-format.js.map +1 -1
- package/dist/modules/apimapper/flows.d.ts +8 -7
- package/dist/modules/apimapper/flows.js +275 -120
- package/dist/modules/apimapper/flows.js.map +1 -1
- package/dist/modules/apimapper/gateway/advanced-read-tool.d.ts +9 -0
- package/dist/modules/apimapper/gateway/advanced-read-tool.js +172 -0
- package/dist/modules/apimapper/gateway/advanced-read-tool.js.map +1 -0
- package/dist/modules/apimapper/gateway/advanced-tool.js +66 -106
- package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -1
- package/dist/modules/apimapper/gateway/collect-module-tools.d.ts +17 -0
- package/dist/modules/apimapper/gateway/collect-module-tools.js +44 -0
- package/dist/modules/apimapper/gateway/collect-module-tools.js.map +1 -0
- package/dist/modules/apimapper/gateway/essentials.d.ts +1 -1
- package/dist/modules/apimapper/gateway/essentials.js +21 -2
- package/dist/modules/apimapper/gateway/essentials.js.map +1 -1
- package/dist/modules/apimapper/gateway/gateway-shared.d.ts +21 -0
- package/dist/modules/apimapper/gateway/gateway-shared.js +124 -0
- package/dist/modules/apimapper/gateway/gateway-shared.js.map +1 -0
- package/dist/modules/apimapper/gateway/test-support.d.ts +1 -17
- package/dist/modules/apimapper/gateway/test-support.js +4 -33
- package/dist/modules/apimapper/gateway/test-support.js.map +1 -1
- package/dist/modules/apimapper/get-skill-cores.d.ts +4 -0
- package/dist/modules/apimapper/get-skill-cores.js +220 -0
- package/dist/modules/apimapper/get-skill-cores.js.map +1 -0
- package/dist/modules/apimapper/get-skill.d.ts +1 -1
- package/dist/modules/apimapper/get-skill.js +74 -9
- package/dist/modules/apimapper/get-skill.js.map +1 -1
- package/dist/modules/apimapper/graph-builder.d.ts +85 -2
- package/dist/modules/apimapper/graph-builder.js +151 -15
- package/dist/modules/apimapper/graph-builder.js.map +1 -1
- package/dist/modules/apimapper/graph.js +152 -48
- package/dist/modules/apimapper/graph.js.map +1 -1
- package/dist/modules/apimapper/index.js +27 -13
- package/dist/modules/apimapper/index.js.map +1 -1
- package/dist/modules/apimapper/jmespath-test.d.ts +4 -0
- package/dist/modules/apimapper/jmespath-test.js +152 -0
- package/dist/modules/apimapper/jmespath-test.js.map +1 -0
- package/dist/modules/apimapper/library.js +553 -88
- package/dist/modules/apimapper/library.js.map +1 -1
- package/dist/modules/apimapper/license.js +12 -36
- package/dist/modules/apimapper/license.js.map +1 -1
- package/dist/modules/apimapper/list-footer.d.ts +27 -0
- package/dist/modules/apimapper/list-footer.js +57 -0
- package/dist/modules/apimapper/list-footer.js.map +1 -0
- package/dist/modules/apimapper/local-sources.js +100 -57
- package/dist/modules/apimapper/local-sources.js.map +1 -1
- package/dist/modules/apimapper/mcp-client-identity.d.ts +32 -0
- package/dist/modules/apimapper/mcp-client-identity.js +70 -0
- package/dist/modules/apimapper/mcp-client-identity.js.map +1 -0
- package/dist/modules/apimapper/merge-constants.d.ts +6 -0
- package/dist/modules/apimapper/merge-constants.js +26 -0
- package/dist/modules/apimapper/merge-constants.js.map +1 -0
- package/dist/modules/apimapper/misc.js +13 -27
- package/dist/modules/apimapper/misc.js.map +1 -1
- package/dist/modules/apimapper/node-schema.d.ts +52 -2
- package/dist/modules/apimapper/node-schema.js +95 -4
- package/dist/modules/apimapper/node-schema.js.map +1 -1
- package/dist/modules/apimapper/onboarding.d.ts +59 -1
- package/dist/modules/apimapper/onboarding.js +231 -28
- package/dist/modules/apimapper/onboarding.js.map +1 -1
- package/dist/modules/apimapper/read-cache.d.ts +16 -3
- package/dist/modules/apimapper/read-cache.js +59 -4
- package/dist/modules/apimapper/read-cache.js.map +1 -1
- package/dist/modules/apimapper/render/index.js +26 -5
- package/dist/modules/apimapper/render/index.js.map +1 -1
- package/dist/modules/apimapper/resource-id.d.ts +13 -0
- package/dist/modules/apimapper/resource-id.js +69 -0
- package/dist/modules/apimapper/resource-id.js.map +1 -0
- package/dist/modules/apimapper/schema.js +9 -18
- package/dist/modules/apimapper/schema.js.map +1 -1
- package/dist/modules/apimapper/settings.js +49 -52
- package/dist/modules/apimapper/settings.js.map +1 -1
- package/dist/modules/apimapper/sites-tools.d.ts +29 -0
- package/dist/modules/apimapper/sites-tools.js +165 -0
- package/dist/modules/apimapper/sites-tools.js.map +1 -0
- package/dist/modules/apimapper/tool-result.d.ts +66 -0
- package/dist/modules/apimapper/tool-result.js +125 -0
- package/dist/modules/apimapper/tool-result.js.map +1 -0
- package/dist/modules/apimapper/toolslist-size.d.ts +12 -11
- package/dist/modules/apimapper/toolslist-size.js +34 -21
- package/dist/modules/apimapper/toolslist-size.js.map +1 -1
- package/dist/modules/apimapper/types.d.ts +34 -0
- package/dist/modules/apimapper/types.js +1 -1
- package/dist/modules/apimapper/types.js.map +1 -1
- package/dist/modules/apimapper/whitelist-drift.d.ts +85 -0
- package/dist/modules/apimapper/whitelist-drift.js +375 -0
- package/dist/modules/apimapper/whitelist-drift.js.map +1 -0
- package/dist/modules/apimapper/workflows.js +302 -58
- package/dist/modules/apimapper/workflows.js.map +1 -1
- package/dist/modules/apimapper/yootheme-binding.d.ts +35 -0
- package/dist/modules/apimapper/yootheme-binding.js +267 -0
- package/dist/modules/apimapper/yootheme-binding.js.map +1 -0
- package/dist/platform/index.d.ts +56 -0
- package/dist/platform/index.js +158 -2
- package/dist/platform/index.js.map +1 -1
- package/dist/proxy/bridge.d.ts +35 -0
- package/dist/proxy/bridge.js +129 -0
- package/dist/proxy/bridge.js.map +1 -0
- package/dist/proxy/mode.d.ts +9 -0
- package/dist/proxy/mode.js +20 -0
- package/dist/proxy/mode.js.map +1 -0
- package/dist/setup/detect-clients.d.ts +40 -1
- package/dist/setup/detect-clients.js +148 -1
- package/dist/setup/detect-clients.js.map +1 -1
- package/dist/setup/probe-auth.d.ts +51 -0
- package/dist/setup/probe-auth.js +141 -0
- package/dist/setup/probe-auth.js.map +1 -0
- package/dist/setup/probe-handshake.js +40 -7
- package/dist/setup/probe-handshake.js.map +1 -1
- package/dist/setup/remove-config.d.ts +8 -0
- package/dist/setup/remove-config.js +145 -0
- package/dist/setup/remove-config.js.map +1 -0
- package/dist/setup/uninstall.d.ts +34 -0
- package/dist/setup/uninstall.js +147 -0
- package/dist/setup/uninstall.js.map +1 -0
- package/dist/setup-cli.d.ts +16 -0
- package/dist/setup-cli.js +63 -1
- package/dist/setup-cli.js.map +1 -1
- package/dist/sites/loader.d.ts +48 -0
- package/dist/sites/loader.js +134 -0
- package/dist/sites/loader.js.map +1 -0
- package/dist/sites/schema.d.ts +69 -0
- package/dist/sites/schema.js +71 -0
- package/dist/sites/schema.js.map +1 -0
- package/dist/sites/secret-resolver.d.ts +47 -0
- package/dist/sites/secret-resolver.js +150 -0
- package/dist/sites/secret-resolver.js.map +1 -0
- package/dist/skill-instructions.d.ts +14 -1
- package/dist/skill-instructions.js +35 -6
- package/dist/skill-instructions.js.map +1 -1
- package/dist/transports/stdio.js +4 -4
- package/dist/transports/stdio.js.map +1 -1
- package/dist/uninstall-skill.d.ts +27 -0
- package/dist/uninstall-skill.js +89 -0
- package/dist/uninstall-skill.js.map +1 -0
- package/docs/architecture.md +21 -21
- package/docs/customgraph-internal-migration.md +4 -4
- package/docs/security.md +2 -21
- package/docs/tools.md +40 -12
- package/manifest.json +77 -79
- package/package.json +69 -65
- package/skills/apimapper/SKILL.md +128 -7
- package/skills/apimapper/reference/conditional-style-multi-items.md +114 -0
- package/skills/apimapper/reference/dynamize-existing-layout.md +158 -0
- package/skills/apimapper/reference/jmespath-cookbook.md +241 -0
- package/skills/apimapper/reference/jmespath-pitfalls.md +189 -0
- package/skills/apimapper/reference/joomla.md +1 -1
- package/skills/apimapper/reference/library-template-discovery.md +65 -0
- package/skills/apimapper/reference/merge-two-sources-on-key.md +204 -0
- package/skills/apimapper/reference/oauth.md +143 -52
- package/skills/apimapper/reference/troubleshooting.md +22 -2
- package/skills/apimapper/reference/yootheme-source-to-builder-handoff.md +348 -0
- package/skills/apimapper/reference/yootheme.md +75 -44
- package/dist/auth/oauth-provider.d.ts +0 -68
- package/dist/auth/oauth-provider.js +0 -232
- package/dist/auth/oauth-provider.js.map +0 -1
- package/dist/server-http.d.ts +0 -22
- package/dist/server-http.js +0 -159
- package/dist/server-http.js.map +0 -1
- package/dist/transports/http.d.ts +0 -29
- package/dist/transports/http.js +0 -267
- package/dist/transports/http.js.map +0 -1
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult, errorResult, readOnly } from "@getimo/mcp-toolkit";
|
|
3
3
|
import { request, hintFor } from "./client.js";
|
|
4
|
-
import {
|
|
4
|
+
import { restErrorResult } from "./tool-result.js";
|
|
5
|
+
import { nodeSchema, edgeSchema, ensureEdgeIds, isOutputNode } from "./node-schema.js";
|
|
6
|
+
/**
|
|
7
|
+
* F10 (2026-06-09): pick the flow's TERMINAL node id — the output-* node that
|
|
8
|
+
* the graph computes up to by default. Returns the id of the LAST output node
|
|
9
|
+
* in document order (a flow has exactly one terminal output; on the rare
|
|
10
|
+
* multi-output graph the last one authored wins, matching the FlowCompiler's
|
|
11
|
+
* findOutputNode tail-bias) or `undefined` when no output node exists. A loose
|
|
12
|
+
* `{ id?, type? }` shape is accepted so it works on both validated FlowNodes
|
|
13
|
+
* and raw hydrated wire objects.
|
|
14
|
+
*/
|
|
15
|
+
function terminalOutputNodeId(nodes) {
|
|
16
|
+
let found;
|
|
17
|
+
for (const n of nodes) {
|
|
18
|
+
if (isOutputNode(n)) {
|
|
19
|
+
const id = n.id;
|
|
20
|
+
if (typeof id === "string" && id !== "")
|
|
21
|
+
found = id;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return found;
|
|
25
|
+
}
|
|
5
26
|
import { buildFlowVisualization, SIDECAR_RESPONSE_MAX_CHARS, } from "./render/sidecar.js";
|
|
6
27
|
/**
|
|
7
28
|
* L-7 (W3F-5): hydrate `{nodes, edges}` from a saved flow when the
|
|
@@ -41,8 +62,15 @@ export function registerGraphTools(server) {
|
|
|
41
62
|
"result without re-executing the pipeline. Use `forceRefresh: true` only after a " +
|
|
42
63
|
"Connection/Credential mutation or when upstream API data is known to have changed. " +
|
|
43
64
|
"Do NOT call repeatedly to 're-render' or 'double-check' the same graph — the second " +
|
|
44
|
-
"call returns the same payload as the first
|
|
45
|
-
"
|
|
65
|
+
"call returns the same payload as the first.\n\n" +
|
|
66
|
+
"**Merge join with 0 rows:** when a `merge` node (strategy `join`) yields 0 items while both " +
|
|
67
|
+
"its inputs had data, the response carries a `merge_diagnostics[<mergeNodeId>]` object " +
|
|
68
|
+
"(`reason: merge_no_match`) with the join keys and a sample of the non-matching key values " +
|
|
69
|
+
"from each side. Read it instead of guessing — the usual cause is a wrong/incomparable join " +
|
|
70
|
+
"key (e.g. string \"P-100\" vs number 42). Sample both sides with apimapper_connection_data, " +
|
|
71
|
+
"then fix the merge joinKey/joinKeyRight." +
|
|
72
|
+
"\n\nExample:\n apimapper_graph_preview({ nodes: [{ id: 'src1', type: 'source', position: { x: 0, y: 0 }, data: { connectionId: 'con_abc123' } }], edges: [], target_node_id: 'src1' })" +
|
|
73
|
+
"\n apimapper_graph_preview({ id: 'flow_Z2fLg70M84' }) // `id` is an alias for `flow_id`",
|
|
46
74
|
inputSchema: {
|
|
47
75
|
// L-7 (W3F-5): `flow_id` shortcut hydrates {nodes, edges} from
|
|
48
76
|
// the saved flow server-side so the caller does not have to
|
|
@@ -52,7 +80,17 @@ export function registerGraphTools(server) {
|
|
|
52
80
|
.string()
|
|
53
81
|
.optional()
|
|
54
82
|
.describe("Saved flow ID. When set, {nodes, edges} are loaded from the flow before preview. " +
|
|
55
|
-
"Inline {nodes, edges} (if also provided) override the loaded values."
|
|
83
|
+
"Inline {nodes, edges} (if also provided) override the loaded values. " +
|
|
84
|
+
"`id` is accepted as an alias (see below); `flow_id` wins when both are passed."),
|
|
85
|
+
// D (2026-06-04): `id` is an alias for `flow_id`. The AI repeatedly
|
|
86
|
+
// passed {id: "flow_…"} → "Invalid arguments". Mirror the dual-name
|
|
87
|
+
// ergonomics of apimapper_flow_full_recompile_publish. When both are
|
|
88
|
+
// present, explicit `flow_id` wins.
|
|
89
|
+
id: z
|
|
90
|
+
.string()
|
|
91
|
+
.optional()
|
|
92
|
+
.describe("Alias for `flow_id`. When `flow_id` is absent and `id` is present, `id` is used to " +
|
|
93
|
+
"hydrate {nodes, edges} from the saved flow. `flow_id` takes precedence when both are set."),
|
|
56
94
|
nodes: z
|
|
57
95
|
.array(nodeSchema)
|
|
58
96
|
.optional()
|
|
@@ -67,28 +105,70 @@ export function registerGraphTools(server) {
|
|
|
67
105
|
targetNodeId: z
|
|
68
106
|
.string()
|
|
69
107
|
.optional()
|
|
70
|
-
.describe("Compute preview up to this node and return its output
|
|
108
|
+
.describe("Compute preview up to this node and return its output. When omitted, defaults " +
|
|
109
|
+
"to the flow's terminal output node (the output-* node) so passing just a flow id " +
|
|
110
|
+
"previews the finished source. Snake_case alias: `target_node_id`."),
|
|
111
|
+
// F60 + F152: snake_case alias. graph_preview is one of the
|
|
112
|
+
// few tools with a camelCase wire contract; cold agents reflexively
|
|
113
|
+
// pass the snake_case form (every other tool uses it, and this tool's
|
|
114
|
+
// OWN example shows `target_node_id`). Accept both — `targetNodeId`
|
|
115
|
+
// (canonical) wins on conflict. The wire body keeps camelCase
|
|
116
|
+
// (whitelist-drift pins {nodes,edges,targetNodeId,forceRefresh}).
|
|
117
|
+
target_node_id: z
|
|
118
|
+
.string()
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("Snake_case alias of `targetNodeId`. `targetNodeId` wins when both are set."),
|
|
121
|
+
// F10 (2026-06-09): accept a `limit` arg gracefully. The AI passes it
|
|
122
|
+
// reflexively (mirroring the *_list / *_query tools); rejecting it as an
|
|
123
|
+
// unknown key forced a confusing retry. The preview already caps the
|
|
124
|
+
// returned items at 50 server-side-of-the-tool; `limit` lets the caller
|
|
125
|
+
// ask for fewer. Clamped to [1, 50] — the upstream pipeline still
|
|
126
|
+
// executes fully; this only trims the items echoed back.
|
|
127
|
+
limit: z
|
|
128
|
+
.number()
|
|
129
|
+
.int()
|
|
130
|
+
.min(1)
|
|
131
|
+
.max(50)
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Max preview items to return (1-50, default 50). Caps only the echoed items list — " +
|
|
134
|
+
"the pipeline still executes in full. Accepted for ergonomic parity with the list/query tools."),
|
|
71
135
|
forceRefresh: z
|
|
72
136
|
.boolean()
|
|
73
137
|
.default(false)
|
|
74
|
-
.describe("Skip snapshot/cache; always live-fetch from upstream"
|
|
138
|
+
.describe("Skip snapshot/cache; always live-fetch from upstream. " +
|
|
139
|
+
"Snake_case alias: `force_refresh`."),
|
|
140
|
+
// F60 + F152: snake_case alias for `forceRefresh` — same
|
|
141
|
+
// ergonomics rationale as `target_node_id`. No default here so an
|
|
142
|
+
// absent value does not shadow the canonical `forceRefresh: false`
|
|
143
|
+
// default; the handler ORs the two (either truthy → refresh).
|
|
144
|
+
force_refresh: z
|
|
145
|
+
.boolean()
|
|
146
|
+
.optional()
|
|
147
|
+
.describe("Snake_case alias of `forceRefresh`. Either spelling being true forces a refresh."),
|
|
75
148
|
},
|
|
76
149
|
annotations: readOnly({ title: "Preview Graph", openWorld: true }),
|
|
77
|
-
}, async ({ flow_id, nodes, edges, targetNodeId, forceRefresh }) => {
|
|
78
|
-
//
|
|
150
|
+
}, async ({ flow_id, id, nodes, edges, targetNodeId, target_node_id, limit, forceRefresh, force_refresh }) => {
|
|
151
|
+
// F60 + F152: resolve the snake_case aliases. Canonical camelCase
|
|
152
|
+
// wins for the target node (explicit `targetNodeId` over the alias);
|
|
153
|
+
// `forceRefresh` is a boolean OR so either spelling being true refreshes.
|
|
154
|
+
const resolvedTargetNodeId = targetNodeId ?? target_node_id;
|
|
155
|
+
const resolvedForceRefresh = forceRefresh || force_refresh === true;
|
|
156
|
+
// D (2026-06-04): resolve the `id` alias — explicit `flow_id` (canonical)
|
|
157
|
+
// wins over `id` when both are present, mirroring
|
|
158
|
+
// apimapper_flow_full_recompile_publish.
|
|
159
|
+
const resolvedFlowId = flow_id ?? id;
|
|
160
|
+
// L-7 (W3F-5): hydrate from the flow id when inline arrays are absent.
|
|
79
161
|
let resolvedNodes = nodes;
|
|
80
162
|
let resolvedEdges = edges;
|
|
81
|
-
if (typeof
|
|
82
|
-
|
|
163
|
+
if (typeof resolvedFlowId === "string" &&
|
|
164
|
+
resolvedFlowId !== "" &&
|
|
83
165
|
(!Array.isArray(resolvedNodes) || resolvedNodes.length === 0)) {
|
|
84
|
-
const h = await hydrateGraphFromFlowId(
|
|
166
|
+
const h = await hydrateGraphFromFlowId(resolvedFlowId);
|
|
85
167
|
if ("error" in h) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
details: { flow_id },
|
|
91
|
-
});
|
|
168
|
+
// Per-site nuance: the hydration failure (h.error always present)
|
|
169
|
+
// pins a fixed `not_found` suggestion regardless of the underlying
|
|
170
|
+
// error code, since a missing/empty flow is the only failure mode here.
|
|
171
|
+
return restErrorResult(h, { flow_id: resolvedFlowId }, { suggestion: hintFor("not_found") });
|
|
92
172
|
}
|
|
93
173
|
resolvedNodes = h.nodes;
|
|
94
174
|
resolvedEdges = h.edges;
|
|
@@ -105,34 +185,62 @@ export function registerGraphTools(server) {
|
|
|
105
185
|
resolvedEdges = [];
|
|
106
186
|
}
|
|
107
187
|
const localNodes = resolvedNodes;
|
|
108
|
-
|
|
188
|
+
// F5 (2026-06-09): stamp a stable id on any id-less inline edge before
|
|
189
|
+
// POST so the backend graph engine accepts the graph (same fix as
|
|
190
|
+
// flow_create). Hydrated edges already carry ids; ensureEdgeIds is a
|
|
191
|
+
// no-op for them.
|
|
192
|
+
const localEdges = ensureEdgeIds(resolvedEdges);
|
|
193
|
+
// F10 (2026-06-09): when no explicit targetNodeId was given, default to
|
|
194
|
+
// the flow's terminal output node so passing just a flow id previews the
|
|
195
|
+
// finished source (instead of an ambiguous "(terminal)" the backend has
|
|
196
|
+
// to guess). An explicit targetNodeId always wins. Falls back to
|
|
197
|
+
// undefined (backend picks) when the graph carries no output node yet.
|
|
198
|
+
const effectiveTargetNodeId = resolvedTargetNodeId ?? terminalOutputNodeId(localNodes);
|
|
109
199
|
// PHP success body: {preview, outputCount, executedNodes, nodeOutputCounts,
|
|
110
200
|
// nodeOutputs}. There's no `trace` key. Audit: F-A2-11.
|
|
111
201
|
const r = await request("/graph/preview", {
|
|
112
202
|
method: "POST",
|
|
113
|
-
body: JSON.stringify({
|
|
203
|
+
body: JSON.stringify({
|
|
204
|
+
nodes: localNodes,
|
|
205
|
+
edges: localEdges,
|
|
206
|
+
targetNodeId: effectiveTargetNodeId,
|
|
207
|
+
forceRefresh: resolvedForceRefresh,
|
|
208
|
+
}),
|
|
114
209
|
});
|
|
115
210
|
if (!r.success) {
|
|
116
|
-
return
|
|
117
|
-
message: r.error ?? "graph preview failed",
|
|
118
|
-
code: r.errorCode ?? (r.status ? String(r.status) : undefined),
|
|
119
|
-
suggestion: hintFor(r.errorCode),
|
|
120
|
-
details: { node_count: localNodes.length, edge_count: localEdges.length, targetNodeId, forceRefresh },
|
|
121
|
-
});
|
|
211
|
+
return restErrorResult(r, { node_count: localNodes.length, edge_count: localEdges.length, targetNodeId: effectiveTargetNodeId, forceRefresh: resolvedForceRefresh }, { message: "graph preview failed" });
|
|
122
212
|
}
|
|
123
213
|
const items = Array.isArray(r.data?.preview) ? r.data.preview : [];
|
|
124
214
|
const itemCount = items.length;
|
|
215
|
+
// A2: forward the merge-no-match diagnostic verbatim (PHP owns the
|
|
216
|
+
// {reason, message, joinKey, joinKeyRight, *_key_sample, …} contract).
|
|
217
|
+
// Additive: only present when PHP attached it (a 0-row join with
|
|
218
|
+
// non-empty inputs), so the happy-path envelope shape is unchanged.
|
|
219
|
+
const mergeDiagnostics = r.data?.mergeDiagnostics !== null &&
|
|
220
|
+
typeof r.data?.mergeDiagnostics === "object" &&
|
|
221
|
+
!Array.isArray(r.data?.mergeDiagnostics) &&
|
|
222
|
+
Object.keys(r.data.mergeDiagnostics).length > 0
|
|
223
|
+
? r.data.mergeDiagnostics
|
|
224
|
+
: undefined;
|
|
225
|
+
// F10: honor `limit` (clamped at the schema to 1..50) when echoing items.
|
|
226
|
+
// The pipeline already executed in full; this only trims the echoed list.
|
|
227
|
+
const itemCap = typeof limit === "number" ? Math.min(limit, 50) : 50;
|
|
125
228
|
return formatResult({
|
|
126
229
|
ok: true,
|
|
127
230
|
item_count: itemCount,
|
|
128
231
|
output_count: r.data?.outputCount,
|
|
129
232
|
executed_nodes: r.data?.executedNodes,
|
|
130
233
|
node_output_counts: r.data?.nodeOutputCounts,
|
|
131
|
-
target_node:
|
|
132
|
-
force_refresh:
|
|
133
|
-
...(typeof
|
|
134
|
-
|
|
135
|
-
|
|
234
|
+
target_node: effectiveTargetNodeId || "(terminal)",
|
|
235
|
+
force_refresh: resolvedForceRefresh,
|
|
236
|
+
...(typeof resolvedFlowId === "string" && resolvedFlowId !== ""
|
|
237
|
+
? { flow_id: resolvedFlowId }
|
|
238
|
+
: {}),
|
|
239
|
+
...(mergeDiagnostics ? { merge_diagnostics: mergeDiagnostics } : {}),
|
|
240
|
+
items: items.slice(0, itemCap),
|
|
241
|
+
note: itemCount > itemCap
|
|
242
|
+
? `Showing first ${itemCap} of ${itemCount} items.`
|
|
243
|
+
: undefined,
|
|
136
244
|
}, false, { maxChars: 6000 });
|
|
137
245
|
});
|
|
138
246
|
// ── apimapper_graph_validate ───────────────────────────────────────
|
|
@@ -140,7 +248,7 @@ export function registerGraphTools(server) {
|
|
|
140
248
|
title: "Graph Validate (Shape Check)",
|
|
141
249
|
description: "Validate a graph's structure (cycles, disconnected nodes, missing outputs, type mismatches) " +
|
|
142
250
|
"WITHOUT executing the pipeline. Fast — no upstream fetches." +
|
|
143
|
-
"\n\nExample:\n apimapper_graph_validate({ nodes: [{ id: 'src1', type: 'source' }, { id: 'out1', type: 'output' }], edges: [{ source: 'src1', target: 'out1' }] })",
|
|
251
|
+
"\n\nExample:\n apimapper_graph_validate({ nodes: [{ id: 'src1', type: 'source', position: { x: 0, y: 0 }, data: { connectionId: 'con_abc123' } }, { id: 'out1', type: 'output', position: { x: 320, y: 0 }, data: {} }], edges: [{ source: 'src1', target: 'out1' }] })",
|
|
144
252
|
inputSchema: {
|
|
145
253
|
// L-7 (W3F-5): symmetric with apimapper_graph_preview — pass
|
|
146
254
|
// `flow_id` to validate a saved flow without re-sending the
|
|
@@ -168,12 +276,10 @@ export function registerGraphTools(server) {
|
|
|
168
276
|
(!Array.isArray(resolvedNodes) || resolvedNodes.length === 0)) {
|
|
169
277
|
const h = await hydrateGraphFromFlowId(flow_id);
|
|
170
278
|
if ("error" in h) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
details: { flow_id },
|
|
176
|
-
});
|
|
279
|
+
// Per-site nuance: the hydration failure (h.error always present)
|
|
280
|
+
// pins a fixed `not_found` suggestion regardless of the underlying
|
|
281
|
+
// error code, since a missing/empty flow is the only failure mode here.
|
|
282
|
+
return restErrorResult(h, { flow_id }, { suggestion: hintFor("not_found") });
|
|
177
283
|
}
|
|
178
284
|
resolvedNodes = h.nodes;
|
|
179
285
|
resolvedEdges = h.edges;
|
|
@@ -190,7 +296,10 @@ export function registerGraphTools(server) {
|
|
|
190
296
|
resolvedEdges = [];
|
|
191
297
|
}
|
|
192
298
|
const localNodes = resolvedNodes;
|
|
193
|
-
|
|
299
|
+
// F5 (2026-06-09): stamp a stable id on any id-less inline edge before
|
|
300
|
+
// POST — same fix as flow_create / graph_preview. The validator reports
|
|
301
|
+
// edges by id, so an id-less edge surfaced confusing diagnostics.
|
|
302
|
+
const localEdges = ensureEdgeIds(resolvedEdges);
|
|
194
303
|
// PHP success body: {valid:true, warnings:[], nodeCount, edgeCount}. On
|
|
195
304
|
// invalid the errors are squashed to a single string via
|
|
196
305
|
// HandlerResult::error() and surface as `r.error` here. Wave 1C may emit
|
|
@@ -203,16 +312,11 @@ export function registerGraphTools(server) {
|
|
|
203
312
|
const structuredErrors = Array.isArray(r.errors)
|
|
204
313
|
? r.errors
|
|
205
314
|
: undefined;
|
|
206
|
-
return
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
node_count: localNodes.length,
|
|
212
|
-
edge_count: localEdges.length,
|
|
213
|
-
...(structuredErrors ? { errors: structuredErrors } : {}),
|
|
214
|
-
},
|
|
215
|
-
});
|
|
315
|
+
return restErrorResult(r, {
|
|
316
|
+
node_count: localNodes.length,
|
|
317
|
+
edge_count: localEdges.length,
|
|
318
|
+
...(structuredErrors ? { errors: structuredErrors } : {}),
|
|
319
|
+
}, { message: "graph validate failed" });
|
|
216
320
|
}
|
|
217
321
|
const valid = r.data?.valid ?? true;
|
|
218
322
|
const warns = r.data?.warnings || [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/modules/apimapper/graph.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/modules/apimapper/graph.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEvF;;;;;;;;GAQG;AACH,SAAS,oBAAoB,CAAC,KAA6B;IACzD,IAAI,KAAyB,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,YAAY,CAAC,CAAuB,CAAC,EAAG,CAAC;YAC3C,MAAM,EAAE,GAAI,CAAsB,CAAC,EAAE,CAAC;YACtC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,EAAE;gBAAE,KAAK,GAAG,EAAE,CAAC;QACtD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAiBD,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AACH,KAAK,UAAU,sBAAsB,CAAC,MAAc;IAIlD,MAAM,CAAC,GAAG,MAAM,OAAO,CAAoB,UAAU,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,QAAQ,MAAM,YAAY;YAC5C,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAK,CAAC,KAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAK,CAAC,KAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,KAAK,EAAE,QAAQ,MAAM,eAAe;YACpC,SAAS,EAAE,YAAY;SACxB,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,sEAAsE;IACtE,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,KAAK,EAAE,kCAAkC;QACzC,WAAW,EACT,wFAAwF;YACxF,yEAAyE;YACzE,2FAA2F;YAC3F,kFAAkF;YAClF,qFAAqF;YACrF,sFAAsF;YACtF,iDAAiD;YACjD,8FAA8F;YAC9F,wFAAwF;YACxF,4FAA4F;YAC5F,6FAA6F;YAC7F,8FAA8F;YAC9F,0CAA0C;YAC1C,yLAAyL;YACzL,2FAA2F;QAC7F,WAAW,EAAE;YACX,+DAA+D;YAC/D,4DAA4D;YAC5D,6DAA6D;YAC7D,2DAA2D;YAC3D,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,mFAAmF;gBACjF,uEAAuE;gBACvE,gFAAgF,CACnF;YACH,oEAAoE;YACpE,oEAAoE;YACpE,qEAAqE;YACrE,oCAAoC;YACpC,EAAE,EAAE,CAAC;iBACF,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,qFAAqF;gBACnF,2FAA2F,CAC9F;YACH,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,UAAU,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,4DAA4D;gBAC1D,2HAA2H;gBAC3H,oFAAoF,CACvF;YACH,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,UAAU,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,yEAAyE;gBACvE,qEAAqE,CACxE;YACH,YAAY,EAAE,CAAC;iBACZ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gFAAgF;gBAC9E,mFAAmF;gBACnF,mEAAmE,CACtE;YACH,4DAA4D;YAC5D,oEAAoE;YACpE,sEAAsE;YACtE,oEAAoE;YACpE,8DAA8D;YAC9D,kEAAkE;YAClE,cAAc,EAAE,CAAC;iBACd,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,4EAA4E,CAAC;YACzF,sEAAsE;YACtE,yEAAyE;YACzE,qEAAqE;YACrE,wEAAwE;YACxE,kEAAkE;YAClE,yDAAyD;YACzD,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,EAAE;iBACV,QAAQ,CACP,oFAAoF;gBAClF,+FAA+F,CAClG;YACH,YAAY,EAAE,CAAC;iBACZ,OAAO,EAAE;iBACT,OAAO,CAAC,KAAK,CAAC;iBACd,QAAQ,CACP,wDAAwD;gBACtD,oCAAoC,CACvC;YACH,yDAAyD;YACzD,kEAAkE;YAClE,mEAAmE;YACnE,8DAA8D;YAC9D,aAAa,EAAE,CAAC;iBACb,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CAAC,kFAAkF,CAAC;SAChG;QACD,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACnE,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,EAAE,EAAE;QACxG,kEAAkE;QAClE,qEAAqE;QACrE,0EAA0E;QAC1E,MAAM,oBAAoB,GAAG,YAAY,IAAI,cAAc,CAAC;QAC5D,MAAM,oBAAoB,GAAG,YAAY,IAAI,aAAa,KAAK,IAAI,CAAC;QACpE,0EAA0E;QAC1E,kDAAkD;QAClD,yCAAyC;QACzC,MAAM,cAAc,GAAG,OAAO,IAAI,EAAE,CAAC;QACrC,uEAAuE;QACvE,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IACE,OAAO,cAAc,KAAK,QAAQ;YAClC,cAAc,KAAK,EAAE;YACrB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,EAC7D,CAAC;YACD,MAAM,CAAC,GAAG,MAAM,sBAAsB,CAAC,cAAc,CAAC,CAAC;YACvD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;gBACjB,kEAAkE;gBAClE,mEAAmE;gBACnE,wEAAwE;gBACxE,OAAO,eAAe,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC/F,CAAC;YACD,aAAa,GAAG,CAAC,CAAC,KAA0C,CAAC;YAC7D,aAAa,GAAG,CAAC,CAAC,KAA0C,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChE,OAAO,WAAW,CAAC;gBACjB,OAAO,EAAE,qDAAqD;gBAC9D,IAAI,EAAE,aAAa;gBACnB,UAAU,EAAE,uEAAuE;gBACnF,OAAO,EAAE,EAAE;aACZ,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,aAAa,GAAG,EAAE,CAAC;QACrB,CAAC;QACD,MAAM,UAAU,GAAG,aAAa,CAAC;QACjC,uEAAuE;QACvE,kEAAkE;QAClE,qEAAqE;QACrE,kBAAkB;QAClB,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;QAChD,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;QACxE,iEAAiE;QACjE,uEAAuE;QACvE,MAAM,qBAAqB,GACzB,oBAAoB,IAAI,oBAAoB,CAAC,UAAU,CAAC,CAAC;QAC3D,4EAA4E;QAC5E,wDAAwD;QACxD,MAAM,CAAC,GAAG,MAAM,OAAO,CAYpB,gBAAgB,EAAE;YACnB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,UAAU;gBACjB,KAAK,EAAE,UAAU;gBACjB,YAAY,EAAE,qBAAqB;gBACnC,YAAY,EAAE,oBAAoB;aACnC,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,oBAAoB,EAAE,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;QAC5M,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;QAC/B,mEAAmE;QACnE,uEAAuE;QACvE,iEAAiE;QACjE,oEAAoE;QACpE,MAAM,gBAAgB,GACpB,CAAC,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI;YACjC,OAAO,CAAC,CAAC,IAAI,EAAE,gBAAgB,KAAK,QAAQ;YAC5C,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,gBAAgB,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,GAAG,CAAC;YAC7C,CAAC,CAAE,CAAC,CAAC,IAAI,CAAC,gBAA4C;YACtD,CAAC,CAAC,SAAS,CAAC;QAChB,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,OAAO,YAAY,CACjB;YACE,EAAE,EAAE,IAAI;YACR,UAAU,EAAE,SAAS;YACrB,YAAY,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW;YACjC,cAAc,EAAE,CAAC,CAAC,IAAI,EAAE,aAAa;YACrC,kBAAkB,EAAE,CAAC,CAAC,IAAI,EAAE,gBAAgB;YAC5C,WAAW,EAAE,qBAAqB,IAAI,YAAY;YAClD,aAAa,EAAE,oBAAoB;YACnC,GAAG,CAAC,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,KAAK,EAAE;gBAC7D,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE;gBAC7B,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC;YAC9B,IAAI,EACF,SAAS,GAAG,OAAO;gBACjB,CAAC,CAAC,iBAAiB,OAAO,OAAO,SAAS,SAAS;gBACnD,CAAC,CAAC,SAAS;SAChB,EACD,KAAK,EACL,EAAE,QAAQ,EAAE,IAAI,EAAE,CACnB,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,sEAAsE;IACtE,MAAM,CAAC,YAAY,CACjB,0BAA0B,EAC1B;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,8FAA8F;YAC9F,6DAA6D;YAC7D,0QAA0Q;QAC5Q,WAAW,EAAE;YACX,6DAA6D;YAC7D,4DAA4D;YAC5D,gBAAgB;YAChB,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,qFAAqF,CACtF;YACH,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,UAAU,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,0MAA0M,CAC3M;YACH,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,UAAU,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CAAC,4FAA4F,CAAC;SAC1G;QACD,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACpE,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QAClC,+DAA+D;QAC/D,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IACE,OAAO,OAAO,KAAK,QAAQ;YAC3B,OAAO,KAAK,EAAE;YACd,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,EAC7D,CAAC;YACD,MAAM,CAAC,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAChD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;gBACjB,kEAAkE;gBAClE,mEAAmE;gBACnE,wEAAwE;gBACxE,OAAO,eAAe,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,aAAa,GAAG,CAAC,CAAC,KAA0C,CAAC;YAC7D,aAAa,GAAG,CAAC,CAAC,KAA0C,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,OAAO,WAAW,CAAC;gBACjB,OAAO,EAAE,kDAAkD;gBAC3D,IAAI,EAAE,aAAa;gBACnB,UAAU,EAAE,uEAAuE;gBACnF,OAAO,EAAE,EAAE;aACZ,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,aAAa,GAAG,EAAE,CAAC;QACrB,CAAC;QACD,MAAM,UAAU,GAAG,aAAa,CAAC;QACjC,uEAAuE;QACvE,wEAAwE;QACxE,kEAAkE;QAClE,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;QAChD,wEAAwE;QACxE,yDAAyD;QACzD,yEAAyE;QACzE,mEAAmE;QACnE,MAAM,CAAC,GAAG,MAAM,OAAO,CAOrB,iBAAiB,EACjB;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;SAC/D,CACF,CAAC;QACF,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAE,CAA4B,CAAC,MAAM,CAAC;gBAC1E,CAAC,CAAE,CAA4B,CAAC,MAAM;gBACtC,CAAC,CAAC,SAAS,CAAC;YACd,OAAO,eAAe,CAAC,CAAC,EAAE;gBACtB,UAAU,EAAE,UAAU,CAAC,MAAM;gBAC7B,UAAU,EAAE,UAAU,CAAC,MAAM;gBAC7B,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1D,EAAE,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;QACpC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;QACrC,+DAA+D;QAC/D,8DAA8D;QAC9D,gEAAgE;QAChE,MAAM,GAAG,GAAG,sBAAsB,CAAC;YACjC,KAAK,EAAE,UAA+C;YACtD,KAAK,EAAE,UAA+C;YACtD,EAAE,EAAE,OAAO,IAAI,WAAW;YAC1B,IAAI,EAAE,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC,iBAAiB;SAC5F,CAAC,CAAC;QACH,OAAO,YAAY,CACjB;YACE,KAAK;YACL,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS;YAC7B,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS;YAC7B,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACtD,QAAQ,EAAE,KAAK;YACf,GAAG,CAAC,GAAG,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;SACpC;QACD,gEAAgE;QAChE,6CAA6C;QAC7C,CAAC,KAAK;QACN,6DAA6D;QAC7D,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CACzC,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -5,10 +5,12 @@ import { registerGraphTools } from "./graph.js";
|
|
|
5
5
|
import { registerLocalSourceTools } from "./local-sources.js";
|
|
6
6
|
import { registerSchemaTools } from "./schema.js";
|
|
7
7
|
import { registerLibraryTools } from "./library.js";
|
|
8
|
+
import { registerYoothemeBindingTools } from "./yootheme-binding.js";
|
|
8
9
|
import { registerCacheTools } from "./cache.js";
|
|
9
10
|
import { registerSettingsTools } from "./settings.js";
|
|
10
11
|
import { registerLicenseTools } from "./license.js";
|
|
11
12
|
import { registerMiscTools } from "./misc.js";
|
|
13
|
+
import { registerJmespathTestTool } from "./jmespath-test.js";
|
|
12
14
|
import { registerWorkflowTools } from "./workflows.js";
|
|
13
15
|
import { registerSkillResources } from "./skill-resources.js";
|
|
14
16
|
import { registerGetSkillTool } from "./get-skill.js";
|
|
@@ -18,6 +20,7 @@ import { registerDiagnoseTool } from "./diagnose.js";
|
|
|
18
20
|
import { registerRenderTool } from "./render/index.js";
|
|
19
21
|
import { CapturingServer } from "./gateway/capturing-server.js";
|
|
20
22
|
import { registerAdvancedTool } from "./gateway/advanced-tool.js";
|
|
23
|
+
import { registerAdvancedReadTool } from "./gateway/advanced-read-tool.js";
|
|
21
24
|
import { toElicitationCapability } from "./elicitation.js";
|
|
22
25
|
/**
|
|
23
26
|
* Module-level cache of the advanced-tool registry captured during the most
|
|
@@ -52,29 +55,36 @@ export const apimapperRestModule = {
|
|
|
52
55
|
// Route every tool registration through the CapturingServer: essentials
|
|
53
56
|
// forward to the real server, the rest are captured for the gateway.
|
|
54
57
|
const capturing = new CapturingServer(server);
|
|
55
|
-
// W3.6
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
58
|
+
// W3.6 / chat-first decision (2026-06-15) — the native elicitation picker
|
|
59
|
+
// is now reserved for OAuth authorization ONLY. `oauth_authorize_begin`
|
|
60
|
+
// (credentials.ts) keeps the picker because explicit consent on WHICH
|
|
61
|
+
// credential to authorize is security-relevant; ordinary credential/flow
|
|
62
|
+
// disambiguation (connection_create, flow_compile) returns a structured
|
|
63
|
+
// candidate-list error so the assistant asks in plain chat instead.
|
|
64
|
+
// The toolkit's `elicitChoice` needs a `{ server: { elicitInput } }`
|
|
65
|
+
// whose `elicitInput` is typed with the toolkit's loose
|
|
66
|
+
// `ElicitInputParams`; the SDK's `McpServer.server.elicitInput` is the
|
|
67
|
+
// stricter discriminated form/url union, so `toElicitationCapability` is
|
|
68
|
+
// the typed adapter that bridges the two (single documented cast — see
|
|
69
|
+
// elicitation.ts). When the argument is absent (host wiring without
|
|
70
|
+
// elicitation), the OAuth path falls back to a structured `errorResult`
|
|
71
|
+
// on genuine ambiguity instead of prompting.
|
|
66
72
|
const elicitation = toElicitationCapability(server);
|
|
67
|
-
registerConnectionTools(capturing
|
|
73
|
+
registerConnectionTools(capturing);
|
|
68
74
|
registerCredentialTools(capturing, elicitation);
|
|
69
|
-
registerFlowTools(capturing
|
|
75
|
+
registerFlowTools(capturing);
|
|
70
76
|
registerGraphTools(capturing);
|
|
71
77
|
registerLocalSourceTools(capturing);
|
|
72
78
|
registerSchemaTools(capturing);
|
|
73
79
|
registerLibraryTools(capturing);
|
|
80
|
+
registerYoothemeBindingTools(capturing);
|
|
74
81
|
registerCacheTools(capturing);
|
|
75
82
|
registerSettingsTools(capturing);
|
|
76
83
|
registerLicenseTools(capturing);
|
|
77
84
|
registerMiscTools(capturing);
|
|
85
|
+
// P-B (JMESPath superpowers) — apimapper_jmespath_test. Not an essential,
|
|
86
|
+
// so the CapturingServer routes it into the apimapper_advanced gateway.
|
|
87
|
+
registerJmespathTestTool(capturing);
|
|
78
88
|
registerWorkflowTools(capturing);
|
|
79
89
|
// Skill resources are an MCP-spec protocol concept but Claude Desktop
|
|
80
90
|
// (2026-05-19 rc-period) does not yet honour the `audience: ["assistant"]`
|
|
@@ -97,6 +107,10 @@ export const apimapperRestModule = {
|
|
|
97
107
|
// Register the single gateway to every captured advanced tool.
|
|
98
108
|
const advancedRegistry = capturing.getAdvancedRegistry();
|
|
99
109
|
registerAdvancedTool(server, advancedRegistry);
|
|
110
|
+
// F200b — and the READ-ONLY sibling gateway, whitelisting just the
|
|
111
|
+
// side-effect-free advanced tools (readOnlyHint-derived). Lets a host
|
|
112
|
+
// call the read surface without write-confirmation prompts.
|
|
113
|
+
registerAdvancedReadTool(server, advancedRegistry);
|
|
100
114
|
lastAdvancedRegistry = advancedRegistry;
|
|
101
115
|
},
|
|
102
116
|
getAdvancedRegistry: () => lastAdvancedRegistry,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/apimapper/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,eAAe,EAA0B,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAkB3D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,IAAI,oBAAgE,CAAC;AAErE,MAAM,CAAC,MAAM,mBAAmB,GAAwB;IACtD,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,kGAAkG;QAClG,oFAAoF;QACpF,iDAAiD;IACnD,QAAQ,EAAE,CAAC,MAAiB,EAAE,EAAE;QAC9B,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QAE9C,yEAAyE;QACzE,qEAAqE;QACrE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/apimapper/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ToolRegistrar } from "./gateway/capturing-server.js";
|
|
2
|
+
/** Test-only: clear the remembered sample hash so each test starts cold. */
|
|
3
|
+
export declare function __resetJmespathSampleHashForTests(): void;
|
|
4
|
+
export declare function registerJmespathTestTool(server: ToolRegistrar): void;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// src/modules/apimapper/jmespath-test.ts — P-B (JMESPath superpowers for cold
|
|
2
|
+
// agents).
|
|
3
|
+
//
|
|
4
|
+
// REST surface: POST /jmespath/test (WP REST + Joomla com_ajax `jmespathTest`).
|
|
5
|
+
// Domain: a stateless dry-run of a JMESPath expression against sample rows,
|
|
6
|
+
// evaluated server-side through the SAME JmesPathAdapter the Transform pipeline
|
|
7
|
+
// uses — so custom primitives (date_weekday / date_iso_to_time / date_iso_to_date
|
|
8
|
+
// / time_in_window / format_number / coalesce_empty / conditional) resolve
|
|
9
|
+
// identically, and a failing expression returns the SAME teaching hints the
|
|
10
|
+
// Transform / flow-write path adds (the arithmetic hint, the depth-split remedy).
|
|
11
|
+
//
|
|
12
|
+
// This is the iteration tool a cold agent reaches for BEFORE wiring an
|
|
13
|
+
// expression into a Transform node: paste the expression + a couple of sample
|
|
14
|
+
// rows, read {result, row_count}, refine, repeat. Pair it with
|
|
15
|
+
// apimapper_get_skill({ topic: 'jmespath-cookbook' }) for copy-paste recipes.
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
import { formatResult, readOnly } from "@getimo/mcp-toolkit";
|
|
19
|
+
import { request } from "./client.js";
|
|
20
|
+
import { restErrorResult } from "./tool-result.js";
|
|
21
|
+
/**
|
|
22
|
+
* F199 (Desktop-E2E #2 forensics, 2026-06-12) — module-internal hash of the
|
|
23
|
+
* LAST sample_rows the tool was called with. When a follow-up call re-sends
|
|
24
|
+
* byte-identical rows (the common "iterate the expression against the same
|
|
25
|
+
* data" loop), the response references the unchanged sample instead of the
|
|
26
|
+
* model re-reading the full echo. The hash is per-process (a single MCP server
|
|
27
|
+
* instance serves one conversation), reset only by the test hook below.
|
|
28
|
+
*/
|
|
29
|
+
let lastSampleRowsHash;
|
|
30
|
+
/** Stable hash of the sample_rows payload (order-preserving JSON of the value). */
|
|
31
|
+
function hashSampleRows(sampleRows) {
|
|
32
|
+
return createHash("sha256").update(JSON.stringify(sampleRows)).digest("hex");
|
|
33
|
+
}
|
|
34
|
+
/** Test-only: clear the remembered sample hash so each test starts cold. */
|
|
35
|
+
export function __resetJmespathSampleHashForTests() {
|
|
36
|
+
lastSampleRowsHash = undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* F199: the dedup advisory emitted when the caller re-sent the SAME sample_rows
|
|
40
|
+
* as the immediately preceding call. It is a steering signal — the agent does
|
|
41
|
+
* not need to keep re-pasting (or re-reading) the unchanged rows.
|
|
42
|
+
*/
|
|
43
|
+
const SAMPLE_UNCHANGED_NOTE = "sample unchanged (same as previous call) — you re-sent identical sample_rows; " +
|
|
44
|
+
"no need to re-paste them, just send the new expression next time.";
|
|
45
|
+
/**
|
|
46
|
+
* F159: the missing-rows advisory the tool emits when sample_rows were omitted
|
|
47
|
+
* for an expression that reads rows and the server didn't already supply one
|
|
48
|
+
* (older backend). Kept in sync with the PHP {@link JmespathTestHandler}.
|
|
49
|
+
*/
|
|
50
|
+
const MISSING_ROWS_NOTE = "no sample_rows supplied — the expression addresses rows, so the empty result " +
|
|
51
|
+
"is because there is no input to evaluate against, NOT because the expression is " +
|
|
52
|
+
"wrong. Supply rows via the `sample_rows` argument (grab real ones with " +
|
|
53
|
+
"apimapper_connection_data) and re-run.";
|
|
54
|
+
/**
|
|
55
|
+
* True when the expression actually references the input data rather than
|
|
56
|
+
* being a self-contained LITERAL or empty. Mirrors
|
|
57
|
+
* {@link JmespathTestHandler::expressionAddressesRows} (PHP): the empty
|
|
58
|
+
* expression, the `@` identity, and a backtick/raw-string literal do NOT
|
|
59
|
+
* address rows; everything else does.
|
|
60
|
+
*/
|
|
61
|
+
function expressionAddressesRows(expression) {
|
|
62
|
+
const trimmed = expression.trim();
|
|
63
|
+
if (trimmed === "" || trimmed === "@")
|
|
64
|
+
return false;
|
|
65
|
+
const first = trimmed[0];
|
|
66
|
+
if (first === "`" || first === "'")
|
|
67
|
+
return false; // pure literal
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
export function registerJmespathTestTool(server) {
|
|
71
|
+
server.registerTool("apimapper_jmespath_test", {
|
|
72
|
+
title: "Test a JMESPath Expression",
|
|
73
|
+
description: "Dry-run a JMESPath expression against sample rows, evaluated server-side through the " +
|
|
74
|
+
"SAME engine as the Transform pipeline (custom primitives date_weekday / date_iso_to_time / " +
|
|
75
|
+
"date_iso_to_date / time_in_window / format_number / coalesce_empty / conditional all resolve). Returns " +
|
|
76
|
+
"{ result, row_count }; a malformed expression returns a 422 with the SAME teaching hint the " +
|
|
77
|
+
"Transform/flow-write path adds (arithmetic, depth-split). Iterate here BEFORE wiring an " +
|
|
78
|
+
"expression into a Transform node. The rows argument is `sample_rows` " +
|
|
79
|
+
"(NOT `data`). For copy-paste recipes call " +
|
|
80
|
+
"apimapper_get_skill({ topic: 'jmespath-cookbook' })." +
|
|
81
|
+
"\n\nExample:\n apimapper_jmespath_test({ expression: \"[*].{name: name, price: format_number(price)}\", " +
|
|
82
|
+
"sample_rows: [{ name: 'Villa', price: 890000 }] })",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
expression: z
|
|
85
|
+
.string()
|
|
86
|
+
.describe("The JMESPath expression to evaluate (e.g. \"[*].name\" or " +
|
|
87
|
+
"\"[?to_number(price) > `100`]\"). Empty string returns sample_rows unchanged."),
|
|
88
|
+
sample_rows: z
|
|
89
|
+
.union([z.array(z.unknown()), z.record(z.string(), z.unknown())])
|
|
90
|
+
.optional()
|
|
91
|
+
.describe("The data to evaluate against — either a LIST of row objects " +
|
|
92
|
+
"(`[{...}, {...}]`, item-level scope) or a single wrapper object " +
|
|
93
|
+
"(`{items: [...]}`, top-level scope). Omit to test a literal expression " +
|
|
94
|
+
"against an empty list. Use connection_data to grab real rows first."),
|
|
95
|
+
},
|
|
96
|
+
// Pure read — never mutates flows/connections/state. Server-side it
|
|
97
|
+
// evaluates against the supplied rows and returns the result.
|
|
98
|
+
annotations: readOnly({ title: "Test JMESPath Expression", openWorld: false }),
|
|
99
|
+
}, async ({ expression, sample_rows }) => {
|
|
100
|
+
const r = await request("/jmespath/test", {
|
|
101
|
+
method: "POST",
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
expression,
|
|
104
|
+
// Default to an empty list so a body-less literal test still works
|
|
105
|
+
// and the server's row_count is deterministic.
|
|
106
|
+
sample_rows: sample_rows ?? [],
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
if (!r.success) {
|
|
110
|
+
// The teaching message rides inside `error` (and `errorBody.error`);
|
|
111
|
+
// restErrorResult surfaces it as the result message verbatim so the
|
|
112
|
+
// agent reads the arithmetic / depth-split hint, not a bare 422.
|
|
113
|
+
return restErrorResult(r, { expression: expression.slice(0, 80) }, { message: "JMESPath test failed" });
|
|
114
|
+
}
|
|
115
|
+
// F159: prefer the server's note; otherwise synthesise the missing-rows
|
|
116
|
+
// advisory ourselves when the caller omitted/emptied sample_rows for a
|
|
117
|
+
// row-addressing expression (covers older backends that don't yet attach
|
|
118
|
+
// the note). Never annotate when rows WERE supplied (an empty result is
|
|
119
|
+
// then a real signal) or for trivial literal/empty expressions.
|
|
120
|
+
const rowsOmitted = sample_rows === undefined ||
|
|
121
|
+
(Array.isArray(sample_rows) && sample_rows.length === 0);
|
|
122
|
+
const note = r.data?.note ??
|
|
123
|
+
(rowsOmitted && expressionAddressesRows(expression) ? MISSING_ROWS_NOTE : undefined);
|
|
124
|
+
// F199: detect a re-sent identical sample_rows blob. Only meaningful when
|
|
125
|
+
// rows were actually supplied — an omitted/empty payload is the
|
|
126
|
+
// missing-rows case (handled above), not an echo to dedup. Update the
|
|
127
|
+
// remembered hash on every call that carries rows so the NEXT call can
|
|
128
|
+
// compare. The unchanged-note rides alongside any existing note rather
|
|
129
|
+
// than replacing it (the two are mutually exclusive in practice, but
|
|
130
|
+
// additive composition keeps both signals intact if they ever co-occur).
|
|
131
|
+
let sampleUnchanged;
|
|
132
|
+
if (!rowsOmitted) {
|
|
133
|
+
const hash = hashSampleRows(sample_rows);
|
|
134
|
+
if (lastSampleRowsHash !== undefined && hash === lastSampleRowsHash) {
|
|
135
|
+
sampleUnchanged = SAMPLE_UNCHANGED_NOTE;
|
|
136
|
+
}
|
|
137
|
+
lastSampleRowsHash = hash;
|
|
138
|
+
}
|
|
139
|
+
const payload = {
|
|
140
|
+
result: r.data?.result ?? null,
|
|
141
|
+
row_count: r.data?.row_count ?? 0,
|
|
142
|
+
};
|
|
143
|
+
if (note !== undefined) {
|
|
144
|
+
payload.note = note;
|
|
145
|
+
}
|
|
146
|
+
if (sampleUnchanged !== undefined) {
|
|
147
|
+
payload.sample_note = sampleUnchanged;
|
|
148
|
+
}
|
|
149
|
+
return formatResult(payload, false, { maxChars: 4000 });
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=jmespath-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jmespath-test.js","sourceRoot":"","sources":["../../../src/modules/apimapper/jmespath-test.ts"],"names":[],"mappings":"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"}
|