@wootsup/mcp 0.1.0 → 0.3.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +148 -83
  2. package/README.md +31 -27
  3. package/SECURITY.md +15 -6
  4. package/dist/auth/keychain.d.ts +27 -1
  5. package/dist/auth/keychain.js +48 -2
  6. package/dist/auth/keychain.js.map +1 -1
  7. package/dist/cli-hint.d.ts +22 -0
  8. package/dist/cli-hint.js +55 -0
  9. package/dist/cli-hint.js.map +1 -0
  10. package/dist/index.js +97 -22
  11. package/dist/index.js.map +1 -1
  12. package/dist/install-skill.js +1 -1
  13. package/dist/modules/apimapper/cache.js +25 -17
  14. package/dist/modules/apimapper/cache.js.map +1 -1
  15. package/dist/modules/apimapper/client.d.ts +62 -1
  16. package/dist/modules/apimapper/client.js +555 -291
  17. package/dist/modules/apimapper/client.js.map +1 -1
  18. package/dist/modules/apimapper/connections.js +230 -75
  19. package/dist/modules/apimapper/connections.js.map +1 -1
  20. package/dist/modules/apimapper/credential-sanitizer.d.ts +5 -0
  21. package/dist/modules/apimapper/credential-sanitizer.js +60 -1
  22. package/dist/modules/apimapper/credential-sanitizer.js.map +1 -1
  23. package/dist/modules/apimapper/credentials.js +19 -47
  24. package/dist/modules/apimapper/credentials.js.map +1 -1
  25. package/dist/modules/apimapper/diagnose.js +21 -2
  26. package/dist/modules/apimapper/diagnose.js.map +1 -1
  27. package/dist/modules/apimapper/flows.js +60 -77
  28. package/dist/modules/apimapper/flows.js.map +1 -1
  29. package/dist/modules/apimapper/gateway/advanced-tool.js +56 -5
  30. package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -1
  31. package/dist/modules/apimapper/gateway/essentials.d.ts +1 -1
  32. package/dist/modules/apimapper/gateway/essentials.js +8 -1
  33. package/dist/modules/apimapper/gateway/essentials.js.map +1 -1
  34. package/dist/modules/apimapper/get-skill.d.ts +1 -1
  35. package/dist/modules/apimapper/get-skill.js +44 -6
  36. package/dist/modules/apimapper/get-skill.js.map +1 -1
  37. package/dist/modules/apimapper/graph.js +40 -36
  38. package/dist/modules/apimapper/graph.js.map +1 -1
  39. package/dist/modules/apimapper/index.js +2 -0
  40. package/dist/modules/apimapper/index.js.map +1 -1
  41. package/dist/modules/apimapper/library.js +425 -83
  42. package/dist/modules/apimapper/library.js.map +1 -1
  43. package/dist/modules/apimapper/license.js +12 -36
  44. package/dist/modules/apimapper/license.js.map +1 -1
  45. package/dist/modules/apimapper/local-sources.js +20 -34
  46. package/dist/modules/apimapper/local-sources.js.map +1 -1
  47. package/dist/modules/apimapper/misc.js +13 -27
  48. package/dist/modules/apimapper/misc.js.map +1 -1
  49. package/dist/modules/apimapper/onboarding.d.ts +30 -1
  50. package/dist/modules/apimapper/onboarding.js +114 -19
  51. package/dist/modules/apimapper/onboarding.js.map +1 -1
  52. package/dist/modules/apimapper/schema.js +9 -18
  53. package/dist/modules/apimapper/schema.js.map +1 -1
  54. package/dist/modules/apimapper/settings.js +49 -52
  55. package/dist/modules/apimapper/settings.js.map +1 -1
  56. package/dist/modules/apimapper/sites-tools.d.ts +29 -0
  57. package/dist/modules/apimapper/sites-tools.js +165 -0
  58. package/dist/modules/apimapper/sites-tools.js.map +1 -0
  59. package/dist/modules/apimapper/tool-result.d.ts +46 -0
  60. package/dist/modules/apimapper/tool-result.js +63 -0
  61. package/dist/modules/apimapper/tool-result.js.map +1 -0
  62. package/dist/modules/apimapper/toolslist-size.d.ts +11 -10
  63. package/dist/modules/apimapper/toolslist-size.js +16 -14
  64. package/dist/modules/apimapper/toolslist-size.js.map +1 -1
  65. package/dist/modules/apimapper/types.d.ts +21 -0
  66. package/dist/modules/apimapper/types.js.map +1 -1
  67. package/dist/modules/apimapper/whitelist-drift.d.ts +85 -0
  68. package/dist/modules/apimapper/whitelist-drift.js +360 -0
  69. package/dist/modules/apimapper/whitelist-drift.js.map +1 -0
  70. package/dist/modules/apimapper/workflows.js +82 -27
  71. package/dist/modules/apimapper/workflows.js.map +1 -1
  72. package/dist/modules/apimapper/yootheme-binding.d.ts +35 -0
  73. package/dist/modules/apimapper/yootheme-binding.js +186 -0
  74. package/dist/modules/apimapper/yootheme-binding.js.map +1 -0
  75. package/dist/platform/index.d.ts +56 -0
  76. package/dist/platform/index.js +151 -2
  77. package/dist/platform/index.js.map +1 -1
  78. package/dist/setup/detect-clients.d.ts +40 -1
  79. package/dist/setup/detect-clients.js +148 -1
  80. package/dist/setup/detect-clients.js.map +1 -1
  81. package/dist/setup/probe-handshake.js +40 -7
  82. package/dist/setup/probe-handshake.js.map +1 -1
  83. package/dist/setup/remove-config.d.ts +8 -0
  84. package/dist/setup/remove-config.js +145 -0
  85. package/dist/setup/remove-config.js.map +1 -0
  86. package/dist/setup/uninstall.d.ts +34 -0
  87. package/dist/setup/uninstall.js +147 -0
  88. package/dist/setup/uninstall.js.map +1 -0
  89. package/dist/setup-cli.d.ts +7 -0
  90. package/dist/setup-cli.js +29 -1
  91. package/dist/setup-cli.js.map +1 -1
  92. package/dist/sites/loader.d.ts +41 -0
  93. package/dist/sites/loader.js +119 -0
  94. package/dist/sites/loader.js.map +1 -0
  95. package/dist/sites/schema.d.ts +69 -0
  96. package/dist/sites/schema.js +71 -0
  97. package/dist/sites/schema.js.map +1 -0
  98. package/dist/sites/secret-resolver.d.ts +47 -0
  99. package/dist/sites/secret-resolver.js +150 -0
  100. package/dist/sites/secret-resolver.js.map +1 -0
  101. package/dist/skill-instructions.d.ts +1 -1
  102. package/dist/skill-instructions.js +5 -0
  103. package/dist/skill-instructions.js.map +1 -1
  104. package/dist/transports/stdio.js +4 -4
  105. package/dist/transports/stdio.js.map +1 -1
  106. package/dist/uninstall-skill.d.ts +27 -0
  107. package/dist/uninstall-skill.js +89 -0
  108. package/dist/uninstall-skill.js.map +1 -0
  109. package/docs/architecture.md +21 -21
  110. package/docs/customgraph-internal-migration.md +4 -4
  111. package/docs/security.md +2 -21
  112. package/docs/tools.md +40 -12
  113. package/manifest.json +77 -79
  114. package/package.json +68 -65
  115. package/skills/apimapper/SKILL.md +53 -7
  116. package/skills/apimapper/reference/conditional-style-multi-items.md +114 -0
  117. package/skills/apimapper/reference/jmespath-pitfalls.md +108 -0
  118. package/skills/apimapper/reference/joomla.md +1 -1
  119. package/skills/apimapper/reference/library-template-discovery.md +65 -0
  120. package/skills/apimapper/reference/merge-two-sources-on-key.md +99 -0
  121. package/skills/apimapper/reference/troubleshooting.md +20 -0
  122. package/skills/apimapper/reference/yootheme.md +1 -1
  123. package/dist/auth/oauth-provider.d.ts +0 -68
  124. package/dist/auth/oauth-provider.js +0 -232
  125. package/dist/auth/oauth-provider.js.map +0 -1
  126. package/dist/server-http.d.ts +0 -22
  127. package/dist/server-http.js +0 -159
  128. package/dist/server-http.js.map +0 -1
  129. package/dist/transports/http.d.ts +0 -29
  130. package/dist/transports/http.js +0 -267
  131. package/dist/transports/http.js.map +0 -1
