@walkeros/mcp 4.7.0-next-1790245733116 → 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.d.ts +42 -3
- package/dist/index.js +940 -674
- package/dist/index.js.map +1 -1
- package/dist/stdio.js +809 -545
- package/dist/stdio.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var RuntimeRefusal = class extends Error {
|
|
|
20
20
|
function refusalHint(error, fallback) {
|
|
21
21
|
return error instanceof RuntimeRefusal ? error.hint : fallback;
|
|
22
22
|
}
|
|
23
|
-
var HINT_OUT_OF_PROCESS = "Build and deploy through the app with deploy_manage
|
|
23
|
+
var HINT_OUT_OF_PROCESS = "Build and deploy through the app with deploy_manage. To simulate, validate or bundle, use the walkerOS CLI on your own machine.";
|
|
24
24
|
function unavailableOperation(operation) {
|
|
25
25
|
const verb = operation === "bundle" ? "Bundling" : operation === "simulate" ? "Simulating" : "Running";
|
|
26
26
|
return new RuntimeRefusal(
|
|
@@ -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 {
|
|
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:
|
|
103
|
-
deviceCode:
|
|
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
|
|
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
|
|
219
|
+
return mcpError2(new Error("Authorization was denied."));
|
|
166
220
|
if (poll.status === "expired")
|
|
167
|
-
return
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
230
|
-
import { mcpResult as mcpResult2, mcpError as
|
|
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(
|
|
427
|
-
|
|
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:
|
|
433
|
-
projectId:
|
|
434
|
-
name:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
548
|
-
import { mcpResult as mcpResult3, mcpError as
|
|
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
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
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
|
-
|
|
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
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
768
|
+
name: z4.string().optional().describe(
|
|
718
769
|
"Flow name. Required for create. Optional for update (to rename) and duplicate."
|
|
719
770
|
),
|
|
720
|
-
content:
|
|
721
|
-
patch:
|
|
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:
|
|
725
|
-
sort:
|
|
726
|
-
order:
|
|
727
|
-
includeDeleted:
|
|
728
|
-
cursor:
|
|
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:
|
|
732
|
-
previewId:
|
|
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:
|
|
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:
|
|
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:
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
kind:
|
|
745
|
-
deploymentVersionId:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
} =
|
|
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
|
|
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
|
|
864
|
-
const
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1128
|
+
return mcpError4(new Error(NO_DEFAULT_PROJECT_ERROR));
|
|
1088
1129
|
}
|
|
1089
1130
|
if (!client.regrantPreview) {
|
|
1090
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
|
1135
|
-
import { mcpResult as mcpResult4, mcpError as
|
|
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:
|
|
1192
|
-
projectId:
|
|
1193
|
-
flowId:
|
|
1194
|
-
slug:
|
|
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:
|
|
1198
|
-
status:
|
|
1199
|
-
wait:
|
|
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:
|
|
1241
|
+
flowName: z5.string().optional().describe(
|
|
1203
1242
|
"Flow name for multi-settings flows. Only used with deploy action."
|
|
1204
1243
|
),
|
|
1205
|
-
cursor:
|
|
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:
|
|
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
|
-
|
|
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
|
-
} =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
1371
|
-
import { mcpResult as mcpResult5, mcpError as
|
|
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:
|
|
1376
|
-
projectId:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
1469
|
+
if (validationError) return mcpError6(new Error(validationError));
|
|
1420
1470
|
try {
|
|
1421
1471
|
const resolvedProjectId = resolveDefaultProject(client, projectId);
|
|
1422
1472
|
if (!resolvedProjectId)
|
|
1423
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
|
1503
|
-
import { mcpResult as mcpResult6, mcpError as
|
|
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:
|
|
1508
|
-
projectId:
|
|
1509
|
-
traceId:
|
|
1510
|
-
limit:
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
1618
|
-
import { mcpResult as mcpResult7, mcpError as
|
|
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:
|
|
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:
|
|
1633
|
-
projectId:
|
|
1634
|
-
sessionId:
|
|
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:
|
|
1638
|
-
container:
|
|
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:
|
|
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:
|
|
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:
|
|
1651
|
-
replace:
|
|
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
|
|
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
|
-
|
|
1668
|
-
const
|
|
1669
|
-
if (
|
|
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
|
-
} =
|
|
1858
|
+
} = parsed.data;
|
|
1809
1859
|
if (!flowId) {
|
|
1810
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
1924
|
-
import { mcpResult as mcpResult8, mcpError as
|
|
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:
|
|
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:
|
|
2028
|
+
projectId: z9.string().optional().describe(
|
|
1981
2029
|
"Project ID. Optional: falls back to the default project when omitted."
|
|
1982
2030
|
),
|
|
1983
|
-
flowId:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
2005
|
-
anchorType:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
2559
|
-
import { mcpResult as mcpResult9, mcpError as
|
|
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:
|
|
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:
|
|
2611
|
+
projectId: z10.string().optional().describe(
|
|
2569
2612
|
"Project ID. Optional: falls back to the default project when omitted."
|
|
2570
2613
|
),
|
|
2571
|
-
pageKey:
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
2740
|
+
if (validationError) return mcpError10(new Error(validationError));
|
|
2704
2741
|
try {
|
|
2705
2742
|
const resolvedProjectId = resolveDefaultProject(client, projectId);
|
|
2706
2743
|
if (!resolvedProjectId) {
|
|
2707
|
-
return
|
|
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
|
|
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
|
|
2781
|
-
import { mcpResult as mcpResult10, mcpError as
|
|
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:
|
|
2786
|
-
anonymous:
|
|
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
|
|
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
|
|
2867
|
+
version: "4.7.0"
|
|
2829
2868
|
});
|
|
2830
2869
|
return mcpResult10({ ok: true });
|
|
2831
2870
|
} catch (error) {
|
|
2832
|
-
return
|
|
2871
|
+
return mcpError11(error);
|
|
2833
2872
|
}
|
|
2834
2873
|
}
|
|
2835
2874
|
function registerFeedbackTool(server, client) {
|
|
@@ -2842,102 +2881,135 @@ function registerFeedbackTool(server, client) {
|
|
|
2842
2881
|
inputSchema: spec.inputSchema,
|
|
2843
2882
|
annotations: spec.annotations
|
|
2844
2883
|
},
|
|
2845
|
-
|
|
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
|
|
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
|
|
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:
|
|
2860
|
-
type:
|
|
2861
|
-
|
|
2862
|
-
|
|
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:
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
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:
|
|
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:
|
|
2883
|
-
totalSize:
|
|
2884
|
-
buildTime:
|
|
2885
|
-
packages:
|
|
2886
|
-
|
|
2887
|
-
name:
|
|
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:
|
|
2891
|
-
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:
|
|
2895
|
-
error:
|
|
2896
|
-
summary:
|
|
2897
|
-
destinations:
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
received:
|
|
2901
|
-
calls:
|
|
2902
|
-
payload:
|
|
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:
|
|
2906
|
-
|
|
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(
|
|
2968
|
+
"Calls a simulated source made on its mock env (only when verbose: true)"
|
|
2969
|
+
),
|
|
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()
|
|
2975
|
+
}).optional().describe(
|
|
2976
|
+
"Why the destination sent nothing: a consent skip, or waiting for its require"
|
|
2977
|
+
),
|
|
2978
|
+
duration: z12.number().optional().describe("Simulation duration in ms")
|
|
2907
2979
|
};
|
|
2908
2980
|
var PushOutputShape = {
|
|
2909
|
-
success:
|
|
2910
|
-
elbResult:
|
|
2911
|
-
duration:
|
|
2912
|
-
error:
|
|
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")
|
|
2913
2985
|
};
|
|
2914
2986
|
var ExamplesListOutputShape = {
|
|
2915
|
-
flow:
|
|
2916
|
-
count:
|
|
2917
|
-
examples:
|
|
2918
|
-
|
|
2919
|
-
step:
|
|
2920
|
-
stepType:
|
|
2921
|
-
stepName:
|
|
2922
|
-
exampleName:
|
|
2923
|
-
source:
|
|
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(
|
|
2924
2996
|
'Where the example came from: "inline" (defined in the flow step) or "package" (shipped by the referenced package)'
|
|
2925
2997
|
),
|
|
2926
|
-
title:
|
|
2927
|
-
description:
|
|
2928
|
-
public:
|
|
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(
|
|
2929
3001
|
"Whether the example is public (defaults to true if omitted)"
|
|
2930
3002
|
),
|
|
2931
|
-
hasIn:
|
|
2932
|
-
hasOut:
|
|
2933
|
-
hasMapping:
|
|
2934
|
-
hasTrigger:
|
|
2935
|
-
in:
|
|
2936
|
-
out:
|
|
2937
|
-
mapping:
|
|
2938
|
-
trigger:
|
|
2939
|
-
type:
|
|
2940
|
-
options:
|
|
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()
|
|
2941
3013
|
}).optional().describe("Trigger metadata for source simulation")
|
|
2942
3014
|
})
|
|
2943
3015
|
).describe("Step examples")
|
|
@@ -2960,42 +3032,14 @@ async function loadValidateInput(runtime, input, type) {
|
|
|
2960
3032
|
throw error;
|
|
2961
3033
|
}
|
|
2962
3034
|
}
|
|
2963
|
-
var DEPRECATED_STORE_PACKAGE = "@walkeros/store-memory";
|
|
2964
|
-
function detectDeprecatedStorePackages(config) {
|
|
2965
|
-
const errors = [];
|
|
2966
|
-
if (!config || typeof config !== "object") return errors;
|
|
2967
|
-
const flows = config.flows;
|
|
2968
|
-
if (!flows || typeof flows !== "object") return errors;
|
|
2969
|
-
for (const [flowName, flowEntry] of Object.entries(
|
|
2970
|
-
flows
|
|
2971
|
-
)) {
|
|
2972
|
-
if (!flowEntry || typeof flowEntry !== "object") continue;
|
|
2973
|
-
const stores = flowEntry.stores;
|
|
2974
|
-
if (!stores || typeof stores !== "object") continue;
|
|
2975
|
-
for (const [storeId, storeEntry] of Object.entries(
|
|
2976
|
-
stores
|
|
2977
|
-
)) {
|
|
2978
|
-
if (!storeEntry || typeof storeEntry !== "object") continue;
|
|
2979
|
-
const pkg = storeEntry.package;
|
|
2980
|
-
if (pkg === DEPRECATED_STORE_PACKAGE) {
|
|
2981
|
-
errors.push({
|
|
2982
|
-
path: `flows.${flowName}.stores.${storeId}`,
|
|
2983
|
-
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.`,
|
|
2984
|
-
code: "DEPRECATED_PACKAGE"
|
|
2985
|
-
});
|
|
2986
|
-
}
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
return errors;
|
|
2990
|
-
}
|
|
2991
3035
|
var TITLE11 = "Validate Flow";
|
|
2992
|
-
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
|
|
2993
|
-
var inputSchema9 =
|
|
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;
|
|
2994
3038
|
var annotations11 = {
|
|
2995
3039
|
readOnlyHint: true,
|
|
2996
3040
|
destructiveHint: false,
|
|
2997
3041
|
idempotentHint: true,
|
|
2998
|
-
openWorldHint:
|
|
3042
|
+
openWorldHint: true
|
|
2999
3043
|
};
|
|
3000
3044
|
function createFlowValidateToolSpec(runtime) {
|
|
3001
3045
|
return {
|
|
@@ -3008,43 +3052,48 @@ function createFlowValidateToolSpec(runtime) {
|
|
|
3008
3052
|
};
|
|
3009
3053
|
}
|
|
3010
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
|
+
}
|
|
3011
3059
|
const {
|
|
3012
3060
|
type,
|
|
3013
3061
|
input: validateInput,
|
|
3014
3062
|
flow,
|
|
3015
|
-
path:
|
|
3016
|
-
|
|
3063
|
+
path: path3,
|
|
3064
|
+
strict,
|
|
3065
|
+
offline
|
|
3066
|
+
} = parsed.data;
|
|
3017
3067
|
try {
|
|
3018
3068
|
const resolved = await loadValidateInput(runtime, validateInput, type);
|
|
3069
|
+
const configDir = runtime.baseDir?.(validateInput);
|
|
3019
3070
|
const result = await validate(type, resolved, {
|
|
3020
3071
|
flow,
|
|
3021
|
-
path:
|
|
3072
|
+
path: path3,
|
|
3073
|
+
strict,
|
|
3074
|
+
offline,
|
|
3075
|
+
...configDir ? { configDir } : {}
|
|
3022
3076
|
});
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
errors: [...result.errors, ...deprecatedErrors]
|
|
3031
|
-
};
|
|
3032
|
-
}
|
|
3033
|
-
}
|
|
3034
|
-
const hints = augmented.valid ? {
|
|
3035
|
-
next: runtime.simulate ? [
|
|
3036
|
-
"Use flow_simulate to test event flow",
|
|
3037
|
-
"Use flow_bundle to build"
|
|
3038
|
-
] : [HINT_OUT_OF_PROCESS]
|
|
3039
|
-
} : {
|
|
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 ? {
|
|
3040
3084
|
next: [
|
|
3041
3085
|
"Fix errors above, then run flow_validate again",
|
|
3042
3086
|
"Read walkeros://reference/flow-schema for correct structure"
|
|
3043
3087
|
]
|
|
3044
|
-
}
|
|
3045
|
-
|
|
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);
|
|
3046
3095
|
} catch (error) {
|
|
3047
|
-
return
|
|
3096
|
+
return mcpError12(
|
|
3048
3097
|
error,
|
|
3049
3098
|
refusalHint(
|
|
3050
3099
|
error,
|
|
@@ -3065,15 +3114,13 @@ function registerFlowValidateTool(server, runtime) {
|
|
|
3065
3114
|
outputSchema: ValidateOutputShape,
|
|
3066
3115
|
annotations: spec.annotations
|
|
3067
3116
|
},
|
|
3068
|
-
|
|
3069
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3070
|
-
spec.handler
|
|
3117
|
+
(args) => flowValidateHandlerBody(runtime, args)
|
|
3071
3118
|
);
|
|
3072
3119
|
}
|
|
3073
3120
|
|
|
3074
3121
|
// src/tools/bundle.ts
|
|
3075
|
-
import { schemas as
|
|
3076
|
-
import { mcpResult as mcpResult12, mcpError as
|
|
3122
|
+
import { schemas as schemas3 } from "@walkeros/cli/dev";
|
|
3123
|
+
import { mcpResult as mcpResult12, mcpError as mcpError13 } from "@walkeros/core";
|
|
3077
3124
|
|
|
3078
3125
|
// src/tools/resolve-config-path.ts
|
|
3079
3126
|
async function resolveConfigPath(client, configPath) {
|
|
@@ -3086,7 +3133,7 @@ async function resolveConfigPath(client, configPath) {
|
|
|
3086
3133
|
var TITLE12 = "Bundle Flow";
|
|
3087
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.";
|
|
3088
3135
|
var inputSchema10 = {
|
|
3089
|
-
...
|
|
3136
|
+
...schemas3.BundleInputShape
|
|
3090
3137
|
};
|
|
3091
3138
|
var annotations12 = {
|
|
3092
3139
|
readOnlyHint: false,
|
|
@@ -3105,10 +3152,12 @@ function createFlowBundleToolSpec(client, runtime) {
|
|
|
3105
3152
|
};
|
|
3106
3153
|
}
|
|
3107
3154
|
async function flowBundleHandlerBody(client, runtime, input) {
|
|
3108
|
-
const
|
|
3155
|
+
const parsed = parseToolInput(inputSchema10, input);
|
|
3156
|
+
if (!parsed.ok) return parsed.error;
|
|
3157
|
+
const { configPath, flow, stats, output } = parsed.data;
|
|
3109
3158
|
if (!runtime.bundle) {
|
|
3110
3159
|
const refusal = unavailableOperation("bundle");
|
|
3111
|
-
return
|
|
3160
|
+
return mcpError13(refusal, refusal.hint);
|
|
3112
3161
|
}
|
|
3113
3162
|
try {
|
|
3114
3163
|
const resolvedConfigPath = await resolveConfigPath(client, configPath);
|
|
@@ -3128,9 +3177,8 @@ async function flowBundleHandlerBody(client, runtime, input) {
|
|
|
3128
3177
|
}
|
|
3129
3178
|
);
|
|
3130
3179
|
}
|
|
3131
|
-
const output_ = result;
|
|
3132
3180
|
return mcpResult12(
|
|
3133
|
-
{ success: true, ...
|
|
3181
|
+
{ success: true, ...result },
|
|
3134
3182
|
{
|
|
3135
3183
|
next: [
|
|
3136
3184
|
"Use flow_simulate to test",
|
|
@@ -3139,7 +3187,7 @@ async function flowBundleHandlerBody(client, runtime, input) {
|
|
|
3139
3187
|
}
|
|
3140
3188
|
);
|
|
3141
3189
|
} catch (error) {
|
|
3142
|
-
return
|
|
3190
|
+
return mcpError13(
|
|
3143
3191
|
error,
|
|
3144
3192
|
refusalHint(error, "Run flow_validate for detailed error messages")
|
|
3145
3193
|
);
|
|
@@ -3157,16 +3205,80 @@ function registerFlowBundleTool(server, client, runtime) {
|
|
|
3157
3205
|
outputSchema: BundleOutputShape,
|
|
3158
3206
|
annotations: spec.annotations
|
|
3159
3207
|
},
|
|
3160
|
-
|
|
3161
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3162
|
-
spec.handler
|
|
3208
|
+
(args) => flowBundleHandlerBody(client, runtime, args)
|
|
3163
3209
|
);
|
|
3164
3210
|
}
|
|
3165
3211
|
|
|
3166
3212
|
// src/tools/simulate.ts
|
|
3167
|
-
import { z as
|
|
3168
|
-
import { schemas as
|
|
3169
|
-
import { mcpResult as
|
|
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";
|
|
3216
|
+
|
|
3217
|
+
// src/tools/simulate-description.ts
|
|
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.`;
|
|
3219
|
+
|
|
3220
|
+
// src/tools/egress.ts
|
|
3221
|
+
import { isObject as isObject2, mcpResult as mcpResult13 } from "@walkeros/core";
|
|
3222
|
+
import { scrubJson, scrubSecrets } from "@walkeros/core/node";
|
|
3223
|
+
function scrubbed(result, known) {
|
|
3224
|
+
const parsed = parseObject(scrubJson(result, { known }));
|
|
3225
|
+
if (!parsed) throw new Error("Result could not be redacted as JSON.");
|
|
3226
|
+
return parsed;
|
|
3227
|
+
}
|
|
3228
|
+
function scrubbedError(response, known) {
|
|
3229
|
+
let structuredContent;
|
|
3230
|
+
try {
|
|
3231
|
+
if (response.structuredContent)
|
|
3232
|
+
structuredContent = scrubbed(response.structuredContent, known);
|
|
3233
|
+
} catch {
|
|
3234
|
+
structuredContent = void 0;
|
|
3235
|
+
}
|
|
3236
|
+
if (structuredContent) {
|
|
3237
|
+
return {
|
|
3238
|
+
...response,
|
|
3239
|
+
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
|
|
3240
|
+
structuredContent
|
|
3241
|
+
};
|
|
3242
|
+
}
|
|
3243
|
+
return {
|
|
3244
|
+
...response,
|
|
3245
|
+
content: response.content.map((part) => ({
|
|
3246
|
+
...part,
|
|
3247
|
+
text: scrubSecrets(part.text, { known })
|
|
3248
|
+
})),
|
|
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) : []
|
|
3278
|
+
};
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
// src/tools/simulate.ts
|
|
3170
3282
|
var STEP_TYPES = [
|
|
3171
3283
|
"source",
|
|
3172
3284
|
"transformer",
|
|
@@ -3177,30 +3289,38 @@ function isStepType(value) {
|
|
|
3177
3289
|
return STEP_TYPES.some((t) => t === value);
|
|
3178
3290
|
}
|
|
3179
3291
|
var TITLE13 = "Simulate Flow";
|
|
3180
|
-
var
|
|
3292
|
+
var COMMANDS = [
|
|
3293
|
+
"config",
|
|
3294
|
+
"consent",
|
|
3295
|
+
"user",
|
|
3296
|
+
"run"
|
|
3297
|
+
];
|
|
3181
3298
|
var inputSchema11 = {
|
|
3182
|
-
configPath:
|
|
3183
|
-
event:
|
|
3184
|
-
"For destinations: { name, data, consent? }
|
|
3299
|
+
configPath: schemas4.SimulateInputShape.configPath,
|
|
3300
|
+
event: z13.union([z13.record(z13.string(), z13.unknown()), z13.string()]).optional().describe(
|
|
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."
|
|
3185
3302
|
),
|
|
3186
|
-
flow:
|
|
3187
|
-
platform:
|
|
3303
|
+
flow: schemas4.SimulateInputShape.flow,
|
|
3304
|
+
platform: schemas4.SimulateInputShape.platform,
|
|
3188
3305
|
// Override the (optional) CLI `step` shape: the simulate handler hard-requires
|
|
3189
3306
|
// a target step (no all-steps mode), so the registered schema must be honest.
|
|
3190
|
-
step:
|
|
3307
|
+
step: z13.string().describe(
|
|
3191
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).'
|
|
3192
3309
|
),
|
|
3193
|
-
verbose:
|
|
3194
|
-
ingest:
|
|
3195
|
-
"Pipeline context a
|
|
3310
|
+
verbose: z13.boolean().optional().describe("Include full payload per destination (default: false)"),
|
|
3311
|
+
ingest: z13.record(z13.string(), z13.unknown()).optional().describe(
|
|
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."
|
|
3196
3313
|
),
|
|
3197
|
-
state:
|
|
3198
|
-
consent:
|
|
3199
|
-
user:
|
|
3200
|
-
globals:
|
|
3201
|
-
timing:
|
|
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()
|
|
3202
3319
|
}).optional().describe(
|
|
3203
|
-
"Collector
|
|
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."
|
|
3321
|
+
),
|
|
3322
|
+
command: z13.enum(COMMANDS).optional().describe(
|
|
3323
|
+
"Destination steps only: run this collector command with event as its data instead of pushing it, as a step example with command does."
|
|
3204
3324
|
)
|
|
3205
3325
|
};
|
|
3206
3326
|
var annotations13 = {
|
|
@@ -3217,18 +3337,40 @@ function createFlowSimulateToolSpec(client, runtime) {
|
|
|
3217
3337
|
return {
|
|
3218
3338
|
name: "flow_simulate",
|
|
3219
3339
|
title: TITLE13,
|
|
3220
|
-
description:
|
|
3340
|
+
description: FLOW_SIMULATE_DESCRIPTION,
|
|
3221
3341
|
inputSchema: inputSchema11,
|
|
3222
3342
|
annotations: annotations13,
|
|
3223
3343
|
handler: (input) => flowSimulateHandlerBody(client, runtime, input)
|
|
3224
3344
|
};
|
|
3225
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
|
+
}
|
|
3226
3355
|
async function flowSimulateHandlerBody(client, runtime, input) {
|
|
3227
|
-
const
|
|
3356
|
+
const parsed = parseToolInput(inputSchema11, input);
|
|
3357
|
+
if (!parsed.ok) return parsed.error;
|
|
3358
|
+
const {
|
|
3359
|
+
configPath,
|
|
3360
|
+
event,
|
|
3361
|
+
flow,
|
|
3362
|
+
platform,
|
|
3363
|
+
step,
|
|
3364
|
+
verbose,
|
|
3365
|
+
ingest,
|
|
3366
|
+
state,
|
|
3367
|
+
command
|
|
3368
|
+
} = parsed.data;
|
|
3228
3369
|
if (!runtime.simulate) {
|
|
3229
3370
|
const refusal = unavailableOperation("simulate");
|
|
3230
|
-
return
|
|
3371
|
+
return mcpError15(refusal, refusal.hint);
|
|
3231
3372
|
}
|
|
3373
|
+
let known = [];
|
|
3232
3374
|
try {
|
|
3233
3375
|
if (!event) {
|
|
3234
3376
|
throw new Error(
|
|
@@ -3263,26 +3405,53 @@ async function flowSimulateHandlerBody(client, runtime, input) {
|
|
|
3263
3405
|
`Unknown step type "${stepType}". Use "source", "collector", "transformer", or "destination".`
|
|
3264
3406
|
);
|
|
3265
3407
|
}
|
|
3408
|
+
if (command !== void 0 && stepType !== "destination") {
|
|
3409
|
+
throw new Error("command applies to destination steps only.");
|
|
3410
|
+
}
|
|
3266
3411
|
const resolvedConfigPath = await resolveConfigPath(client, configPath);
|
|
3412
|
+
const run = await readRun(runtime, resolvedConfigPath);
|
|
3413
|
+
known = run.knownSecrets;
|
|
3267
3414
|
const result = await runtime.simulate(
|
|
3268
3415
|
resolvedConfigPath,
|
|
3269
|
-
{
|
|
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
|
+
}
|
|
3270
3431
|
);
|
|
3271
3432
|
const success = !result.error;
|
|
3272
3433
|
const errorMessage = result.error?.message;
|
|
3273
3434
|
if (result.step === "source") {
|
|
3274
3435
|
const eventCount = result.events.length;
|
|
3275
|
-
const
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3436
|
+
const commandCount = result.calls.filter(
|
|
3437
|
+
(call) => call.fn === "elb"
|
|
3438
|
+
).length;
|
|
3439
|
+
const summary = `Source captured ${eventCount} event${eventCount !== 1 ? "s" : ""} and ${commandCount} command${commandCount !== 1 ? "s" : ""}`;
|
|
3440
|
+
const shownCalls = verbose ? result.calls : result.calls.filter((call) => call.fn === "elb");
|
|
3441
|
+
return mcpResult14(
|
|
3442
|
+
scrubbed(
|
|
3443
|
+
{
|
|
3444
|
+
success,
|
|
3445
|
+
error: errorMessage,
|
|
3446
|
+
summary,
|
|
3447
|
+
capturedEvents: result.events,
|
|
3448
|
+
...shownCalls.length > 0 ? { calls: shownCalls } : {},
|
|
3449
|
+
duration: result.duration
|
|
3450
|
+
},
|
|
3451
|
+
known
|
|
3452
|
+
),
|
|
3284
3453
|
{
|
|
3285
|
-
next: eventCount > 0 ? [
|
|
3454
|
+
next: eventCount + commandCount > 0 ? [
|
|
3286
3455
|
"Use flow_simulate with a destination step to test downstream processing"
|
|
3287
3456
|
] : [
|
|
3288
3457
|
"Check source package examples with package_get, verify trigger type matches"
|
|
@@ -3291,28 +3460,34 @@ async function flowSimulateHandlerBody(client, runtime, input) {
|
|
|
3291
3460
|
);
|
|
3292
3461
|
}
|
|
3293
3462
|
if (result.step === "transformer") {
|
|
3294
|
-
return
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3463
|
+
return mcpResult14(
|
|
3464
|
+
scrubbed(
|
|
3465
|
+
{
|
|
3466
|
+
success,
|
|
3467
|
+
error: errorMessage,
|
|
3468
|
+
summary: `Transformer processed event`,
|
|
3469
|
+
capturedEvents: result.events,
|
|
3470
|
+
duration: result.duration
|
|
3471
|
+
},
|
|
3472
|
+
known
|
|
3473
|
+
),
|
|
3302
3474
|
{
|
|
3303
3475
|
next: ["Use flow_bundle to build for production"]
|
|
3304
3476
|
}
|
|
3305
3477
|
);
|
|
3306
3478
|
}
|
|
3307
3479
|
if (result.step === "collector") {
|
|
3308
|
-
return
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3480
|
+
return mcpResult14(
|
|
3481
|
+
scrubbed(
|
|
3482
|
+
{
|
|
3483
|
+
success,
|
|
3484
|
+
error: errorMessage,
|
|
3485
|
+
summary: `Collector enriched event`,
|
|
3486
|
+
capturedEvents: result.events,
|
|
3487
|
+
duration: result.duration
|
|
3488
|
+
},
|
|
3489
|
+
known
|
|
3490
|
+
),
|
|
3316
3491
|
{
|
|
3317
3492
|
next: ["Use flow_simulate with a destination step to test delivery"]
|
|
3318
3493
|
}
|
|
@@ -3333,31 +3508,41 @@ async function flowSimulateHandlerBody(client, runtime, input) {
|
|
|
3333
3508
|
(d) => d.received
|
|
3334
3509
|
).length;
|
|
3335
3510
|
const warnings = [];
|
|
3336
|
-
if (receivedCount === 0)
|
|
3337
|
-
warnings.push(
|
|
3338
|
-
'Destination did not receive the event. Common causes: (1) destination config has consent: { marketing: true } but event lacks matching consent, (2) mapping rules do not match the event name, (3) policy redacted required fields. Add consent to the event: { name: "...", data: {...}, consent: { marketing: true } }.'
|
|
3339
|
-
);
|
|
3340
|
-
}
|
|
3511
|
+
if (receivedCount === 0 && success) warnings.push(notReceived(result));
|
|
3341
3512
|
const resultObj = {
|
|
3342
3513
|
success,
|
|
3343
3514
|
error: errorMessage,
|
|
3344
3515
|
summary: `${receivedCount}/${destCount} destinations received the event`,
|
|
3345
3516
|
destinations,
|
|
3517
|
+
...result.skipped ? { skipped: result.skipped } : {},
|
|
3346
3518
|
duration: result.duration
|
|
3347
3519
|
};
|
|
3348
|
-
return
|
|
3520
|
+
return mcpResult14(scrubbed(resultObj, known), {
|
|
3349
3521
|
next: ["Use flow_bundle to build for production"],
|
|
3350
3522
|
...warnings.length > 0 ? { warnings } : {}
|
|
3351
3523
|
});
|
|
3352
3524
|
} catch (error) {
|
|
3353
|
-
const
|
|
3354
|
-
|
|
3355
|
-
if (msg.includes("not found in collector")) {
|
|
3356
|
-
hint = 'If this destination has require: ["consent"] or require: ["user"], it stays pending until that event fires. For simulation, either remove require from the config or simulate with a flow that omits require on the target destination.';
|
|
3357
|
-
}
|
|
3358
|
-
return mcpError13(error, refusalHint(error, hint));
|
|
3525
|
+
const hint = "Run flow_validate for detailed error messages";
|
|
3526
|
+
return scrubbedError(mcpError15(error, refusalHint(error, hint)), known);
|
|
3359
3527
|
}
|
|
3360
3528
|
}
|
|
3529
|
+
function keysOf(consent) {
|
|
3530
|
+
const keys = Object.entries(consent ?? {}).filter(([, granted]) => granted).map(([key]) => key);
|
|
3531
|
+
return keys.length > 0 ? keys.join(", ") : "none";
|
|
3532
|
+
}
|
|
3533
|
+
function notReceived(result) {
|
|
3534
|
+
const { skipped } = result;
|
|
3535
|
+
if (skipped?.reason === "pending") {
|
|
3536
|
+
const require2 = skipped.require ?? [];
|
|
3537
|
+
const waits = require2.length ? require2.join(", ") : "its require";
|
|
3538
|
+
const advice = require2.includes("consent") ? "pass state.consent (e.g. { functional: true }) to start it." : `it starts once the flow provides ${waits}; a simulation cannot seed that.`;
|
|
3539
|
+
return `Destination waits for ${waits} (require) and never started: ${advice}`;
|
|
3540
|
+
}
|
|
3541
|
+
if (skipped?.reason === "consent") {
|
|
3542
|
+
return `Consent skip: requires ${keysOf(skipped.required)}; granted ${keysOf(skipped.granted)}. Grant it in state.consent or in the event's consent.`;
|
|
3543
|
+
}
|
|
3544
|
+
return "Destination made no calls. Common causes: (1) mapping rules do not match the event name or ignore it, (2) policy redacted required fields, (3) a before chain stopped the event.";
|
|
3545
|
+
}
|
|
3361
3546
|
function registerFlowSimulateTool(server, client, runtime) {
|
|
3362
3547
|
const spec = createFlowSimulateToolSpec(client, runtime);
|
|
3363
3548
|
server.registerTool(
|
|
@@ -3370,25 +3555,23 @@ function registerFlowSimulateTool(server, client, runtime) {
|
|
|
3370
3555
|
outputSchema: SimulateOutputShape,
|
|
3371
3556
|
annotations: spec.annotations
|
|
3372
3557
|
},
|
|
3373
|
-
|
|
3374
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3375
|
-
spec.handler
|
|
3558
|
+
(args) => flowSimulateHandlerBody(client, runtime, args)
|
|
3376
3559
|
);
|
|
3377
3560
|
}
|
|
3378
3561
|
|
|
3379
3562
|
// src/tools/push.ts
|
|
3380
|
-
import { z as
|
|
3381
|
-
import { schemas as
|
|
3382
|
-
import {
|
|
3563
|
+
import { z as z14 } from "zod";
|
|
3564
|
+
import { schemas as schemas5 } from "@walkeros/cli/dev";
|
|
3565
|
+
import { mcpError as mcpError16 } from "@walkeros/core";
|
|
3383
3566
|
var TITLE14 = "Push Events";
|
|
3384
|
-
var
|
|
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.";
|
|
3385
3568
|
var inputSchema12 = {
|
|
3386
|
-
configPath:
|
|
3387
|
-
event:
|
|
3569
|
+
configPath: schemas5.PushInputShape.configPath,
|
|
3570
|
+
event: z14.record(z14.string(), z14.unknown()).describe(
|
|
3388
3571
|
'Event object, e.g. { name: "page view", data: { title: "Home" } }'
|
|
3389
3572
|
),
|
|
3390
|
-
flow:
|
|
3391
|
-
platform:
|
|
3573
|
+
flow: schemas5.PushInputShape.flow,
|
|
3574
|
+
platform: schemas5.PushInputShape.platform
|
|
3392
3575
|
};
|
|
3393
3576
|
var annotations14 = {
|
|
3394
3577
|
readOnlyHint: false,
|
|
@@ -3400,37 +3583,49 @@ function createFlowPushToolSpec(runtime) {
|
|
|
3400
3583
|
return {
|
|
3401
3584
|
name: "flow_push",
|
|
3402
3585
|
title: TITLE14,
|
|
3403
|
-
description:
|
|
3586
|
+
description: DESCRIPTION11,
|
|
3404
3587
|
inputSchema: inputSchema12,
|
|
3405
3588
|
annotations: annotations14,
|
|
3406
3589
|
handler: (input) => flowPushHandlerBody(runtime, input)
|
|
3407
3590
|
};
|
|
3408
3591
|
}
|
|
3409
3592
|
async function flowPushHandlerBody(runtime, input) {
|
|
3410
|
-
const
|
|
3593
|
+
const parsed = parseToolInput(inputSchema12, input);
|
|
3594
|
+
if (!parsed.ok) return parsed.error;
|
|
3595
|
+
const { configPath, event, flow, platform } = parsed.data;
|
|
3411
3596
|
if (!runtime.push) {
|
|
3412
3597
|
const refusal = unavailableOperation("push");
|
|
3413
|
-
return
|
|
3598
|
+
return mcpError16(refusal, refusal.hint);
|
|
3414
3599
|
}
|
|
3600
|
+
let known = [];
|
|
3415
3601
|
try {
|
|
3602
|
+
const run = await readRun(runtime, configPath);
|
|
3603
|
+
known = run.knownSecrets;
|
|
3416
3604
|
const result = await runtime.push(configPath, event, {
|
|
3417
3605
|
flow,
|
|
3418
|
-
platform
|
|
3606
|
+
platform,
|
|
3607
|
+
config: run.config
|
|
3419
3608
|
});
|
|
3420
3609
|
if (!result.success) {
|
|
3421
|
-
return
|
|
3422
|
-
|
|
3423
|
-
|
|
3610
|
+
return scrubbedError(
|
|
3611
|
+
mcpError16(
|
|
3612
|
+
new Error(result.error || "Push failed"),
|
|
3613
|
+
"Check destination configuration and connectivity."
|
|
3614
|
+
),
|
|
3615
|
+
known
|
|
3424
3616
|
);
|
|
3425
3617
|
}
|
|
3426
|
-
return
|
|
3618
|
+
return scrubbedPushResult(result, known);
|
|
3427
3619
|
} catch (error) {
|
|
3428
|
-
return
|
|
3429
|
-
|
|
3430
|
-
refusalHint(
|
|
3620
|
+
return scrubbedError(
|
|
3621
|
+
mcpError16(
|
|
3431
3622
|
error,
|
|
3432
|
-
|
|
3433
|
-
|
|
3623
|
+
refusalHint(
|
|
3624
|
+
error,
|
|
3625
|
+
"Check configPath and event format. For web flows, use flow_simulate."
|
|
3626
|
+
)
|
|
3627
|
+
),
|
|
3628
|
+
known
|
|
3434
3629
|
);
|
|
3435
3630
|
}
|
|
3436
3631
|
}
|
|
@@ -3446,22 +3641,21 @@ function registerFlowPushTool(server, runtime) {
|
|
|
3446
3641
|
outputSchema: PushOutputShape,
|
|
3447
3642
|
annotations: spec.annotations
|
|
3448
3643
|
},
|
|
3449
|
-
|
|
3450
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3451
|
-
spec.handler
|
|
3644
|
+
(args) => flowPushHandlerBody(runtime, args)
|
|
3452
3645
|
);
|
|
3453
3646
|
}
|
|
3454
3647
|
|
|
3455
3648
|
// src/tools/examples.ts
|
|
3456
|
-
import { z as
|
|
3457
|
-
import { fetchPackage, mcpResult as mcpResult15, mcpError as
|
|
3649
|
+
import { z as z15 } from "zod";
|
|
3650
|
+
import { fetchPackage, mcpResult as mcpResult15, mcpError as mcpError17 } from "@walkeros/core";
|
|
3651
|
+
import { resolveExportName, selectDevExamples } from "@walkeros/cli";
|
|
3458
3652
|
|
|
3459
3653
|
// src/catalog.ts
|
|
3460
3654
|
var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
|
|
3461
3655
|
var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
|
|
3462
3656
|
var WALKEROS_JSON_PATH = "dist/walkerOS.json";
|
|
3463
3657
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
3464
|
-
var CLIENT_HEADER = "walkeros-mcp/4.7.0
|
|
3658
|
+
var CLIENT_HEADER = "walkeros-mcp/4.7.0";
|
|
3465
3659
|
function getPackageBaseUrl() {
|
|
3466
3660
|
return process.env.WALKEROS_APP_URL || void 0;
|
|
3467
3661
|
}
|
|
@@ -3616,17 +3810,17 @@ function applyFilters(entries, filters) {
|
|
|
3616
3810
|
// src/tools/examples.ts
|
|
3617
3811
|
var MAX_PACKAGE_LOOKUPS = 25;
|
|
3618
3812
|
var TITLE15 = "Flow Examples";
|
|
3619
|
-
var
|
|
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.';
|
|
3620
3814
|
var inputSchema13 = {
|
|
3621
|
-
configPath:
|
|
3815
|
+
configPath: z15.string().min(1).describe(
|
|
3622
3816
|
"Inline JSON string, file path, or URL of a flow configuration (hosted server: inline JSON or a saved flow id only)"
|
|
3623
3817
|
),
|
|
3624
|
-
flow:
|
|
3625
|
-
step:
|
|
3626
|
-
full:
|
|
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(
|
|
3627
3821
|
"Return full in/out/mapping data for each example (default: false, returns metadata only)"
|
|
3628
3822
|
),
|
|
3629
|
-
includeHidden:
|
|
3823
|
+
includeHidden: z15.boolean().optional().describe(
|
|
3630
3824
|
"Include examples marked public: false (default: false). Set true for test/debug discovery."
|
|
3631
3825
|
)
|
|
3632
3826
|
};
|
|
@@ -3640,16 +3834,21 @@ function createFlowExamplesToolSpec(runtime) {
|
|
|
3640
3834
|
return {
|
|
3641
3835
|
name: "flow_examples",
|
|
3642
3836
|
title: TITLE15,
|
|
3643
|
-
description:
|
|
3837
|
+
description: DESCRIPTION12,
|
|
3644
3838
|
inputSchema: inputSchema13,
|
|
3645
3839
|
annotations: annotations15,
|
|
3646
3840
|
handler: (input) => flowExamplesHandlerBody(runtime, input)
|
|
3647
3841
|
};
|
|
3648
3842
|
}
|
|
3649
3843
|
async function flowExamplesHandlerBody(runtime, input) {
|
|
3650
|
-
const
|
|
3844
|
+
const parsed = parseToolInput(inputSchema13, input);
|
|
3845
|
+
if (!parsed.ok) return parsed.error;
|
|
3846
|
+
const { configPath, flow, step, full, includeHidden } = parsed.data;
|
|
3651
3847
|
try {
|
|
3652
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
|
+
}
|
|
3653
3852
|
const flowNames = Object.keys(rawConfig.flows || {});
|
|
3654
3853
|
const flowName = flow || (flowNames.length === 1 ? flowNames[0] : void 0);
|
|
3655
3854
|
if (!flowName) {
|
|
@@ -3690,32 +3889,37 @@ async function flowExamplesHandlerBody(runtime, input) {
|
|
|
3690
3889
|
return items;
|
|
3691
3890
|
};
|
|
3692
3891
|
const baseUrl = getPackageBaseUrl();
|
|
3693
|
-
const
|
|
3892
|
+
const loadPackage = async (packageName) => {
|
|
3694
3893
|
try {
|
|
3695
|
-
|
|
3894
|
+
return await fetchPackage(packageName, {
|
|
3696
3895
|
baseUrl,
|
|
3697
3896
|
client: CLIENT_HEADER
|
|
3698
3897
|
});
|
|
3699
|
-
const stepExamples = info.examples?.step;
|
|
3700
|
-
if (stepExamples && typeof stepExamples === "object")
|
|
3701
|
-
return stepExamples;
|
|
3702
3898
|
} catch {
|
|
3703
3899
|
}
|
|
3704
3900
|
return void 0;
|
|
3705
3901
|
};
|
|
3706
3902
|
const packageLookups = /* @__PURE__ */ new Map();
|
|
3707
3903
|
let skippedPackages = false;
|
|
3708
|
-
const
|
|
3904
|
+
const skippedExamples = [];
|
|
3905
|
+
const packageFor = (packageName) => {
|
|
3709
3906
|
const existing = packageLookups.get(packageName);
|
|
3710
3907
|
if (existing) return existing;
|
|
3711
3908
|
if (packageLookups.size >= MAX_PACKAGE_LOOKUPS) {
|
|
3712
3909
|
skippedPackages = true;
|
|
3713
3910
|
return Promise.resolve(void 0);
|
|
3714
3911
|
}
|
|
3715
|
-
const lookup =
|
|
3912
|
+
const lookup = loadPackage(packageName);
|
|
3716
3913
|
packageLookups.set(packageName, lookup);
|
|
3717
3914
|
return lookup;
|
|
3718
3915
|
};
|
|
3916
|
+
const stepExamplesFor = (info, exportName) => {
|
|
3917
|
+
const selected = selectDevExamples(
|
|
3918
|
+
{ examples: info.examples, exportExamples: info.exportExamples },
|
|
3919
|
+
exportName
|
|
3920
|
+
);
|
|
3921
|
+
return stepExamplesOf(selected?.step);
|
|
3922
|
+
};
|
|
3719
3923
|
const stepTypes = [
|
|
3720
3924
|
{ key: "sources", type: "source" },
|
|
3721
3925
|
{ key: "transformers", type: "transformer" },
|
|
@@ -3726,15 +3930,20 @@ async function flowExamplesHandlerBody(runtime, input) {
|
|
|
3726
3930
|
for (const [name, ref] of Object.entries(refs)) {
|
|
3727
3931
|
if (step && `${type}.${name}` !== step) continue;
|
|
3728
3932
|
if (ref.examples) {
|
|
3729
|
-
examples.push(
|
|
3730
|
-
...toItems(ref.examples, type, name, "inline")
|
|
3731
|
-
);
|
|
3933
|
+
examples.push(...toItems(ref.examples, type, name, "inline"));
|
|
3732
3934
|
continue;
|
|
3733
3935
|
}
|
|
3734
3936
|
if (!ref.package) continue;
|
|
3735
|
-
const
|
|
3736
|
-
if (
|
|
3737
|
-
|
|
3937
|
+
const info = await packageFor(ref.package);
|
|
3938
|
+
if (!info) continue;
|
|
3939
|
+
const { exportName } = resolveExportName(flowSettings, type, name);
|
|
3940
|
+
const packageExamples = stepExamplesFor(info, exportName);
|
|
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}`);
|
|
3738
3947
|
}
|
|
3739
3948
|
}
|
|
3740
3949
|
const result = {
|
|
@@ -3748,6 +3957,11 @@ async function flowExamplesHandlerBody(runtime, input) {
|
|
|
3748
3957
|
"No examples found. Add examples to step entries, or reference a package that ships examples (see package_get)."
|
|
3749
3958
|
);
|
|
3750
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
|
+
}
|
|
3751
3965
|
if (skippedPackages) {
|
|
3752
3966
|
warnings.push(
|
|
3753
3967
|
`Package examples were looked up for the first ${MAX_PACKAGE_LOOKUPS} packages only. Use step to narrow the result.`
|
|
@@ -3761,7 +3975,7 @@ async function flowExamplesHandlerBody(runtime, input) {
|
|
|
3761
3975
|
};
|
|
3762
3976
|
return mcpResult15(result, hints);
|
|
3763
3977
|
} catch (error) {
|
|
3764
|
-
return
|
|
3978
|
+
return mcpError17(
|
|
3765
3979
|
error,
|
|
3766
3980
|
refusalHint(error, "Check configPath \u2014 expected a flow.json file")
|
|
3767
3981
|
);
|
|
@@ -3779,15 +3993,13 @@ function registerFlowExamplesTool(server, runtime) {
|
|
|
3779
3993
|
outputSchema: ExamplesListOutputShape,
|
|
3780
3994
|
annotations: spec.annotations
|
|
3781
3995
|
},
|
|
3782
|
-
|
|
3783
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3784
|
-
spec.handler
|
|
3996
|
+
(args) => flowExamplesHandlerBody(runtime, args)
|
|
3785
3997
|
);
|
|
3786
3998
|
}
|
|
3787
3999
|
|
|
3788
4000
|
// src/tools/flow-load.ts
|
|
3789
|
-
import { z as
|
|
3790
|
-
import { mcpResult as mcpResult16, mcpError as
|
|
4001
|
+
import { z as z16 } from "zod";
|
|
4002
|
+
import { mcpResult as mcpResult16, mcpError as mcpError18 } from "@walkeros/core";
|
|
3791
4003
|
var WEB_SKELETON = {
|
|
3792
4004
|
version: 4,
|
|
3793
4005
|
flows: {
|
|
@@ -3809,18 +4021,18 @@ var SERVER_SKELETON = {
|
|
|
3809
4021
|
}
|
|
3810
4022
|
};
|
|
3811
4023
|
var TITLE16 = "Load or Create Flow";
|
|
3812
|
-
var
|
|
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.";
|
|
3813
4025
|
var inputSchema14 = {
|
|
3814
|
-
source:
|
|
4026
|
+
source: z16.string().optional().describe(
|
|
3815
4027
|
"Flow source: local file path (./flow.json), URL (https://...), inline JSON string, or API flow ID (cfg_...). Omit to create a new flow."
|
|
3816
4028
|
),
|
|
3817
|
-
platform:
|
|
4029
|
+
platform: z16.enum(["web", "server"]).optional().describe(
|
|
3818
4030
|
"Platform for new flows. Required when source is omitted. web = browser tracking, server = Node.js HTTP."
|
|
3819
4031
|
)
|
|
3820
4032
|
};
|
|
3821
4033
|
var outputSchema = {
|
|
3822
|
-
version:
|
|
3823
|
-
flows:
|
|
4034
|
+
version: z16.number().describe("Flow config version"),
|
|
4035
|
+
flows: z16.record(z16.string(), z16.unknown()).describe("Flow entries")
|
|
3824
4036
|
};
|
|
3825
4037
|
var annotations16 = {
|
|
3826
4038
|
readOnlyHint: true,
|
|
@@ -3832,18 +4044,20 @@ function createFlowLoadToolSpec(client, runtime) {
|
|
|
3832
4044
|
return {
|
|
3833
4045
|
name: "flow_load",
|
|
3834
4046
|
title: TITLE16,
|
|
3835
|
-
description:
|
|
4047
|
+
description: DESCRIPTION13,
|
|
3836
4048
|
inputSchema: inputSchema14,
|
|
3837
4049
|
annotations: annotations16,
|
|
3838
4050
|
handler: (input) => flowLoadHandlerBody(client, runtime, input)
|
|
3839
4051
|
};
|
|
3840
4052
|
}
|
|
3841
4053
|
async function flowLoadHandlerBody(client, runtime, input) {
|
|
3842
|
-
const
|
|
4054
|
+
const parsed = parseToolInput(inputSchema14, input);
|
|
4055
|
+
if (!parsed.ok) return parsed.error;
|
|
4056
|
+
const { source, platform } = parsed.data;
|
|
3843
4057
|
if (source && isCloudId(source)) {
|
|
3844
4058
|
const resolvedProjectId = resolveDefaultProject(client, void 0);
|
|
3845
4059
|
if (!resolvedProjectId) {
|
|
3846
|
-
return
|
|
4060
|
+
return mcpError18(new Error(NO_DEFAULT_PROJECT_ERROR));
|
|
3847
4061
|
}
|
|
3848
4062
|
try {
|
|
3849
4063
|
const flow = await client.getFlow({
|
|
@@ -3857,7 +4071,7 @@ async function flowLoadHandlerBody(client, runtime, input) {
|
|
|
3857
4071
|
}
|
|
3858
4072
|
);
|
|
3859
4073
|
} catch (error) {
|
|
3860
|
-
return
|
|
4074
|
+
return mcpError18(error, isAuthError(error) ? AUTH_HINT : void 0);
|
|
3861
4075
|
}
|
|
3862
4076
|
}
|
|
3863
4077
|
try {
|
|
@@ -3868,7 +4082,7 @@ async function flowLoadHandlerBody(client, runtime, input) {
|
|
|
3868
4082
|
});
|
|
3869
4083
|
}
|
|
3870
4084
|
if (!platform) {
|
|
3871
|
-
return
|
|
4085
|
+
return mcpError18(
|
|
3872
4086
|
new Error(
|
|
3873
4087
|
"Provide source (file path, URL, or flow ID) to load existing flow, or platform (web/server) to create a new one."
|
|
3874
4088
|
)
|
|
@@ -3882,11 +4096,11 @@ async function flowLoadHandlerBody(client, runtime, input) {
|
|
|
3882
4096
|
]
|
|
3883
4097
|
});
|
|
3884
4098
|
} catch (error) {
|
|
3885
|
-
if (error instanceof RuntimeRefusal) return
|
|
4099
|
+
if (error instanceof RuntimeRefusal) return mcpError18(error, error.hint);
|
|
3886
4100
|
const msg = error instanceof Error ? error.message : "";
|
|
3887
4101
|
if (msg.includes("not found") || msg.includes("ENOENT"))
|
|
3888
|
-
return
|
|
3889
|
-
return
|
|
4102
|
+
return mcpError18(error, "Check configPath \u2014 expected a flow.json file");
|
|
4103
|
+
return mcpError18(error);
|
|
3890
4104
|
}
|
|
3891
4105
|
}
|
|
3892
4106
|
function registerFlowLoadTool(server, client, runtime) {
|
|
@@ -3901,25 +4115,23 @@ function registerFlowLoadTool(server, client, runtime) {
|
|
|
3901
4115
|
outputSchema,
|
|
3902
4116
|
annotations: spec.annotations
|
|
3903
4117
|
},
|
|
3904
|
-
|
|
3905
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3906
|
-
spec.handler
|
|
4118
|
+
(args) => flowLoadHandlerBody(client, runtime, args)
|
|
3907
4119
|
);
|
|
3908
4120
|
}
|
|
3909
4121
|
|
|
3910
4122
|
// src/tools/package.ts
|
|
3911
|
-
import { z as
|
|
3912
|
-
import { fetchPackage as fetchPackage2, mcpResult as mcpResult17, mcpError as
|
|
4123
|
+
import { z as z17 } from "zod";
|
|
4124
|
+
import { fetchPackage as fetchPackage2, mcpResult as mcpResult17, mcpError as mcpError19 } from "@walkeros/core";
|
|
3913
4125
|
import { mergeConfigSchema } from "@walkeros/core/dev";
|
|
3914
4126
|
var SEARCH_TITLE = "Search Package";
|
|
3915
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.";
|
|
3916
4128
|
var searchInputSchema = {
|
|
3917
|
-
package:
|
|
4129
|
+
package: z17.string().min(1).optional().describe(
|
|
3918
4130
|
"Exact npm package name for detailed lookup (e.g., @walkeros/web-destination-snowplow)"
|
|
3919
4131
|
),
|
|
3920
|
-
type:
|
|
3921
|
-
platform:
|
|
3922
|
-
version:
|
|
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)")
|
|
3923
4135
|
};
|
|
3924
4136
|
var searchAnnotations = {
|
|
3925
4137
|
readOnlyHint: true,
|
|
@@ -3938,12 +4150,9 @@ function createPackageSearchToolSpec() {
|
|
|
3938
4150
|
};
|
|
3939
4151
|
}
|
|
3940
4152
|
async function packageSearchHandlerBody(input) {
|
|
3941
|
-
const
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
platform,
|
|
3945
|
-
version
|
|
3946
|
-
} = input ?? {};
|
|
4153
|
+
const parsed = parseToolInput(searchInputSchema, input);
|
|
4154
|
+
if (!parsed.ok) return parsed.error;
|
|
4155
|
+
const { package: packageName, type, platform, version } = parsed.data;
|
|
3947
4156
|
const baseUrl = getPackageBaseUrl();
|
|
3948
4157
|
if (!packageName) {
|
|
3949
4158
|
const { entries, warnings } = await fetchCatalog({
|
|
@@ -3976,7 +4185,7 @@ async function packageSearchHandlerBody(input) {
|
|
|
3976
4185
|
next: ["Use package_get for schemas and examples"]
|
|
3977
4186
|
});
|
|
3978
4187
|
} catch (error) {
|
|
3979
|
-
return
|
|
4188
|
+
return mcpError19(
|
|
3980
4189
|
error,
|
|
3981
4190
|
"Package not found. Use package_search without parameters to browse available packages."
|
|
3982
4191
|
);
|
|
@@ -3993,19 +4202,17 @@ function registerPackageSearchTool(server) {
|
|
|
3993
4202
|
// No outputSchema: browse mode returns {catalog, count}, lookup returns metadata — incompatible shapes
|
|
3994
4203
|
annotations: spec.annotations
|
|
3995
4204
|
},
|
|
3996
|
-
|
|
3997
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
3998
|
-
spec.handler
|
|
4205
|
+
(args) => packageSearchHandlerBody(args)
|
|
3999
4206
|
);
|
|
4000
4207
|
}
|
|
4001
4208
|
var GET_TITLE = "Get Package";
|
|
4002
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".';
|
|
4003
4210
|
var getInputSchema = {
|
|
4004
|
-
package:
|
|
4211
|
+
package: z17.string().min(1).describe(
|
|
4005
4212
|
"Exact npm package name (e.g., @walkeros/web-destination-snowplow)"
|
|
4006
4213
|
),
|
|
4007
|
-
version:
|
|
4008
|
-
section:
|
|
4214
|
+
version: z17.string().optional().describe("Package version (default: latest)"),
|
|
4215
|
+
section: z17.enum(["hints", "examples", "all"]).optional().describe(
|
|
4009
4216
|
"Section to expand with full content. Default: summary view with schemas + hint texts + example descriptions"
|
|
4010
4217
|
)
|
|
4011
4218
|
};
|
|
@@ -4025,12 +4232,35 @@ function createPackageGetToolSpec() {
|
|
|
4025
4232
|
handler: (input) => packageGetHandlerBody(input)
|
|
4026
4233
|
};
|
|
4027
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
|
+
}
|
|
4028
4260
|
async function packageGetHandlerBody(input) {
|
|
4029
|
-
const
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
section
|
|
4033
|
-
} = input ?? {};
|
|
4261
|
+
const parsed = parseToolInput(getInputSchema, input);
|
|
4262
|
+
if (!parsed.ok) return parsed.error;
|
|
4263
|
+
const { package: packageName, version, section } = parsed.data;
|
|
4034
4264
|
const baseUrl = getPackageBaseUrl();
|
|
4035
4265
|
try {
|
|
4036
4266
|
const info = await fetchPackage2(packageName, {
|
|
@@ -4038,45 +4268,42 @@ async function packageGetHandlerBody(input) {
|
|
|
4038
4268
|
baseUrl,
|
|
4039
4269
|
client: CLIENT_HEADER
|
|
4040
4270
|
});
|
|
4041
|
-
const mergedSchemas = {};
|
|
4042
|
-
if (info.type) {
|
|
4043
|
-
mergedSchemas.config = mergeConfigSchema(
|
|
4044
|
-
info.type,
|
|
4045
|
-
info.schemas
|
|
4046
|
-
);
|
|
4047
|
-
}
|
|
4048
|
-
for (const [key, value] of Object.entries(info.schemas)) {
|
|
4049
|
-
if (key !== "settings") {
|
|
4050
|
-
mergedSchemas[key] = value;
|
|
4051
|
-
}
|
|
4052
|
-
}
|
|
4053
4271
|
const result = {
|
|
4054
4272
|
package: info.packageName,
|
|
4055
4273
|
version: info.version,
|
|
4056
4274
|
type: info.type,
|
|
4057
4275
|
platform: normalizePlatform(info.platform),
|
|
4058
|
-
schemas:
|
|
4276
|
+
schemas: shapeSchemas(info.type, info.schemas)
|
|
4059
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
|
+
}
|
|
4060
4286
|
if (info.hints) {
|
|
4061
4287
|
if (section === "hints" || section === "all") {
|
|
4062
4288
|
result.hints = info.hints;
|
|
4063
4289
|
} else {
|
|
4064
4290
|
const hintSummary = {};
|
|
4065
4291
|
for (const [key, hint] of Object.entries(info.hints)) {
|
|
4066
|
-
const
|
|
4067
|
-
hintSummary[key] = { text
|
|
4292
|
+
const text = stringField(hint, "text");
|
|
4293
|
+
if (text !== void 0) hintSummary[key] = { text };
|
|
4068
4294
|
}
|
|
4069
4295
|
result.hints = hintSummary;
|
|
4070
4296
|
}
|
|
4071
4297
|
}
|
|
4072
4298
|
if (section === "examples" || section === "all") {
|
|
4073
4299
|
result.examples = info.examples;
|
|
4300
|
+
if (info.exportExamples) result.exportExamples = info.exportExamples;
|
|
4074
4301
|
} else {
|
|
4075
4302
|
result.exampleSummaries = info.exampleSummaries;
|
|
4076
4303
|
}
|
|
4077
4304
|
return mcpResult17(result);
|
|
4078
4305
|
} catch (error) {
|
|
4079
|
-
return
|
|
4306
|
+
return mcpError19(
|
|
4080
4307
|
error,
|
|
4081
4308
|
"Use package_search to browse available package names."
|
|
4082
4309
|
);
|
|
@@ -4093,9 +4320,7 @@ function registerGetPackageSchemaTool(server) {
|
|
|
4093
4320
|
// No outputSchema: removed to avoid SDK -32602 crashes on unexpected field values
|
|
4094
4321
|
annotations: spec.annotations
|
|
4095
4322
|
},
|
|
4096
|
-
|
|
4097
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
4098
|
-
spec.handler
|
|
4323
|
+
(args) => packageGetHandlerBody(args)
|
|
4099
4324
|
);
|
|
4100
4325
|
}
|
|
4101
4326
|
|
|
@@ -23722,7 +23947,7 @@ function stripTrailingSlashes(value) {
|
|
|
23722
23947
|
// src/tools/diagnostics.ts
|
|
23723
23948
|
var CONTRACT_OPENAPI_VERSION = spec_default.info.version;
|
|
23724
23949
|
var TITLE17 = "Diagnostics";
|
|
23725
|
-
var
|
|
23950
|
+
var DESCRIPTION14 = "Report the MCP runtime surface: MCP and CLI versions, the resolved app URL and its source, app /api/health reachability, the bundled OpenAPI contract version, and which source served the last package catalog fetch. Read-only and callable when logged out; use it when a request fails to see which versions and backend you are on.";
|
|
23726
23951
|
var inputSchema15 = {};
|
|
23727
23952
|
var annotations17 = {
|
|
23728
23953
|
readOnlyHint: true,
|
|
@@ -23734,7 +23959,7 @@ function createDiagnosticsToolSpec(client, packageVersion) {
|
|
|
23734
23959
|
return {
|
|
23735
23960
|
name: "diagnostics",
|
|
23736
23961
|
title: TITLE17,
|
|
23737
|
-
description:
|
|
23962
|
+
description: DESCRIPTION14,
|
|
23738
23963
|
inputSchema: inputSchema15,
|
|
23739
23964
|
annotations: annotations17,
|
|
23740
23965
|
handler: () => diagnosticsHandlerBody(client, packageVersion)
|
|
@@ -23808,9 +24033,7 @@ function registerDiagnosticsTool(server, client, packageVersion) {
|
|
|
23808
24033
|
inputSchema: spec.inputSchema,
|
|
23809
24034
|
annotations: spec.annotations
|
|
23810
24035
|
},
|
|
23811
|
-
|
|
23812
|
-
// type-erased (input: unknown) => Promise<unknown> form by design.
|
|
23813
|
-
spec.handler
|
|
24036
|
+
() => diagnosticsHandlerBody(client, packageVersion)
|
|
23814
24037
|
);
|
|
23815
24038
|
}
|
|
23816
24039
|
|
|
@@ -23860,7 +24083,7 @@ function registerPackageSchemaResources(server) {
|
|
|
23860
24083
|
}
|
|
23861
24084
|
|
|
23862
24085
|
// src/resources/references.ts
|
|
23863
|
-
import { schemas as
|
|
24086
|
+
import { schemas as schemas6 } from "@walkeros/core/dev";
|
|
23864
24087
|
function registerReferenceResources(server) {
|
|
23865
24088
|
server.resource(
|
|
23866
24089
|
"flow-schema",
|
|
@@ -23873,7 +24096,7 @@ function registerReferenceResources(server) {
|
|
|
23873
24096
|
contents: [
|
|
23874
24097
|
{
|
|
23875
24098
|
uri: "walkeros://reference/flow-schema",
|
|
23876
|
-
text: JSON.stringify(
|
|
24099
|
+
text: JSON.stringify(schemas6.configJsonSchema, null, 2),
|
|
23877
24100
|
mimeType: "application/json"
|
|
23878
24101
|
}
|
|
23879
24102
|
]
|
|
@@ -23890,7 +24113,7 @@ function registerReferenceResources(server) {
|
|
|
23890
24113
|
contents: [
|
|
23891
24114
|
{
|
|
23892
24115
|
uri: "walkeros://reference/event-model",
|
|
23893
|
-
text: JSON.stringify(
|
|
24116
|
+
text: JSON.stringify(schemas6.eventJsonSchema, null, 2),
|
|
23894
24117
|
mimeType: "application/json"
|
|
23895
24118
|
}
|
|
23896
24119
|
]
|
|
@@ -23909,10 +24132,10 @@ function registerReferenceResources(server) {
|
|
|
23909
24132
|
uri: "walkeros://reference/mapping",
|
|
23910
24133
|
text: JSON.stringify(
|
|
23911
24134
|
{
|
|
23912
|
-
rules:
|
|
23913
|
-
valueConfig:
|
|
23914
|
-
rule:
|
|
23915
|
-
policy:
|
|
24135
|
+
rules: schemas6.rulesJsonSchema,
|
|
24136
|
+
valueConfig: schemas6.valueConfigJsonSchema,
|
|
24137
|
+
rule: schemas6.ruleJsonSchema,
|
|
24138
|
+
policy: schemas6.policyJsonSchema
|
|
23916
24139
|
},
|
|
23917
24140
|
null,
|
|
23918
24141
|
2
|
|
@@ -23933,7 +24156,7 @@ function registerReferenceResources(server) {
|
|
|
23933
24156
|
contents: [
|
|
23934
24157
|
{
|
|
23935
24158
|
uri: "walkeros://reference/consent",
|
|
23936
|
-
text: JSON.stringify(
|
|
24159
|
+
text: JSON.stringify(schemas6.consentJsonSchema, null, 2),
|
|
23937
24160
|
mimeType: "application/json"
|
|
23938
24161
|
}
|
|
23939
24162
|
]
|
|
@@ -24009,7 +24232,7 @@ function registerReferenceResources(server) {
|
|
|
24009
24232
|
contents: [
|
|
24010
24233
|
{
|
|
24011
24234
|
uri: "walkeros://reference/contract",
|
|
24012
|
-
text: JSON.stringify(
|
|
24235
|
+
text: JSON.stringify(schemas6.contractJsonSchema, null, 2),
|
|
24013
24236
|
mimeType: "application/json"
|
|
24014
24237
|
}
|
|
24015
24238
|
]
|
|
@@ -24019,7 +24242,7 @@ function registerReferenceResources(server) {
|
|
|
24019
24242
|
"examples",
|
|
24020
24243
|
"walkeros://reference/examples",
|
|
24021
24244
|
{
|
|
24022
|
-
description: "Complete flow config
|
|
24245
|
+
description: "Complete, tested flow config (flow-complete.json): web, server and warehouse flows with mapping, consent, contracts, routes, state, stores and step examples. Its guide is examples/flow-complete.md in @walkeros/cli.",
|
|
24023
24246
|
mimeType: "application/json"
|
|
24024
24247
|
},
|
|
24025
24248
|
async () => {
|
|
@@ -24087,17 +24310,17 @@ function registerReferenceResources(server) {
|
|
|
24087
24310
|
}
|
|
24088
24311
|
|
|
24089
24312
|
// src/prompts/add-step.ts
|
|
24090
|
-
import { z as
|
|
24313
|
+
import { z as z18 } from "zod";
|
|
24091
24314
|
function registerAddStepPrompt(server) {
|
|
24092
24315
|
server.registerPrompt(
|
|
24093
24316
|
"add-step",
|
|
24094
24317
|
{
|
|
24095
24318
|
description: "Add a source, destination, transformer, or store step to a flow configuration. Guides through package selection, config scaffolding, and wiring.",
|
|
24096
24319
|
argsSchema: {
|
|
24097
|
-
stepType:
|
|
24320
|
+
stepType: z18.string().optional().describe(
|
|
24098
24321
|
"Type of step to add: source, destination, transformer, or store"
|
|
24099
24322
|
),
|
|
24100
|
-
flowPath:
|
|
24323
|
+
flowPath: z18.string().optional().describe("Path to the flow.json file to modify")
|
|
24101
24324
|
}
|
|
24102
24325
|
},
|
|
24103
24326
|
async ({ stepType, flowPath }) => ({
|
|
@@ -24143,14 +24366,14 @@ function registerAddStepPrompt(server) {
|
|
|
24143
24366
|
}
|
|
24144
24367
|
|
|
24145
24368
|
// src/prompts/setup-mapping.ts
|
|
24146
|
-
import { z as
|
|
24369
|
+
import { z as z19 } from "zod";
|
|
24147
24370
|
function registerSetupMappingPrompt(server) {
|
|
24148
24371
|
server.registerPrompt(
|
|
24149
24372
|
"setup-mapping",
|
|
24150
24373
|
{
|
|
24151
24374
|
description: "Set up event mapping for any step in a flow. Teaches mapping syntax and uses package examples as templates.",
|
|
24152
24375
|
argsSchema: {
|
|
24153
|
-
stepName:
|
|
24376
|
+
stepName: z19.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
|
|
24154
24377
|
}
|
|
24155
24378
|
},
|
|
24156
24379
|
async ({ stepName }) => ({
|
|
@@ -24188,14 +24411,14 @@ function registerSetupMappingPrompt(server) {
|
|
|
24188
24411
|
}
|
|
24189
24412
|
|
|
24190
24413
|
// src/prompts/manage-contract.ts
|
|
24191
|
-
import { z as
|
|
24414
|
+
import { z as z20 } from "zod";
|
|
24192
24415
|
function registerManageContractPrompt(server) {
|
|
24193
24416
|
server.registerPrompt(
|
|
24194
24417
|
"manage-contract",
|
|
24195
24418
|
{
|
|
24196
24419
|
description: "Create or update event contracts for a flow. Can generate contracts from existing mappings or scaffold mappings from contracts.",
|
|
24197
24420
|
argsSchema: {
|
|
24198
|
-
direction:
|
|
24421
|
+
direction: z20.string().optional().describe(
|
|
24199
24422
|
'Direction: "from-mappings" (extract contract from existing mappings), "from-scratch" (create new contract), or "to-mappings" (scaffold mappings from contract)'
|
|
24200
24423
|
)
|
|
24201
24424
|
}
|
|
@@ -24239,7 +24462,7 @@ var SERVER_INSTRUCTIONS = `walkerOS is an open-source, privacy-first event data
|
|
|
24239
24462
|
|
|
24240
24463
|
- **Never guess package names.** Always use \`package_search\` first to find exact names, then \`package_get\` for details.
|
|
24241
24464
|
- **Never construct flow configs from memory.** Read \`walkeros://reference/flow-schema\` and use \`package_get\` for package-specific schemas.
|
|
24242
|
-
- **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).
|
|
24243
24466
|
- **Simulate before deploying.** Use \`flow_simulate\` to test with mocked API calls before \`flow_bundle\` or \`flow_push\`.
|
|
24244
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.
|
|
24245
24468
|
|
|
@@ -24697,7 +24920,11 @@ function createStreamableHttpHandler(server, opts = {}) {
|
|
|
24697
24920
|
}
|
|
24698
24921
|
|
|
24699
24922
|
// src/runtime/local.ts
|
|
24923
|
+
import * as fs from "fs";
|
|
24924
|
+
import * as path2 from "path";
|
|
24700
24925
|
import {
|
|
24926
|
+
collectKnownSecrets,
|
|
24927
|
+
loadConfig,
|
|
24701
24928
|
loadJsonConfig,
|
|
24702
24929
|
bundle as bundle2,
|
|
24703
24930
|
push,
|
|
@@ -24706,6 +24933,8 @@ import {
|
|
|
24706
24933
|
simulateCollector,
|
|
24707
24934
|
simulateDestination
|
|
24708
24935
|
} from "@walkeros/cli";
|
|
24936
|
+
import { isObject as isObject3 } from "@walkeros/core";
|
|
24937
|
+
import { schemas as schemas7 } from "@walkeros/core/dev";
|
|
24709
24938
|
|
|
24710
24939
|
// src/runtime/bundle-cache.ts
|
|
24711
24940
|
import { createHash } from "crypto";
|
|
@@ -24796,6 +25025,10 @@ async function getOrBuildBundle(resolvedConfig) {
|
|
|
24796
25025
|
function createLocalRuntime() {
|
|
24797
25026
|
return {
|
|
24798
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
|
+
},
|
|
24799
25032
|
bundle: (input, opts) => bundle2(input, {
|
|
24800
25033
|
flowName: opts.flowName,
|
|
24801
25034
|
stats: opts.stats,
|
|
@@ -24809,51 +25042,84 @@ function createLocalRuntime() {
|
|
|
24809
25042
|
bundlePath = void 0;
|
|
24810
25043
|
}
|
|
24811
25044
|
const common = { bundlePath, flow: opts.flow, silent: true };
|
|
25045
|
+
const config = opts.config ?? input;
|
|
24812
25046
|
switch (opts.stepType) {
|
|
24813
25047
|
case "source":
|
|
24814
|
-
return simulateSource(
|
|
25048
|
+
return simulateSource(config, opts.event, {
|
|
24815
25049
|
sourceId: opts.stepId,
|
|
24816
|
-
...common
|
|
25050
|
+
...common,
|
|
25051
|
+
consent: opts.state?.consent
|
|
24817
25052
|
});
|
|
24818
25053
|
case "transformer":
|
|
24819
|
-
return simulateTransformer(
|
|
24820
|
-
|
|
24821
|
-
|
|
24822
|
-
|
|
24823
|
-
|
|
25054
|
+
return simulateTransformer(config, partialEvent(opts.event), {
|
|
25055
|
+
transformerId: opts.stepId,
|
|
25056
|
+
...common,
|
|
25057
|
+
ingest: opts.ingest,
|
|
25058
|
+
consent: opts.state?.consent
|
|
25059
|
+
});
|
|
24824
25060
|
case "collector":
|
|
24825
|
-
return simulateCollector(
|
|
24826
|
-
|
|
24827
|
-
|
|
24828
|
-
|
|
24829
|
-
|
|
25061
|
+
return simulateCollector(config, partialEvent(opts.event), {
|
|
25062
|
+
collectorName: opts.stepId,
|
|
25063
|
+
...common,
|
|
25064
|
+
state: opts.state,
|
|
25065
|
+
ingest: opts.ingest
|
|
25066
|
+
});
|
|
24830
25067
|
case "destination":
|
|
24831
|
-
return simulateDestination(
|
|
24832
|
-
|
|
24833
|
-
|
|
24834
|
-
|
|
24835
|
-
|
|
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
|
+
});
|
|
24836
25075
|
}
|
|
24837
25076
|
},
|
|
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
|
+
},
|
|
24838
25084
|
push: (input, event, opts) => push(input, event, {
|
|
24839
25085
|
json: true,
|
|
24840
25086
|
flow: opts.flow,
|
|
24841
|
-
platform: opts.platform
|
|
25087
|
+
platform: opts.platform,
|
|
25088
|
+
...opts.config !== void 0 && { raw: opts.config }
|
|
24842
25089
|
})
|
|
24843
25090
|
};
|
|
24844
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
|
+
}
|
|
24845
25111
|
|
|
24846
25112
|
// src/tool-definitions.ts
|
|
24847
|
-
import { z as
|
|
24848
|
-
import { schemas as
|
|
25113
|
+
import { z as z21 } from "zod";
|
|
25114
|
+
import { schemas as schemas8 } from "@walkeros/cli/dev";
|
|
24849
25115
|
var TOOL_DEFINITIONS = [
|
|
24850
25116
|
{
|
|
24851
25117
|
name: "auth",
|
|
24852
25118
|
title: "Authentication",
|
|
24853
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.",
|
|
24854
25120
|
inputSchema: {
|
|
24855
|
-
action:
|
|
24856
|
-
deviceCode:
|
|
25121
|
+
action: z21.enum(["status", "login", "logout"]),
|
|
25122
|
+
deviceCode: z21.string().optional()
|
|
24857
25123
|
},
|
|
24858
25124
|
annotations: {
|
|
24859
25125
|
readOnlyHint: false,
|
|
@@ -24867,7 +25133,7 @@ var TOOL_DEFINITIONS = [
|
|
|
24867
25133
|
title: "Project Management",
|
|
24868
25134
|
description: "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.",
|
|
24869
25135
|
inputSchema: {
|
|
24870
|
-
action:
|
|
25136
|
+
action: z21.enum([
|
|
24871
25137
|
"list",
|
|
24872
25138
|
"get",
|
|
24873
25139
|
"create",
|
|
@@ -24875,8 +25141,8 @@ var TOOL_DEFINITIONS = [
|
|
|
24875
25141
|
"delete",
|
|
24876
25142
|
"set_default"
|
|
24877
25143
|
]),
|
|
24878
|
-
projectId:
|
|
24879
|
-
name:
|
|
25144
|
+
projectId: z21.string().optional(),
|
|
25145
|
+
name: z21.string().optional()
|
|
24880
25146
|
},
|
|
24881
25147
|
annotations: {
|
|
24882
25148
|
readOnlyHint: false,
|
|
@@ -24890,7 +25156,7 @@ var TOOL_DEFINITIONS = [
|
|
|
24890
25156
|
title: "Flow Management",
|
|
24891
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.",
|
|
24892
25158
|
inputSchema: {
|
|
24893
|
-
action:
|
|
25159
|
+
action: z21.enum([
|
|
24894
25160
|
"list",
|
|
24895
25161
|
"get",
|
|
24896
25162
|
"create",
|
|
@@ -24902,19 +25168,19 @@ var TOOL_DEFINITIONS = [
|
|
|
24902
25168
|
"preview_create",
|
|
24903
25169
|
"preview_delete"
|
|
24904
25170
|
]),
|
|
24905
|
-
flowId:
|
|
24906
|
-
projectId:
|
|
24907
|
-
name:
|
|
24908
|
-
content:
|
|
24909
|
-
patch:
|
|
24910
|
-
fields:
|
|
24911
|
-
sort:
|
|
24912
|
-
order:
|
|
24913
|
-
includeDeleted:
|
|
24914
|
-
previewId:
|
|
24915
|
-
flowName:
|
|
24916
|
-
flowSettingsId:
|
|
24917
|
-
siteUrl:
|
|
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()
|
|
24918
25184
|
},
|
|
24919
25185
|
annotations: {
|
|
24920
25186
|
readOnlyHint: false,
|
|
@@ -24928,14 +25194,14 @@ var TOOL_DEFINITIONS = [
|
|
|
24928
25194
|
title: "Deploy Management",
|
|
24929
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.",
|
|
24930
25196
|
inputSchema: {
|
|
24931
|
-
action:
|
|
24932
|
-
projectId:
|
|
24933
|
-
flowId:
|
|
24934
|
-
slug:
|
|
24935
|
-
type:
|
|
24936
|
-
status:
|
|
24937
|
-
wait:
|
|
24938
|
-
flowName:
|
|
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()
|
|
24939
25205
|
},
|
|
24940
25206
|
annotations: {
|
|
24941
25207
|
readOnlyHint: false,
|
|
@@ -24949,12 +25215,12 @@ var TOOL_DEFINITIONS = [
|
|
|
24949
25215
|
title: "Secret Management",
|
|
24950
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).",
|
|
24951
25217
|
inputSchema: {
|
|
24952
|
-
action:
|
|
24953
|
-
projectId:
|
|
24954
|
-
flowId:
|
|
24955
|
-
name:
|
|
24956
|
-
value:
|
|
24957
|
-
secretId:
|
|
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()
|
|
24958
25224
|
},
|
|
24959
25225
|
annotations: {
|
|
24960
25226
|
readOnlyHint: false,
|
|
@@ -24968,17 +25234,17 @@ var TOOL_DEFINITIONS = [
|
|
|
24968
25234
|
title: "Observe Session",
|
|
24969
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.",
|
|
24970
25236
|
inputSchema: {
|
|
24971
|
-
action:
|
|
24972
|
-
flowId:
|
|
24973
|
-
projectId:
|
|
24974
|
-
sessionId:
|
|
24975
|
-
arms:
|
|
24976
|
-
container:
|
|
24977
|
-
preview:
|
|
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()
|
|
24978
25244
|
}).optional(),
|
|
24979
|
-
origins:
|
|
24980
|
-
level:
|
|
24981
|
-
replace:
|
|
25245
|
+
origins: z21.array(z21.string()).optional(),
|
|
25246
|
+
level: z21.enum(["off", "standard", "trace"]).optional(),
|
|
25247
|
+
replace: z21.boolean().optional()
|
|
24982
25248
|
},
|
|
24983
25249
|
annotations: {
|
|
24984
25250
|
readOnlyHint: false,
|
|
@@ -24992,10 +25258,10 @@ var TOOL_DEFINITIONS = [
|
|
|
24992
25258
|
title: "Observe Journeys",
|
|
24993
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.",
|
|
24994
25260
|
inputSchema: {
|
|
24995
|
-
flowId:
|
|
24996
|
-
projectId:
|
|
24997
|
-
traceId:
|
|
24998
|
-
limit:
|
|
25261
|
+
flowId: z21.string(),
|
|
25262
|
+
projectId: z21.string().optional(),
|
|
25263
|
+
traceId: z21.string().optional(),
|
|
25264
|
+
limit: z21.number().int().min(1).max(100).optional()
|
|
24999
25265
|
},
|
|
25000
25266
|
annotations: {
|
|
25001
25267
|
readOnlyHint: true,
|
|
@@ -25007,13 +25273,13 @@ var TOOL_DEFINITIONS = [
|
|
|
25007
25273
|
{
|
|
25008
25274
|
name: "flow_validate",
|
|
25009
25275
|
title: "Validate Flow",
|
|
25010
|
-
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
|
|
25011
|
-
inputSchema:
|
|
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,
|
|
25012
25278
|
annotations: {
|
|
25013
25279
|
readOnlyHint: true,
|
|
25014
25280
|
destructiveHint: false,
|
|
25015
25281
|
idempotentHint: true,
|
|
25016
|
-
openWorldHint:
|
|
25282
|
+
openWorldHint: true
|
|
25017
25283
|
}
|
|
25018
25284
|
},
|
|
25019
25285
|
{
|
|
@@ -25021,9 +25287,9 @@ var TOOL_DEFINITIONS = [
|
|
|
25021
25287
|
title: "Bundle Flow",
|
|
25022
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.",
|
|
25023
25289
|
inputSchema: {
|
|
25024
|
-
...
|
|
25025
|
-
remote:
|
|
25026
|
-
content:
|
|
25290
|
+
...schemas8.BundleInputShape,
|
|
25291
|
+
remote: z21.boolean().optional(),
|
|
25292
|
+
content: z21.record(z21.string(), z21.unknown()).optional()
|
|
25027
25293
|
},
|
|
25028
25294
|
annotations: {
|
|
25029
25295
|
readOnlyHint: false,
|
|
@@ -25035,14 +25301,14 @@ var TOOL_DEFINITIONS = [
|
|
|
25035
25301
|
{
|
|
25036
25302
|
name: "flow_simulate",
|
|
25037
25303
|
title: "Simulate Flow",
|
|
25038
|
-
description:
|
|
25304
|
+
description: FLOW_SIMULATE_DESCRIPTION,
|
|
25039
25305
|
inputSchema: {
|
|
25040
|
-
configPath:
|
|
25041
|
-
event:
|
|
25042
|
-
flow:
|
|
25043
|
-
platform:
|
|
25044
|
-
step:
|
|
25045
|
-
verbose:
|
|
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()
|
|
25046
25312
|
},
|
|
25047
25313
|
annotations: {
|
|
25048
25314
|
// Not read-only: simulation compiles and runs the flow in process.
|
|
@@ -25057,10 +25323,10 @@ var TOOL_DEFINITIONS = [
|
|
|
25057
25323
|
title: "Push Events",
|
|
25058
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.",
|
|
25059
25325
|
inputSchema: {
|
|
25060
|
-
configPath:
|
|
25061
|
-
event:
|
|
25062
|
-
flow:
|
|
25063
|
-
platform:
|
|
25326
|
+
configPath: schemas8.PushInputShape.configPath,
|
|
25327
|
+
event: z21.record(z21.string(), z21.unknown()),
|
|
25328
|
+
flow: schemas8.PushInputShape.flow,
|
|
25329
|
+
platform: schemas8.PushInputShape.platform
|
|
25064
25330
|
},
|
|
25065
25331
|
annotations: {
|
|
25066
25332
|
readOnlyHint: false,
|
|
@@ -25074,11 +25340,11 @@ var TOOL_DEFINITIONS = [
|
|
|
25074
25340
|
title: "Flow Examples",
|
|
25075
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.",
|
|
25076
25342
|
inputSchema: {
|
|
25077
|
-
configPath:
|
|
25078
|
-
flow:
|
|
25079
|
-
step:
|
|
25080
|
-
full:
|
|
25081
|
-
includeHidden:
|
|
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()
|
|
25082
25348
|
},
|
|
25083
25349
|
annotations: {
|
|
25084
25350
|
readOnlyHint: true,
|
|
@@ -25092,8 +25358,8 @@ var TOOL_DEFINITIONS = [
|
|
|
25092
25358
|
title: "Load or Create Flow",
|
|
25093
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.",
|
|
25094
25360
|
inputSchema: {
|
|
25095
|
-
source:
|
|
25096
|
-
platform:
|
|
25361
|
+
source: z21.string().optional(),
|
|
25362
|
+
platform: z21.enum(["web", "server"]).optional()
|
|
25097
25363
|
},
|
|
25098
25364
|
annotations: {
|
|
25099
25365
|
readOnlyHint: true,
|
|
@@ -25107,10 +25373,10 @@ var TOOL_DEFINITIONS = [
|
|
|
25107
25373
|
title: "Search Package",
|
|
25108
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.",
|
|
25109
25375
|
inputSchema: {
|
|
25110
|
-
package:
|
|
25111
|
-
type:
|
|
25112
|
-
platform:
|
|
25113
|
-
version:
|
|
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()
|
|
25114
25380
|
},
|
|
25115
25381
|
annotations: {
|
|
25116
25382
|
readOnlyHint: true,
|
|
@@ -25124,9 +25390,9 @@ var TOOL_DEFINITIONS = [
|
|
|
25124
25390
|
title: "Get Package",
|
|
25125
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".',
|
|
25126
25392
|
inputSchema: {
|
|
25127
|
-
package:
|
|
25128
|
-
version:
|
|
25129
|
-
section:
|
|
25393
|
+
package: z21.string().min(1),
|
|
25394
|
+
version: z21.string().optional(),
|
|
25395
|
+
section: z21.enum(["hints", "examples", "all"]).optional()
|
|
25130
25396
|
},
|
|
25131
25397
|
annotations: {
|
|
25132
25398
|
readOnlyHint: true,
|
|
@@ -25140,8 +25406,8 @@ var TOOL_DEFINITIONS = [
|
|
|
25140
25406
|
title: "Send Feedback",
|
|
25141
25407
|
description: "Send feedback about walkerOS",
|
|
25142
25408
|
inputSchema: {
|
|
25143
|
-
text:
|
|
25144
|
-
anonymous:
|
|
25409
|
+
text: z21.string(),
|
|
25410
|
+
anonymous: z21.boolean().optional()
|
|
25145
25411
|
},
|
|
25146
25412
|
annotations: {
|
|
25147
25413
|
readOnlyHint: false,
|