@walkeros/mcp 4.7.0-next-1790722899482 → 4.7.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/dist/index.js CHANGED
@@ -94,13 +94,65 @@ function createHostedRuntime(client) {
94
94
  }
95
95
 
96
96
  // src/tools/auth.ts
97
+ import { z as z2 } from "zod";
98
+ import { mcpResult, mcpError as mcpError2 } from "@walkeros/core";
99
+
100
+ // src/tools/narrow.ts
101
+ import { schemas } from "@walkeros/core/dev";
102
+ function isRecord(value) {
103
+ return typeof value === "object" && value !== null && !Array.isArray(value);
104
+ }
105
+ function stringField(value, key) {
106
+ if (!isRecord(value)) return void 0;
107
+ const field = value[key];
108
+ return typeof field === "string" ? field : void 0;
109
+ }
110
+ function recordField(value, key) {
111
+ if (!isRecord(value)) return void 0;
112
+ const field = value[key];
113
+ return isRecord(field) ? field : void 0;
114
+ }
115
+ function fieldsOf(value) {
116
+ return isRecord(value) ? value : {};
117
+ }
118
+ function isFlowJson(value) {
119
+ return isRecord(value) && isRecord(value.flows);
120
+ }
121
+ function stepExamplesOf(value) {
122
+ if (!isRecord(value)) return void 0;
123
+ const examples = {};
124
+ const skipped = [];
125
+ for (const [name, example] of Object.entries(value)) {
126
+ const parsed = schemas.FlowSchemas.StepExampleSchema.safeParse(example);
127
+ if (parsed.success) examples[name] = parsed.data;
128
+ else skipped.push(name);
129
+ }
130
+ return { examples, skipped };
131
+ }
132
+
133
+ // src/tools/parse-input.ts
97
134
  import { z } from "zod";