@@ -0,0 +1,360 @@
1
+ // src/modules/apimapper/whitelist-drift.ts — Wave-16 #88
2
+ //
3
+ // MCP↔PHP whitelist drift detector — shared harness.
4
+ //
5
+ // PURPOSE
6
+ // -------
7
+ // Every API Mapper MCP tool that mutates state POSTs/PUTs a JSON body to a
8
+ // WordPress REST route under /wp-json/api-mapper/v1/. If a tool puts a key in
9
+ // that body which the PHP handler does NOT read, one of two bad things happens:
10
+ //
11
+ // * the PHP layer silently DROPS the key (the tool advertises behaviour that
12
+ // never takes effect — e.g. an ordering option that does nothing), or
13
+ // * the PHP layer REJECTS the request (e.g. ConnectionAdminController's
14
+ // ALLOWED_PATCH_KEYS 422s an unknown patch key).
15
+ //
16
+ // Both are real defects, and both are invisible to the type system because the
17
+ // MCP and PHP sides live in different languages. This harness reconciles the
18
+ // two surfaces so a CI test fails the moment they drift.
19
+ //
20
+ // THE THREE INPUTS
21
+ // ----------------
22
+ // 1. The LIVE MCP tool surface — enumerated at runtime from the registered
23
+ // module (essentials forwarded to a real McpServer + advanced registry +
24
+ // the externally-registered profile/status tools). See collectLiveTools().
25
+ // 2. TOOL_WIRE_MAP — the hand-maintained bridge from each body-sending tool to
26
+ // the REST route it calls and the EXACT wire body keys it sends. The wire
27
+ // keys are NOT always the zod keys: several tools remap (e.g.
28
+ // local_source_query's zod `content_type` → wire `contentType`). A PHP scan
29
+ // cannot see this remap and the zod schema does not encode the route, so
30
+ // this bridge is curated. It is anti-rot-guarded: the test asserts it
31
+ // covers EXACTLY the live tool set (minus declared local tools), so a new
32
+ // or removed tool fails CI until the map is updated.
33
+ // 3. The PHP-accepted-params manifest (tests/fixtures/php-accepted-params.json)
34
+ // — route → accepted body keys, generated by scripts/dump-rest-whitelist.php
35
+ // from the real controllers and hand-reconciled. Plus `_allowed_drift`
36
+ // (per-tool justified exceptions) and `_local_tools` (tools with no REST
37
+ // route).
38
+ //
39
+ // The harness is pure + import-safe (no network, no env requirement) so it can
40
+ // be imported by both the vitest pin test and the standalone gate script.
41
+ import { readFileSync } from "node:fs";
42
+ import { fileURLToPath } from "node:url";
43
+ import { dirname, resolve } from "node:path";
44
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
45
+ import { apimapperRestModule } from "./index.js";
46
+ /**
47
+ * Curated bridge: body-sending tool → route + wire body keys.
48
+ *
49
+ * ONLY tools that send a request body appear here. Read-only (GET) tools and
50
+ * path/query-only tools carry no body-drift surface and are listed in the
51
+ * manifest's `_local_tools` (when they hit no route at all) or are simply
52
+ * absent (when they hit a GET route — GET routes never drift on body keys).
53
+ *
54
+ * `envelope` tools forward a free-form record (`patch` / `pipeline` / a settings
55
+ * map) whose individual keys are validated on the PHP side (e.g.
56
+ * ConnectionAdminController::ALLOWED_PATCH_KEYS). Their wrapper key is recorded
57
+ * so the test confirms the tool is accounted for; per-key validation lives in
58
+ * the PHP layer and is covered by PHP-side tests.
59
+ */
60
+ export const TOOL_WIRE_MAP = {
61
+ // ── Connections ────────────────────────────────────────────────────
62
+ apimapper_connection_create: {
63
+ route: "POST /connections",
64
+ bodyKeys: [
65
+ "name",
66
+ "endpoint",
67
+ "method",
68
+ "auth_type",
69
+ "credential_id",
70
+ "items_path",
71
+ "cache_ttl",
72
+ "description",
73
+ ],
74
+ kind: "structured",
75
+ },
76
+ apimapper_connection_update: {
77
+ route: "PUT /connections/{id}",
78
+ bodyKeys: ["patch"],
79
+ kind: "envelope",
80
+ },
81
+ apimapper_connection_recover: {
82
+ route: "PUT /connections/{id}",
83
+ bodyKeys: ["patch"],
84
+ kind: "envelope",
85
+ },
86
+ apimapper_connection_test: {
87
+ route: "POST /connections/test",
88
+ bodyKeys: ["connection_id"],
89
+ kind: "structured",
90
+ },
91
+ apimapper_connection_health_check: {
92
+ route: "POST /connections/health-check",
93
+ bodyKeys: ["connection_ids"],
94
+ kind: "structured",
95
+ },
96
+ apimapper_connection_pipeline_update: {
97
+ route: "PUT /connections/{id}/pipeline",
98
+ bodyKeys: ["pipeline"],
99
+ kind: "envelope",
100
+ },
101
+ // ── Credentials ────────────────────────────────────────────────────
102
+ apimapper_credential_create: {
103
+ route: "POST /credentials",
104
+ bodyKeys: [
105
+ "name",
106
+ "auth_type",
107
+ "auth_data",
108
+ "oauth_provider",
109
+ "provider",
110
+ "oauth_token_expires_at",
111
+ ],
112
+ kind: "structured",
113
+ },
114
+ apimapper_credential_update: {
115
+ route: "PUT /credentials/{id}",
116
+ bodyKeys: ["patch"],
117
+ kind: "envelope",
118
+ },
119
+ apimapper_credential_link: {
120
+ route: "POST /oauth/authorize",
121
+ bodyKeys: ["existing_credential_id", "scopes"],
122
+ kind: "structured",
123
+ },
124
+ apimapper_oauth_authorize_begin: {
125
+ route: "POST /oauth/authorize",
126
+ bodyKeys: ["existing_credential_id", "scopes"],
127
+ kind: "structured",
128
+ },
129
+ // ── Flows ──────────────────────────────────────────────────────────
130
+ apimapper_flow_create: {
131
+ route: "POST /flows",
132
+ bodyKeys: ["name", "description", "nodes", "edges", "viewport"],
133
+ kind: "structured",
134
+ },
135
+ apimapper_flow_update: {
136
+ route: "PUT /flows/{id}",
137
+ bodyKeys: ["patch"],
138
+ kind: "envelope",
139
+ },
140
+ apimapper_flow_import_validate: {
141
+ route: "POST /flows/import/validate",
142
+ bodyKeys: ["bundle"],
143
+ kind: "envelope",
144
+ },
145
+ apimapper_flow_import: {
146
+ route: "POST /flows/import",
147
+ bodyKeys: ["bundle"],
148
+ kind: "envelope",
149
+ },
150
+ // ── Graph / Schema ─────────────────────────────────────────────────
151
+ apimapper_graph_preview: {
152
+ route: "POST /graph/preview",
153
+ bodyKeys: ["nodes", "edges", "targetNodeId", "forceRefresh"],
154
+ kind: "structured",
155
+ },
156
+ apimapper_graph_validate: {
157
+ route: "POST /graph/validate",
158
+ bodyKeys: ["nodes", "edges"],
159
+ kind: "structured",
160
+ },
161
+ apimapper_schema_profile: {
162
+ route: "POST /schema-profile",
163
+ bodyKeys: ["nodes", "edges", "target_node_id", "flow_id"],
164
+ kind: "structured",
165
+ },
166
+ // ── Local sources ──────────────────────────────────────────────────
167
+ apimapper_local_source_query: {
168
+ route: "POST /local-sources/query",
169
+ // Wire keys after the handler's zod→wire remap: content_type→contentType,
170
+ // orderby→sort, order→sortDirection (see #88 reconciliation).
171
+ bodyKeys: ["contentType", "filters", "limit", "offset", "sort", "sortDirection"],
172
+ kind: "structured",
173
+ },
174
+ // ── Cache / Settings ───────────────────────────────────────────────
175
+ apimapper_cache_invalidate: {
176
+ route: "POST /cache/admin/invalidate",
177
+ bodyKeys: ["scope", "payload"],
178
+ kind: "structured",
179
+ },
180
+ apimapper_settings_update: {
181
+ route: "POST /settings",
182
+ bodyKeys: ["patch"],
183
+ kind: "envelope",
184
+ },
185
+ // ── License ────────────────────────────────────────────────────────
186
+ apimapper_license_activate: {
187
+ route: "POST /license/activate",
188
+ bodyKeys: ["license_key", "email"],
189
+ kind: "structured",
190
+ },
191
+ apimapper_license_beta_channel: {
192
+ route: "POST /license/beta-channel",
193
+ bodyKeys: ["enabled"],
194
+ kind: "structured",
195
+ },
196
+ // ── Misc ───────────────────────────────────────────────────────────
197
+ apimapper_health_warnings_dismiss: {
198
+ route: "POST /admin/health-warnings/dismiss",
199
+ bodyKeys: ["id"],
200
+ kind: "structured",
201
+ },
202
+ apimapper_feedback_submit: {
203
+ route: "POST /feedback",
204
+ bodyKeys: ["type", "subject", "message", "email", "attachments", "idempotency_key"],
205
+ kind: "structured",
206
+ },
207
+ apimapper_release_download: {
208
+ route: "POST /releases/download",
209
+ bodyKeys: ["version", "product"],
210
+ kind: "structured",
211
+ },
212
+ };
213
+ /**
214
+ * Resolve the committed fixture path. From this module
215
+ * (`<pkg>/{src,dist}/modules/apimapper/whitelist-drift.{ts,js}`) the package
216
+ * root is three directories up; the fixture is `tests/fixtures/...` under it.
217
+ * The depth is identical for the source layout (vitest/tsx) and the built
218
+ * `dist/` layout, so the same relative offset works in both.
219
+ */
220
+ export function manifestPath() {
221
+ const here = dirname(fileURLToPath(import.meta.url));
222
+ return resolve(here, "..", "..", "..", "tests", "fixtures", "php-accepted-params.json");
223
+ }
224
+ /** Narrowing guard for the parsed manifest JSON. */
225
+ function isManifest(value) {
226
+ if (typeof value !== "object" || value === null)
227
+ return false;
228
+ const v = value;
229
+ return (typeof v.routes === "object" &&
230
+ v.routes !== null &&
231
+ typeof v._allowed_drift === "object" &&
232
+ v._allowed_drift !== null &&
233
+ typeof v._local_tools === "object" &&
234
+ v._local_tools !== null);
235
+ }
236
+ /** Load + validate the committed PHP-accepted-params manifest. */
237
+ export function loadManifest(path = manifestPath()) {
238
+ const raw = JSON.parse(readFileSync(path, "utf8"));
239
+ if (!isManifest(raw)) {
240
+ throw new Error(`Invalid php-accepted-params manifest at ${path}`);
241
+ }
242
+ return raw;
243
+ }
244
+ /**
245
+ * Enumerate every registered MCP tool name. Mirrors the runtime tool surface:
246
+ * - module essentials forwarded to a real McpServer,
247
+ * - the gateway-captured advanced tools,
248
+ * - the profile / status tools registered in src/index.ts AFTER module load.
249
+ *
250
+ * The src/index.ts trio is appended explicitly: they are registered on the real
251
+ * server outside the module's register(), so a module-only enumeration would
252
+ * miss them. They are pure local/profile tools (no REST body) and live in
253
+ * `_local_tools`; listing them here keeps the coverage check honest.
254
+ */
255
+ export function collectLiveTools() {
256
+ const server = new McpServer({ name: "drift-probe", version: "0.0.0" });
257
+ const names = new Set();
258
+ // Intercept registerTool so essentials forwarded to the real server are seen.
259
+ const realRegister = server.registerTool.bind(server);
260
+ const patched = server;
261
+ patched.registerTool = (name, config, cb) => {
262
+ names.add(name);
263
+ return realRegister(name, config, cb);
264
+ };
265
+ apimapperRestModule.register(server);
266
+ const advanced = apimapperRestModule.getAdvancedRegistry();
267
+ if (advanced) {
268
+ for (const name of advanced.keys())
269
+ names.add(name);
270
+ }
271
+ // Externally-registered (src/index.ts) — no REST body; covered by _local_tools.
272
+ for (const n of ["apimapper_use_profile", "apimapper_list_profiles", "apimapper_rest_modules_status"]) {
273
+ names.add(n);
274
+ }
275
+ return [...names].sort();
276
+ }
277
+ /**
278
+ * Compute the drift report from the live tool surface + the curated wire map +
279
+ * the PHP-accepted manifest. Pure — no I/O.
280
+ */
281
+ export function computeDrift(liveTools, manifest) {
282
+ const drift = [];
283
+ const inverse = [];
284
+ const uncovered = [];
285
+ const live = new Set(liveTools);
286
+ // Coverage: every live tool must be in the wire map OR declared local.
287
+ for (const tool of liveTools) {
288
+ const inWireMap = Object.prototype.hasOwnProperty.call(TOOL_WIRE_MAP, tool);
289
+ const isLocal = Object.prototype.hasOwnProperty.call(manifest._local_tools, tool);
290
+ if (!inWireMap && !isLocal)
291
+ uncovered.push(tool);
292
+ }
293
+ // Anti-rot: nothing in the wire map / local map may reference a vanished tool.
294
+ const stale = [];
295
+ for (const tool of Object.keys(TOOL_WIRE_MAP)) {
296
+ if (!live.has(tool))
297
+ stale.push(tool);
298
+ }
299
+ for (const tool of Object.keys(manifest._local_tools)) {
300
+ if (!live.has(tool))
301
+ stale.push(tool);
302
+ }
303
+ // Forward direction: each wire body key must be accepted or allow-listed.
304
+ for (const [tool, binding] of Object.entries(TOOL_WIRE_MAP)) {
305
+ if (!live.has(tool))
306
+ continue; // reported as stale above
307
+ const accepted = new Set(manifest.routes[binding.route] ?? []);
308
+ const allowed = manifest._allowed_drift[tool] ?? {};
309
+ for (const key of binding.bodyKeys) {
310
+ if (accepted.has(key))
311
+ continue;
312
+ if (Object.prototype.hasOwnProperty.call(allowed, key))
313
+ continue;
314
+ drift.push({ tool, route: binding.route, key });
315
+ }
316
+ }
317
+ // Inverse direction (advisory): PHP-accepted keys no tool sends.
318
+ //
319
+ // Built per route from the union of the STRUCTURED bindings' literal body
320
+ // keys. Routes that ANY envelope binding targets are skipped entirely: an
321
+ // envelope tool forwards a free-form record that can legitimately carry any
322
+ // of the route's accepted keys, so "no tool sends key X" is meaningless there
323
+ // (per-key validity for envelope routes is a PHP-side concern). The inverse
324
+ // check therefore only fires for routes whose tools send a fixed, literal key
325
+ // set — exactly where a PHP-only key really is unreachable from the MCP.
326
+ const sentByRoute = new Map();
327
+ const envelopeRoutes = new Set();
328
+ for (const binding of Object.values(TOOL_WIRE_MAP)) {
329
+ if (binding.kind === "envelope") {
330
+ envelopeRoutes.add(binding.route);
331
+ continue;
332
+ }
333
+ if (!sentByRoute.has(binding.route))
334
+ sentByRoute.set(binding.route, new Set());
335
+ const set = sentByRoute.get(binding.route);
336
+ for (const k of binding.bodyKeys)
337
+ set.add(k);
338
+ }
339
+ for (const [route, accepted] of Object.entries(manifest.routes)) {
340
+ if (envelopeRoutes.has(route))
341
+ continue; // free-form record carries any key
342
+ const sent = sentByRoute.get(route);
343
+ if (!sent)
344
+ continue; // no structured tool targets this route with a body
345
+ const ignore = manifest._inverse_ignore?.[route] ?? {};
346
+ for (const key of accepted) {
347
+ if (sent.has(key))
348
+ continue;
349
+ if (Object.prototype.hasOwnProperty.call(ignore, key))
350
+ continue;
351
+ inverse.push({ route, key });
352
+ }
353
+ }
354
+ drift.sort((a, b) => a.tool.localeCompare(b.tool) || a.key.localeCompare(b.key));
355
+ inverse.sort((a, b) => a.route.localeCompare(b.route) || a.key.localeCompare(b.key));
356
+ uncovered.sort();
357
+ stale.sort();
358
+ return { drift, inverse, uncovered, stale };
359
+ }
360
+ //# sourceMappingURL=whitelist-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whitelist-drift.js","sourceRoot":"","sources":["../../../src/modules/apimapper/whitelist-drift.ts"],"names":[],"mappings":"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"}
@@ -56,9 +56,20 @@ export function registerWorkflowTools(server) {
56
56
  transform: TransformSpec.optional().describe("Optional Transform node"),
57
57
  output: OutputSpec.describe("Output node config"),
58
58
  compile: z.boolean().default(true).describe("Compile after save (= publish to YOOtheme)"),
59
+ autofix: z
60
+ .boolean()
61
+ .default(true)
62
+ .describe("Defaults to true. When compile:true, auto-repair empty-output-schema compile errors " +
63
+ "by calling detect-schema then retrying compile so the new source compiles and " +
64
+ "appears. Pass false to opt out (verbatim old behaviour — no detect-schema retry). " +
65
+ "Mirrors `flow_full_recompile_publish` autofix."),
59
66
  },
