@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/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
- const { deleted } = await client.logout();
240
- const hadEnvToken = typeof process.env.WALKEROS_TOKEN === "string" && process.env.WALKEROS_TOKEN.length > 0;
241
- delete process.env.WALKEROS_TOKEN;
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 && hadEnvToken) {
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 (hadEnvToken) {
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 isAuthError(error) {
385
+ function isAuthenticationError(error) {
286
386
  if (!(error instanceof Error)) return false;
287
- const msg = error.message.toLowerCase();
288
- if (msg.includes("unauthorized") || msg.includes("forbidden") || msg.includes("invalid token") || msg.includes("token expired") || msg.includes("not authenticated")) {
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
- var AUTH_HINT = 'Are you logged in? Use auth(action: "status") to check.';
297
-
298
- // src/user-data.ts
299
- function wrapUserData(s) {
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
- const safe = Array.isArray(projects) ? items.map(wrapProjectName) : { ...fieldsOf(projects), projects: items.map(wrapProjectName) };
540
- return mcpResult2(safe);
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(wrapProjectName(project));
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(wrapProjectName(created), {
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(wrapProjectName(updated));
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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 safeSummary(flow) {
727
- const name = stringField(flow, "name");
728
- return isRecord(flow) && name !== void 0 ? { ...flow, name: wrapUserData(name) } : flow;
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
- const flows = isRecord(data2) ? data2.flows : void 0;
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(safeSummary) : data;
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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 (isAuthError(error)) throw error;
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 = resolveProjectId(client, projectId);
1958
+ const resolvedProjectId = resolveDefaultProject(client, projectId);
1880
1959
  if (!resolvedProjectId) {
1881
- return mcpError8(new Error(NO_DEFAULT_PROJECT_ERROR2));
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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.1"
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.1";
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(error, isAuthError(error) ? AUTH_HINT : void 0);
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, rule-level, and field-level consent gating",
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 gates specific event types.",
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, mapping rules, and individual fields. Privacy-first by design.
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 per-rule \`policy\`, \`mapping[].name\` (rename), \`mapping[].ignore\` (drop from chain), \`consent\`, and \`include\` apply. Vendor-payload fields (\`data\`, \`silent\`, \`mapping[].data\`) are no-ops at this position.
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
- getDefaultProject,
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 getDefaultProject();
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 `isAuthError` reads)
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
- return logout();
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.1" }
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. */