98
- import { mcpResult, mcpError } from "@walkeros/core";
135
+ import { mcpError } from "@walkeros/core";
136
+ function inputIssuesMessage(error) {
137
+ return error.issues.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`).join("; ");
138
+ }
139
+ function parseToolInput(shape, raw) {
140
+ const parsed = z.object(shape).safeParse(raw ?? {});
141
+ if (!parsed.success) {
142
+ return {
143
+ ok: false,
144
+ error: mcpError(new Error(inputIssuesMessage(parsed.error)))
145
+ };
146
+ }
147
+ return { ok: true, data: parsed.data };
148
+ }
149
+
150
+ // src/tools/auth.ts
99
151
  var TITLE = "Authentication";
100
152
  var DESCRIPTION = "Manage walkerOS authentication. Check login status, log in via the device authorization grant, or log out. No terminal or browser required, the MCP client handles the authorization URL.";
101
153
  var inputSchema = {
102
- action: z.enum(["status", "login", "logout"]).describe("Authentication action to perform"),
103
- deviceCode: z.string().optional().describe(
154
+ action: z2.enum(["status", "login", "logout"]).describe("Authentication action to perform"),
155
+ deviceCode: z2.string().optional().describe(
104
156
  "Device code from a previous pending login attempt. Provide to resume polling without requesting a new code."
105
157
  )
106
158
  };
@@ -121,7 +173,9 @@ function createAuthToolSpec(client) {
121
173
  };
122
174
  }
123
175
  async function authHandlerBody(client, input) {
124
- const { action, deviceCode } = input ?? {};
176
+ const parsed = parseToolInput(inputSchema, input);
177
+ if (!parsed.ok) return parsed.error;
178
+ const { action, deviceCode } = parsed.data;
125
179
  try {
126
180
  switch (action) {
127
181
  case "status": {
@@ -134,7 +188,7 @@ async function authHandlerBody(client, input) {
134
188
  const user = await client.whoami();
135
189
  return mcpResult({
136
190
  authenticated: true,
137
- ...user
191
+ ...fieldsOf(user)
138
192
  });
139
193
  }
140
194
  case "login": {
@@ -162,14 +216,14 @@ async function authHandlerBody(client, input) {
162
216
  });
163
217
  }
164
218
  if (poll.status === "denied")
165
- return mcpError(new Error("Authorization was denied."));
219
+ return mcpError2(new Error("Authorization was denied."));
166
220
  if (poll.status === "expired")
167
- return mcpError(
221
+ return mcpError2(
168
222
  new Error(
169
223
  'The one-time code expired. Run auth with action "login" for a new one.'
170
224
  )
171
225
  );
172
- return mcpError(new Error(poll.error));
226
+ return mcpError2(new Error(poll.error));
173
227
  }
174
228
  const code = await client.requestDeviceCode();
175
229
  const loginUrl = code.verificationUriComplete;
@@ -206,7 +260,7 @@ async function authHandlerBody(client, input) {
206
260
  );
207
261
  }
208
262
  } catch (error) {
209
- return mcpError(error);
263
+ return mcpError2(error);
210
264
  }
211
265
  }
212
266
  function registerAuthTool(server, client) {
@@ -219,15 +273,13 @@ function registerAuthTool(server, client) {
219
273
  inputSchema: spec.inputSchema,
220
274
  annotations: spec.annotations
221
275
  },
222
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
223
- // type-erased (input: unknown) => Promise<unknown> form by design.
224
- spec.handler
276
+ (args) => authHandlerBody(client, args)
225
277
  );
226
278
  }
227
279
 
228
280
  // src/tools/project-manage.ts
229
- import { z as z2 } from "zod";
230
- import { mcpResult as mcpResult2, mcpError as mcpError2 } from "@walkeros/core";
281
+ import { z as z3 } from "zod";
282
+ import { mcpResult as mcpResult2, mcpError as mcpError3 } from "@walkeros/core";
231
283
 
232
284
  // src/types.ts
233
285
  function isAuthError(error) {
@@ -423,21 +475,22 @@ var FRAME_MANAGE_REQUIREMENTS = {
423
475
  };
424
476
 
425
477
  // src/tools/project-manage.ts
426
- function wrapProjectName(p) {
427
- return p.name !== void 0 ? { ...p, name: wrapUserData(p.name) } : p;
478
+ function wrapProjectName(project) {
479
+ const name = stringField(project, "name");
480
+ return isRecord(project) && name !== void 0 ? { ...project, name: wrapUserData(name) } : project;
428
481
  }
429
482
  var TITLE2 = "Project Management";
430
483
  var DESCRIPTION2 = "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.";
431
484
  var inputSchema2 = {
432
- action: z2.enum(["list", "get", "create", "update", "delete", "set_default"]).describe("Project management action to perform"),
433
- projectId: z2.string().optional().describe("Required for get, update, delete, set_default."),
434
- name: z2.string().optional().describe(
485
+ action: z3.enum(["list", "get", "create", "update", "delete", "set_default"]).describe("Project management action to perform"),
486
+ projectId: z3.string().optional().describe("Required for get, update, delete, set_default."),
487
+ name: z3.string().optional().describe(
435
488
  "Required for create and update (update also requires projectId)."
436
489
  ),
437
- cursor: z2.string().optional().describe(
490
+ cursor: z3.string().optional().describe(
438
491
  "Pagination cursor from a previous list response. Only used with the list action."
439
492
  ),
440
- limit: z2.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action.")
493
+ limit: z3.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action.")
441
494
  };
442
495
  var annotations2 = {
443
496
  readOnlyHint: false,
@@ -456,19 +509,22 @@ function createProjectManageToolSpec(client) {
456
509
  };
457
510
  }
458
511
  async function projectManageHandlerBody(client, input) {
459
- const { action, projectId, name, cursor, limit } = input ?? {};
512
+ const parsed = parseToolInput(inputSchema2, input);
513
+ if (!parsed.ok) return parsed.error;
514
+ const { action, projectId, name, cursor, limit } = parsed.data;
460
515
  const validationError = validateActionInput(
461
516
  "project_manage",
462
517
  action ?? "",
463
518
  { projectId, name },
464
519
  PROJECT_MANAGE_REQUIREMENTS
465
520
  );
466
- if (validationError) return mcpError2(new Error(validationError));
521
+ if (validationError) return mcpError3(new Error(validationError));
467
522
  try {
468
523
  switch (action) {
469
524
  case "list": {
470
525
  const projects = await client.listProjects({ cursor, limit });
471
- const items = Array.isArray(projects) ? projects : projects?.projects || [];
526
+ const listed = isRecord(projects) ? projects.projects : void 0;
527
+ const items = Array.isArray(projects) ? projects : Array.isArray(listed) ? listed : [];
472
528
  if (items.length === 0) {
473
529
  return mcpResult2(
474
530
  { projects: [] },
@@ -480,8 +536,7 @@ async function projectManageHandlerBody(client, input) {
480
536
  }
481
537
  );
482
538
  }
483
- const typedItems = items;
484
- const safe = Array.isArray(projects) ? typedItems.map(wrapProjectName) : { ...projects, projects: typedItems.map(wrapProjectName) };
539
+ const safe = Array.isArray(projects) ? items.map(wrapProjectName) : { ...fieldsOf(projects), projects: items.map(wrapProjectName) };
485
540
  return mcpResult2(safe);
486
541
  }
487
542
  case "get": {
@@ -524,7 +579,7 @@ async function projectManageHandlerBody(client, input) {
524
579
  );
525
580
  }
526
581
  } catch (error) {
527
- return mcpError2(error, isAuthError(error) ? AUTH_HINT : void 0);
582
+ return mcpError3(error, isAuthError(error) ? AUTH_HINT : void 0);
528
583
  }
529
584
  }
530
585
  function registerProjectManageTool(server, client) {
@@ -537,15 +592,13 @@ function registerProjectManageTool(server, client) {
537
592
  inputSchema: spec.inputSchema,
538
593
  annotations: spec.annotations
539
594
  },
540
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
541
- // type-erased (input: unknown) => Promise<unknown> form by design.
542
- spec.handler
595
+ (args) => projectManageHandlerBody(client, args)
543
596
  );
544
597
  }
545
598
 
546
599
  // src/tools/flow-manage.ts
547
- import { z as z3 } from "zod";
548
- import { mcpResult as mcpResult3, mcpError as mcpError3 } from "@walkeros/core";
600
+ import { z as z4 } from "zod";
601
+ import { mcpResult as mcpResult3, mcpError as mcpError4 } from "@walkeros/core";
549
602
 
550
603
  // src/ui-parts.ts
551
604
  function flowCanvasResult(payload) {
@@ -659,19 +712,10 @@ function resolveDefaultProject(client, projectId) {
659
712
 
660
713
  // src/tools/flow-manage.ts
661
714
  function pickPlatform(content) {
662
- if (content && typeof content === "object") {
663
- const flows = content.flows;
664
- if (flows && typeof flows === "object") {
665
- for (const flow of Object.values(flows)) {
666
- if (flow && typeof flow === "object") {
667
- const config = flow.config;
668
- if (config && typeof config === "object") {
669
- const platform = config.platform;
670
- if (platform === "web" || platform === "server") return platform;
671
- }
672
- }
673
- }
674
- }
715
+ const flows = recordField(content, "flows");
716
+ for (const flow of Object.values(flows ?? {})) {
717
+ const platform = stringField(recordField(flow, "config"), "platform");
718
+ if (platform === "web" || platform === "server") return platform;
675
719
  }
676
720
  return "server";
677
721
  }
@@ -680,22 +724,29 @@ function flowPageUrl(client, projectId, flowId) {
680
724
  return links.flow({ baseUrl: client.appBaseUrl(), projectId, flowId });
681
725
  }
682
726
  function safeSummary(flow) {
683
- return flow.name !== void 0 ? { ...flow, name: wrapUserData(flow.name) } : flow;
727
+ const name = stringField(flow, "name");
728
+ return isRecord(flow) && name !== void 0 ? { ...flow, name: wrapUserData(name) } : flow;
684
729
  }
685
730
  function safeDetail(flow) {
686
- const withName = flow.name !== void 0 ? { ...flow, name: wrapUserData(flow.name) } : { ...flow };
687
- if (flow.config !== void 0) {
688
- withName.config = redactNestedStrings(
689
- flow.config,
690
- { skip: keepStructural }
691
- );
731
+ const fields = { ...fieldsOf(flow) };
732
+ const name = stringField(fields, "name");
733
+ if (name !== void 0) fields.name = wrapUserData(name);
734
+ if (fields.config !== void 0) {
735
+ fields.config = redactNestedStrings(fields.config, {
736
+ skip: keepStructural
737
+ });
692
738
  }
693
- return withName;
739
+ return {
740
+ fields,
741
+ id: stringField(fields, "id"),
742
+ name: stringField(fields, "name"),
743
+ config: recordField(fields, "config")
744
+ };
694
745
  }
695
746
  var TITLE3 = "Flow Management";
696
747
  var DESCRIPTION3 = "Manage walkerOS flows and their previews. List/get/create/update/delete/duplicate flows, or create/inspect/delete preview bundles and mint activation grants (preview_regrant) for testing flow changes on live sites.";
697
748
  var inputSchema3 = {
698
- action: z3.enum([
749
+ action: z4.enum([
699
750
  "list",
700
751
  "get",
701
752
  "create",
@@ -708,52 +759,52 @@ var inputSchema3 = {
708
759
  "preview_delete",
709
760
  "preview_regrant"
710
761
  ]).describe("Flow management action to perform"),
711
- flowId: z3.string().optional().describe(
762
+ flowId: z4.string().optional().describe(
712
763
  "Flow ID (flow_...) or config ID (cfg_...). Required for get, update, delete, duplicate, preview_list, preview_get, preview_create, preview_delete, preview_regrant."
713
764
  ),
714
- projectId: z3.string().optional().describe(
765
+ projectId: z4.string().optional().describe(
715
766
  "Project ID. Optional filter for list (omit to list all projects). Required for create if no default project set."
716
767
  ),
717
- name: z3.string().optional().describe(
768
+ name: z4.string().optional().describe(
718
769
  "Flow name. Required for create. Optional for update (to rename) and duplicate."
719
770
  ),
720
- content: z3.record(z3.string(), z3.unknown()).optional().describe("Flow.Json content. Used for create and update."),
721
- patch: z3.boolean().optional().describe(
771
+ content: z4.record(z4.string(), z4.unknown()).optional().describe("Flow.Json content. Used for create and update."),
772
+ patch: z4.boolean().optional().describe(
722
773
  "Merge-patch for update (default true). When true, only provided fields are updated."
723
774
  ),
724
- fields: z3.array(z3.string()).optional().describe("Dot-path selectors for get to return only specific fields."),
725
- sort: z3.enum(["name", "updated_at", "created_at"]).optional().describe("Sort field for list."),
726
- order: z3.enum(["asc", "desc"]).optional().describe("Sort order for list."),
727
- includeDeleted: z3.boolean().optional().describe("Include soft-deleted flows in list results."),
728
- cursor: z3.string().optional().describe(
775
+ fields: z4.array(z4.string()).optional().describe("Dot-path selectors for get to return only specific fields."),
776
+ sort: z4.enum(["name", "updated_at", "created_at"]).optional().describe("Sort field for list."),
777
+ order: z4.enum(["asc", "desc"]).optional().describe("Sort order for list."),
778
+ includeDeleted: z4.boolean().optional().describe("Include soft-deleted flows in list results."),
779
+ cursor: z4.string().optional().describe(
729
780
  "Pagination cursor from a previous list response. Only used with the list action."
730
781
  ),
731
- limit: z3.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action."),
732
- previewId: z3.string().optional().describe(
782
+ limit: z4.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action."),
783
+ previewId: z4.string().optional().describe(
733
784
  "Preview ID (prv_...). Required for preview_get, preview_delete, and preview_regrant (all also require flowId)."
734
785
  ),
735
- flowName: z3.string().optional().describe(
786
+ flowName: z4.string().optional().describe(
736
787
  "Used by preview_create \u2014 provide one of flowName or flowSettingsId (preview_create also requires flowId)."
737
788
  ),
738
- flowSettingsId: z3.string().optional().describe(
789
+ flowSettingsId: z4.string().optional().describe(
739
790
  "Used by preview_create \u2014 provide one of flowName or flowSettingsId (preview_create also requires flowId)."
740
791
  ),
741
- source: z3.discriminatedUnion("kind", [
742
- z3.object({ kind: z3.literal("draft") }),
743
- z3.object({
744
- kind: z3.literal("deployment-version"),
745
- deploymentVersionId: z3.string()
792
+ source: z4.discriminatedUnion("kind", [
793
+ z4.object({ kind: z4.literal("draft") }),
794
+ z4.object({
795
+ kind: z4.literal("deployment-version"),
796
+ deploymentVersionId: z4.string()
746
797
  })
747
798
  ]).optional().describe(
748
799
  "What the preview should run, for preview_create: the flow's draft (default) or a deployed version's stored config (kind 'deployment-version' with its deploymentVersionId)."
749
800
  ),
750
- siteUrl: z3.string().optional().describe(
801
+ siteUrl: z4.string().optional().describe(
751
802
  "Optional site URL (e.g. https://shop.example.com) for preview_create. When provided, the activation grant is minted for that origin so the returned activationUrl works there."
752
803
  ),
753
- origins: z3.array(z3.string()).optional().describe(
804
+ origins: z4.array(z4.string()).optional().describe(
754
805
  "Site origins (bare https://host[:port]) to mint a preview activation grant for. Used by preview_regrant; the returned activationUrl targets the first origin."
755
806
  ),
756
- sessionId: z3.string().optional().describe(
807
+ sessionId: z4.string().optional().describe(
757
808
  "Observe session id \u2014 when set, preview_regrant mints an activation/forwarding grant PAIR: the returned activationUrl both activates the web preview and lets the page forward events to the session container (elbPreviewSession param). Pass it to observe server-side hops; omit for a plain web preview."
758
809
  )
759
810
  };
@@ -779,9 +830,6 @@ var PREVIEW_SUMMARY_FIELDS = [
779
830
  "createdBy",
780
831
  "createdAt"
781
832
  ];
782
- function isRecord(value) {
783
- return typeof value === "object" && value !== null && !Array.isArray(value);
784
- }
785
833
  function redactPreview(data) {
786
834
  if (!isRecord(data)) return {};
787
835
  const out = {};
@@ -820,6 +868,8 @@ function createFlowManageToolSpec(client) {
820
868
  };
821
869
  }
822
870
  async function flowManageHandlerBody(client, input) {
871
+ const parsed = parseToolInput(inputSchema3, input);
872
+ if (!parsed.ok) return parsed.error;
823
873
  const {
824
874
  action,
825
875
  flowId,
@@ -840,14 +890,14 @@ async function flowManageHandlerBody(client, input) {
840
890
  siteUrl,
841
891
  origins,
842
892
  sessionId
843
- } = input ?? {};
893
+ } = parsed.data;
844
894
  const validationError = validateActionInput(
845
895
  "flow_manage",
846
896
  action ?? "",
847
897
  { flowId, projectId, name, previewId, flowName, flowSettingsId },
848
898
  FLOW_MANAGE_REQUIREMENTS
849
899
  );
850
- if (validationError) return mcpError3(new Error(validationError));
900
+ if (validationError) return mcpError4(new Error(validationError));
851
901
  try {
852
902
  switch (action) {
853
903
  case "list": {
@@ -860,9 +910,8 @@ async function flowManageHandlerBody(client, input) {
860
910
  cursor,
861
911
  limit
862
912
  });
863
- const dataObj = data2;
864
- const flows = dataObj.flows;
865
- const safe2 = Array.isArray(flows) ? { ...dataObj, flows: flows.map(safeSummary) } : data2;
913
+ const flows = isRecord(data2) ? data2.flows : void 0;
914
+ const safe2 = isRecord(data2) && Array.isArray(flows) ? { ...data2, flows: flows.map(safeSummary) } : data2;
866
915
  return mcpResult3(safe2);
867
916
  }
868
917
  const data = await client.listAllFlows({
@@ -887,16 +936,14 @@ async function flowManageHandlerBody(client, input) {
887
936
  assertParam(flowId, "flowId", "get");
888
937
  const resolvedProjectId = resolveDefaultProject(client, projectId);
889
938
  if (!resolvedProjectId) {
890
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
939
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
891
940
  }
892
941
  const flow = await client.getFlow({
893
942
  flowId,
894
943
  projectId: resolvedProjectId,
895
944
  fields
896
945
  });
897
- const safe = safeDetail(
898
- flow
899
- );
946
+ const safe = safeDetail(flow);
900
947
  const appUrl = flowPageUrl(client, resolvedProjectId, safe.id);
901
948
  return flowCanvasResult({
902
949
  flowId: safe.id,
@@ -921,16 +968,14 @@ async function flowManageHandlerBody(client, input) {
921
968
  assertParam(name, "name", "create");
922
969
  const resolvedProjectId = resolveDefaultProject(client, projectId);
923
970
  if (!resolvedProjectId) {
924
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
971
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
925
972
  }
926
973
  const created = await client.createFlow({
927
974
  name,
928
975
  content: content ?? {},
929
976
  projectId: resolvedProjectId
930
977
  });
931
- const safeCreated = safeDetail(
932
- created
933
- );
978
+ const safeCreated = safeDetail(created);
934
979
  const createdAppUrl = flowPageUrl(
935
980
  client,
936
981
  resolvedProjectId,
@@ -959,7 +1004,7 @@ async function flowManageHandlerBody(client, input) {
959
1004
  assertParam(flowId, "flowId", "update");
960
1005
  const resolvedProjectId = resolveDefaultProject(client, projectId);
961
1006
  if (!resolvedProjectId) {
962
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1007
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
963
1008
  }
964
1009
  const updated = await client.updateFlow({
965
1010
  flowId,
@@ -968,9 +1013,7 @@ async function flowManageHandlerBody(client, input) {
968
1013
  content,
969
1014
  mergePatch: patch ?? true
970
1015
  });
971
- const safeUpdated = safeDetail(
972
- updated
973
- );
1016
+ const safeUpdated = safeDetail(updated);
974
1017
  return flowCanvasResult({
975
1018
  flowId: safeUpdated.id,
976
1019
  configName: safeUpdated.name ?? "default",
@@ -993,7 +1036,7 @@ async function flowManageHandlerBody(client, input) {
993
1036
  assertParam(flowId, "flowId", "delete");
994
1037
  const resolvedProjectId = resolveDefaultProject(client, projectId);
995
1038
  if (!resolvedProjectId) {
996
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1039
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
997
1040
  }
998
1041
  const deleted = await client.deleteFlow({
999
1042
  flowId,
@@ -1005,22 +1048,20 @@ async function flowManageHandlerBody(client, input) {
1005
1048
  assertParam(flowId, "flowId", "duplicate");
1006
1049
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1007
1050
  if (!resolvedProjectId) {
1008
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1051
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1009
1052
  }
1010
1053
  const duplicated = await client.duplicateFlow({
1011
1054
  flowId,
1012
1055
  name,
1013
1056
  projectId: resolvedProjectId
1014
1057
  });
1015
- return mcpResult3(
1016
- safeDetail(duplicated)
1017
- );
1058
+ return mcpResult3(safeDetail(duplicated).fields);
1018
1059
  }
1019
1060
  case "preview_list": {
1020
1061
  assertParam(flowId, "flowId", "preview_list");
1021
1062
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1022
1063
  if (!resolvedProjectId) {
1023
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1064
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1024
1065
  }
1025
1066
  const data = await client.listPreviews({
1026
1067
  projectId: resolvedProjectId,
@@ -1033,7 +1074,7 @@ async function flowManageHandlerBody(client, input) {
1033
1074
  assertParam(previewId, "previewId", "preview_get");
1034
1075
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1035
1076
  if (!resolvedProjectId) {
1036
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1077
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1037
1078
  }
1038
1079
  const data = await client.getPreview({
1039
1080
  projectId: resolvedProjectId,
@@ -1046,7 +1087,7 @@ async function flowManageHandlerBody(client, input) {
1046
1087
  assertParam(flowId, "flowId", "preview_create");
1047
1088
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1048
1089
  if (!resolvedProjectId) {
1049
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1090
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1050
1091
  }
1051
1092
  const preview = await client.createPreview({
1052
1093
  projectId: resolvedProjectId,
@@ -1068,7 +1109,7 @@ async function flowManageHandlerBody(client, input) {
1068
1109
  assertParam(previewId, "previewId", "preview_delete");
1069
1110
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1070
1111
  if (!resolvedProjectId) {
1071
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1112
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1072
1113
  }
1073
1114
  const data = await client.deletePreview({
1074
1115
  projectId: resolvedProjectId,
@@ -1084,10 +1125,10 @@ async function flowManageHandlerBody(client, input) {
1084
1125
  assertParam(previewId, "previewId", "preview_regrant");
1085
1126
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1086
1127
  if (!resolvedProjectId) {
1087
- return mcpError3(new Error(NO_DEFAULT_PROJECT_ERROR));
1128
+ return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
1088
1129
  }
1089
1130
  if (!client.regrantPreview) {
1090
- return mcpError3(
1131
+ return mcpError4(
1091
1132
  new Error("preview_regrant is not supported by this client")
1092
1133
  );
1093
1134
  }
@@ -1111,7 +1152,7 @@ async function flowManageHandlerBody(client, input) {
1111
1152
  );
1112
1153
  }
1113
1154
  } catch (error) {
1114
- return mcpError3(error, isAuthError(error) ? AUTH_HINT : void 0);
1155
+ return mcpError4(error, isAuthError(error) ? AUTH_HINT : void 0);
1115
1156
  }
1116
1157
  }
1117
1158
  function registerFlowManageTool(server, client) {
@@ -1124,15 +1165,13 @@ function registerFlowManageTool(server, client) {
1124
1165
  inputSchema: spec.inputSchema,
1125
1166
  annotations: spec.annotations
1126
1167
  },
1127
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
1128
- // type-erased (input: unknown) => Promise<unknown> form by design.
1129
- spec.handler
1168
+ (args) => flowManageHandlerBody(client, args)
1130
1169
  );
1131
1170
  }
1132
1171
 
1133
1172
  // src/tools/deploy-manage.ts
1134
- import { z as z4 } from "zod";
1135
- import { mcpResult as mcpResult4, mcpError as mcpError4 } from "@walkeros/core";
1173
+ import { z as z5 } from "zod";
1174
+ import { mcpResult as mcpResult4, mcpError as mcpError5 } from "@walkeros/core";
1136
1175
 
1137
1176
  // src/tools/_resolvers.ts
1138
1177
  var DeploymentNotFoundError = class extends Error {
@@ -1188,24 +1227,24 @@ async function resolveDeploymentSlug(args) {
1188
1227
  var TITLE4 = "Deploy Management";
1189
1228
  var DESCRIPTION4 = "Deploy walkerOS flows and manage deployments. deploy waits for the deployment to reach a terminal status by default (wait=true), with a 12-minute budget; pass wait=false to return immediately with the deployment id. A finished deployment carries its status and, on failure, an errorMessage with the user-facing reason; use the get action to re-read it. list supports cursor and limit for pagination. delete removes an active deployment. For get and delete pass flowId (required) plus optional slug to disambiguate when a flow has multiple active deployments. If a flow has >=2 active deployments and no slug is supplied, the tool returns a MULTIPLE_DEPLOYMENTS error with a details[] list showing each deployment's slug, type, status, and updatedAt.";
1190
1229
  var inputSchema4 = {
1191
- action: z4.enum(["deploy", "list", "get", "delete"]).describe("Deployment action to perform"),
1192
- projectId: z4.string().optional().describe("Project ID. Optional; falls back to the default project."),
1193
- flowId: z4.string().optional().describe("Required for deploy, get, delete."),
1194
- slug: z4.string().optional().describe(
1230
+ action: z5.enum(["deploy", "list", "get", "delete"]).describe("Deployment action to perform"),
1231
+ projectId: z5.string().optional().describe("Project ID. Optional; falls back to the default project."),
1232
+ flowId: z5.string().optional().describe("Required for deploy, get, delete."),
1233
+ slug: z5.string().optional().describe(
1195
1234
  "Deployment slug. Optional disambiguator for get/delete when the flow has multiple active deployments."
1196
1235
  ),
1197
- type: z4.enum(["web", "server"]).optional().describe("Deployment type filter for list."),
1198
- status: z4.string().optional().describe("Status filter for list."),
1199
- wait: z4.boolean().optional().describe(
1236
+ type: z5.enum(["web", "server"]).optional().describe("Deployment type filter for list."),
1237
+ status: z5.string().optional().describe("Status filter for list."),
1238
+ wait: z5.boolean().optional().describe(
1200
1239
  "Wait for the deployment to reach a terminal status (default true), with a 12-minute budget. Set false to return the deployment id immediately. Only used with deploy action."
1201
1240
  ),
1202
- flowName: z4.string().optional().describe(
1241
+ flowName: z5.string().optional().describe(
1203
1242
  "Flow name for multi-settings flows. Only used with deploy action."
1204
1243
  ),
1205
- cursor: z4.string().optional().describe(
1244
+ cursor: z5.string().optional().describe(
1206
1245
  "Pagination cursor from a previous list response. Only used with the list action."
1207
1246
  ),
1208
- limit: z4.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action.")
1247
+ limit: z5.number().int().min(1).max(100).optional().describe("Max items per page (1-100). Only used with the list action.")
1209
1248
  };
1210
1249
  var annotations4 = {
1211
1250
  readOnlyHint: false,
@@ -1240,13 +1279,22 @@ function withAppUrl(data, appUrl) {
1240
1279
  }
1241
1280
  return { ...data, appUrl };
1242
1281
  }
1282
+ function readDeploymentSummary(value) {
1283
+ if (!isRecord(value)) return [];
1284
+ const slug = stringField(value, "slug");
1285
+ const type = stringField(value, "type");
1286
+ const status = stringField(value, "status");
1287
+ const updatedAt = stringField(value, "updatedAt");
1288
+ return slug !== void 0 && type !== void 0 && status !== void 0 && updatedAt !== void 0 ? [{ ...value, slug, type, status, updatedAt }] : [];
1289
+ }
1243
1290
  function listForResolver(client, projectId) {
1244
1291
  return async (q) => {
1245
1292
  const resp = await client.listDeployments({
1246
1293
  projectId: projectId || q.projectId || void 0,
1247
1294
  flowId: q.flowId
1248
1295
  });
1249
- return resp.deployments ?? [];
1296
+ const deployments = isRecord(resp) ? resp.deployments : void 0;
1297
+ return Array.isArray(deployments) ? deployments.flatMap(readDeploymentSummary) : [];
1250
1298
  };
1251
1299
  }
1252
1300
  function createDeployManageToolSpec(client) {
@@ -1260,6 +1308,8 @@ function createDeployManageToolSpec(client) {
1260
1308
  };
1261
1309
  }
1262
1310
  async function deployManageHandlerBody(client, input) {
1311
+ const parsed = parseToolInput(inputSchema4, input);
1312
+ if (!parsed.ok) return parsed.error;
1263
1313
  const {
1264
1314
  action,
1265
1315
  projectId,
@@ -1271,14 +1321,14 @@ async function deployManageHandlerBody(client, input) {
1271
1321
  flowName,
1272
1322
  cursor,
1273
1323
  limit
1274
- } = input ?? {};
1324
+ } = parsed.data;
1275
1325
  const validationError = validateActionInput(
1276
1326
  "deploy_manage",
1277
1327
  action ?? "",
1278
1328
  { flowId, projectId },
1279
1329
  DEPLOY_MANAGE_REQUIREMENTS
1280
1330
  );
1281
- if (validationError) return mcpError4(new Error(validationError));
1331
+ if (validationError) return mcpError5(new Error(validationError));
1282
1332
  try {
1283
1333
  switch (action) {
1284
1334
  case "deploy": {
@@ -1337,7 +1387,7 @@ async function deployManageHandlerBody(client, input) {
1337
1387
  return mcpResult4(
1338
1388
  redactDisplayNames({
1339
1389
  deleted: true,
1340
- ...data
1390
+ ...fieldsOf(data)
1341
1391
  })
1342
1392
  );
1343
1393
  }
@@ -1347,7 +1397,7 @@ async function deployManageHandlerBody(client, input) {
1347
1397
  );
1348
1398
  }
1349
1399
  } catch (error) {
1350
- return mcpError4(error, isAuthError(error) ? AUTH_HINT : void 0);
1400
+ return mcpError5(error, isAuthError(error) ? AUTH_HINT : void 0);
1351
1401
  }
1352
1402
  }
1353
1403
  function registerDeployTool(server, client) {
@@ -1360,35 +1410,33 @@ function registerDeployTool(server, client) {
1360
1410
  inputSchema: spec.inputSchema,
1361
1411
  annotations: spec.annotations
1362
1412
  },
1363
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
1364
- // type-erased (input: unknown) => Promise<unknown> form by design.
1365
- spec.handler
1413
+ (args) => deployManageHandlerBody(client, args)
1366
1414
  );
1367
1415
  }
1368
1416
 
1369
1417
  // src/tools/secret-manage.ts
1370
- import { z as z5 } from "zod";
1371
- import { mcpResult as mcpResult5, mcpError as mcpError5 } from "@walkeros/core";
1418
+ import { z as z6 } from "zod";
1419
+ import { mcpResult as mcpResult5, mcpError as mcpError6 } from "@walkeros/core";
1372
1420
  var TITLE5 = "Secret Management";
1373
1421
  var DESCRIPTION5 = "Manage a flow\u2019s managed secrets (the $secret.<NAME> values its steps reference at deploy/run time). Actions: list (metadata only), set (create), update (rotate value), delete. Secrets are write-mostly: values are encrypted at rest and are NEVER returned, listed, or echoed. Reference a secret from a flow step as $secret.<NAME>. Credentials, tokens, and private keys must use $secret, not $env: the deploy pipeline only injects values referenced as $secret.<NAME> into the server runner. Server flows only.";
1374
1422
  var inputSchema5 = {
1375
- action: z5.enum(["list", "set", "update", "delete"]).describe("Secret management action to perform"),
1376
- projectId: z5.string().optional().describe(
1423
+ action: z6.enum(["list", "set", "update", "delete"]).describe("Secret management action to perform"),
1424
+ projectId: z6.string().optional().describe(
1377
1425
  "Project ID. Optional: falls back to the default project when omitted."
1378
1426
  ),
1379
- flowId: z5.string().describe(
1427
+ flowId: z6.string().describe(
1380
1428
  "Flow ID (flow_...) or config ID (cfg_...). Required for list, set, update, and delete: secrets are flow-scoped."
1381
1429
  ),
1382
- name: z5.string().regex(
1430
+ name: z6.string().regex(
1383
1431
  /^[A-Z_][A-Z0-9_]*$/,
1384
1432
  "Secret name must be uppercase letters, digits, and underscores, starting with a letter or underscore."
1385
1433
  ).optional().describe(
1386
1434
  "Secret name (UPPER_SNAKE_CASE). Required for set. Referenced in flows as $secret.<NAME>."
1387
1435
  ),
1388
- value: z5.string().min(1).max(65536).optional().describe(
1436
+ value: z6.string().min(1).max(65536).optional().describe(
1389
1437
  "Secret value (1-65536 chars). Required for set and update. Write-only: never returned or logged."
1390
1438
  ),
1391
- secretId: z5.string().optional().describe(
1439
+ secretId: z6.string().optional().describe(
1392
1440
  'Secret ID (sec_...). Required for update and delete. Use action "list" to find it.'
1393
1441
  )
1394
1442
  };
@@ -1409,18 +1457,20 @@ function createSecretManageToolSpec(client) {
1409
1457
  };
1410
1458
  }
1411
1459
  async function secretManageHandlerBody(client, input) {
1412
- const { action, projectId, flowId, name, value, secretId } = input ?? {};
1460
+ const parsed = parseToolInput(inputSchema5, input);
1461
+ if (!parsed.ok) return parsed.error;
1462
+ const { action, projectId, flowId, name, value, secretId } = parsed.data;
1413
1463
  const validationError = validateActionInput(
1414
1464
  "secret_manage",
1415
1465
  action ?? "",
1416
1466
  { flowId, name, value, secretId },
1417
1467
  SECRET_MANAGE_REQUIREMENTS
1418
1468
  );
1419
- if (validationError) return mcpError5(new Error(validationError));
1469
+ if (validationError) return mcpError6(new Error(validationError));
1420
1470
  try {
1421
1471
  const resolvedProjectId = resolveDefaultProject(client, projectId);
1422
1472
  if (!resolvedProjectId)
1423
- return mcpError5(new Error(NO_DEFAULT_PROJECT_ERROR));
1473
+ return mcpError6(new Error(NO_DEFAULT_PROJECT_ERROR));
1424
1474
  switch (action) {
1425
1475
  case "list": {
1426
1476
  assertParam(flowId, "flowId", "list");
@@ -1479,7 +1529,7 @@ async function secretManageHandlerBody(client, input) {
1479
1529
  );
1480
1530
  }
1481
1531
  } catch (error) {
1482
- return mcpError5(error, isAuthError(error) ? AUTH_HINT : void 0);
1532
+ return mcpError6(error, isAuthError(error) ? AUTH_HINT : void 0);
1483
1533
  }
1484
1534
  }
1485
1535
  function registerSecretManageTool(server, client) {
@@ -1492,22 +1542,20 @@ function registerSecretManageTool(server, client) {
1492
1542
  inputSchema: spec.inputSchema,
1493
1543
  annotations: spec.annotations
1494
1544
  },
1495
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
1496
- // type-erased (input: unknown) => Promise<unknown> form by design.
1497
- spec.handler
1545
+ (args) => secretManageHandlerBody(client, args)
1498
1546
  );
1499
1547
  }
1500
1548
 
1501
1549
  // src/tools/observe-journeys.ts
1502
- import { z as z6 } from "zod";
1503
- import { mcpResult as mcpResult6, mcpError as mcpError6 } from "@walkeros/core";
1550
+ import { z as z7 } from "zod";
1551
+ import { mcpResult as mcpResult6, mcpError as mcpError7 } from "@walkeros/core";
1504
1552
  var TITLE6 = "Observe Journeys";
1505
1553
  var DESCRIPTION6 = "Read the assembled, cross-runtime journeys for a flow that is currently being observed (an active Observe session). Pass flowId; the active session is resolved for you (a flow has at most one). Each journey is one traced event reconstructed end to end across web and server: its ordered hops (source, transformer, collector, destination), each hop status (pending/done/skipped/error), captured in/out payloads, consent, and vendor calls. Use this to see what actually happened to live events: which destinations fired, what mapping ran, where an event was skipped or errored, and whether records were lost (gaps + a journey `lossy` flag). When the flow has no active session the result is `{ sessionId: null, journeys: [], gaps: [] }` \u2014 start an Observe session in the app and drive traffic first, then read again. Narrow with traceId (one trace) and limit (page cap, most recent kept; default 50). Read-only.";
1506
1554
  var inputSchema6 = {
1507
- flowId: z6.string().describe("Flow to read journeys for (its active Observe session)."),
1508
- projectId: z6.string().optional().describe("Project ID. Optional; falls back to the default project."),
1509
- traceId: z6.string().optional().describe("Return only the journeys for this trace id."),
1510
- limit: z6.number().int().min(1).max(100).optional().describe(
1555
+ flowId: z7.string().describe("Flow to read journeys for (its active Observe session)."),
1556
+ projectId: z7.string().optional().describe("Project ID. Optional; falls back to the default project."),
1557
+ traceId: z7.string().optional().describe("Return only the journeys for this trace id."),
1558
+ limit: z7.number().int().min(1).max(100).optional().describe(
1511
1559
  "Max journeys to return (1-100, most recent kept). Defaults to 50."
1512
1560
  )
1513
1561
  };
@@ -1565,9 +1613,11 @@ function createObserveJourneysToolSpec(client) {
1565
1613
  };
1566
1614
  }
1567
1615
  async function observeJourneysHandlerBody(client, input) {
1568
- const { flowId, projectId, traceId, limit } = input ?? {};
1616
+ const parsed = parseToolInput(inputSchema6, input);
1617
+ if (!parsed.ok) return parsed.error;
1618
+ const { flowId, projectId, traceId, limit } = parsed.data;
1569
1619
  if (!flowId) {
1570
- return mcpError6(new Error("flowId is required for observe_journeys."));
1620
+ return mcpError7(new Error("flowId is required for observe_journeys."));
1571
1621
  }
1572
1622
  try {
1573
1623
  const result = await client.listJourneys({
@@ -1594,7 +1644,7 @@ async function observeJourneysHandlerBody(client, input) {
1594
1644
  ]
1595
1645
  });
1596
1646
  } catch (error) {
1597
- return mcpError6(error, isAuthError(error) ? AUTH_HINT : void 0);
1647
+ return mcpError7(error, isAuthError(error) ? AUTH_HINT : void 0);
1598
1648
  }
1599
1649
  }
1600
1650
  function registerObserveJourneysTool(server, client) {
@@ -1607,15 +1657,13 @@ function registerObserveJourneysTool(server, client) {
1607
1657
  inputSchema: spec.inputSchema,
1608
1658
  annotations: spec.annotations
1609
1659
  },
1610
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
1611
- // type-erased (input: unknown) => Promise<unknown> form by design.
1612
- spec.handler
1660
+ (args) => observeJourneysHandlerBody(client, args)
1613
1661
  );
1614
1662
  }
1615
1663
 
1616
1664
  // src/tools/observe-session.ts
1617
- import { z as z7 } from "zod";
1618
- import { mcpResult as mcpResult7, mcpError as mcpError7 } from "@walkeros/core";
1665
+ import { z as z8 } from "zod";
1666
+ import { mcpResult as mcpResult7, mcpError as mcpError8 } from "@walkeros/core";
1619
1667
  var TITLE7 = "Observe Session";
1620
1668
  var DESCRIPTION7 = "Open, inspect, or end an Observe session: a time-boxed window on one flow that runtimes attach to as arms. A preview arm streams from a browser, a container arm runs server-side, and both feed ONE shared journeys feed. start opens the window (arms picks which runtimes attach), status reports per-arm state plus recordsReceived and expiresAt, stop ends the whole session including every arm. A flow has at most one session, so status/stop resolve it from flowId when sessionId is omitted. Read the events with observe_journeys; this tool never returns event data and never judges whether events are correct.";
1621
1669
  var HINT_SIMULATE_FIRST = "Simulate before preview: flow_simulate checks mapping with no browser.";
@@ -1626,29 +1674,29 @@ var HINT_EMPTY_FEED = "recordsReceived is 0: nothing has reached the feed yet. D
1626
1674
  var HINT_ENDED = "Session ended and both arms detached. Start a new one with observe_session start.";
1627
1675
  var HINT_NO_WINDOW = "No Observe session on this flow. Open one with observe_session start.";
1628
1676
  var inputSchema7 = {
1629
- action: z7.enum(["start", "status", "stop"]).describe(
1677
+ action: z8.enum(["start", "status", "stop"]).describe(
1630
1678
  "start opens a session, status reports arm state, stop ends the whole session."
1631
1679
  ),
1632
- flowId: z7.string().describe("Flow the Observe session runs on."),
1633
- projectId: z7.string().optional().describe("Project ID. Optional; falls back to the default project."),
1634
- sessionId: z7.string().optional().describe(
1680
+ flowId: z8.string().describe("Flow the Observe session runs on."),
1681
+ projectId: z8.string().optional().describe("Project ID. Optional; falls back to the default project."),
1682
+ sessionId: z8.string().optional().describe(
1635
1683
  "Session to act on for status/stop. Optional; the flow has at most one session and it is resolved for you."
1636
1684
  ),
1637
- arms: z7.object({
1638
- container: z7.literal(true).optional().describe(
1685
+ arms: z8.object({
1686
+ container: z8.literal(true).optional().describe(
1639
1687
  "Pass true to attach the server container arm, which selects the flow's server settings when no preview arm is named. Only true is accepted: a web settings that references a server flow always brings its container arm along, so a container cannot be suppressed here."
1640
1688
  ),
1641
- preview: z7.string().optional().describe(
1689
+ preview: z8.string().optional().describe(
1642
1690
  "Name the flow settings this session observes. A web settings attaches the browser preview arm (plus the container arm of any server flow it references); a server settings attaches the container arm alone. Omit to use the flow's single web settings."
1643
1691
  )
1644
1692
  }).optional().describe(
1645
1693
  "Which runtimes attach. Omit to attach the default preview arm; a web settings that references a server flow brings its container arm with it."
1646
1694
  ),
1647
- origins: z7.array(z7.string()).optional().describe(
1695
+ origins: z8.array(z8.string()).optional().describe(
1648
1696
  "Bare https origins (https://host[:port]) the session may ingest web events from."
1649
1697
  ),
1650
- level: z7.enum(["off", "standard", "trace"]).optional().describe("Container observation verbosity. Defaults to the app's own."),
1651
- replace: z7.boolean().optional().describe(
1698
+ level: z8.enum(["off", "standard", "trace"]).optional().describe("Container observation verbosity. Defaults to the app's own."),
1699
+ replace: z8.boolean().optional().describe(
1652
1700
  "Replace the flow's existing window instead of attaching to it. Re-provisions from the new config."
1653
1701
  )
1654
1702
  };
@@ -1659,14 +1707,14 @@ var annotations7 = {
1659
1707
  openWorldHint: true
1660
1708
  };
1661
1709
  function readSettings(flow) {
1662
- if (!flow || typeof flow !== "object") return [];
1710
+ if (!isRecord(flow)) return [];
1663
1711
  const settings = flow.settings;
1664
1712
  if (!Array.isArray(settings)) return [];
1665
1713
  const entries = [];
1666
1714
  for (const entry of settings) {
1667
- if (!entry || typeof entry !== "object") continue;
1668
- const { name, platform } = entry;
1669
- if (typeof name !== "string") continue;
1715
+ const name = stringField(entry, "name");
1716
+ const platform = stringField(entry, "platform");
1717
+ if (name === void 0) continue;
1670
1718
  if (platform !== "web" && platform !== "server") continue;
1671
1719
  entries.push({ name, platform });
1672
1720
  }
@@ -1796,6 +1844,8 @@ function createObserveSessionToolSpec(client) {
1796
1844
  };
1797
1845
  }
1798
1846
  async function observeSessionHandlerBody(client, input) {
1847
+ const parsed = parseToolInput(inputSchema7, input);
1848
+ if (!parsed.ok) return parsed.error;
1799
1849
  const {
1800
1850
  action,
1801
1851
  flowId,
@@ -1805,19 +1855,19 @@ async function observeSessionHandlerBody(client, input) {
1805
1855
  origins,
1806
1856
  level,
1807
1857
  replace
1808
- } = input ?? {};
1858
+ } = parsed.data;
1809
1859
  if (!flowId) {
1810
- return mcpError7(new Error("flowId is required for observe_session."));
1860
+ return mcpError8(new Error("flowId is required for observe_session."));
1811
1861
  }
1812
1862
  const resolvedProjectId = resolveProjectId(client, projectId);
1813
1863
  if (!resolvedProjectId) {
1814
- return mcpError7(new Error(NO_DEFAULT_PROJECT_ERROR2));
1864
+ return mcpError8(new Error(NO_DEFAULT_PROJECT_ERROR2));
1815
1865
  }
1816
1866
  try {
1817
1867
  switch (action) {
1818
1868
  case "start": {
1819
1869
  if (!client.startObserveSession) {
1820
- return mcpError7(
1870
+ return mcpError8(
1821
1871
  new Error("observe_session start is not supported by this client.")
1822
1872
  );
1823
1873
  }
@@ -1843,7 +1893,7 @@ async function observeSessionHandlerBody(client, input) {
1843
1893
  }
1844
1894
  case "status": {
1845
1895
  if (!client.getObserveSession) {
1846
- return mcpError7(
1896
+ return mcpError8(
1847
1897
  new Error(
1848
1898
  "observe_session status is not supported by this client."
1849
1899
  )
@@ -1870,7 +1920,7 @@ async function observeSessionHandlerBody(client, input) {
1870
1920
  }
1871
1921
  case "stop": {
1872
1922
  if (!client.endObserveSession) {
1873
- return mcpError7(
1923
+ return mcpError8(
1874
1924
  new Error("observe_session stop is not supported by this client.")
1875
1925
  );
1876
1926
  }
@@ -1900,7 +1950,7 @@ async function observeSessionHandlerBody(client, input) {
1900
1950
  );
1901
1951
  }
1902
1952
  } catch (error) {
1903
- return mcpError7(error, isAuthError(error) ? AUTH_HINT : void 0);
1953
+ return mcpError8(error, isAuthError(error) ? AUTH_HINT : void 0);
1904
1954
  }
1905
1955
  }
1906
1956
  function registerObserveSessionTool(server, client) {
@@ -1913,15 +1963,13 @@ function registerObserveSessionTool(server, client) {
1913
1963
  inputSchema: spec.inputSchema,
1914
1964
  annotations: spec.annotations
1915
1965
  },
1916
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
1917
- // type-erased (input: unknown) => Promise<unknown> form by design.
1918
- spec.handler
1966
+ (args) => observeSessionHandlerBody(client, args)
1919
1967
  );
1920
1968
  }
1921
1969
 
1922
1970
  // src/tools/hub-manage.ts
1923
- import { z as z8 } from "zod";
1924
- import { mcpResult as mcpResult8, mcpError as mcpError8 } from "@walkeros/core";
1971
+ import { z as z9 } from "zod";
1972
+ import { mcpResult as mcpResult8, mcpError as mcpError9 } from "@walkeros/core";
1925
1973
 
1926
1974
  // src/tools/feature-gate.ts
1927
1975
  var FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE";
@@ -1974,56 +2022,56 @@ var TOOL_ANCHOR_TYPES = [
1974
2022
  "tag"
1975
2023
  ];
1976
2024
  var HUB_MANAGE_INPUT_SCHEMA = {
1977
- action: z8.enum(ACTIONS, {
2025
+ action: z9.enum(ACTIONS, {
1978
2026
  error: () => `Unknown action. Use one of: ${ACTIONS.join(", ")}`
1979
2027
  }).describe("Which part of the release history to read or write"),
1980
- projectId: z8.string().optional().describe(
2028
+ projectId: z9.string().optional().describe(
1981
2029
  "Project ID. Optional: falls back to the default project when omitted."
1982
2030
  ),
1983
- flowId: z8.string().optional().describe(
2031
+ flowId: z9.string().optional().describe(
1984
2032
  'Flow ID (flow_...). Required for every action except "knowledge", which hangs on a page rather than a flow and refuses this field.'
1985
2033
  ),
1986
- versionId: z8.string().min(1).optional().describe(
2034
+ versionId: z9.string().min(1).optional().describe(
1987
2035
  'Release version ID (ver_...) from action "releases". Addresses one release for release_get and rationale_set. Pass this or versionNumber.'
1988
2036
  ),
1989
- versionNumber: z8.number().int().positive().optional().describe(
2037
+ versionNumber: z9.number().int().positive().optional().describe(
1990
2038
  'Spine release number for this flow, the `versionNumber` field of action "releases". Alternative to versionId. Not the same as a row\'s deploymentAttempt.'
1991
2039
  ),
1992
- step: z8.string().optional().describe(
2040
+ step: z9.string().optional().describe(
1993
2041
  'Step key as "type.name", e.g. "destination.ga4" or "contract.checkout". Required for step_history.'
1994
2042
  ),
1995
- flow: z8.string().optional().describe(
2043
+ flow: z9.string().optional().describe(
1996
2044
  'Named flow inside the config, e.g. "web" or "server". Optional for step_history: omit to scan every named flow. Ignored for contract steps, which are top-level.'
1997
2045
  ),
1998
- text: z8.string().trim().min(1).max(MAX_ANNOTATION_TEXT_LENGTH).optional().describe(
2046
+ text: z9.string().trim().min(1).max(MAX_ANNOTATION_TEXT_LENGTH).optional().describe(
1999
2047
  `The text to write (1-${MAX_ANNOTATION_TEXT_LENGTH} chars). Required for rationale_set and note_add. As rationale it replaces the note already on the release and never touches the machine summary; as a note it is appended to a thread and nothing is ever replaced.`
2000
2048
  ),
2001
- limit: z8.number().int().positive().optional().describe(
2049
+ limit: z9.number().int().positive().optional().describe(
2002
2050
  `Page size. Releases to list for action "releases" (max 100), or releases to SCAN for step_history (max ${MAX_STEP_HISTORY_LIMIT}). For step_history this bounds releases, not entries: a step present in several named flows yields one entry per flow per release, and the scan stops at ${MAX_STEP_HISTORY_ENTRIES} entries with entriesTruncated set. Narrow with "flow" to avoid that. For threads it bounds threads, and a read that carries messages is held to ${MAX_THREADS_WITH_MESSAGES} of them. Knowledge entries are bounded the same way.`
2003
2051
  ),
2004
- offset: z8.number().int().min(0).optional().describe('Releases to skip. Action "releases" only.'),
2005
- anchorType: z8.enum(TOOL_ANCHOR_TYPES).optional().describe(
2052
+ offset: z9.number().int().min(0).optional().describe('Releases to skip. Action "releases" only.'),
2053
+ anchorType: z9.enum(TOOL_ANCHOR_TYPES).optional().describe(
2006
2054
  'What a thread hangs on. Defaults to "release", the only anchor the app writes today. Pair it with anchorKey; a key means a different thing under each type.'
2007
2055
  ),
2008
- anchorKey: z8.string().min(1).max(MAX_ANCHOR_KEY_LENGTH).optional().describe(
2056
+ anchorKey: z9.string().min(1).max(MAX_ANCHOR_KEY_LENGTH).optional().describe(
2009
2057
  'What the anchor addresses within its type: a release version ID (ver_...) for "release", a "type.name" step key for "step". For a release you can pass versionId or versionNumber instead. Omit entirely on action "threads" to read every thread on the flow.'
2010
2058
  ),
2011
- anchorLabel: z8.string().min(1).max(MAX_ANCHOR_LABEL_LENGTH).optional().describe(
2059
+ anchorLabel: z9.string().min(1).max(MAX_ANCHOR_LABEL_LENGTH).optional().describe(
2012
2060
  'How the anchor reads on screen, stored once when a thread is opened so a later rename leaves it readable. Derived for a release ("v14"); pass it only when opening a thread on another anchor type.'
2013
2061
  ),
2014
- threadId: z8.string().min(1).optional().describe(
2062
+ threadId: z9.string().min(1).optional().describe(
2015
2063
  'Thread ID (thr_...) from action "threads". Pass it to note_add to reply in that thread; omit it to open a new thread on the anchor.'
2016
2064
  ),
2017
- status: z8.enum(THREAD_STATUSES).optional().describe(
2065
+ status: z9.enum(THREAD_STATUSES).optional().describe(
2018
2066
  'Read only threads in this state. Action "threads" only; omit for both.'
2019
2067
  ),
2020
- pageKey: z8.string().min(1).max(MAX_SOURCE_KEY_LENGTH).optional().describe(
2068
+ pageKey: z9.string().min(1).max(MAX_SOURCE_KEY_LENGTH).optional().describe(
2021
2069
  'The page a note was left on, as Tag Mode addressed it, usually the page URL. Narrows action "knowledge" to every frame that page holds, at any depth; omit it to read the whole project.'
2022
2070
  ),
2023
- frameId: z8.string().regex(FRAME_ID_PATTERN).optional().describe(
2071
+ frameId: z9.string().regex(FRAME_ID_PATTERN).optional().describe(
2024
2072
  'One frame (frm_...), the named rectangle a note hangs on. Action "knowledge" only. Narrower than pageKey, since a page holds several frames.'
2025
2073
  ),
2026
- markId: z8.string().min(1).max(MAX_MARK_ID_LENGTH).optional().describe(
2074
+ markId: z9.string().min(1).max(MAX_MARK_ID_LENGTH).optional().describe(
2027
2075
  'One tag within "frameId", by its tag id (the id of an entry in frame_manage marks.tags). Action "knowledge" only, and refused without frameId, since a mark id alone addresses nothing. Naming a mark is also what attaches the message bodies.'
2028
2076
  )
2029
2077
  };
@@ -2069,7 +2117,7 @@ var HUB_HINT_ENTRY_NAMES_FLOW = "An entry names the flow it was written against
2069
2117
  var HUB_HINT_KNOWLEDGE_READ_ONLY = "This tool only reads knowledge. Answering a note, and settling it, are done by a person in the app.";
2070
2118
  var HUB_HINT_READ_FRAME = 'Use frame_manage action "get" with the frameId to read the frame and its marks.';
2071
2119
  var HUB_NOT_FOUND_HINT = 'Use action "releases" to find version ids and action "threads" to find thread ids.';
2072
- var hubInputSchema = z8.object(HUB_MANAGE_INPUT_SCHEMA);
2120
+ var hubInputSchema = z9.object(HUB_MANAGE_INPUT_SCHEMA);
2073
2121
  var HubToolError = class extends Error {
2074
2122
  constructor(code, message) {
2075
2123
  super(message);
@@ -2489,12 +2537,7 @@ async function hubManageHandler(client, rawInput) {
2489
2537
  try {
2490
2538
  const parsed = hubInputSchema.safeParse(rawInput ?? {});
2491
2539
  if (!parsed.success) {
2492
- throw new HubToolError(
2493
- "INVALID_INPUT",
2494
- parsed.error.issues.map(
2495
- (issue) => `${issue.path.join(".") || "input"}: ${issue.message}`
2496
- ).join("; ")
2497
- );
2540
+ throw new HubToolError("INVALID_INPUT", inputIssuesMessage(parsed.error));
2498
2541
  }
2499
2542
  const input = parsed.data;
2500
2543
  const { action } = input;
@@ -2527,7 +2570,7 @@ async function hubManageHandler(client, rawInput) {
2527
2570
  return await handleNoteAdd(client, projectId, flowId, input);
2528
2571
  }
2529
2572
  } catch (error) {
2530
- return mcpError8(error, errorHint(error, "hub", HUB_NOT_FOUND_HINT));
2573
+ return mcpError9(error, errorHint(error, "hub", HUB_NOT_FOUND_HINT));
2531
2574
  }
2532
2575
  }
2533
2576
  function createHubManageToolSpec(client) {
@@ -2555,23 +2598,23 @@ function registerHubManageTool(server, client) {
2555
2598
  }
2556
2599
 
2557
2600
  // src/tools/frame-manage.ts
2558
- import { z as z9 } from "zod";
2559
- import { mcpResult as mcpResult9, mcpError as mcpError9 } from "@walkeros/core";
2601
+ import { z as z10 } from "zod";
2602
+ import { mcpResult as mcpResult9, mcpError as mcpError10 } from "@walkeros/core";
2560
2603
  var FRAME_ID_PATTERN2 = /^frm_[A-Za-z0-9_-]{21}$/;
2561
2604
  var MAX_PAGE_KEY_CHARS = 1024;
2562
2605
  var TITLE9 = "Frames";
2563
2606
  var FRAME_MANAGE_DESCRIPTION = 'Read the frames of a measurement plan: named rectangles with marks inside them, drawn in Tag Mode or in the app. Actions: list (every frame of the project, without marks), page (the frames of one page at any depth, with marks), get (one frame with its marks). Read-only: frames are drawn and edited in Tag Mode or the app, never here. A frame name is documentation; the marks inside it carry the meaning. A frame that extends another stores only what it adds, so its tags may carry only the fields they change. Marks are { tags, note }: tags is one flat list of tags, each with an id, a kind such as entity, property or action, a name, and a parentId naming the tag it sits under; note is the frame\u2019s own description and thread. Use hub_manage action "knowledge" with a frameId or markId to read what people wrote on a frame. A markId is a tag id: a tag\u2019s id, parentId and threadRef come back literal when they have the shape the app mints, so they can be passed straight back; every other string value in the marks is wrapped as data, and so is an object key that is not a plain identifier.';
2564
2607
  var FRAME_MANAGE_INPUT_SCHEMA = {
2565
- action: z9.enum(["list", "page", "get"]).describe(
2608
+ action: z10.enum(["list", "page", "get"]).describe(
2566
2609
  "list the project\u2019s frames, read one page with marks, or read one frame"
2567
2610
  ),
2568
- projectId: z9.string().optional().describe(
2611
+ projectId: z10.string().optional().describe(
2569
2612
  "Project ID. Optional: falls back to the default project when omitted."
2570
2613
  ),
2571
- pageKey: z9.string().min(1).max(MAX_PAGE_KEY_CHARS).optional().describe(
2614
+ pageKey: z10.string().min(1).max(MAX_PAGE_KEY_CHARS).optional().describe(
2572
2615
  "The page as its frames address it (the `source.key` of a page frame, usually the page URL without query). Required for page."
2573
2616
  ),
2574
- frameId: z9.string().regex(FRAME_ID_PATTERN2).optional().describe(
2617
+ frameId: z10.string().regex(FRAME_ID_PATTERN2).optional().describe(
2575
2618
  'Frame ID (frm_...). Required for get. Use action "list" or "page" to find one.'
2576
2619
  )
2577
2620
  };
@@ -2681,17 +2724,11 @@ function serializeFrame(frame) {
2681
2724
  marks: walkMarks(frame.marks)
2682
2725
  };
2683
2726
  }
2684
- var frameInputSchema = z9.object(FRAME_MANAGE_INPUT_SCHEMA);
2727
+ var frameInputSchema = z10.object(FRAME_MANAGE_INPUT_SCHEMA);
2685
2728
  async function frameManageHandler(client, rawInput) {
2686
2729
  const parsed = frameInputSchema.safeParse(rawInput ?? {});
2687
2730
  if (!parsed.success) {
2688
- return mcpError9(
2689
- new Error(
2690
- parsed.error.issues.map(
2691
- (issue) => `${issue.path.join(".") || "input"}: ${issue.message}`
2692
- ).join("; ")
2693
- )
2694
- );
2731
+ return mcpError10(new Error(inputIssuesMessage(parsed.error)));
2695
2732
  }
2696
2733
  const { action, projectId, pageKey, frameId } = parsed.data;
2697
2734
  const validationError = validateActionInput(
@@ -2700,11 +2737,11 @@ async function frameManageHandler(client, rawInput) {
2700
2737
  { pageKey, frameId },
2701
2738
  FRAME_MANAGE_REQUIREMENTS
2702
2739
  );
2703
- if (validationError) return mcpError9(new Error(validationError));
2740
+ if (validationError) return mcpError10(new Error(validationError));
2704
2741
  try {
2705
2742
  const resolvedProjectId = resolveDefaultProject(client, projectId);
2706
2743
  if (!resolvedProjectId) {
2707
- return mcpError9(new Error(NO_DEFAULT_PROJECT_ERROR));
2744
+ return mcpError10(new Error(NO_DEFAULT_PROJECT_ERROR));
2708
2745
  }
2709
2746
  switch (action) {
2710
2747
  case "list": {
@@ -2749,7 +2786,7 @@ async function frameManageHandler(client, rawInput) {
2749
2786
  }
2750
2787
  }
2751
2788
  } catch (error) {
2752
- return mcpError9(error, errorHint(error, "frames", FRAME_NOT_FOUND_HINT));
2789
+ return mcpError10(error, errorHint(error, "frames", FRAME_NOT_FOUND_HINT));
2753
2790
  }
2754
2791
  }
2755
2792
  function createFrameManageToolSpec(client) {
@@ -2777,13 +2814,13 @@ function registerFrameManageTool(server, client) {
2777
2814
  }
2778
2815
 
2779
2816
  // src/tools/feedback.ts
2780
- import { z as z10 } from "zod";
2781
- import { mcpResult as mcpResult10, mcpError as mcpError10 } from "@walkeros/core";
2817
+ import { z as z11 } from "zod";
2818
+ import { mcpResult as mcpResult10, mcpError as mcpError11 } from "@walkeros/core";
2782
2819
  var TITLE10 = "Send Feedback";
2783
2820
  var DESCRIPTION8 = "Send feedback about walkerOS";
2784
2821
  var inputSchema8 = {
2785
- text: z10.string().describe("Your feedback text"),
2786
- anonymous: z10.boolean().optional().describe(
2822
+ text: z11.string().describe("Your feedback text"),
2823
+ anonymous: z11.boolean().optional().describe(
2787
2824
  "Include user/project info? false = include, true = anonymous. Only needed on first call if not yet configured."
2788
2825
  )
2789
2826
  };
@@ -2804,7 +2841,9 @@ function createFeedbackToolSpec(client) {
2804
2841
  };
2805
2842
  }
2806
2843
  async function feedbackHandlerBody(client, input) {
2807
- const { text, anonymous: explicitAnonymous } = input ?? {};
2844
+ const parsed = parseToolInput(inputSchema8, input);
2845
+ if (!parsed.ok) return parsed.error;
2846
+ const { text, anonymous: explicitAnonymous } = parsed.data;
2808
2847
  try {
2809
2848
  let anonymous = client.getFeedbackPreference();
2810
2849
  if (anonymous === void 0 && explicitAnonymous === void 0) {
@@ -2825,11 +2864,11 @@ async function feedbackHandlerBody(client, input) {
2825
2864
  const isAnonymous = explicitAnonymous ?? anonymous ?? true;
2826
2865
  await client.submitFeedback(text, {
2827
2866
  anonymous: isAnonymous,
2828
- version: "4.7.0-next-1790722899482"
2867
+ version: "4.7.0"
2829
2868
  });
2830
2869
  return mcpResult10({ ok: true });
2831
2870
  } catch (error) {
2832
- return mcpError10(error);
2871
+ return mcpError11(error);
2833
2872
  }
2834
2873
  }
2835
2874
  function registerFeedbackTool(server, client) {
@@ -2842,113 +2881,135 @@ function registerFeedbackTool(server, client) {
2842
2881
  inputSchema: spec.inputSchema,
2843
2882
  annotations: spec.annotations
2844
2883
  },
2845
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
2846
- // type-erased (input: unknown) => Promise<unknown> form by design.
2847
- spec.handler
2884
+ (args) => feedbackHandlerBody(client, args)
2848
2885
  );
2849
2886
  }
2850
2887
 
2851
2888
  // src/tools/validate.ts
2852
2889
  import { validate } from "@walkeros/cli";
2853
- import { schemas } from "@walkeros/cli/dev";
2854
- import { mcpResult as mcpResult11, mcpError as mcpError11 } from "@walkeros/core";
2890
+ import { schemas as schemas2 } from "@walkeros/cli/dev";
2891
+ import { mcpResult as mcpResult11, mcpError as mcpError12 } from "@walkeros/core";
2855
2892
 
2856
2893
  // src/schemas/output.ts
2857
- import { z as z11 } from "zod";
2894
+ import { z as z12 } from "zod";
2895
+ var ValidateIssueFields = {
2896
+ path: z12.string(),
2897
+ message: z12.string(),
2898
+ value: z12.unknown().optional(),
2899
+ code: z12.string().optional().describe("Stable code (the documented validate code list)"),
2900
+ keyword: z12.string().optional().describe("JSON Schema keyword of an ENTRY_SCHEMA finding")
2901
+ };
2858
2902
  var ValidateOutputShape = {
2859
- valid: z11.boolean().describe("Whether validation passed"),
2860
- type: z11.union([
2861
- z11.enum(["contract", "entry", "event", "flow", "mapping"]),
2862
- z11.string().regex(/^(destinations|sources|transformers)\.\w+$/)
2903
+ valid: z12.boolean().describe("Whether validation passed"),
2904
+ type: z12.union([
2905
+ z12.enum(["contract", "entry", "event", "flow", "mapping"]),
2906
+ z12.string().regex(/^(destinations|sources|transformers)\.\w+$/)
2863
2907
  ]).describe("What was validated"),
2864
- errors: z11.array(
2865
- z11.object({
2866
- path: z11.string(),
2867
- message: z11.string(),
2868
- value: z11.unknown().optional(),
2869
- code: z11.string().optional()
2870
- })
2871
- ).describe("Validation errors"),
2872
- warnings: z11.array(
2873
- z11.object({
2874
- path: z11.string(),
2875
- message: z11.string(),
2876
- suggestion: z11.string().optional()
2908
+ errors: z12.array(z12.object(ValidateIssueFields)).describe("Validation errors"),
2909
+ warnings: z12.array(
2910
+ z12.object({
2911
+ ...ValidateIssueFields,
2912
+ suggestion: z12.string().optional()
2877
2913
  })
2878
2914
  ).describe("Validation warnings"),
2879
- details: z11.record(z11.string(), z11.unknown()).describe("Additional validation details")
2915
+ details: z12.object({
2916
+ scope: z12.object({
2917
+ flows: z12.array(z12.string()),
2918
+ entry: z12.object({
2919
+ section: z12.string().optional(),
2920
+ key: z12.string(),
2921
+ flows: z12.array(z12.string()),
2922
+ searchedFlows: z12.array(z12.string())
2923
+ }).optional(),
2924
+ checks: z12.array(z12.string()),
2925
+ offline: z12.literal(true).optional()
2926
+ }).optional().describe("What the run covered"),
2927
+ skipped: z12.array(
2928
+ z12.object({
2929
+ path: z12.string(),
2930
+ check: z12.string(),
2931
+ reason: z12.string(),
2932
+ code: z12.string()
2933
+ })
2934
+ ).optional().describe("Checks in scope that did not run, with the reason"),
2935
+ deferred: z12.array(z12.object({ path: z12.string(), reference: z12.string() })).optional().describe("Values known only at runtime, not schema-checked")
2936
+ }).catchall(z12.unknown()).describe("Additional validation details"),
2937
+ _hints: z12.object({
2938
+ next: z12.array(z12.string()).optional(),
2939
+ warnings: z12.array(z12.string()).optional()
2940
+ }).optional().describe("Suggested next steps")
2880
2941
  };
2881
2942
  var BundleOutputShape = {
2882
- success: z11.boolean().describe("Whether bundling succeeded"),
2883
- totalSize: z11.number().optional().describe("Total bundle size in bytes"),
2884
- buildTime: z11.number().optional().describe("Build time in milliseconds"),
2885
- packages: z11.array(
2886
- z11.object({
2887
- name: z11.string()
2943
+ success: z12.boolean().describe("Whether bundling succeeded"),
2944
+ totalSize: z12.number().optional().describe("Total bundle size in bytes"),
2945
+ buildTime: z12.number().optional().describe("Build time in milliseconds"),
2946
+ packages: z12.array(
2947
+ z12.object({
2948
+ name: z12.string()
2888
2949
  })
2889
2950
  ).optional().describe("Names of packages included in the bundle"),
2890
- treeshakingEffective: z11.boolean().optional().describe("Whether tree-shaking was effective"),
2891
- message: z11.string().optional().describe("Status message")
2951
+ treeshakingEffective: z12.boolean().optional().describe("Whether tree-shaking was effective"),
2952
+ message: z12.string().optional().describe("Status message")
2892
2953
  };
2893
2954
  var SimulateOutputShape = {
2894
- success: z11.boolean().describe("Whether simulation succeeded"),
2895
- error: z11.string().optional().describe("Error message if failed"),
2896
- summary: z11.string().describe("One-line result summary"),
2897
- destinations: z11.record(
2898
- z11.string(),
2899
- z11.object({
2900
- received: z11.boolean().describe("Whether destination received the event"),
2901
- calls: z11.number().describe("Number of API calls made"),
2902
- payload: z11.unknown().optional().describe("All intercepted API calls (only when verbose: true)")
2955
+ success: z12.boolean().describe("Whether simulation succeeded"),
2956
+ error: z12.string().optional().describe("Error message if failed"),
2957
+ summary: z12.string().describe("One-line result summary"),
2958
+ destinations: z12.record(
2959
+ z12.string(),
2960
+ z12.object({
2961
+ received: z12.boolean().describe("Whether destination received the event"),
2962
+ calls: z12.number().describe("Number of API calls made"),
2963
+ payload: z12.unknown().optional().describe("All intercepted API calls (only when verbose: true)")
2903
2964
  })
2904
2965
  ).optional().describe("Per-destination results"),
2905
- capturedEvents: z11.array(z11.record(z11.string(), z11.unknown())).optional().describe("Events captured by source simulation"),
2906
- calls: z11.array(z11.unknown()).optional().describe(
2966
+ capturedEvents: z12.array(z12.record(z12.string(), z12.unknown())).optional().describe("Events captured by source simulation"),
2967
+ calls: z12.array(z12.unknown()).optional().describe(
2907
2968
  "Calls a simulated source made on its mock env (only when verbose: true)"
2908
2969
  ),
2909
- skipped: z11.object({
2910
- reason: z11.enum(["consent", "pending"]),
2911
- required: z11.record(z11.string(), z11.boolean()).optional(),
2912
- granted: z11.record(z11.string(), z11.boolean()).optional(),
2913
- require: z11.array(z11.string()).optional()
2970
+ skipped: z12.object({
2971
+ reason: z12.enum(["consent", "pending"]),
2972
+ required: z12.record(z12.string(), z12.boolean()).optional(),
2973
+ granted: z12.record(z12.string(), z12.boolean()).optional(),
2974
+ require: z12.array(z12.string()).optional()
2914
2975
  }).optional().describe(
2915
2976
  "Why the destination sent nothing: a consent skip, or waiting for its require"
2916
2977
  ),
2917
- duration: z11.number().optional().describe("Simulation duration in ms")
2978
+ duration: z12.number().optional().describe("Simulation duration in ms")
2918
2979
  };
2919
2980
  var PushOutputShape = {
2920
- success: z11.boolean().describe("Whether push succeeded"),
2921
- elbResult: z11.unknown().optional().describe("Push result from the collector"),
2922
- duration: z11.number().describe("Push duration in milliseconds"),
2923
- error: z11.string().optional().describe("Error message if push failed")
2981
+ success: z12.boolean().describe("Whether push succeeded"),
2982
+ elbResult: z12.unknown().optional().describe("Push result from the collector"),
2983
+ duration: z12.number().describe("Push duration in milliseconds"),
2984
+ error: z12.string().optional().describe("Error message if push failed")
2924
2985
  };
2925
2986
  var ExamplesListOutputShape = {
2926
- flow: z11.string().describe("Flow name"),
2927
- count: z11.number().describe("Number of examples found"),
2928
- examples: z11.array(
2929
- z11.object({
2930
- step: z11.string().describe('Step location (e.g., "destination.gtag")'),
2931
- stepType: z11.enum(["source", "transformer", "destination"]).describe("Step type"),
2932
- stepName: z11.string().describe("Step name"),
2933
- exampleName: z11.string().describe("Example name"),
2934
- source: z11.enum(["inline", "package"]).describe(
2987
+ flow: z12.string().describe("Flow name"),
2988
+ count: z12.number().describe("Number of examples found"),
2989
+ examples: z12.array(
2990
+ z12.object({
2991
+ step: z12.string().describe('Step location (e.g., "destination.gtag")'),
2992
+ stepType: z12.enum(["source", "transformer", "destination"]).describe("Step type"),
2993
+ stepName: z12.string().describe("Step name"),
2994
+ exampleName: z12.string().describe("Example name"),
2995
+ source: z12.enum(["inline", "package"]).describe(
2935
2996
  'Where the example came from: "inline" (defined in the flow step) or "package" (shipped by the referenced package)'
2936
2997
  ),
2937
- title: z11.string().optional().describe("Human-readable title if set"),
2938
- description: z11.string().optional().describe("Short human-readable description"),
2939
- public: z11.boolean().optional().describe(
2998
+ title: z12.string().optional().describe("Human-readable title if set"),
2999
+ description: z12.string().optional().describe("Short human-readable description"),
3000
+ public: z12.boolean().optional().describe(
2940
3001
  "Whether the example is public (defaults to true if omitted)"
2941
3002
  ),
2942
- hasIn: z11.boolean().describe("Whether the example has an input value"),
2943
- hasOut: z11.boolean().describe("Whether the example has an output value"),
2944
- hasMapping: z11.boolean().describe("Whether the example has a mapping configuration"),
2945
- hasTrigger: z11.boolean().describe("Whether the example has trigger metadata"),
2946
- in: z11.unknown().optional().describe("Input event data"),
2947
- out: z11.unknown().optional().describe("Expected output data"),
2948
- mapping: z11.unknown().optional().describe("Mapping configuration for destinations"),
2949
- trigger: z11.object({
2950
- type: z11.string().optional(),
2951
- options: z11.unknown().optional()
3003
+ hasIn: z12.boolean().describe("Whether the example has an input value"),
3004
+ hasOut: z12.boolean().describe("Whether the example has an output value"),
3005
+ hasMapping: z12.boolean().describe("Whether the example has a mapping configuration"),
3006
+ hasTrigger: z12.boolean().describe("Whether the example has trigger metadata"),
3007
+ in: z12.unknown().optional().describe("Input event data"),
3008
+ out: z12.unknown().optional().describe("Expected output data"),
3009
+ mapping: z12.unknown().optional().describe("Mapping configuration for destinations"),
3010
+ trigger: z12.object({
3011
+ type: z12.string().optional(),
3012
+ options: z12.unknown().optional()
2952
3013
  }).optional().describe("Trigger metadata for source simulation")
2953
3014
  })
2954
3015
  ).describe("Step examples")
@@ -2971,42 +3032,14 @@ async function loadValidateInput(runtime, input, type) {
2971
3032
  throw error;
2972
3033
  }
2973
3034
  }
2974
- var DEPRECATED_STORE_PACKAGE = "@walkeros/store-memory";
2975
- function detectDeprecatedStorePackages(config) {
2976
- const errors = [];
2977
- if (!config || typeof config !== "object") return errors;
2978
- const flows = config.flows;
2979
- if (!flows || typeof flows !== "object") return errors;
2980
- for (const [flowName, flowEntry] of Object.entries(
2981
- flows
2982
- )) {
2983
- if (!flowEntry || typeof flowEntry !== "object") continue;
2984
- const stores = flowEntry.stores;
2985
- if (!stores || typeof stores !== "object") continue;
2986
- for (const [storeId, storeEntry] of Object.entries(
2987
- stores
2988
- )) {
2989
- if (!storeEntry || typeof storeEntry !== "object") continue;
2990
- const pkg = storeEntry.package;
2991
- if (pkg === DEPRECATED_STORE_PACKAGE) {
2992
- errors.push({
2993
- path: `flows.${flowName}.stores.${storeId}`,
2994
- message: `Store "${storeId}" uses ${DEPRECATED_STORE_PACKAGE}, which has been removed. Use the built-in cache by omitting cache.store, or remove the store declaration if it was only used as a cache target.`,
2995
- code: "DEPRECATED_PACKAGE"
2996
- });
2997
- }
2998
- }
2999
- }
3000
- return errors;
3001
- }
3002
3035
  var TITLE11 = "Validate Flow";
3003
- var DESCRIPTION9 = "Validate walkerOS events, flow configurations, mapping rules, or data contracts. Accepts JSON strings, file paths, or URLs as input; on the hosted server only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. Returns validation results with errors, warnings, and details.";
3004
- var inputSchema9 = schemas.ValidateInputShape;
3036
+ var DESCRIPTION9 = "Validate walkerOS events, flow configurations, mapping rules, or data contracts. Accepts JSON strings, file paths, or URLs as input; on the hosted server only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. With only type and input, a flow runs every check on every flow and step, including each package's settings schema (fetched from the package CDN; offline: true skips that and says so). flow and path narrow the run; strict turns warnings and skips into failures: valid is false. Returns valid, errors and warnings with stable codes, and details.scope (what was checked), details.skipped (checks that could not run) and details.deferred (values known only at runtime).";
3037
+ var inputSchema9 = schemas2.ValidateInputShape;
3005
3038
  var annotations11 = {
3006
3039
  readOnlyHint: true,
3007
3040
  destructiveHint: false,
3008
3041
  idempotentHint: true,
3009
- openWorldHint: false
3042
+ openWorldHint: true
3010
3043
  };
3011
3044
  function createFlowValidateToolSpec(runtime) {
3012
3045
  return {
@@ -3019,43 +3052,48 @@ function createFlowValidateToolSpec(runtime) {
3019
3052
  };
3020
3053
  }
3021
3054
  async function flowValidateHandlerBody(runtime, input) {
3055
+ const parsed = schemas2.ValidateInputSchema.safeParse(input ?? {});
3056
+ if (!parsed.success) {
3057
+ return mcpError12(parsed.error, "Check the flow_validate input fields");
3058
+ }
3022
3059
  const {
3023
3060
  type,
3024
3061
  input: validateInput,
3025
3062
  flow,
3026
- path: path2
3027
- } = input ?? {};
3063
+ path: path3,
3064
+ strict,
3065
+ offline
3066
+ } = parsed.data;
3028
3067
  try {
3029
3068
  const resolved = await loadValidateInput(runtime, validateInput, type);
3069
+ const configDir = runtime.baseDir?.(validateInput);
3030
3070
  const result = await validate(type, resolved, {
3031
3071
  flow,
3032
- path: path2
3072
+ path: path3,
3073
+ strict,
3074
+ offline,
3075
+ ...configDir ? { configDir } : {}
3033
3076
  });
3034
- let augmented = result;
3035
- if (type === "flow") {
3036
- const deprecatedErrors = detectDeprecatedStorePackages(resolved);
3037
- if (deprecatedErrors.length > 0) {
3038
- augmented = {
3039
- ...result,
3040
- valid: false,
3041
- errors: [...result.errors, ...deprecatedErrors]
3042
- };
3043
- }
3044
- }
3045
- const hints = augmented.valid ? {
3046
- next: runtime.simulate ? [
3047
- "Use flow_simulate to test event flow",
3048
- "Use flow_bundle to build"
3049
- ] : [HINT_OUT_OF_PROCESS]
3050
- } : {
3077
+ const skipped = result.details.skipped ?? [];
3078
+ const next = runtime.simulate ? ["Use flow_simulate to test event flow", "Use flow_bundle to build"] : [HINT_OUT_OF_PROCESS];
3079
+ const hints = !result.valid && result.errors.length === 0 ? {
3080
+ next: [
3081
+ `strict: ${result.warnings.length} warning(s) and ${skipped.length} skipped check(s) count as failures; resolve them, or run without strict`
3082
+ ]
3083
+ } : !result.valid ? {
3051
3084
  next: [
3052
3085
  "Fix errors above, then run flow_validate again",
3053
3086
  "Read walkeros://reference/flow-schema for correct structure"
3054
3087
  ]
3055
- };
3056
- return mcpResult11(augmented, hints);
3088
+ } : skipped.length > 0 ? {
3089
+ next: [
3090
+ `Valid in checked scope; ${skipped.length} check(s) skipped, see details.skipped`,
3091
+ ...next
3092
+ ]
3093
+ } : { next };
3094
+ return mcpResult11(result, hints);
3057
3095
  } catch (error) {
3058
- return mcpError11(
3096
+ return mcpError12(
3059
3097
  error,
3060
3098
  refusalHint(
3061
3099
  error,
@@ -3076,15 +3114,13 @@ function registerFlowValidateTool(server, runtime) {
3076
3114
  outputSchema: ValidateOutputShape,
3077
3115
  annotations: spec.annotations
3078
3116
  },
3079
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
3080
- // type-erased (input: unknown) => Promise<unknown> form by design.
3081
- spec.handler
3117
+ (args) => flowValidateHandlerBody(runtime, args)
3082
3118
  );
3083
3119
  }
3084
3120
 
3085
3121
  // src/tools/bundle.ts
3086
- import { schemas as schemas2 } from "@walkeros/cli/dev";
3087
- import { mcpResult as mcpResult12, mcpError as mcpError12 } from "@walkeros/core";
3122
+ import { schemas as schemas3 } from "@walkeros/cli/dev";
3123
+ import { mcpResult as mcpResult12, mcpError as mcpError13 } from "@walkeros/core";
3088
3124
 
3089
3125
  // src/tools/resolve-config-path.ts
3090
3126
  async function resolveConfigPath(client, configPath) {
@@ -3097,7 +3133,7 @@ async function resolveConfigPath(client, configPath) {
3097
3133
  var TITLE12 = "Bundle Flow";
3098
3134
  var DESCRIPTION10 = "Bundle a walkerOS flow configuration into deployable JavaScript. Resolves all destinations, sources, and transformers, then outputs a tree-shaken production bundle. Returns bundle statistics.";
3099
3135
  var inputSchema10 = {
3100
- ...schemas2.BundleInputShape
3136
+ ...schemas3.BundleInputShape
3101
3137
  };
3102
3138
  var annotations12 = {
3103
3139
  readOnlyHint: false,
@@ -3116,10 +3152,12 @@ function createFlowBundleToolSpec(client, runtime) {
3116
3152
  };
3117
3153
  }
3118
3154
  async function flowBundleHandlerBody(client, runtime, input) {
3119
- const { configPath, flow, stats, output } = input ?? {};
3155
+ const parsed = parseToolInput(inputSchema10, input);
3156
+ if (!parsed.ok) return parsed.error;
3157
+ const { configPath, flow, stats, output } = parsed.data;
3120
3158
  if (!runtime.bundle) {
3121
3159
  const refusal = unavailableOperation("bundle");
3122
- return mcpError12(refusal, refusal.hint);
3160
+ return mcpError13(refusal, refusal.hint);
3123
3161
  }
3124
3162
  try {
3125
3163
  const resolvedConfigPath = await resolveConfigPath(client, configPath);
@@ -3139,9 +3177,8 @@ async function flowBundleHandlerBody(client, runtime, input) {
3139
3177
  }
3140
3178
  );
3141
3179
  }
3142
- const output_ = result;
3143
3180
  return mcpResult12(
3144
- { success: true, ...output_ },
3181
+ { success: true, ...result },
3145
3182
  {
3146
3183
  next: [
3147
3184
  "Use flow_simulate to test",
@@ -3150,7 +3187,7 @@ async function flowBundleHandlerBody(client, runtime, input) {
3150
3187
  }
3151
3188
  );
3152
3189
  } catch (error) {
3153
- return mcpError12(
3190
+ return mcpError13(
3154
3191
  error,
3155
3192
  refusalHint(error, "Run flow_validate for detailed error messages")
3156
3193
  );
@@ -3168,54 +3205,39 @@ function registerFlowBundleTool(server, client, runtime) {
3168
3205
  outputSchema: BundleOutputShape,
3169
3206
  annotations: spec.annotations
3170
3207
  },
3171
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
3172
- // type-erased (input: unknown) => Promise<unknown> form by design.
3173
- spec.handler
3208
+ (args) => flowBundleHandlerBody(client, runtime, args)
3174
3209
  );
3175
3210
  }
3176
3211
 
3177
3212
  // src/tools/simulate.ts
3178
- import { z as z12 } from "zod";
3179
- import { schemas as schemas3 } from "@walkeros/cli/dev";
3180
- import { isObject as isObject2, mcpResult as mcpResult13, mcpError as mcpError13 } from "@walkeros/core";
3181
- import { scrubSecrets, toPrintable } from "@walkeros/core/node";
3182
- import { maskKnownNumbers } from "@walkeros/cli";
3213
+ import { z as z13 } from "zod";
3214
+ import { schemas as schemas4 } from "@walkeros/cli/dev";
3215
+ import { filterValues, mcpResult as mcpResult14, mcpError as mcpError15 } from "@walkeros/core";
3183
3216
 
3184
3217
  // src/tools/simulate-description.ts
3185
3218
  var FLOW_SIMULATE_DESCRIPTION = `Simulate events through a walkerOS flow without making real API calls. For destinations: event is a walkerOS event { name: "entity action", data: {...} }. For sources: event is { content, trigger?: { type?, options? } }, where content is the walkerOS event { name: "entity action", data: {...} }. Only the simulated source starts. step (required) targets the step to simulate, e.g. "destination.gtag". Use flow_examples to discover available test data. A destination simulation starts only its target destination. A source's own walker commands (e.g. a CMP's walker consent) are returned as elb calls. Consent: state.consent is the collector consent the step starts from (any step; a consent-gated source such as the session source waits for it). A destination with require: ["consent"] waits until consent is present, so pass state.consent to start it; a destination with consent: { marketing: true } receives an event only when that consent is granted in state.consent or in the event's own consent. When a destination sends nothing, the result says why (waiting for its require, or a consent skip). command runs a step example with command (e.g. "consent") on a destination: event is the command's data, state.consent still applies first. Mapping transforms event names and data at the destination level. Policy redacts or injects fields before mapping runs.`;
3186
3219
 
3187
- // src/tools/simulate.ts
3188
- var STEP_TYPES = [
3189
- "source",
3190
- "transformer",
3191
- "collector",
3192
- "destination"
3193
- ];
3194
- function isStepType(value) {
3195
- return STEP_TYPES.some((t) => t === value);
3196
- }
3220
+ // src/tools/egress.ts
3221
+ import { isObject as isObject2, mcpResult as mcpResult13 } from "@walkeros/core";
3222
+ import { scrubJson, scrubSecrets } from "@walkeros/core/node";
3197
3223
  function scrubbed(result, known) {
3198
- const text = scrubSecrets(
3199
- JSON.stringify(maskKnownNumbers(toPrintable(result), known)),
3200
- { known }
3201
- );
3202
- let parsed;
3203
- try {
3204
- parsed = JSON.parse(text);
3205
- } catch {
3206
- parsed = void 0;
3207
- }
3208
- if (!isObject2(parsed))
3209
- throw new Error("Simulation result could not be redacted as JSON.");
3224
+ const parsed = parseObject(scrubJson(result, { known }));
3225
+ if (!parsed) throw new Error("Result could not be redacted as JSON.");
3210
3226
  return parsed;
3211
3227
  }
3212
3228
  function scrubbedError(response, known) {
3213
3229
  let structuredContent;
3214
3230
  try {
3215
- structuredContent = scrubbed(response.structuredContent, known);
3231
+ if (response.structuredContent)
3232
+ structuredContent = scrubbed(response.structuredContent, known);
3216
3233
  } catch {
3217
- structuredContent = {
3218
- error: "Simulation failed; the error could not be redacted."
3234
+ structuredContent = void 0;
3235
+ }
3236
+ if (structuredContent) {
3237
+ return {
3238
+ ...response,
3239
+ content: [{ type: "text", text: JSON.stringify(structuredContent) }],
3240
+ structuredContent
3219
3241
  };
3220
3242
  }
3221
3243
  return {
@@ -3224,9 +3246,48 @@ function scrubbedError(response, known) {
3224
3246
  ...part,
3225
3247
  text: scrubSecrets(part.text, { known })
3226
3248
  })),
3227
- structuredContent
3249
+ structuredContent: { error: "The error could not be redacted." }
3250
+ };
3251
+ }
3252
+ function scrubbedPushResult(result, known) {
3253
+ const text = scrubJson(result, { known, space: 2 });
3254
+ const parsed = parseObject(text);
3255
+ if (parsed)
3256
+ return mcpResult13({
3257
+ ...parsed,
3258
+ success: result.success,
3259
+ duration: result.duration
3260
+ });
3261
+ return {
3262
+ content: [{ type: "text", text }],
3263
+ structuredContent: { success: result.success, duration: result.duration }
3264
+ };
3265
+ }
3266
+ function parseObject(text) {
3267
+ try {
3268
+ const parsed = JSON.parse(text);
3269
+ return isObject2(parsed) ? parsed : void 0;
3270
+ } catch {
3271
+ return void 0;
3272
+ }
3273
+ }
3274
+ async function readRun(runtime, input) {
3275
+ if (runtime.loadRun) return runtime.loadRun(input);
3276
+ return {
3277
+ knownSecrets: runtime.knownSecrets ? await runtime.knownSecrets(input) : []
3228
3278
  };
3229
3279
  }
3280
+
3281
+ // src/tools/simulate.ts
3282
+ var STEP_TYPES = [
3283
+ "source",
3284
+ "transformer",
3285
+ "collector",
3286
+ "destination"
3287
+ ];
3288
+ function isStepType(value) {
3289
+ return STEP_TYPES.some((t) => t === value);
3290
+ }
3230
3291
  var TITLE13 = "Simulate Flow";
3231
3292
  var COMMANDS = [
3232
3293
  "config",
@@ -3235,30 +3296,30 @@ var COMMANDS = [
3235
3296
  "run"
3236
3297
  ];
3237
3298
  var inputSchema11 = {
3238
- configPath: schemas3.SimulateInputShape.configPath,
3239
- event: z12.union([z12.record(z12.string(), z12.unknown()), z12.string()]).optional().describe(
3299
+ configPath: schemas4.SimulateInputShape.configPath,
3300
+ event: z13.union([z13.record(z13.string(), z13.unknown()), z13.string()]).optional().describe(
3240
3301
  "For destinations: { name, data, consent? }; the event's consent counts toward the destination's consent requirement, on top of state.consent. With command: the command's data, e.g. { marketing: true } for consent. For sources: { content, trigger? } where content is the walkerOS event { name, data }. A web source's page URL goes in trigger.options.url (default http://localhost). Can also be a JSON string or file path."
3241
3302
  ),
3242
- flow: schemas3.SimulateInputShape.flow,
3243
- platform: schemas3.SimulateInputShape.platform,
3303
+ flow: schemas4.SimulateInputShape.flow,
3304
+ platform: schemas4.SimulateInputShape.platform,
3244
3305
  // Override the (optional) CLI `step` shape: the simulate handler hard-requires
3245
3306
  // a target step (no all-steps mode), so the registered schema must be honest.
3246
- step: z12.string().describe(
3307
+ step: z13.string().describe(
3247
3308
  'Required. Target step as "type.name", e.g. "source.demo", "collector.default", "destination.gtag", "transformer.router". A collector step runs enrichment and then collector.next, returning every event the destinations would receive (none after a stop).'
3248
3309
  ),
3249
- verbose: z12.boolean().optional().describe("Include full payload per destination (default: false)"),
3250
- ingest: z12.record(z12.string(), z12.unknown()).optional().describe(
3310
+ verbose: z13.boolean().optional().describe("Include full payload per destination (default: false)"),
3311
+ ingest: z13.record(z13.string(), z13.unknown()).optional().describe(
3251
3312
  "Pipeline context a step reads via ctx.ingest, e.g. { url } for a request decoder or { ip, userAgent } for a conversion API. Used for transformer, collector and destination steps (their before chains included); _meta is always set by the runtime."
3252
3313
  ),
3253
- state: z12.object({
3254
- consent: z12.record(z12.string(), z12.boolean()).optional(),
3255
- user: z12.record(z12.string(), z12.unknown()).optional(),
3256
- globals: z12.record(z12.string(), z12.unknown()).optional(),
3257
- timing: z12.number().optional()
3314
+ state: z13.object({
3315
+ consent: z13.record(z13.string(), z13.boolean()).optional(),
3316
+ user: z13.record(z13.string(), z13.unknown()).optional(),
3317
+ globals: z13.record(z13.string(), z13.unknown()).optional(),
3318
+ timing: z13.number().optional()
3258
3319
  }).optional().describe(
3259
3320
  "Collector state the step starts from. consent: every step (starts a destination that requires consent and feeds its consent check; for a source, the consent a consent-gated source waits for). user/globals/timing: collector steps, seeded before enrichment runs."
3260
3321
  ),
3261
- command: z12.enum(COMMANDS).optional().describe(
3322
+ command: z13.enum(COMMANDS).optional().describe(
3262
3323
  "Destination steps only: run this collector command with event as its data instead of pushing it, as a step example with command does."
3263
3324
  )
3264
3325
  };
@@ -3282,7 +3343,18 @@ function createFlowSimulateToolSpec(client, runtime) {
3282
3343
  handler: (input) => flowSimulateHandlerBody(client, runtime, input)
3283
3344
  };
3284
3345
  }
3346
+ function toProperties(value) {
3347
+ if (!value) return void 0;
3348
+ const properties = {};
3349
+ for (const [key, entry] of Object.entries(value)) {
3350
+ const property = filterValues(entry);
3351
+ if (property !== void 0) properties[key] = property;
3352
+ }
3353
+ return properties;
3354
+ }
3285
3355
  async function flowSimulateHandlerBody(client, runtime, input) {
3356
+ const parsed = parseToolInput(inputSchema11, input);
3357
+ if (!parsed.ok) return parsed.error;
3286
3358
  const {
3287
3359
  configPath,
3288
3360
  event,
@@ -3293,10 +3365,10 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3293
3365
  ingest,
3294
3366
  state,
3295
3367
  command
3296
- } = input ?? {};
3368
+ } = parsed.data;
3297
3369
  if (!runtime.simulate) {
3298
3370
  const refusal = unavailableOperation("simulate");
3299
- return mcpError13(refusal, refusal.hint);
3371
+ return mcpError15(refusal, refusal.hint);
3300
3372
  }
3301
3373
  let known = [];
3302
3374
  try {
@@ -3337,10 +3409,25 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3337
3409
  throw new Error("command applies to destination steps only.");
3338
3410
  }
3339
3411
  const resolvedConfigPath = await resolveConfigPath(client, configPath);
3340
- known = await knownSecretsOf(runtime, resolvedConfigPath);
3412
+ const run = await readRun(runtime, resolvedConfigPath);
3413
+ known = run.knownSecrets;
3341
3414
  const result = await runtime.simulate(
3342
3415
  resolvedConfigPath,
3343
- { stepType, stepId, event: resolvedEvent, flow, ingest, state, command }
3416
+ {
3417
+ stepType,
3418
+ stepId,
3419
+ event: resolvedEvent,
3420
+ flow,
3421
+ ingest,
3422
+ state: state && {
3423
+ consent: state.consent,
3424
+ user: toProperties(state.user),
3425
+ globals: toProperties(state.globals),
3426
+ timing: state.timing
3427
+ },
3428
+ command,
3429
+ config: run.config
3430
+ }
3344
3431
  );
3345
3432
  const success = !result.error;
3346
3433
  const errorMessage = result.error?.message;
@@ -3351,7 +3438,7 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3351
3438
  ).length;
3352
3439
  const summary = `Source captured ${eventCount} event${eventCount !== 1 ? "s" : ""} and ${commandCount} command${commandCount !== 1 ? "s" : ""}`;
3353
3440
  const shownCalls = verbose ? result.calls : result.calls.filter((call) => call.fn === "elb");
3354
- return mcpResult13(
3441
+ return mcpResult14(
3355
3442
  scrubbed(
3356
3443
  {
3357
3444
  success,
@@ -3373,7 +3460,7 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3373
3460
  );
3374
3461
  }
3375
3462
  if (result.step === "transformer") {
3376
- return mcpResult13(
3463
+ return mcpResult14(
3377
3464
  scrubbed(
3378
3465
  {
3379
3466
  success,
@@ -3390,7 +3477,7 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3390
3477
  );
3391
3478
  }
3392
3479
  if (result.step === "collector") {
3393
- return mcpResult13(
3480
+ return mcpResult14(
3394
3481
  scrubbed(
3395
3482
  {
3396
3483
  success,
@@ -3430,21 +3517,13 @@ async function flowSimulateHandlerBody(client, runtime, input) {
3430
3517
  ...result.skipped ? { skipped: result.skipped } : {},
3431
3518
  duration: result.duration
3432
3519
  };
3433
- return mcpResult13(scrubbed(resultObj, known), {
3520
+ return mcpResult14(scrubbed(resultObj, known), {
3434
3521
  next: ["Use flow_bundle to build for production"],
3435
3522
  ...warnings.length > 0 ? { warnings } : {}
3436
3523
  });
3437
3524
  } catch (error) {
3438
3525
  const hint = "Run flow_validate for detailed error messages";
3439
- return scrubbedError(mcpError13(error, refusalHint(error, hint)), known);
3440
- }
3441
- }
3442
- async function knownSecretsOf(runtime, input) {
3443
- if (!runtime.knownSecrets) return [];
3444
- try {
3445
- return await runtime.knownSecrets(input);
3446
- } catch {
3447
- return [];
3526
+ return scrubbedError(mcpError15(error, refusalHint(error, hint)), known);
3448
3527
  }
3449
3528
  }
3450
3529
  function keysOf(consent) {
@@ -3476,25 +3555,23 @@ function registerFlowSimulateTool(server, client, runtime) {
3476
3555
  outputSchema: SimulateOutputShape,
3477
3556
  annotations: spec.annotations
3478
3557
  },
3479
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
3480
- // type-erased (input: unknown) => Promise<unknown> form by design.
3481
- spec.handler
3558
+ (args) => flowSimulateHandlerBody(client, runtime, args)
3482
3559
  );
3483
3560
  }
3484
3561
 
3485
3562
  // src/tools/push.ts
3486
- import { z as z13 } from "zod";
3487
- import { schemas as schemas4 } from "@walkeros/cli/dev";
3488
- import { mcpResult as mcpResult14, mcpError as mcpError14 } from "@walkeros/core";
3563
+ import { z as z14 } from "zod";
3564
+ import { schemas as schemas5 } from "@walkeros/cli/dev";
3565
+ import { mcpError as mcpError16 } from "@walkeros/core";
3489
3566
  var TITLE14 = "Push Events";
3490
3567
  var DESCRIPTION11 = "Push a real event through a walkerOS flow to actual destinations. Makes real API calls to real endpoints. Best suited for server-side flows \u2014 web flows should use flow_simulate for testing.";
3491
3568
  var inputSchema12 = {
3492
- configPath: schemas4.PushInputShape.configPath,
3493
- event: z13.record(z13.string(), z13.unknown()).describe(
3569
+ configPath: schemas5.PushInputShape.configPath,
3570
+ event: z14.record(z14.string(), z14.unknown()).describe(
3494
3571
  'Event object, e.g. { name: "page view", data: { title: "Home" } }'
3495
3572
  ),
3496
- flow: schemas4.PushInputShape.flow,
3497
- platform: schemas4.PushInputShape.platform
3573
+ flow: schemas5.PushInputShape.flow,
3574
+ platform: schemas5.PushInputShape.platform
3498
3575
  };
3499
3576
  var annotations14 = {
3500
3577
  readOnlyHint: false,
@@ -3513,30 +3590,42 @@ function createFlowPushToolSpec(runtime) {
3513
3590
  };
3514
3591
  }
3515
3592
  async function flowPushHandlerBody(runtime, input) {
3516
- const { configPath, event, flow, platform } = input ?? {};
3593
+ const parsed = parseToolInput(inputSchema12, input);
3594
+ if (!parsed.ok) return parsed.error;
3595
+ const { configPath, event, flow, platform } = parsed.data;
3517
3596
  if (!runtime.push) {
3518
3597
  const refusal = unavailableOperation("push");
3519
- return mcpError14(refusal, refusal.hint);
3598
+ return mcpError16(refusal, refusal.hint);
3520
3599
  }
3600
+ let known = [];
3521
3601
  try {
3602
+ const run = await readRun(runtime, configPath);
3603
+ known = run.knownSecrets;
3522
3604
  const result = await runtime.push(configPath, event, {
3523
3605
  flow,
3524
- platform
3606
+ platform,
3607
+ config: run.config
3525
3608
  });
3526
3609
  if (!result.success) {
3527
- return mcpError14(
3528
- new Error(result.error || "Push failed"),
3529
- "Check destination configuration and connectivity."
3610
+ return scrubbedError(
3611
+ mcpError16(
3612
+ new Error(result.error || "Push failed"),
3613
+ "Check destination configuration and connectivity."
3614
+ ),
3615
+ known
3530
3616
  );
3531
3617
  }
3532
- return mcpResult14(result);
3618
+ return scrubbedPushResult(result, known);
3533
3619
  } catch (error) {
3534
- return mcpError14(
3535
- error,
3536
- refusalHint(
3620
+ return scrubbedError(
3621
+ mcpError16(
3537
3622
  error,
3538
- "Check configPath and event format. For web flows, use flow_simulate."
3539
- )
3623
+ refusalHint(
3624
+ error,
3625
+ "Check configPath and event format. For web flows, use flow_simulate."
3626
+ )
3627
+ ),
3628
+ known
3540
3629
  );
3541
3630
  }
3542
3631
  }
@@ -3552,15 +3641,13 @@ function registerFlowPushTool(server, runtime) {
3552
3641
  outputSchema: PushOutputShape,
3553
3642
  annotations: spec.annotations
3554
3643
  },
3555
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
3556
- // type-erased (input: unknown) => Promise<unknown> form by design.
3557
- spec.handler
3644
+ (args) => flowPushHandlerBody(runtime, args)
3558
3645
  );
3559
3646
  }
3560
3647
 
3561
3648
  // src/tools/examples.ts
3562
- import { z as z14 } from "zod";
3563
- import { fetchPackage, mcpResult as mcpResult15, mcpError as mcpError15 } from "@walkeros/core";
3649
+ import { z as z15 } from "zod";
3650
+ import { fetchPackage, mcpResult as mcpResult15, mcpError as mcpError17 } from "@walkeros/core";
3564
3651
  import { resolveExportName, selectDevExamples } from "@walkeros/cli";
3565
3652
 
3566
3653
  // src/catalog.ts
@@ -3568,7 +3655,7 @@ var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
3568
3655
  var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
3569
3656
  var WALKEROS_JSON_PATH = "dist/walkerOS.json";
3570
3657
  var CACHE_TTL = 5 * 60 * 1e3;
3571
- var CLIENT_HEADER = "walkeros-mcp/4.7.0-next-1790722899482";
3658
+ var CLIENT_HEADER = "walkeros-mcp/4.7.0";
3572
3659
  function getPackageBaseUrl() {
3573
3660
  return process.env.WALKEROS_APP_URL || void 0;
3574
3661
  }
@@ -3725,15 +3812,15 @@ var MAX_PACKAGE_LOOKUPS = 25;
3725
3812
  var TITLE15 = "Flow Examples";
3726
3813
  var DESCRIPTION12 = 'List all step examples in a walkerOS flow configuration. Shows example names, step locations, and in/out shapes. Inline examples on a step take precedence; steps without inline examples fall back to the examples shipped by their referenced package. Each result is tagged with its source ("inline" or "package"). On the hosted server configPath accepts only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. Use this to discover available test fixtures and simulation data.';
3727
3814
  var inputSchema13 = {
3728
- configPath: z14.string().min(1).describe(
3815
+ configPath: z15.string().min(1).describe(
3729
3816
  "Inline JSON string, file path, or URL of a flow configuration (hosted server: inline JSON or a saved flow id only)"
3730
3817
  ),
3731
- flow: z14.string().optional().describe("Flow name for multi-flow configs"),
3732
- step: z14.string().optional().describe('Filter to a specific step (e.g., "destination.gtag")'),
3733
- full: z14.boolean().optional().describe(
3818
+ flow: z15.string().optional().describe("Flow name for multi-flow configs"),
3819
+ step: z15.string().optional().describe('Filter to a specific step (e.g., "destination.gtag")'),
3820
+ full: z15.boolean().optional().describe(
3734
3821
  "Return full in/out/mapping data for each example (default: false, returns metadata only)"
3735
3822
  ),
3736
- includeHidden: z14.boolean().optional().describe(
3823
+ includeHidden: z15.boolean().optional().describe(
3737
3824
  "Include examples marked public: false (default: false). Set true for test/debug discovery."
3738
3825
  )
3739
3826
  };
@@ -3754,9 +3841,14 @@ function createFlowExamplesToolSpec(runtime) {
3754
3841
  };
3755
3842
  }
3756
3843
  async function flowExamplesHandlerBody(runtime, input) {
3757
- const { configPath, flow, step, full, includeHidden } = input ?? {};
3844
+ const parsed = parseToolInput(inputSchema13, input);
3845
+ if (!parsed.ok) return parsed.error;
3846
+ const { configPath, flow, step, full, includeHidden } = parsed.data;
3758
3847
  try {
3759
3848
  const rawConfig = await runtime.load(configPath);
3849
+ if (!isFlowJson(rawConfig)) {
3850
+ throw new Error("Config is not a flow config: it has no flows object.");
3851
+ }
3760
3852
  const flowNames = Object.keys(rawConfig.flows || {});
3761
3853
  const flowName = flow || (flowNames.length === 1 ? flowNames[0] : void 0);
3762
3854
  if (!flowName) {
@@ -3809,6 +3901,7 @@ async function flowExamplesHandlerBody(runtime, input) {
3809
3901
  };
3810
3902
  const packageLookups = /* @__PURE__ */ new Map();
3811
3903
  let skippedPackages = false;
3904
+ const skippedExamples = [];
3812
3905
  const packageFor = (packageName) => {
3813
3906
  const existing = packageLookups.get(packageName);
3814
3907
  if (existing) return existing;
@@ -3825,10 +3918,7 @@ async function flowExamplesHandlerBody(runtime, input) {
3825
3918
  { examples: info.examples, exportExamples: info.exportExamples },
3826
3919
  exportName
3827
3920
  );
3828
- const stepExamples = selected?.step;
3829
- if (stepExamples && typeof stepExamples === "object")
3830
- return stepExamples;
3831
- return void 0;
3921
+ return stepExamplesOf(selected?.step);
3832
3922
  };
3833
3923
  const stepTypes = [
3834
3924
  { key: "sources", type: "source" },
@@ -3840,9 +3930,7 @@ async function flowExamplesHandlerBody(runtime, input) {
3840
3930
  for (const [name, ref] of Object.entries(refs)) {
3841
3931
  if (step && `${type}.${name}` !== step) continue;
3842
3932
  if (ref.examples) {
3843
- examples.push(
3844
- ...toItems(ref.examples, type, name, "inline")
3845
- );
3933
+ examples.push(...toItems(ref.examples, type, name, "inline"));
3846
3934
  continue;
3847
3935
  }
3848
3936
  if (!ref.package) continue;
@@ -3850,8 +3938,12 @@ async function flowExamplesHandlerBody(runtime, input) {
3850
3938
  if (!info) continue;
3851
3939
  const { exportName } = resolveExportName(flowSettings, type, name);
3852
3940
  const packageExamples = stepExamplesFor(info, exportName);
3853
- if (packageExamples)
3854
- examples.push(...toItems(packageExamples, type, name, "package"));
3941
+ if (!packageExamples) continue;
3942
+ examples.push(
3943
+ ...toItems(packageExamples.examples, type, name, "package")
3944
+ );
3945
+ for (const exampleName of packageExamples.skipped)
3946
+ skippedExamples.push(`${type}.${name}.${exampleName}`);
3855
3947
  }
3856
3948
  }
3857
3949
  const result = {
@@ -3865,6 +3957,11 @@ async function flowExamplesHandlerBody(runtime, input) {
3865
3957
  "No examples found. Add examples to step entries, or reference a package that ships examples (see package_get)."
3866
3958
  );
3867
3959
  }
3960
+ if (skippedExamples.length > 0) {
3961
+ warnings.push(
3962
+ `Skipped ${skippedExamples.length} package example(s) that do not match the step example schema: ${skippedExamples.join(", ")}.`
3963
+ );
3964
+ }
3868
3965
  if (skippedPackages) {
3869
3966
  warnings.push(
3870
3967
  `Package examples were looked up for the first ${MAX_PACKAGE_LOOKUPS} packages only. Use step to narrow the result.`
@@ -3878,7 +3975,7 @@ async function flowExamplesHandlerBody(runtime, input) {
3878
3975
  };
3879
3976
  return mcpResult15(result, hints);
3880
3977
  } catch (error) {
3881
- return mcpError15(
3978
+ return mcpError17(
3882
3979
  error,
3883
3980
  refusalHint(error, "Check configPath \u2014 expected a flow.json file")
3884
3981
  );
@@ -3896,15 +3993,13 @@ function registerFlowExamplesTool(server, runtime) {
3896
3993
  outputSchema: ExamplesListOutputShape,
3897
3994
  annotations: spec.annotations
3898
3995
  },
3899
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
3900
- // type-erased (input: unknown) => Promise<unknown> form by design.
3901
- spec.handler
3996
+ (args) => flowExamplesHandlerBody(runtime, args)
3902
3997
  );
3903
3998
  }
3904
3999
 
3905
4000
  // src/tools/flow-load.ts
3906
- import { z as z15 } from "zod";
3907
- import { mcpResult as mcpResult16, mcpError as mcpError16 } from "@walkeros/core";
4001
+ import { z as z16 } from "zod";
4002
+ import { mcpResult as mcpResult16, mcpError as mcpError18 } from "@walkeros/core";
3908
4003
  var WEB_SKELETON = {
3909
4004
  version: 4,
3910
4005
  flows: {
@@ -3928,16 +4023,16 @@ var SERVER_SKELETON = {
3928
4023
  var TITLE16 = "Load or Create Flow";
3929
4024
  var DESCRIPTION13 = "Load an existing flow configuration from a local file path, URL, or walkerOS API (by flow ID). On the hosted server only inline JSON or a saved flow id is accepted, no file paths or URLs. Or create a new empty flow by specifying a platform (web or server). Use the add-step prompt to add sources, destinations, transformers, or stores to the flow.";
3930
4025
  var inputSchema14 = {
3931
- source: z15.string().optional().describe(
4026
+ source: z16.string().optional().describe(
3932
4027
  "Flow source: local file path (./flow.json), URL (https://...), inline JSON string, or API flow ID (cfg_...). Omit to create a new flow."
3933
4028
  ),
3934
- platform: z15.enum(["web", "server"]).optional().describe(
4029
+ platform: z16.enum(["web", "server"]).optional().describe(
3935
4030
  "Platform for new flows. Required when source is omitted. web = browser tracking, server = Node.js HTTP."
3936
4031
  )
3937
4032
  };
3938
4033
  var outputSchema = {
3939
- version: z15.number().describe("Flow config version"),
3940
- flows: z15.record(z15.string(), z15.unknown()).describe("Flow entries")
4034
+ version: z16.number().describe("Flow config version"),
4035
+ flows: z16.record(z16.string(), z16.unknown()).describe("Flow entries")
3941
4036
  };
3942
4037
  var annotations16 = {
3943
4038
  readOnlyHint: true,
@@ -3956,11 +4051,13 @@ function createFlowLoadToolSpec(client, runtime) {
3956
4051
  };
3957
4052
  }
3958
4053
  async function flowLoadHandlerBody(client, runtime, input) {
3959
- const { source, platform } = input ?? {};
4054
+ const parsed = parseToolInput(inputSchema14, input);
4055
+ if (!parsed.ok) return parsed.error;
4056
+ const { source, platform } = parsed.data;
3960
4057
  if (source && isCloudId(source)) {
3961
4058
  const resolvedProjectId = resolveDefaultProject(client, void 0);
3962
4059
  if (!resolvedProjectId) {
3963
- return mcpError16(new Error(NO_DEFAULT_PROJECT_ERROR));
4060
+ return mcpError18(new Error(NO_DEFAULT_PROJECT_ERROR));
3964
4061
  }
3965
4062
  try {
3966
4063
  const flow = await client.getFlow({
@@ -3974,7 +4071,7 @@ async function flowLoadHandlerBody(client, runtime, input) {
3974
4071
  }
3975
4072
  );
3976
4073
  } catch (error) {
3977
- return mcpError16(error, isAuthError(error) ? AUTH_HINT : void 0);
4074
+ return mcpError18(error, isAuthError(error) ? AUTH_HINT : void 0);
3978
4075
  }
3979
4076
  }
3980
4077
  try {
@@ -3985,7 +4082,7 @@ async function flowLoadHandlerBody(client, runtime, input) {
3985
4082
  });
3986
4083
  }
3987
4084
  if (!platform) {
3988
- return mcpError16(
4085
+ return mcpError18(
3989
4086
  new Error(
3990
4087
  "Provide source (file path, URL, or flow ID) to load existing flow, or platform (web/server) to create a new one."
3991
4088
  )
@@ -3999,11 +4096,11 @@ async function flowLoadHandlerBody(client, runtime, input) {
3999
4096
  ]
4000
4097
  });
4001
4098
  } catch (error) {
4002
- if (error instanceof RuntimeRefusal) return mcpError16(error, error.hint);
4099
+ if (error instanceof RuntimeRefusal) return mcpError18(error, error.hint);
4003
4100
  const msg = error instanceof Error ? error.message : "";
4004
4101
  if (msg.includes("not found") || msg.includes("ENOENT"))
4005
- return mcpError16(error, "Check configPath \u2014 expected a flow.json file");
4006
- return mcpError16(error);
4102
+ return mcpError18(error, "Check configPath \u2014 expected a flow.json file");
4103
+ return mcpError18(error);
4007
4104
  }
4008
4105
  }
4009
4106
  function registerFlowLoadTool(server, client, runtime) {
@@ -4018,25 +4115,23 @@ function registerFlowLoadTool(server, client, runtime) {
4018
4115
  outputSchema,
4019
4116
  annotations: spec.annotations
4020
4117
  },
4021
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
4022
- // type-erased (input: unknown) => Promise<unknown> form by design.
4023
- spec.handler
4118
+ (args) => flowLoadHandlerBody(client, runtime, args)
4024
4119
  );
4025
4120
  }
4026
4121
 
4027
4122
  // src/tools/package.ts
4028
- import { z as z16 } from "zod";
4029
- import { fetchPackage as fetchPackage2, mcpResult as mcpResult17, mcpError as mcpError17 } from "@walkeros/core";
4123
+ import { z as z17 } from "zod";
4124
+ import { fetchPackage as fetchPackage2, mcpResult as mcpResult17, mcpError as mcpError19 } from "@walkeros/core";
4030
4125
  import { mergeConfigSchema } from "@walkeros/core/dev";
4031
4126
  var SEARCH_TITLE = "Search Package";
4032
4127
  var SEARCH_DESCRIPTION = "Start here for package discovery. Never guess package names: use this tool first to find exact names. Without package name: returns catalog filtered by type/platform. With package name: returns metadata, hint keys, and example summaries.";
4033
4128
  var searchInputSchema = {
4034
- package: z16.string().min(1).optional().describe(
4129
+ package: z17.string().min(1).optional().describe(
4035
4130
  "Exact npm package name for detailed lookup (e.g., @walkeros/web-destination-snowplow)"
4036
4131
  ),
4037
- type: z16.enum(["source", "destination", "transformer", "store"]).optional().describe("Filter by package type (browse mode)"),
4038
- platform: z16.enum(["web", "server"]).optional().describe("Filter by platform (browse mode, includes universal packages)"),
4039
- version: z16.string().optional().describe("Package version for detailed lookup (default: latest)")
4132
+ type: z17.enum(["source", "destination", "transformer", "store"]).optional().describe("Filter by package type (browse mode)"),
4133
+ platform: z17.enum(["web", "server"]).optional().describe("Filter by platform (browse mode, includes universal packages)"),
4134
+ version: z17.string().optional().describe("Package version for detailed lookup (default: latest)")
4040
4135
  };
4041
4136
  var searchAnnotations = {
4042
4137
  readOnlyHint: true,
@@ -4055,12 +4150,9 @@ function createPackageSearchToolSpec() {
4055
4150
  };
4056
4151
  }
4057
4152
  async function packageSearchHandlerBody(input) {
4058
- const {
4059
- package: packageName,
4060
- type,
4061
- platform,
4062
- version
4063
- } = input ?? {};
4153
+ const parsed = parseToolInput(searchInputSchema, input);
4154
+ if (!parsed.ok) return parsed.error;
4155
+ const { package: packageName, type, platform, version } = parsed.data;
4064
4156
  const baseUrl = getPackageBaseUrl();
4065
4157
  if (!packageName) {
4066
4158
  const { entries, warnings } = await fetchCatalog({
@@ -4093,7 +4185,7 @@ async function packageSearchHandlerBody(input) {
4093
4185
  next: ["Use package_get for schemas and examples"]
4094
4186
  });
4095
4187
  } catch (error) {
4096
- return mcpError17(
4188
+ return mcpError19(
4097
4189
  error,
4098
4190
  "Package not found. Use package_search without parameters to browse available packages."
4099
4191
  );
@@ -4110,19 +4202,17 @@ function registerPackageSearchTool(server) {
4110
4202
  // No outputSchema: browse mode returns {catalog, count}, lookup returns metadata — incompatible shapes
4111
4203
  annotations: spec.annotations
4112
4204
  },
4113
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
4114
- // type-erased (input: unknown) => Promise<unknown> form by design.
4115
- spec.handler
4205
+ (args) => packageSearchHandlerBody(args)
4116
4206
  );
4117
4207
  }
4118
4208
  var GET_TITLE = "Get Package";
4119
4209
  var GET_DESCRIPTION = 'Requires exact package name: do not guess names, use package_search first to find them. Returns schemas + hint texts + example summaries by default (lightweight). Use section parameter for full content: "hints" (with code blocks), "examples" (full in/out data), or "all".';
4120
4210
  var getInputSchema = {
4121
- package: z16.string().min(1).describe(
4211
+ package: z17.string().min(1).describe(
4122
4212
  "Exact npm package name (e.g., @walkeros/web-destination-snowplow)"
4123
4213
  ),
4124
- version: z16.string().optional().describe("Package version (default: latest)"),
4125
- section: z16.enum(["hints", "examples", "all"]).optional().describe(
4214
+ version: z17.string().optional().describe("Package version (default: latest)"),
4215
+ section: z17.enum(["hints", "examples", "all"]).optional().describe(
4126
4216
  "Section to expand with full content. Default: summary view with schemas + hint texts + example descriptions"
4127
4217
  )
4128
4218
  };
@@ -4142,12 +4232,35 @@ function createPackageGetToolSpec() {
4142
4232
  handler: (input) => packageGetHandlerBody(input)
4143
4233
  };
4144
4234
  }
4235
+ var STEP_PACKAGE_TYPES = [
4236
+ "source",
4237
+ "destination",
4238
+ "transformer",
4239
+ "store"
4240
+ ];
4241
+ function isStepPackageType(type) {
4242
+ return STEP_PACKAGE_TYPES.some((stepType) => stepType === type);
4243
+ }
4244
+ function shapeSchemas(type, schemas9) {
4245
+ const shaped = {};
4246
+ if (isStepPackageType(type)) {
4247
+ const settings = recordField(schemas9, "settings");
4248
+ const credentials = recordField(schemas9, "credentials");
4249
+ shaped.config = mergeConfigSchema(type, {
4250
+ ...schemas9,
4251
+ settings,
4252
+ credentials
4253
+ });
4254
+ }
4255
+ for (const [key, value] of Object.entries(schemas9)) {
4256
+ if (key !== "settings") shaped[key] = value;
4257
+ }
4258
+ return shaped;
4259
+ }
4145
4260
  async function packageGetHandlerBody(input) {
4146
- const {
4147
- package: packageName,
4148
- version,
4149
- section
4150
- } = input ?? {};
4261
+ const parsed = parseToolInput(getInputSchema, input);
4262
+ if (!parsed.ok) return parsed.error;
4263
+ const { package: packageName, version, section } = parsed.data;
4151
4264
  const baseUrl = getPackageBaseUrl();
4152
4265
  try {
4153
4266
  const info = await fetchPackage2(packageName, {
@@ -4155,33 +4268,29 @@ async function packageGetHandlerBody(input) {
4155
4268
  baseUrl,
4156
4269
  client: CLIENT_HEADER
4157
4270
  });
4158
- const mergedSchemas = {};
4159
- if (info.type) {
4160
- mergedSchemas.config = mergeConfigSchema(
4161
- info.type,
4162
- info.schemas
4163
- );
4164
- }
4165
- for (const [key, value] of Object.entries(info.schemas)) {
4166
- if (key !== "settings") {
4167
- mergedSchemas[key] = value;
4168
- }
4169
- }
4170
4271
  const result = {
4171
4272
  package: info.packageName,
4172
4273
  version: info.version,
4173
4274
  type: info.type,
4174
4275
  platform: normalizePlatform(info.platform),
4175
- schemas: mergedSchemas
4276
+ schemas: shapeSchemas(info.type, info.schemas)
4176
4277
  };
4278
+ if (info.exportSchemas) {
4279
+ result.exportSchemas = Object.fromEntries(
4280
+ Object.entries(info.exportSchemas).map(([name, schemas9]) => [
4281
+ name,
4282
+ shapeSchemas(info.type, schemas9)
4283
+ ])
4284
+ );
4285
+ }
4177
4286
  if (info.hints) {
4178
4287
  if (section === "hints" || section === "all") {
4179
4288
  result.hints = info.hints;
4180
4289
  } else {
4181
4290
  const hintSummary = {};
4182
4291
  for (const [key, hint] of Object.entries(info.hints)) {
4183
- const h = hint;
4184
- hintSummary[key] = { text: h.text };
4292
+ const text = stringField(hint, "text");
4293
+ if (text !== void 0) hintSummary[key] = { text };
4185
4294
  }
4186
4295
  result.hints = hintSummary;
4187
4296
  }
@@ -4194,7 +4303,7 @@ async function packageGetHandlerBody(input) {
4194
4303
  }
4195
4304
  return mcpResult17(result);
4196
4305
  } catch (error) {
4197
- return mcpError17(
4306
+ return mcpError19(
4198
4307
  error,
4199
4308
  "Use package_search to browse available package names."
4200
4309
  );
@@ -4211,9 +4320,7 @@ function registerGetPackageSchemaTool(server) {
4211
4320
  // No outputSchema: removed to avoid SDK -32602 crashes on unexpected field values
4212
4321
  annotations: spec.annotations
4213
4322
  },
4214
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
4215
- // type-erased (input: unknown) => Promise<unknown> form by design.
4216
- spec.handler
4323
+ (args) => packageGetHandlerBody(args)
4217
4324
  );
4218
4325
  }
4219
4326
 
@@ -23926,9 +24033,7 @@ function registerDiagnosticsTool(server, client, packageVersion) {
23926
24033
  inputSchema: spec.inputSchema,
23927
24034
  annotations: spec.annotations
23928
24035
  },
23929
- // SDK infers handler type from inputSchema shape; ToolSpec.handler is the
23930
- // type-erased (input: unknown) => Promise<unknown> form by design.
23931
- spec.handler
24036
+ () => diagnosticsHandlerBody(client, packageVersion)
23932
24037
  );
23933
24038
  }
23934
24039
 
@@ -23978,7 +24083,7 @@ function registerPackageSchemaResources(server) {
23978
24083
  }
23979
24084
 
23980
24085
  // src/resources/references.ts
23981
- import { schemas as schemas5 } from "@walkeros/core/dev";
24086
+ import { schemas as schemas6 } from "@walkeros/core/dev";
23982
24087
  function registerReferenceResources(server) {
23983
24088
  server.resource(
23984
24089
  "flow-schema",
@@ -23991,7 +24096,7 @@ function registerReferenceResources(server) {
23991
24096
  contents: [
23992
24097
  {
23993
24098
  uri: "walkeros://reference/flow-schema",
23994
- text: JSON.stringify(schemas5.configJsonSchema, null, 2),
24099
+ text: JSON.stringify(schemas6.configJsonSchema, null, 2),
23995
24100
  mimeType: "application/json"
23996
24101
  }
23997
24102
  ]
@@ -24008,7 +24113,7 @@ function registerReferenceResources(server) {
24008
24113
  contents: [
24009
24114
  {
24010
24115
  uri: "walkeros://reference/event-model",
24011
- text: JSON.stringify(schemas5.eventJsonSchema, null, 2),
24116
+ text: JSON.stringify(schemas6.eventJsonSchema, null, 2),
24012
24117
  mimeType: "application/json"
24013
24118
  }
24014
24119
  ]
@@ -24027,10 +24132,10 @@ function registerReferenceResources(server) {
24027
24132
  uri: "walkeros://reference/mapping",
24028
24133
  text: JSON.stringify(
24029
24134
  {
24030
- rules: schemas5.rulesJsonSchema,
24031
- valueConfig: schemas5.valueConfigJsonSchema,
24032
- rule: schemas5.ruleJsonSchema,
24033
- policy: schemas5.policyJsonSchema
24135
+ rules: schemas6.rulesJsonSchema,
24136
+ valueConfig: schemas6.valueConfigJsonSchema,
24137
+ rule: schemas6.ruleJsonSchema,
24138
+ policy: schemas6.policyJsonSchema
24034
24139
  },
24035
24140
  null,
24036
24141
  2
@@ -24051,7 +24156,7 @@ function registerReferenceResources(server) {
24051
24156
  contents: [
24052
24157
  {
24053
24158
  uri: "walkeros://reference/consent",
24054
- text: JSON.stringify(schemas5.consentJsonSchema, null, 2),
24159
+ text: JSON.stringify(schemas6.consentJsonSchema, null, 2),
24055
24160
  mimeType: "application/json"
24056
24161
  }
24057
24162
  ]
@@ -24127,7 +24232,7 @@ function registerReferenceResources(server) {
24127
24232
  contents: [
24128
24233
  {
24129
24234
  uri: "walkeros://reference/contract",
24130
- text: JSON.stringify(schemas5.contractJsonSchema, null, 2),
24235
+ text: JSON.stringify(schemas6.contractJsonSchema, null, 2),
24131
24236
  mimeType: "application/json"
24132
24237
  }
24133
24238
  ]
@@ -24205,17 +24310,17 @@ function registerReferenceResources(server) {
24205
24310
  }
24206
24311
 
24207
24312
  // src/prompts/add-step.ts
24208
- import { z as z17 } from "zod";
24313
+ import { z as z18 } from "zod";
24209
24314
  function registerAddStepPrompt(server) {
24210
24315
  server.registerPrompt(
24211
24316
  "add-step",
24212
24317
  {
24213
24318
  description: "Add a source, destination, transformer, or store step to a flow configuration. Guides through package selection, config scaffolding, and wiring.",
24214
24319
  argsSchema: {
24215
- stepType: z17.string().optional().describe(
24320
+ stepType: z18.string().optional().describe(
24216
24321
  "Type of step to add: source, destination, transformer, or store"
24217
24322
  ),
24218
- flowPath: z17.string().optional().describe("Path to the flow.json file to modify")
24323
+ flowPath: z18.string().optional().describe("Path to the flow.json file to modify")
24219
24324
  }
24220
24325
  },
24221
24326
  async ({ stepType, flowPath }) => ({
@@ -24261,14 +24366,14 @@ function registerAddStepPrompt(server) {
24261
24366
  }
24262
24367
 
24263
24368
  // src/prompts/setup-mapping.ts
24264
- import { z as z18 } from "zod";
24369
+ import { z as z19 } from "zod";
24265
24370
  function registerSetupMappingPrompt(server) {
24266
24371
  server.registerPrompt(
24267
24372
  "setup-mapping",
24268
24373
  {
24269
24374
  description: "Set up event mapping for any step in a flow. Teaches mapping syntax and uses package examples as templates.",
24270
24375
  argsSchema: {
24271
- stepName: z18.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
24376
+ stepName: z19.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
24272
24377
  }
24273
24378
  },
24274
24379
  async ({ stepName }) => ({
@@ -24306,14 +24411,14 @@ function registerSetupMappingPrompt(server) {
24306
24411
  }
24307
24412
 
24308
24413
  // src/prompts/manage-contract.ts
24309
- import { z as z19 } from "zod";
24414
+ import { z as z20 } from "zod";
24310
24415
  function registerManageContractPrompt(server) {
24311
24416
  server.registerPrompt(
24312
24417
  "manage-contract",
24313
24418
  {
24314
24419
  description: "Create or update event contracts for a flow. Can generate contracts from existing mappings or scaffold mappings from contracts.",
24315
24420
  argsSchema: {
24316
- direction: z19.string().optional().describe(
24421
+ direction: z20.string().optional().describe(
24317
24422
  'Direction: "from-mappings" (extract contract from existing mappings), "from-scratch" (create new contract), or "to-mappings" (scaffold mappings from contract)'
24318
24423
  )
24319
24424
  }
@@ -24357,7 +24462,7 @@ var SERVER_INSTRUCTIONS = `walkerOS is an open-source, privacy-first event data
24357
24462
 