60
67
  annotations: creating({ title: "Setup Flow with Sources", openWorld: true }),
61
- }, async ({ name, description, sources, merge, transform, output, compile }, extra) => {
68
+ }, async ({ name, description, sources, merge, transform, output, compile, autofix }, extra) => {
69
+ // C (2026-06-04): autofix defaults to true. Treat `undefined` (omitted
70
+ // arg / unit-test harness that bypasses the schema default) as the
71
+ // on-default; only an explicit `autofix:false` opts out.
72
+ const autofixEnabled = autofix !== false;
62
73
  // W3.5 — progress side-channel. `null` when the caller sent no
63
74
  // progressToken; `progress?.report(...)` then no-ops. Total steps:
64
75
  // build-graph + create + (compile when requested).
@@ -116,9 +127,29 @@ export function registerWorkflowTools(server) {
116
127
  // does not include the full flow object.
117
128
  let compiled = false;
118
129
  let compileError;
130
+ const autofixActions = [];
119
131
  if (compile) {
120
132
  await progress?.report(2, totalSteps, "Compiling and publishing to YOOtheme…");
121
- const compileR = await request(`/flows/${encodeURIComponent(flowId)}/compile`, { method: "POST" });
133
+ let compileR = await request(`/flows/${encodeURIComponent(flowId)}/compile`, { method: "POST" });
134
+ // F5 (W9b, 2026-05-29): autofix mirror of flow_full_recompile_publish.
135
+ // CODE_EMPTY_SCHEMA = 4 (PHP FlowCompilerException constant, frozen).
136
+ // On empty-schema error, call detect-schema then retry compile. This
137
+ // makes the composite tool self-healing on the most common compile
138
+ // failure (newly created flow has no output schema yet).
139
+ const COMPILER_CODE_EMPTY_SCHEMA = 4;
140
+ if (!compileR.success &&
141
+ autofixEnabled &&
142
+ compileR.errorBody?.compiler_error_code === COMPILER_CODE_EMPTY_SCHEMA) {
143
+ autofixActions.push("Detected empty output schema, running detect-schema");
144
+ const detectR = await request(`/flows/${encodeURIComponent(flowId)}/detect-schema`, { method: "POST" });
145
+ if (detectR.success) {
146
+ autofixActions.push("Schema detected, retrying compile");
147
+ compileR = await request(`/flows/${encodeURIComponent(flowId)}/compile`, { method: "POST" });
148
+ }
149
+ else {
150
+ autofixActions.push(`Schema detection failed: ${detectR.error ?? "unknown"}; cannot retry compile`);
151
+ }
152
+ }
122
153
  if (!compileR.success) {
123
154
  compileError = compileR.error;
124
155
  steps.push(`2. Compile FAILED: ${compileR.error}`);
@@ -132,7 +163,8 @@ export function registerWorkflowTools(server) {
132
163
  }
133
164
  else {
134
165
  compiled = true;
135
- steps.push("2. Compiled flow visible in YOOtheme dropdown");
166
+ const autofixSuffix = autofixActions.length > 0 ? " (autofix applied)" : "";
167
+ steps.push(`2. Compiled — flow visible in YOOtheme dropdown${autofixSuffix}`);
136
168
  }
137
169
  }
138
170
  }
@@ -142,6 +174,7 @@ export function registerWorkflowTools(server) {
142
174
  flow_id: flowId,
143
175
  compiled: false,
144
176
  compile_error: compileError,
177
+ autofix_actions: autofixActions.length > 0 ? autofixActions : undefined,
145
178
  steps,
146
179
  next_action: "investigate_compile_error",
147
180
  cleanup: `Call apimapper_flow_delete with id="${flowId}" + confirm=true to roll back the orphan, OR fix node config and call apimapper_flow_compile again.`,
@@ -298,20 +331,30 @@ export function registerWorkflowTools(server) {
298
331
  // so the source appears in YOOtheme immediately without a second MCP
299
332
  // package (matches audit recommendation A1 P1).
300
333
  //
301
- // The default (`autofix:false`) preserves the v2.0.7 behaviour verbatim so
302
- // existing tool callers do not see a behaviour change. The PHP layer
303
- // surfaces `compiler_error_code` on compile-error responses (FlowHandler.php)
304
- // so this branch reads a numeric class rather than string-matching messages.
334
+ // C (2026-06-04): the default is now `autofix:true`. Observed live in a
335
+ // Claude Desktop session: when the AI omits `autofix`, the old default
336
+ // (false) meant the YOOtheme schema cache was never flushed, so the source
337
+ // did NOT appear in the YOOtheme builder after publish. Flipping the default
338
+ // makes the autofix path (detect-schema retry + flush-yt) the normal path,
339
+ // so a plain `apimapper_flow_full_recompile_publish({id})` reliably publishes
340
+ // a visible source. `autofix:false` is now an explicit opt-out that restores
341
+ // the verbatim v2.0.7 behaviour (compile + admin-cache only, no detect-schema
342
+ // retry, no YT flush). The handler treats `autofix !== false` as enabled, so
343
+ // an omitted/undefined value behaves identically to the schema default at the
344
+ // real SDK call boundary. The PHP layer surfaces `compiler_error_code` on
345
+ // compile-error responses (FlowHandler.php) so this branch reads a numeric
346
+ // class rather than string-matching messages.
305
347
  server.registerTool("apimapper_flow_full_recompile_publish", {
306
348
  title: "Full Recompile + Cache Clear (Composite)",
307
- description: "Compile a flow + invalidate admin cache in one call. Use after upstream API changes " +
308
- "to ensure the flow + schema are fresh. Each step's success is surfaced separately, " +
309
- "and a cache-clear failure does NOT silently downgrade compile success. " +
310
- "Pass autofix:true to auto-repair common compile errors " +
311
- "(empty output schema → re-detect; then retry compile) and to flush the " +
312
- "YOOtheme schema cache so the source becomes visible in YOOtheme without " +
313
- "a second MCP package." +
314
- "\n\nExample:\n apimapper_flow_full_recompile_publish({ id: 'flow_Z2fLg70M84', autofix: true })",
349
+ description: "Compile a flow + invalidate admin cache + flush the YOOtheme schema cache in one call. " +
350
+ "Use after upstream API changes to ensure the flow + schema are fresh. Each step's success " +
351
+ "is surfaced separately, and a cache-clear failure does NOT silently downgrade compile success. " +
352
+ "autofix defaults to true: it auto-repairs common compile errors " +
353
+ "(empty output schema → re-detect; then retry compile) AND flushes the " +
354
+ "YOOtheme schema cache so the source becomes visible in the YOOtheme builder " +
355
+ "no second MCP package needed. Pass autofix:false to opt out (compile + admin-cache " +
356
+ "only, no detect-schema retry, no YT flush — the verbatim v2.0.7 behaviour)." +
357
+ "\n\nExample:\n apimapper_flow_full_recompile_publish({ id: 'flow_Z2fLg70M84' })",
315
358
  inputSchema: {
316
359
  // L-6 (W3F-5): accept either `id` (canonical, matches every other
317
360
  // flow_* tool) or `flow_id` (legacy alias kept so existing callers
@@ -327,10 +370,11 @@ export function registerWorkflowTools(server) {
327
370
  .describe("Deprecated alias for `id` — accepted for back-compat with pre-W3F-5 callers."),
328
371
  autofix: z
329
372
  .boolean()
330
- .default(false)
331
- .describe("When true: on empty-schema compile error, call detect-schema and retry compile. " +
332
- "On compile success, also flush the YOOtheme schema cache so the source surfaces " +
333
- "in the YOOtheme builder. Default false preserves v2.0.7 behaviour."),
373
+ .default(true)
374
+ .describe("When true (default): on empty-schema compile error, call detect-schema and retry " +
375
+ "compile. On compile success, also flush the YOOtheme schema cache so the source " +
376
+ "surfaces in the YOOtheme builder. Pass false to opt out — compile + admin-cache " +
377
+ "only, no detect-schema retry, no YT flush (the verbatim v2.0.7 behaviour)."),
334
378
  },
335
379
  annotations: mutating({ title: "Full Recompile & Publish Flow", openWorld: true }),
336
380
  }, async ({ id, flow_id: flowIdAlias, autofix }, extra) => {
@@ -346,9 +390,15 @@ export function registerWorkflowTools(server) {
346
390
  const steps = [];
347
391
  const errors = [];
348
392
  const autofixActions = [];
349
- // W3.5: progress side-channel. autofix:true adds a third stage
393
+ // C (2026-06-04): autofix defaults to true. Treat `undefined` (caller
394
+ // omitted the arg, and the unit-test harness bypasses the schema default)
395
+ // identically to the on-default, so only an explicit `autofix:false`
396
+ // opts out. This keeps the handler faithful to the documented default
397
+ // whether or not the SDK applied the Zod default before dispatch.
398
+ const autofixEnabled = autofix !== false;
399
+ // W3.5: progress side-channel. autofix adds a third stage
350
400
  // (YOOtheme schema cache flush) so it's a 3-step pipeline.
351
- const totalSteps = autofix ? 3 : 2;
401
+ const totalSteps = autofixEnabled ? 3 : 2;
352
402
  const progress = extra ? createProgressReporter(extra) : null;
353
403
  await progress?.report(0, totalSteps, "Recompiling flow…");
354
404
  // Stage 1: compile (with optional autofix retry)
@@ -359,7 +409,7 @@ export function registerWorkflowTools(server) {
359
409
  // because both share src/modules/core/src/Flow/FlowCompilerException.php).
360
410
  const COMPILER_CODE_EMPTY_SCHEMA = 4;
361
411
  if (!compileR.success &&
362
- autofix === true &&
412
+ autofixEnabled &&
363
413
  compileR.errorBody?.compiler_error_code === COMPILER_CODE_EMPTY_SCHEMA) {
364
414
  autofixActions.push("Detected empty output schema, running detect-schema");
365
415
  const detectR = await request(`/flows/${encodeURIComponent(flow_id)}/detect-schema`, { method: "POST" });
@@ -377,7 +427,7 @@ export function registerWorkflowTools(server) {
377
427
  status: compileR.status,
378
428
  errorCode: compileR.errorCode,
379
429
  compiler_error_code: compileR.errorBody?.compiler_error_code,
380
- context: { flow_id, stage: "compile", autofix: !!autofix },
430
+ context: { flow_id, stage: "compile", autofix: autofixEnabled },
381
431
  autofix_actions: autofixActions.length > 0 ? autofixActions : undefined,
382
432
  hint: hintFor(compileR.errorCode),
383
433
  }, true);
@@ -406,7 +456,7 @@ export function registerWorkflowTools(server) {
406
456
  // {flushed: false, error: <msg>} in the body when the buster threw.
407
457
  // We treat the request-level success/failure as authoritative and
408
458
  // record any flushed:false as a non-fatal warning step.
409
- if (autofix === true) {
459
+ if (autofixEnabled) {
410
460
  await progress?.report(2, totalSteps, "Flushing YOOtheme schema cache…");
411
461
  const ytR = await request("/cache/flush-yt", { method: "POST" });
412
462
  if (ytR.success && ytR.data?.flushed !== false) {
@@ -434,11 +484,16 @@ export function registerWorkflowTools(server) {
434
484
  errors: ok ? undefined : errors,
435
485
  autofix_actions: autofixActions.length > 0 ? autofixActions : undefined,
436
486
  next: ok
437
- ? autofix
487
+ ? autofixEnabled
438
488
  ? "Flow recompiled, admin cache invalidated, and YOOtheme schema cache flushed. The source should now be visible in the YOOtheme builder."
439
- : "Flow is fresh in both admin + render layers. YOOtheme schema cache is NOT cleared by this tool; pass autofix:true (or call yootheme_clear_cache via the YOOtheme MCP) if the source does not appear in the builder."
489
+ : "Flow is fresh in both admin + render layers. You passed autofix:false, so the YOOtheme schema cache was NOT cleared by this tool; re-run without autofix:false (the default flushes it) or call yootheme_clear_cache via the YOOtheme MCP if the source does not appear in the builder."
440
490
  : "Compile succeeded but a cache step had issues. Manually call apimapper_cache_invalidate scope=all if downstream still sees stale data.",
441
- }, ok, { maxChars: 2500 });
491
+ },
492
+ // Wave-5 F7 fix (2026-05-29): formatResult's 2nd positional is `isError`.
493
+ // Pre-fix we passed `ok` here, which inverted the meaning — ok:true was
494
+ // tagged as `<error>` envelope. Pass `!ok` so success-with-no-errors
495
+ // renders as success and partial (errors.length > 0) renders as error.
496
+ !ok, { maxChars: 2500 });
442
497
  });
443
498
  }
444
499
  //# sourceMappingURL=workflows.js.map