@walkeros/mcp 4.7.1 → 4.7.2-next-1791213015481
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/README.md +11 -6
- package/dist/index.d.ts +30 -5
- package/dist/index.js +218 -140
- package/dist/index.js.map +1 -1
- package/dist/stdio.js +162 -84
- package/dist/stdio.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -97,6 +97,81 @@ function createHostedRuntime(client) {
|
|
|
97
97
|
import { z as z2 } from "zod";
|
|
98
98
|
import { mcpResult, mcpError as mcpError2 } from "@walkeros/core";
|
|
99
99
|
|
|
100
|
+
// src/user-data.ts
|
|
101
|
+
function wrapUserData(s) {
|
|
102
|
+
const alreadyWrapped = s.startsWith("<user_data>") && s.endsWith("</user_data>") && s.slice(11, -12).indexOf("</user_data>") === -1;
|
|
103
|
+
if (alreadyWrapped) return s;
|
|
104
|
+
const neutralised = s.replace(/<\/user_data>/g, "</user_data_>");
|
|
105
|
+
return `<user_data>${neutralised}</user_data>`;
|
|
106
|
+
}
|
|
107
|
+
var DISPLAY_TEXT_KEYS = /* @__PURE__ */ new Set([
|
|
108
|
+
"name",
|
|
109
|
+
"flowName",
|
|
110
|
+
"summary"
|
|
111
|
+
]);
|
|
112
|
+
function wrapListedRecord(value) {
|
|
113
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
114
|
+
return value;
|
|
115
|
+
const fields = Object.entries(value);
|
|
116
|
+
const out = {};
|
|
117
|
+
for (const [key, field] of fields) {
|
|
118
|
+
out[key] = DISPLAY_TEXT_KEYS.has(key) && typeof field === "string" ? wrapUserData(field) : field;
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
var STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
|
|
123
|
+
"id",
|
|
124
|
+
"flowId",
|
|
125
|
+
"projectId",
|
|
126
|
+
"previewId",
|
|
127
|
+
"version",
|
|
128
|
+
"slug",
|
|
129
|
+
"kind",
|
|
130
|
+
"createdAt",
|
|
131
|
+
"updatedAt",
|
|
132
|
+
"deletedAt",
|
|
133
|
+
"package",
|
|
134
|
+
"platform"
|
|
135
|
+
]);
|
|
136
|
+
var keepStructural = (key) => STRUCTURAL_KEYS.has(key);
|
|
137
|
+
function redactNestedStrings(value, opts) {
|
|
138
|
+
return walk(value, opts);
|
|
139
|
+
}
|
|
140
|
+
function redactDisplayNames(value) {
|
|
141
|
+
return walkDisplay(value);
|
|
142
|
+
}
|
|
143
|
+
function walkDisplay(value) {
|
|
144
|
+
if (Array.isArray(value)) return value.map(walkDisplay);
|
|
145
|
+
if (value && typeof value === "object") {
|
|
146
|
+
const out = {};
|
|
147
|
+
for (const [k, v] of Object.entries(value)) {
|
|
148
|
+
if (DISPLAY_TEXT_KEYS.has(k) && typeof v === "string") {
|
|
149
|
+
out[k] = wrapUserData(v);
|
|
150
|
+
} else {
|
|
151
|
+
out[k] = walkDisplay(v);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
function walk(value, opts) {
|
|
159
|
+
if (typeof value === "string") return wrapUserData(value);
|
|
160
|
+
if (Array.isArray(value)) return value.map((v) => walk(v, opts));
|
|
161
|
+
if (value && typeof value === "object") {
|
|
162
|
+
const out = {};
|
|
163
|
+
for (const [k, v] of Object.entries(value)) {
|
|
164
|
+
if (opts?.skip?.(k) && typeof v === "string") {
|
|
165
|
+
out[k] = v;
|
|
166
|
+
} else {
|
|
167
|
+
out[k] = walk(v, opts);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
|
|
100
175
|
// src/tools/narrow.ts
|
|
101
176
|
import { schemas } from "@walkeros/core/dev";
|
|
102
177
|
function isRecord(value) {
|
|
@@ -150,6 +225,13 @@ function parseToolInput(shape, raw) {
|
|
|
150
225
|
// src/tools/auth.ts
|
|
151
226
|
var TITLE = "Authentication";
|
|
152
227
|
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.";
|
|
228
|
+
var HOST_LOGIN_MESSAGE = "This connection is already authenticated by the host; no login needed.";
|
|
229
|
+
var HOST_LOGOUT_MESSAGE = "This connection is authorized by the host, so there is no session here to log out of. To end it, disconnect walkerOS in your MCP client, or revoke it in the walkerOS app under Account, Connected apps.";
|
|
230
|
+
var STILL_AUTHENTICATED = {
|
|
231
|
+
config: "A newer session was stored while logging out and was kept. Call auth logout again to remove it.",
|
|
232
|
+
env: "WALKEROS_TOKEN is still set for this server process, so calls stay authenticated. Remove it from the MCP server configuration.",
|
|
233
|
+
host: HOST_LOGOUT_MESSAGE
|
|
234
|
+
};
|
|
153
235
|
var inputSchema = {
|
|
154
236
|
action: z2.enum(["status", "login", "logout"]).describe("Authentication action to perform"),
|
|
155
237
|
deviceCode: z2.string().optional().describe(
|
|
@@ -188,10 +270,20 @@ async function authHandlerBody(client, input) {
|
|
|
188
270
|
const user = await client.whoami();
|
|
189
271
|
return mcpResult({
|
|
190
272
|
authenticated: true,
|
|
191
|
-
...fieldsOf(user)
|
|
273
|
+
...redactDisplayNames(fieldsOf(user))
|
|
192
274
|
});
|
|
193
275
|
}
|
|
194
276
|
case "login": {
|
|
277
|
+
if (client.credentialSource() === "host") {
|
|
278
|
+
return mcpResult(
|
|
279
|
+
{ authenticated: true, message: HOST_LOGIN_MESSAGE },
|
|
280
|
+
{
|
|
281
|
+
next: [
|
|
282
|
+
'Use auth with action "status" to see which account you are on'
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
}
|
|
195
287
|
if (deviceCode) {
|
|
196
288
|
const poll = await client.pollForToken(deviceCode, {
|
|
197
289
|
timeoutMs: 6e4
|
|
@@ -236,15 +328,23 @@ async function authHandlerBody(client, input) {
|
|
|
236
328
|
});
|
|
237
329
|
}
|
|
238
330
|
case "logout": {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
331
|
+
if (client.credentialSource() === "host") {
|
|
332
|
+
return mcpError2(new Error(HOST_LOGOUT_MESSAGE));
|
|
333
|
+
}
|
|
334
|
+
const { deleted, envCleared } = await client.logout();
|
|
335
|
+
const remaining = client.credentialSource();
|
|
336
|
+
if (remaining !== null) {
|
|
337
|
+
return mcpResult({
|
|
338
|
+
loggedOut: false,
|
|
339
|
+
message: STILL_AUTHENTICATED[remaining]
|
|
340
|
+
});
|
|
341
|
+
}
|
|
242
342
|
let message;
|
|
243
|
-
if (deleted &&
|
|
343
|
+
if (deleted && envCleared) {
|
|
244
344
|
message = "Logged out. Config removed and WALKEROS_TOKEN cleared from process environment.";
|
|
245
345
|
} else if (deleted) {
|
|
246
346
|
message = "Logged out and config removed.";
|
|
247
|
-
} else if (
|
|
347
|
+
} else if (envCleared) {
|
|
248
348
|
message = "No config found. WALKEROS_TOKEN cleared from process environment.";
|
|
249
349
|
} else {
|
|
250
350
|
message = "No config found, already logged out.";
|
|
@@ -282,79 +382,17 @@ import { z as z3 } from "zod";
|
|
|
282
382
|
import { mcpResult as mcpResult2, mcpError as mcpError3 } from "@walkeros/core";
|
|
283
383
|
|
|
284
384
|
// src/types.ts
|
|
285
|
-
function
|
|
385
|
+
function isAuthenticationError(error) {
|
|
286
386
|
if (!(error instanceof Error)) return false;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
const code = error.code;
|
|
292
|
-
if (!code) return false;
|
|
293
|
-
const upperCode = code.toUpperCase();
|
|
294
|
-
return upperCode === "UNAUTHORIZED" || upperCode === "FORBIDDEN" || upperCode === "401" || upperCode === "403" || upperCode.startsWith("AUTH_");
|
|
387
|
+
if ("status" in error && error.status === 401) return true;
|
|
388
|
+
return "code" in error && error.code === "UNAUTHORIZED";
|
|
295
389
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const alreadyWrapped = s.startsWith("<user_data>") && s.endsWith("</user_data>") && s.slice(11, -12).indexOf("</user_data>") === -1;
|
|
301
|
-
if (alreadyWrapped) return s;
|
|
302
|
-
const neutralised = s.replace(/<\/user_data>/g, "</user_data_>");
|
|
303
|
-
return `<user_data>${neutralised}</user_data>`;
|
|
304
|
-
}
|
|
305
|
-
var STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
|
|
306
|
-
"id",
|
|
307
|
-
"flowId",
|
|
308
|
-
"projectId",
|
|
309
|
-
"previewId",
|
|
310
|
-
"version",
|
|
311
|
-
"slug",
|
|
312
|
-
"kind",
|
|
313
|
-
"createdAt",
|
|
314
|
-
"updatedAt",
|
|
315
|
-
"deletedAt",
|
|
316
|
-
"package",
|
|
317
|
-
"platform"
|
|
318
|
-
]);
|
|
319
|
-
var keepStructural = (key) => STRUCTURAL_KEYS.has(key);
|
|
320
|
-
function redactNestedStrings(value, opts) {
|
|
321
|
-
return walk(value, opts);
|
|
322
|
-
}
|
|
323
|
-
var DISPLAY_NAME_KEYS = /* @__PURE__ */ new Set(["name", "flowName"]);
|
|
324
|
-
function redactDisplayNames(value) {
|
|
325
|
-
return walkDisplay(value);
|
|
326
|
-
}
|
|
327
|
-
function walkDisplay(value) {
|
|
328
|
-
if (Array.isArray(value)) return value.map(walkDisplay);
|
|
329
|
-
if (value && typeof value === "object") {
|
|
330
|
-
const out = {};
|
|
331
|
-
for (const [k, v] of Object.entries(value)) {
|
|
332
|
-
if (DISPLAY_NAME_KEYS.has(k) && typeof v === "string") {
|
|
333
|
-
out[k] = wrapUserData(v);
|
|
334
|
-
} else {
|
|
335
|
-
out[k] = walkDisplay(v);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return out;
|
|
339
|
-
}
|
|
340
|
-
return value;
|
|
341
|
-
}
|
|
342
|
-
function walk(value, opts) {
|
|
343
|
-
if (typeof value === "string") return wrapUserData(value);
|
|
344
|
-
if (Array.isArray(value)) return value.map((v) => walk(v, opts));
|
|
345
|
-
if (value && typeof value === "object") {
|
|
346
|
-
const out = {};
|
|
347
|
-
for (const [k, v] of Object.entries(value)) {
|
|
348
|
-
if (opts?.skip?.(k) && typeof v === "string") {
|
|
349
|
-
out[k] = v;
|
|
350
|
-
} else {
|
|
351
|
-
out[k] = walk(v, opts);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return out;
|
|
355
|
-
}
|
|
356
|
-
return value;
|
|
390
|
+
function isAccessRefusal(error) {
|
|
391
|
+
if (!(error instanceof Error)) return false;
|
|
392
|
+
if ("status" in error && error.status === 403) return true;
|
|
393
|
+
return "code" in error && (error.code === "FORBIDDEN" || error.code === "INSUFFICIENT_SCOPE");
|
|
357
394
|
}
|
|
395
|
+
var AUTH_HINT = 'Are you logged in? Use auth(action: "status") to check.';
|
|
358
396
|
|
|
359
397
|
// src/action-requirements.ts
|
|
360
398
|
function validateActionInput(toolName, action, input, map) {
|
|
@@ -475,10 +513,6 @@ var FRAME_MANAGE_REQUIREMENTS = {
|
|
|
475
513
|
};
|
|
476
514
|
|
|
477
515
|
// src/tools/project-manage.ts
|
|
478
|
-
function wrapProjectName(project) {
|
|
479
|
-
const name = stringField(project, "name");
|
|
480
|
-
return isRecord(project) && name !== void 0 ? { ...project, name: wrapUserData(name) } : project;
|
|
481
|
-
}
|
|
482
516
|
var TITLE2 = "Project Management";
|
|
483
517
|
var DESCRIPTION2 = "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.";
|
|
484
518
|
var inputSchema2 = {
|
|
@@ -536,17 +570,19 @@ async function projectManageHandlerBody(client, input) {
|
|
|
536
570
|
}
|
|
537
571
|
);
|
|
538
572
|
}
|
|
539
|
-
|
|
540
|
-
|
|
573
|
+
return mcpResult2({
|
|
574
|
+
...fieldsOf(projects),
|
|
575
|
+
projects: items.map(wrapListedRecord)
|
|
576
|
+
});
|
|
541
577
|
}
|
|
542
578
|
case "get": {
|
|
543
579
|
const project = await client.getProject({ projectId });
|
|
544
|
-
return mcpResult2(
|
|
580
|
+
return mcpResult2(wrapListedRecord(project));
|
|
545
581
|
}
|
|
546
582
|
case "create": {
|
|
547
583
|
assertParam(name, "name", "create");
|
|
548
584
|
const created = await client.createProject({ name });
|
|
549
|
-
return mcpResult2(
|
|
585
|
+
return mcpResult2(wrapListedRecord(created), {
|
|
550
586
|
next: [
|
|
551
587
|
'Use project_manage with action "set_default" to make this your active project'
|
|
552
588
|
]
|
|
@@ -555,7 +591,7 @@ async function projectManageHandlerBody(client, input) {
|
|
|
555
591
|
case "update": {
|
|
556
592
|
assertParam(name, "name", "update");
|
|
557
593
|
const updated = await client.updateProject({ projectId, name });
|
|
558
|
-
return mcpResult2(
|
|
594
|
+
return mcpResult2(wrapListedRecord(updated));
|
|
559
595
|
}
|
|
560
596
|
case "delete": {
|
|
561
597
|
const deleted = await client.deleteProject({ projectId });
|
|
@@ -579,7 +615,10 @@ async function projectManageHandlerBody(client, input) {
|
|
|
579
615
|
);
|
|
580
616
|
}
|
|
581
617
|
} catch (error) {
|
|
582
|
-
return mcpError3(
|
|
618
|
+
return mcpError3(
|
|
619
|
+
error,
|
|
620
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
621
|
+
);
|
|
583
622
|
}
|
|
584
623
|
}
|
|
585
624
|
function registerProjectManageTool(server, client) {
|
|
@@ -723,9 +762,20 @@ function flowPageUrl(client, projectId, flowId) {
|
|
|
723
762
|
if (flowId === void 0) return void 0;
|
|
724
763
|
return links.flow({ baseUrl: client.appBaseUrl(), projectId, flowId });
|
|
725
764
|
}
|
|
726
|
-
function
|
|
727
|
-
|
|
728
|
-
|
|
765
|
+
function safeFlowPage(data) {
|
|
766
|
+
if (Array.isArray(data)) return { flows: data.map(wrapListedRecord) };
|
|
767
|
+
const flows = isRecord(data) ? data.flows : void 0;
|
|
768
|
+
return isRecord(data) && Array.isArray(flows) ? { ...data, flows: flows.map(wrapListedRecord) } : redactDisplayNames(data);
|
|
769
|
+
}
|
|
770
|
+
function safeFlowGroup(group) {
|
|
771
|
+
const safe = wrapListedRecord(group);
|
|
772
|
+
if (!isRecord(safe)) return safe;
|
|
773
|
+
const { project, flows } = safe;
|
|
774
|
+
return {
|
|
775
|
+
...safe,
|
|
776
|
+
...project !== void 0 && { project: wrapListedRecord(project) },
|
|
777
|
+
...Array.isArray(flows) && { flows: flows.map(wrapListedRecord) }
|
|
778
|
+
};
|
|
729
779
|
}
|
|
730
780
|
function safeDetail(flow) {
|
|
731
781
|
const fields = { ...fieldsOf(flow) };
|
|
@@ -910,9 +960,7 @@ async function flowManageHandlerBody(client, input) {
|
|
|
910
960
|
cursor,
|
|
911
961
|
limit
|
|
912
962
|
});
|
|
913
|
-
|
|
914
|
-
const safe2 = isRecord(data2) && Array.isArray(flows) ? { ...data2, flows: flows.map(safeSummary) } : data2;
|
|
915
|
-
return mcpResult3(safe2);
|
|
963
|
+
return mcpResult3(safeFlowPage(data2));
|
|
916
964
|
}
|
|
917
965
|
const data = await client.listAllFlows({
|
|
918
966
|
sort,
|
|
@@ -921,7 +969,7 @@ async function flowManageHandlerBody(client, input) {
|
|
|
921
969
|
cursor,
|
|
922
970
|
limit
|
|
923
971
|
});
|
|
924
|
-
const safe = Array.isArray(data) ? data.map(
|
|
972
|
+
const safe = Array.isArray(data) ? data.map(safeFlowGroup) : redactDisplayNames(data);
|
|
925
973
|
return mcpResult3(
|
|
926
974
|
{ projects: safe },
|
|
927
975
|
{
|
|
@@ -1152,7 +1200,10 @@ async function flowManageHandlerBody(client, input) {
|
|
|
1152
1200
|
);
|
|
1153
1201
|
}
|
|
1154
1202
|
} catch (error) {
|
|
1155
|
-
return mcpError4(
|
|
1203
|
+
return mcpError4(
|
|
1204
|
+
error,
|
|
1205
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
1206
|
+
);
|
|
1156
1207
|
}
|
|
1157
1208
|
}
|
|
1158
1209
|
function registerFlowManageTool(server, client) {
|
|
@@ -1414,7 +1465,10 @@ async function deployManageHandlerBody(client, input) {
|
|
|
1414
1465
|
);
|
|
1415
1466
|
}
|
|
1416
1467
|
} catch (error) {
|
|
1417
|
-
return mcpError5(
|
|
1468
|
+
return mcpError5(
|
|
1469
|
+
error,
|
|
1470
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
1471
|
+
);
|
|
1418
1472
|
}
|
|
1419
1473
|
}
|
|
1420
1474
|
function registerDeployTool(server, client) {
|
|
@@ -1546,7 +1600,10 @@ async function secretManageHandlerBody(client, input) {
|
|
|
1546
1600
|
);
|
|
1547
1601
|
}
|
|
1548
1602
|
} catch (error) {
|
|
1549
|
-
return mcpError6(
|
|
1603
|
+
return mcpError6(
|
|
1604
|
+
error,
|
|
1605
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
1606
|
+
);
|
|
1550
1607
|
}
|
|
1551
1608
|
}
|
|
1552
1609
|
function registerSecretManageTool(server, client) {
|
|
@@ -1661,7 +1718,10 @@ async function observeJourneysHandlerBody(client, input) {
|
|
|
1661
1718
|
]
|
|
1662
1719
|
});
|
|
1663
1720
|
} catch (error) {
|
|
1664
|
-
return mcpError7(
|
|
1721
|
+
return mcpError7(
|
|
1722
|
+
error,
|
|
1723
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
1724
|
+
);
|
|
1665
1725
|
}
|
|
1666
1726
|
}
|
|
1667
1727
|
function registerObserveJourneysTool(server, client) {
|
|
@@ -1681,6 +1741,28 @@ function registerObserveJourneysTool(server, client) {
|
|
|
1681
1741
|
// src/tools/observe-session.ts
|
|
1682
1742
|
import { z as z8 } from "zod";
|
|
1683
1743
|
import { mcpResult as mcpResult7, mcpError as mcpError8 } from "@walkeros/core";
|
|
1744
|
+
|
|
1745
|
+
// src/tools/feature-gate.ts
|
|
1746
|
+
var FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE";
|
|
1747
|
+
function codeOf(error) {
|
|
1748
|
+
if (!(error instanceof Error) || !("code" in error)) return void 0;
|
|
1749
|
+
const code = error.code;
|
|
1750
|
+
return typeof code === "string" ? code : void 0;
|
|
1751
|
+
}
|
|
1752
|
+
function isFeatureDenial(error) {
|
|
1753
|
+
return codeOf(error) === FEATURE_NOT_AVAILABLE;
|
|
1754
|
+
}
|
|
1755
|
+
function featureDenialHint(feature) {
|
|
1756
|
+
return `The "${feature}" feature is not enabled for this project. Tell the person that "${feature}" needs a plan or project entitlement that unlocks it, which is changed in the app, not through this tool.`;
|
|
1757
|
+
}
|
|
1758
|
+
function errorHint(error, feature, notFoundHint) {
|
|
1759
|
+
if (isFeatureDenial(error)) return featureDenialHint(feature);
|
|
1760
|
+
if (isAuthenticationError(error)) return AUTH_HINT;
|
|
1761
|
+
if (codeOf(error) === "NOT_FOUND") return notFoundHint;
|
|
1762
|
+
return void 0;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// src/tools/observe-session.ts
|
|
1684
1766
|
var TITLE7 = "Observe Session";
|
|
1685
1767
|
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.";
|
|
1686
1768
|
var HINT_SIMULATE_FIRST = "Simulate before preview: flow_simulate checks mapping with no browser.";
|
|
@@ -1838,7 +1920,8 @@ async function resolveSessionId(client, options) {
|
|
|
1838
1920
|
});
|
|
1839
1921
|
return result.sessionId;
|
|
1840
1922
|
} catch (error) {
|
|
1841
|
-
if (
|
|
1923
|
+
if (isAuthenticationError(error) || isAccessRefusal(error) || isFeatureDenial(error))
|
|
1924
|
+
throw error;
|
|
1842
1925
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1843
1926
|
throw new SessionResolutionError(
|
|
1844
1927
|
`${SESSION_RESOLUTION_FAILED} (${detail})`,
|
|
@@ -1846,10 +1929,6 @@ async function resolveSessionId(client, options) {
|
|
|
1846
1929
|
);
|
|
1847
1930
|
}
|
|
1848
1931
|
}
|
|
1849
|
-
function resolveProjectId(client, projectId) {
|
|
1850
|
-
return projectId ?? client.getDefaultProject();
|
|
1851
|
-
}
|
|
1852
|
-
var NO_DEFAULT_PROJECT_ERROR2 = "No project ID given and no default project set. Pass projectId or set one with project_manage set_default.";
|
|
1853
1932
|
function createObserveSessionToolSpec(client) {
|
|
1854
1933
|
return {
|
|
1855
1934
|
name: "observe_session",
|
|
@@ -1876,9 +1955,9 @@ async function observeSessionHandlerBody(client, input) {
|
|
|
1876
1955
|
if (!flowId) {
|
|
1877
1956
|
return mcpError8(new Error("flowId is required for observe_session."));
|
|
1878
1957
|
}
|
|
1879
|
-
const resolvedProjectId =
|
|
1958
|
+
const resolvedProjectId = resolveDefaultProject(client, projectId);
|
|
1880
1959
|
if (!resolvedProjectId) {
|
|
1881
|
-
return mcpError8(new Error(
|
|
1960
|
+
return mcpError8(new Error(NO_DEFAULT_PROJECT_ERROR));
|
|
1882
1961
|
}
|
|
1883
1962
|
try {
|
|
1884
1963
|
switch (action) {
|
|
@@ -1967,7 +2046,10 @@ async function observeSessionHandlerBody(client, input) {
|
|
|
1967
2046
|
);
|
|
1968
2047
|
}
|
|
1969
2048
|
} catch (error) {
|
|
1970
|
-
return mcpError8(
|
|
2049
|
+
return mcpError8(
|
|
2050
|
+
error,
|
|
2051
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
2052
|
+
);
|
|
1971
2053
|
}
|
|
1972
2054
|
}
|
|
1973
2055
|
function registerObserveSessionTool(server, client) {
|
|
@@ -1987,28 +2069,6 @@ function registerObserveSessionTool(server, client) {
|
|
|
1987
2069
|
// src/tools/hub-manage.ts
|
|
1988
2070
|
import { z as z9 } from "zod";
|
|
1989
2071
|
import { mcpResult as mcpResult8, mcpError as mcpError9 } from "@walkeros/core";
|
|
1990
|
-
|
|
1991
|
-
// src/tools/feature-gate.ts
|
|
1992
|
-
var FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE";
|
|
1993
|
-
function codeOf(error) {
|
|
1994
|
-
if (!(error instanceof Error) || !("code" in error)) return void 0;
|
|
1995
|
-
const code = error.code;
|
|
1996
|
-
return typeof code === "string" ? code : void 0;
|
|
1997
|
-
}
|
|
1998
|
-
function isFeatureDenial(error) {
|
|
1999
|
-
return codeOf(error) === FEATURE_NOT_AVAILABLE;
|
|
2000
|
-
}
|
|
2001
|
-
function featureDenialHint(feature) {
|
|
2002
|
-
return `The "${feature}" feature is not enabled for this project. Tell the person that "${feature}" needs a plan or project entitlement that unlocks it, which is changed in the app, not through this tool.`;
|
|
2003
|
-
}
|
|
2004
|
-
function errorHint(error, feature, notFoundHint) {
|
|
2005
|
-
if (isFeatureDenial(error)) return featureDenialHint(feature);
|
|
2006
|
-
if (isAuthError(error)) return AUTH_HINT;
|
|
2007
|
-
if (codeOf(error) === "NOT_FOUND") return notFoundHint;
|
|
2008
|
-
return void 0;
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
// src/tools/hub-manage.ts
|
|
2012
2072
|
var MAX_ANNOTATION_TEXT_LENGTH = 4e3;
|
|
2013
2073
|
var MAX_ANCHOR_KEY_LENGTH = 255;
|
|
2014
2074
|
var MAX_ANCHOR_LABEL_LENGTH = 255;
|
|
@@ -2881,7 +2941,7 @@ async function feedbackHandlerBody(client, input) {
|
|
|
2881
2941
|
const isAnonymous = explicitAnonymous ?? anonymous ?? true;
|
|
2882
2942
|
await client.submitFeedback(text, {
|
|
2883
2943
|
anonymous: isAnonymous,
|
|
2884
|
-
version: "4.7.
|
|
2944
|
+
version: "4.7.2-next-1791213015481"
|
|
2885
2945
|
});
|
|
2886
2946
|
return mcpResult10({ ok: true });
|
|
2887
2947
|
} catch (error) {
|
|
@@ -3673,7 +3733,7 @@ var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
|
|
|
3673
3733
|
var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
|
|
3674
3734
|
var WALKEROS_JSON_PATH = "dist/walkerOS.json";
|
|
3675
3735
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
3676
|
-
var CLIENT_HEADER = "walkeros-mcp/4.7.
|
|
3736
|
+
var CLIENT_HEADER = "walkeros-mcp/4.7.2-next-1791213015481";
|
|
3677
3737
|
function getPackageBaseUrl() {
|
|
3678
3738
|
return process.env.WALKEROS_APP_URL || void 0;
|
|
3679
3739
|
}
|
|
@@ -4091,7 +4151,10 @@ async function flowLoadHandlerBody(client, runtime, input) {
|
|
|
4091
4151
|
}
|
|
4092
4152
|
);
|
|
4093
4153
|
} catch (error) {
|
|
4094
|
-
return mcpError18(
|
|
4154
|
+
return mcpError18(
|
|
4155
|
+
error,
|
|
4156
|
+
isAuthenticationError(error) ? AUTH_HINT : void 0
|
|
4157
|
+
);
|
|
4095
4158
|
}
|
|
4096
4159
|
}
|
|
4097
4160
|
try {
|
|
@@ -4602,7 +4665,7 @@ function registerReferenceResources(server, client) {
|
|
|
4602
4665
|
"consent",
|
|
4603
4666
|
"walkeros://reference/consent",
|
|
4604
4667
|
{
|
|
4605
|
-
description: "JSON Schema for walkerOS consent: destination-level
|
|
4668
|
+
description: "JSON Schema for walkerOS consent: destination-level and field-level consent gating",
|
|
4606
4669
|
mimeType: "application/json"
|
|
4607
4670
|
},
|
|
4608
4671
|
async () => ({
|
|
@@ -4844,7 +4907,7 @@ function registerSetupMappingPrompt(server) {
|
|
|
4844
4907
|
"Policy and consent in mapping:",
|
|
4845
4908
|
"- config.policy runs BEFORE mapping rules \u2014 use it to inject or redact fields on the event.",
|
|
4846
4909
|
"- rule.policy runs after config.policy but before data transformation \u2014 use for event-specific pre-processing.",
|
|
4847
|
-
"- config.consent gates ALL events to this destination. rule.consent
|
|
4910
|
+
"- config.consent gates ALL events to this destination. rule.consent is not enforced yet.",
|
|
4848
4911
|
"- Individual value configs support consent: { marketing: true } for field-level gating."
|
|
4849
4912
|
].join("\n")
|
|
4850
4913
|
}
|
|
@@ -4959,10 +5022,10 @@ Every component in a flow is a **step**: sources capture events, transformers pr
|
|
|
4959
5022
|
- **Mapping** transforms events using data/map/loop/set/condition rules. Same syntax on sources and destinations. Mapping rules use NESTED entity \u2192 action keying: event name "product add" maps to \`{ "product": { "add": Rule } }\`. Wildcards: \`{ "*": { "view": Rule } }\`.
|
|
4960
5023
|
- **Contracts** define event schemas using entity-action keying. Can generate FROM mappings or scaffold mappings FROM contracts.
|
|
4961
5024
|
- **Variables** ($var, $env, $secret, $code, $store) enable DRY, environment-aware config. \`$var.name\` is a reusable flow variable from the top-level \`variables\` block; whole-string refs preserve native type (object/array/scalar), inline interpolation requires a scalar, deep paths via \`$var.name.deep.path\`. \`$env.NAME[:default]\` is an environment variable resolved at bundle/deploy time (non-secret config only). \`$secret.NAME\` is a managed secret the deploy pipeline injects into the server runner at runtime; credentials, tokens, and private keys must use \`$secret\`, not \`$env\`.
|
|
4962
|
-
- **Consent** gates destinations
|
|
5025
|
+
- **Consent** gates destinations (\`config.consent\`) and individual fields (a value's \`consent\`). A mapping rule's \`consent\` is not enforced yet. Privacy-first by design.
|
|
4963
5026
|
- **Routing** uses one grammar in every chain field (\`source.before\`, \`source.next\`, \`transformer.before\`, \`transformer.next\`, \`collector.next\`, \`destination.before\`, \`destination.next\`). A route is a string ID, a sequence (\`["a", "b"]\`), or a RouteConfig: \`{ match?, next }\`, \`{ match?, one: [...] }\` (first match wins), \`{ match?, many: [...] }\` (every match becomes its own copy of the event with its own id and finishes the rest of the path on its own, never merged), or \`{ match?, stop: true }\` (ends that copy). In a sequence, a member's own \`next\` runs right after it, then the sequence continues. \`match\` reads \`{ ingest, event }\` and each route is evaluated when the event reaches it. A \`stop\` in \`collector.next\` drops the event for every destination; per-destination filtering belongs in \`destination.before\`. An array of only route configs is an implicit \`one\`. The optional \`match\` field is omitted to mean always-match (no wildcard literal).
|
|
4964
5027
|
- **Pass-through steps** are transformer entries with no \`code\` and no \`package\`. The runtime synthesizes the push for them automatically. Three flavors share this shape: a \`before\` / \`next\`-only step (named hop reusable across destinations), a \`cache\`-only step (dedup, rate-limit), and a \`mapping\`-only step (declarative event-to-event transform). A pass-through must declare at least one of \`before\`, \`next\`, \`cache\`, or \`mapping\`.
|
|
4965
|
-
- **Mapping at the transformer position** uses the same \`Mapping.Config\` shape as destinations, but the semantic is event-to-event: \`policy\` and
|
|
5028
|
+
- **Mapping at the transformer position** uses the same \`Mapping.Config\` shape as destinations, but the semantic is event-to-event: only config-level \`policy\` and a rule's \`condition\`, \`policy\`, \`name\` (rename) and \`ignore\` (drop from chain) apply. Everything that shapes a vendor payload or gates a destination is a no-op there: config-level \`consent\`, \`include\`, \`data\`, and a rule's \`consent\`, \`include\`, \`remove\`, \`batch\`, \`settings\`, \`extend\`, \`data\`, \`silent\`; validation warns about them (\`TRANSFORMER_MAPPING_NO_OP\`). A \`config.mapping\` wins over a step-level \`mapping\`.
|
|
4966
5029
|
- **Closed-schema rule on transformer entries:** known keys only. Operative keys are \`code\`, \`package\`, \`before\`, \`next\`, \`cache\`, \`mapping\`. Combined with structural keys (\`config\`, \`env\`, \`validate\`, \`disabled\`, \`id\`, etc.). Unknown top-level keys on a transformer step are errors (catches typos like \`dedup: {}\` instead of nested under \`cache\`). \`code\` + \`package\` together is a conflict.
|
|
4967
5030
|
- **Cache** memoizes step output on a configured store. Set \`cache.stop: true\` to short-circuit the chain on HIT (sources default to stop-on-HIT); in a source chain or \`collector.next\` that halts the event for all destinations. Set \`cache.namespace\` to prefix keys; omit it to write keys directly. \`CacheRule.match\` is optional, omit for always-match.
|
|
4968
5031
|
|
|
@@ -5104,7 +5167,7 @@ import {
|
|
|
5104
5167
|
updateProject,
|
|
5105
5168
|
deleteProject,
|
|
5106
5169
|
setDefaultProject,
|
|
5107
|
-
|
|
5170
|
+
resolveProjectId,
|
|
5108
5171
|
listAllFlows,
|
|
5109
5172
|
listFlows,
|
|
5110
5173
|
getFlow,
|
|
@@ -5169,11 +5232,18 @@ var HttpToolClient = class {
|
|
|
5169
5232
|
async deleteProject(options) {
|
|
5170
5233
|
return deleteProject(options);
|
|
5171
5234
|
}
|
|
5235
|
+
/** Refuses while `WALKEROS_PROJECT_ID` names another project (see the CLI). */
|
|
5172
5236
|
setDefaultProject(projectId) {
|
|
5173
5237
|
setDefaultProject(projectId);
|
|
5174
5238
|
}
|
|
5239
|
+
/**
|
|
5240
|
+
* `WALKEROS_PROJECT_ID`, then the CLI config's default, through the same
|
|
5241
|
+
* resolution the CLI's own commands use. Read here, at the door that owns
|
|
5242
|
+
* this process's environment, never in the shared tool layer: a hosted door
|
|
5243
|
+
* runs in a server process whose variables are no person's selection.
|
|
5244
|
+
*/
|
|
5175
5245
|
getDefaultProject() {
|
|
5176
|
-
return
|
|
5246
|
+
return resolveProjectId();
|
|
5177
5247
|
}
|
|
5178
5248
|
async listAllFlows(options) {
|
|
5179
5249
|
return listAllFlows(options);
|
|
@@ -5241,8 +5311,8 @@ var HttpToolClient = class {
|
|
|
5241
5311
|
/**
|
|
5242
5312
|
* Observe session lifecycle over the CLI's authenticated boundary. The trio
|
|
5243
5313
|
* routes through the same `apiFetch` as every other method here, so token
|
|
5244
|
-
* resolution, base URL, and `ApiError` shaping (which
|
|
5245
|
-
* stay identical to the rest of the client.
|
|
5314
|
+
* resolution, base URL, and `ApiError` shaping (which
|
|
5315
|
+
* `isAuthenticationError` reads) stay identical to the rest of the client.
|
|
5246
5316
|
*/
|
|
5247
5317
|
async startObserveSession(options) {
|
|
5248
5318
|
return startObserveSession(options);
|
|
@@ -5298,8 +5368,16 @@ var HttpToolClient = class {
|
|
|
5298
5368
|
credentialSource() {
|
|
5299
5369
|
return credentialSource();
|
|
5300
5370
|
}
|
|
5371
|
+
/**
|
|
5372
|
+
* Revoke and drop the stored session, then clear a `WALKEROS_TOKEN` from
|
|
5373
|
+
* this process: the local door owns its environment, so a later call in the
|
|
5374
|
+
* same session no longer authenticates with it.
|
|
5375
|
+
*/
|
|
5301
5376
|
async logout() {
|
|
5302
|
-
|
|
5377
|
+
const result = await logout();
|
|
5378
|
+
const envCleared = Boolean(process.env.WALKEROS_TOKEN);
|
|
5379
|
+
delete process.env.WALKEROS_TOKEN;
|
|
5380
|
+
return { ...result, envCleared };
|
|
5303
5381
|
}
|
|
5304
5382
|
/**
|
|
5305
5383
|
* The app this local door talks to: `WALKEROS_APP_URL`, then the CLI config
|
|
@@ -5333,7 +5411,7 @@ var HttpToolClient = class {
|
|
|
5333
5411
|
async checkContract() {
|
|
5334
5412
|
return compareContract({
|
|
5335
5413
|
baseUrl: this.appBaseUrl(),
|
|
5336
|
-
client: { type: "mcp", version: "4.7.
|
|
5414
|
+
client: { type: "mcp", version: "4.7.2-next-1791213015481" }
|
|
5337
5415
|
});
|
|
5338
5416
|
}
|
|
5339
5417
|
/** The live public OpenAPI document of `appBaseUrl()`, without a credential. */
|