24358
24463
  - **Never guess package names.** Always use \`package_search\` first to find exact names, then \`package_get\` for details.
24359
24464
  - **Never construct flow configs from memory.** Read \`walkeros://reference/flow-schema\` and use \`package_get\` for package-specific schemas.
24360
- - **Always validate.** Run \`flow_validate\` after every config change. If validation fails, fix and re-validate.
24465
+ - **Always validate.** Run \`flow_validate\` after every config change. If validation fails, fix and re-validate. By default it checks every flow and step, package settings included; a valid result can still list \`details.skipped\` checks, so read them before trusting it (\`strict: true\` turns warnings and skips into failures: \`valid\` is false).
24361
24466
  - **Simulate before deploying.** Use \`flow_simulate\` to test with mocked API calls before \`flow_bundle\` or \`flow_push\`.
24362
24467
  - **When a request fails,** call \`diagnostics\` to see which MCP/CLI versions, app URL, and backend you are on, plus whether the app is reachable.
24363
24468
 
@@ -24815,8 +24920,11 @@ function createStreamableHttpHandler(server, opts = {}) {
24815
24920
  }
24816
24921
 
24817
24922
  // src/runtime/local.ts
24923
+ import * as fs from "fs";
24924
+ import * as path2 from "path";
24818
24925
  import {
24819
24926
  collectKnownSecrets,
24927
+ loadConfig,
24820
24928
  loadJsonConfig,
24821
24929
  bundle as bundle2,
24822
24930
  push,
@@ -24825,6 +24933,8 @@ import {
24825
24933
  simulateCollector,
24826
24934
  simulateDestination
24827
24935
  } from "@walkeros/cli";
24936
+ import { isObject as isObject3 } from "@walkeros/core";
24937
+ import { schemas as schemas7 } from "@walkeros/core/dev";
24828
24938
 
24829
24939
  // src/runtime/bundle-cache.ts
24830
24940
  import { createHash } from "crypto";
@@ -24915,6 +25025,10 @@ async function getOrBuildBundle(resolvedConfig) {
24915
25025
  function createLocalRuntime() {
24916
25026
  return {
24917
25027
  load: (input) => loadJsonConfig(input),
25028
+ baseDir(input) {
25029
+ const file = path2.resolve(input);
25030
+ return fs.existsSync(file) && fs.statSync(file).isFile() ? path2.dirname(file) : void 0;
25031
+ },
24918
25032
  bundle: (input, opts) => bundle2(input, {
24919
25033
  flowName: opts.flowName,
24920
25034
  stats: opts.stats,
@@ -24928,69 +25042,84 @@ function createLocalRuntime() {
24928
25042
  bundlePath = void 0;
24929
25043
  }
24930
25044
  const common = { bundlePath, flow: opts.flow, silent: true };
25045
+ const config = opts.config ?? input;
24931
25046
  switch (opts.stepType) {
24932
25047
  case "source":
24933
- return simulateSource(input, opts.event, {
25048
+ return simulateSource(config, opts.event, {
24934
25049
  sourceId: opts.stepId,
24935
25050
  ...common,
24936
25051
  consent: opts.state?.consent
24937
25052
  });
24938
25053
  case "transformer":
24939
- return simulateTransformer(
24940
- input,
24941
- opts.event,
24942
- {
24943
- transformerId: opts.stepId,
24944
- ...common,
24945
- ingest: opts.ingest,
24946
- consent: opts.state?.consent
24947
- }
24948
- );
25054
+ return simulateTransformer(config, partialEvent(opts.event), {
25055
+ transformerId: opts.stepId,
25056
+ ...common,
25057
+ ingest: opts.ingest,
25058
+ consent: opts.state?.consent
25059
+ });
24949
25060
  case "collector":
24950
- return simulateCollector(
24951
- input,
24952
- opts.event,
24953
- {
24954
- collectorName: opts.stepId,
24955
- ...common,
24956
- state: opts.state,
24957
- ingest: opts.ingest
24958
- }
24959
- );
25061
+ return simulateCollector(config, partialEvent(opts.event), {
25062
+ collectorName: opts.stepId,
25063
+ ...common,
25064
+ state: opts.state,
25065
+ ingest: opts.ingest
25066
+ });
24960
25067
  case "destination":
24961
- return simulateDestination(
24962
- input,
24963
- opts.event,
24964
- {
24965
- destinationId: opts.stepId,
24966
- ...common,
24967
- ingest: opts.ingest,
24968
- consent: opts.state?.consent,
24969
- command: opts.command
24970
- }
24971
- );
25068
+ return simulateDestination(config, eventObject(opts.event), {
25069
+ destinationId: opts.stepId,
25070
+ ...common,
25071
+ ingest: opts.ingest,
25072
+ consent: opts.state?.consent,
25073
+ command: opts.command
25074
+ });
24972
25075
  }
24973
25076
  },
24974
25077
  knownSecrets: async (input) => collectKnownSecrets(await loadJsonConfig(input)),
25078
+ async loadRun(input) {
25079
+ const content = await loadConfig(input, { json: false });
25080
+ const config = typeof content === "string" ? parseJson(content) : void 0;
25081
+ if (!isFlowJson(config)) return { knownSecrets: [] };
25082
+ return { config, knownSecrets: collectKnownSecrets(config) };
25083
+ },
24975
25084
  push: (input, event, opts) => push(input, event, {
24976
25085
  json: true,
24977
25086
  flow: opts.flow,
24978
- platform: opts.platform
25087
+ platform: opts.platform,
25088
+ ...opts.config !== void 0 && { raw: opts.config }
24979
25089
  })
24980
25090
  };
24981
25091
  }
25092
+ function partialEvent(value) {
25093
+ if (isPartialEvent(value)) return value;
25094
+ const parsed = schemas7.PartialEventSchema.safeParse(value);
25095
+ throw new Error(parsed.error?.message ?? "Invalid event");
25096
+ }
25097
+ function isPartialEvent(value) {
25098
+ return schemas7.PartialEventSchema.safeParse(value).success;
25099
+ }
25100
+ function eventObject(value) {
25101
+ if (isObject3(value)) return value;
25102
+ throw new Error("event must be an object.");
25103
+ }
25104
+ function parseJson(content) {
25105
+ try {
25106
+ return JSON.parse(content);
25107
+ } catch {
25108
+ return void 0;
25109
+ }
25110
+ }
24982
25111
 
24983
25112
  // src/tool-definitions.ts
24984
- import { z as z20 } from "zod";
24985
- import { schemas as schemas6 } from "@walkeros/cli/dev";
25113
+ import { z as z21 } from "zod";
25114
+ import { schemas as schemas8 } from "@walkeros/cli/dev";
24986
25115
  var TOOL_DEFINITIONS = [
24987
25116
  {
24988
25117
  name: "auth",
24989
25118
  title: "Authentication",
24990
25119
  description: "Manage walkerOS authentication. Check login status, log in via device code flow, or log out. No terminal or browser required, the MCP client handles the authorization URL.",
24991
25120
  inputSchema: {
24992
- action: z20.enum(["status", "login", "logout"]),
24993
- deviceCode: z20.string().optional()
25121
+ action: z21.enum(["status", "login", "logout"]),
25122
+ deviceCode: z21.string().optional()
24994
25123
  },
24995
25124
  annotations: {
24996
25125
  readOnlyHint: false,
@@ -25004,7 +25133,7 @@ var TOOL_DEFINITIONS = [
25004
25133
  title: "Project Management",
25005
25134
  description: "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.",
25006
25135
  inputSchema: {
25007
- action: z20.enum([
25136
+ action: z21.enum([
25008
25137
  "list",
25009
25138
  "get",
25010
25139
  "create",
@@ -25012,8 +25141,8 @@ var TOOL_DEFINITIONS = [
25012
25141
  "delete",
25013
25142
  "set_default"
25014
25143
  ]),
25015
- projectId: z20.string().optional(),
25016
- name: z20.string().optional()
25144
+ projectId: z21.string().optional(),
25145
+ name: z21.string().optional()
25017
25146
  },
25018
25147
  annotations: {
25019
25148
  readOnlyHint: false,
@@ -25027,7 +25156,7 @@ var TOOL_DEFINITIONS = [
25027
25156
  title: "Flow Management",
25028
25157
  description: "Manage walkerOS flows and their previews. List/get/create/update/delete/duplicate flows, or create/inspect/delete preview bundles for testing flow changes on live sites.",
25029
25158
  inputSchema: {
25030
- action: z20.enum([
25159
+ action: z21.enum([
25031
25160
  "list",
25032
25161
  "get",
25033
25162
  "create",
@@ -25039,19 +25168,19 @@ var TOOL_DEFINITIONS = [
25039
25168
  "preview_create",
25040
25169
  "preview_delete"
25041
25170
  ]),
25042
- flowId: z20.string().optional(),
25043
- projectId: z20.string().optional(),
25044
- name: z20.string().optional(),
25045
- content: z20.record(z20.string(), z20.unknown()).optional(),
25046
- patch: z20.boolean().optional(),
25047
- fields: z20.array(z20.string()).optional(),
25048
- sort: z20.enum(["name", "updated_at", "created_at"]).optional(),
25049
- order: z20.enum(["asc", "desc"]).optional(),
25050
- includeDeleted: z20.boolean().optional(),
25051
- previewId: z20.string().optional(),
25052
- flowName: z20.string().optional(),
25053
- flowSettingsId: z20.string().optional(),
25054
- siteUrl: z20.string().optional()
25171
+ flowId: z21.string().optional(),
25172
+ projectId: z21.string().optional(),
25173
+ name: z21.string().optional(),
25174
+ content: z21.record(z21.string(), z21.unknown()).optional(),
25175
+ patch: z21.boolean().optional(),
25176
+ fields: z21.array(z21.string()).optional(),
25177
+ sort: z21.enum(["name", "updated_at", "created_at"]).optional(),
25178
+ order: z21.enum(["asc", "desc"]).optional(),
25179
+ includeDeleted: z21.boolean().optional(),
25180
+ previewId: z21.string().optional(),
25181
+ flowName: z21.string().optional(),
25182
+ flowSettingsId: z21.string().optional(),
25183
+ siteUrl: z21.string().optional()
25055
25184
  },
25056
25185
  annotations: {
25057
25186
  readOnlyHint: false,
@@ -25065,14 +25194,14 @@ var TOOL_DEFINITIONS = [
25065
25194
  title: "Deploy Management",
25066
25195
  description: "Deploy walkerOS flows and manage deployments. For get/delete actions pass flowId (required) plus optional slug to disambiguate when a flow has multiple active deployments. If a flow has >=2 active deployments and no slug is supplied, the tool returns a MULTIPLE_DEPLOYMENTS error with a details[] list showing each deployment's slug, type, status, and updatedAt.",
25067
25196
  inputSchema: {
25068
- action: z20.enum(["deploy", "list", "get", "delete"]),
25069
- projectId: z20.string().optional(),
25070
- flowId: z20.string().optional(),
25071
- slug: z20.string().optional(),
25072
- type: z20.enum(["web", "server"]).optional(),
25073
- status: z20.string().optional(),
25074
- wait: z20.boolean().optional(),
25075
- flowName: z20.string().optional()
25197
+ action: z21.enum(["deploy", "list", "get", "delete"]),
25198
+ projectId: z21.string().optional(),
25199
+ flowId: z21.string().optional(),
25200
+ slug: z21.string().optional(),
25201
+ type: z21.enum(["web", "server"]).optional(),
25202
+ status: z21.string().optional(),
25203
+ wait: z21.boolean().optional(),
25204
+ flowName: z21.string().optional()
25076
25205
  },
25077
25206
  annotations: {
25078
25207
  readOnlyHint: false,
@@ -25086,12 +25215,12 @@ var TOOL_DEFINITIONS = [
25086
25215
  title: "Secret Management",
25087
25216
  description: "Manage a flow\u2019s managed secrets (the $secret.<NAME> values its steps reference at deploy/run time). Actions: list (metadata only), set (create), update (rotate value), delete. Secrets are write-mostly: values are encrypted at rest and are NEVER returned, listed, or echoed. Reference a secret from a flow step as $secret.<NAME> (credentials, tokens, and private keys use $secret, not $env).",
25088
25217
  inputSchema: {
25089
- action: z20.enum(["list", "set", "update", "delete"]),
25090
- projectId: z20.string().optional(),
25091
- flowId: z20.string(),
25092
- name: z20.string().optional(),
25093
- value: z20.string().optional(),
25094
- secretId: z20.string().optional()
25218
+ action: z21.enum(["list", "set", "update", "delete"]),
25219
+ projectId: z21.string().optional(),
25220
+ flowId: z21.string(),
25221
+ name: z21.string().optional(),
25222
+ value: z21.string().optional(),
25223
+ secretId: z21.string().optional()
25095
25224
  },
25096
25225
  annotations: {
25097
25226
  readOnlyHint: false,
@@ -25105,17 +25234,17 @@ var TOOL_DEFINITIONS = [
25105
25234
  title: "Observe Session",
25106
25235
  description: "Open, inspect, or end an Observe session: a time-boxed window on one flow that runtimes attach to as arms. A preview arm streams from a browser, a container arm runs server-side, and both feed ONE shared journeys feed. start opens the window (arms picks which runtimes attach), status reports per-arm state plus recordsReceived and expiresAt, stop ends the whole session including every arm. A flow has at most one session, so status/stop resolve it from flowId when sessionId is omitted. Read the events with observe_journeys; this tool never returns event data and never judges whether events are correct.",
25107
25236
  inputSchema: {
25108
- action: z20.enum(["start", "status", "stop"]),
25109
- flowId: z20.string(),
25110
- projectId: z20.string().optional(),
25111
- sessionId: z20.string().optional(),
25112
- arms: z20.object({
25113
- container: z20.literal(true).optional(),
25114
- preview: z20.string().optional()
25237
+ action: z21.enum(["start", "status", "stop"]),
25238
+ flowId: z21.string(),
25239
+ projectId: z21.string().optional(),
25240
+ sessionId: z21.string().optional(),
25241
+ arms: z21.object({
25242
+ container: z21.literal(true).optional(),
25243
+ preview: z21.string().optional()
25115
25244
  }).optional(),
25116
- origins: z20.array(z20.string()).optional(),
25117
- level: z20.enum(["off", "standard", "trace"]).optional(),
25118
- replace: z20.boolean().optional()
25245
+ origins: z21.array(z21.string()).optional(),
25246
+ level: z21.enum(["off", "standard", "trace"]).optional(),
25247
+ replace: z21.boolean().optional()
25119
25248
  },
25120
25249
  annotations: {
25121
25250
  readOnlyHint: false,
@@ -25129,10 +25258,10 @@ var TOOL_DEFINITIONS = [
25129
25258
  title: "Observe Journeys",
25130
25259
  description: "Read the assembled, cross-runtime journeys for a flow that is currently being observed (an active Observe session). Pass flowId; the active session is resolved for you (a flow has at most one). Each journey is one traced event reconstructed end to end across web and server: its ordered hops, per-hop status, captured in/out payloads, consent, and vendor calls. When the flow has no active session the result is { sessionId: null, journeys: [], gaps: [] }. Narrow with traceId (one trace) and limit (1-100, most recent kept; default 50). Read-only.",
25131
25260
  inputSchema: {
25132
- flowId: z20.string(),
25133
- projectId: z20.string().optional(),
25134
- traceId: z20.string().optional(),
25135
- limit: z20.number().int().min(1).max(100).optional()
25261
+ flowId: z21.string(),
25262
+ projectId: z21.string().optional(),
25263
+ traceId: z21.string().optional(),
25264
+ limit: z21.number().int().min(1).max(100).optional()
25136
25265
  },
25137
25266
  annotations: {
25138
25267
  readOnlyHint: true,
@@ -25144,13 +25273,13 @@ var TOOL_DEFINITIONS = [
25144
25273
  {
25145
25274
  name: "flow_validate",
25146
25275
  title: "Validate Flow",
25147
- description: "Validate walkerOS events, flow configurations, mapping rules, or data contracts. Accepts JSON strings, file paths, or URLs as input; on the hosted server only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. Returns validation results with errors, warnings, and details.",
25148
- inputSchema: schemas6.ValidateInputShape,
25276
+ description: "Validate walkerOS events, flow configurations, mapping rules, or data contracts. Accepts JSON strings, file paths, or URLs as input; on the hosted server only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. With only type and input, a flow runs every check on every flow and step, including each package's settings schema (fetched from the package CDN; offline: true skips that and says so). flow and path narrow the run; strict turns warnings and skips into failures: valid is false. Returns valid, errors and warnings with stable codes, and details.scope (what was checked), details.skipped (checks that could not run) and details.deferred (values known only at runtime).",
25277
+ inputSchema: schemas8.ValidateInputShape,
25149
25278
  annotations: {
25150
25279
  readOnlyHint: true,
25151
25280
  destructiveHint: false,
25152
25281
  idempotentHint: true,
25153
- openWorldHint: false
25282
+ openWorldHint: true
25154
25283
  }
25155
25284
  },
25156
25285
  {
@@ -25158,9 +25287,9 @@ var TOOL_DEFINITIONS = [
25158
25287
  title: "Bundle Flow",
25159
25288
  description: "Bundle a walkerOS flow configuration into deployable JavaScript. Resolves all destinations, sources, and transformers, then outputs a tree-shaken production bundle. Returns bundle statistics. Set remote: true to use the walkerOS cloud service instead of local build tools.",
25160
25289
  inputSchema: {
25161
- ...schemas6.BundleInputShape,
25162
- remote: z20.boolean().optional(),
25163
- content: z20.record(z20.string(), z20.unknown()).optional()
25290
+ ...schemas8.BundleInputShape,
25291
+ remote: z21.boolean().optional(),
25292
+ content: z21.record(z21.string(), z21.unknown()).optional()
25164
25293
  },
25165
25294
  annotations: {
25166
25295
  readOnlyHint: false,
@@ -25174,12 +25303,12 @@ var TOOL_DEFINITIONS = [
25174
25303
  title: "Simulate Flow",
25175
25304
  description: FLOW_SIMULATE_DESCRIPTION,
25176
25305
  inputSchema: {
25177
- configPath: schemas6.SimulateInputShape.configPath,
25178
- event: z20.union([z20.record(z20.string(), z20.unknown()), z20.string()]).optional(),
25179
- flow: schemas6.SimulateInputShape.flow,
25180
- platform: schemas6.SimulateInputShape.platform,
25181
- step: schemas6.SimulateInputShape.step,
25182
- verbose: z20.boolean().optional()
25306
+ configPath: schemas8.SimulateInputShape.configPath,
25307
+ event: z21.union([z21.record(z21.string(), z21.unknown()), z21.string()]).optional(),
25308
+ flow: schemas8.SimulateInputShape.flow,
25309
+ platform: schemas8.SimulateInputShape.platform,
25310
+ step: schemas8.SimulateInputShape.step,
25311
+ verbose: z21.boolean().optional()
25183
25312
  },
25184
25313
  annotations: {
25185
25314
  // Not read-only: simulation compiles and runs the flow in process.
@@ -25194,10 +25323,10 @@ var TOOL_DEFINITIONS = [
25194
25323
  title: "Push Events",
25195
25324
  description: "Push a real event through a walkerOS flow to actual destinations. Makes real API calls to real endpoints. Best suited for server-side flows, web flows should use flow_simulate for testing.",
25196
25325
  inputSchema: {
25197
- configPath: schemas6.PushInputShape.configPath,
25198
- event: z20.record(z20.string(), z20.unknown()),
25199
- flow: schemas6.PushInputShape.flow,
25200
- platform: schemas6.PushInputShape.platform
25326
+ configPath: schemas8.PushInputShape.configPath,
25327
+ event: z21.record(z21.string(), z21.unknown()),
25328
+ flow: schemas8.PushInputShape.flow,
25329
+ platform: schemas8.PushInputShape.platform
25201
25330
  },
25202
25331
  annotations: {
25203
25332
  readOnlyHint: false,
@@ -25211,11 +25340,11 @@ var TOOL_DEFINITIONS = [
25211
25340
  title: "Flow Examples",
25212
25341
  description: "List all step examples in a walkerOS flow configuration. Shows example names, step locations, and in/out shapes. On the hosted server configPath accepts only inline JSON or a saved flow id (flow_ or cfg_), no file paths or URLs. Use this to discover available test fixtures and simulation data.",
25213
25342
  inputSchema: {
25214
- configPath: z20.string().min(1),
25215
- flow: z20.string().optional(),
25216
- step: z20.string().optional(),
25217
- full: z20.boolean().optional(),
25218
- includeHidden: z20.boolean().optional()
25343
+ configPath: z21.string().min(1),
25344
+ flow: z21.string().optional(),
25345
+ step: z21.string().optional(),
25346
+ full: z21.boolean().optional(),
25347
+ includeHidden: z21.boolean().optional()
25219
25348
  },
25220
25349
  annotations: {
25221
25350
  readOnlyHint: true,
@@ -25229,8 +25358,8 @@ var TOOL_DEFINITIONS = [
25229
25358
  title: "Load or Create Flow",
25230
25359
  description: "Load an existing flow configuration from a local file path, URL, or walkerOS API (by flow ID). On the hosted server only inline JSON or a saved flow id is accepted, no file paths or URLs. Or create a new empty flow by specifying a platform (web or server). Use the add-step prompt to add sources, destinations, transformers, or stores to the flow.",
25231
25360
  inputSchema: {
25232
- source: z20.string().optional(),
25233
- platform: z20.enum(["web", "server"]).optional()
25361
+ source: z21.string().optional(),
25362
+ platform: z21.enum(["web", "server"]).optional()
25234
25363
  },
25235
25364
  annotations: {
25236
25365
  readOnlyHint: true,
@@ -25244,10 +25373,10 @@ var TOOL_DEFINITIONS = [
25244
25373
  title: "Search Package",
25245
25374
  description: "Start here for package discovery. Never guess package names, use this tool first to find exact names. Without package name: returns catalog filtered by type/platform. With package name: returns metadata, hint keys, and example summaries.",
25246
25375
  inputSchema: {
25247
- package: z20.string().min(1).optional(),
25248
- type: z20.enum(["source", "destination", "transformer", "store"]).optional(),
25249
- platform: z20.enum(["web", "server"]).optional(),
25250
- version: z20.string().optional()
25376
+ package: z21.string().min(1).optional(),
25377
+ type: z21.enum(["source", "destination", "transformer", "store"]).optional(),
25378
+ platform: z21.enum(["web", "server"]).optional(),
25379
+ version: z21.string().optional()
25251
25380
  },
25252
25381
  annotations: {
25253
25382
  readOnlyHint: true,
@@ -25261,9 +25390,9 @@ var TOOL_DEFINITIONS = [
25261
25390
  title: "Get Package",
25262
25391
  description: 'Requires exact package name, do not guess names, use package_search first to find them. Returns schemas + hint texts + example summaries by default (lightweight). Use section parameter for full content: "hints" (with code blocks), "examples" (full in/out data), or "all".',
25263
25392
  inputSchema: {
25264
- package: z20.string().min(1),
25265
- version: z20.string().optional(),
25266
- section: z20.enum(["hints", "examples", "all"]).optional()
25393
+ package: z21.string().min(1),
25394
+ version: z21.string().optional(),
25395
+ section: z21.enum(["hints", "examples", "all"]).optional()
25267
25396
  },
25268
25397
  annotations: {
25269
25398
  readOnlyHint: true,
@@ -25277,8 +25406,8 @@ var TOOL_DEFINITIONS = [
25277
25406
  title: "Send Feedback",
25278
25407
  description: "Send feedback about walkerOS",
25279
25408
  inputSchema: {
25280
- text: z20.string(),
25281
- anonymous: z20.boolean().optional()
25409
+ text: z21.string(),
25410
+ anonymous: z21.boolean().optional()
25282
25411
  },
25283
25412
  annotations: {
25284
25413
  readOnlyHint: false,