@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/stdio.js CHANGED
@@ -826,7 +826,7 @@ var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
826
826
  var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
827
827
  var WALKEROS_JSON_PATH = "dist/walkerOS.json";
828
828
  var CACHE_TTL = 5 * 60 * 1e3;
829
- var CLIENT_HEADER = "walkeros-mcp/4.7.1";
829
+ var CLIENT_HEADER = "walkeros-mcp/4.7.2-next-1791213015481";
830
830
  function getPackageBaseUrl() {
831
831
  return process.env.WALKEROS_APP_URL || void 0;
832
832
  }
@@ -1413,16 +1413,15 @@ import { z as z7 } from "zod";
1413
1413
  import { mcpResult as mcpResult7, mcpError as mcpError9 } from "@walkeros/core";
1414
1414
 
1415
1415
  // src/types.ts
1416
- function isAuthError(error) {
1416
+ function isAuthenticationError(error) {
1417
1417
  if (!(error instanceof Error)) return false;
1418
- const msg = error.message.toLowerCase();
1419
- if (msg.includes("unauthorized") || msg.includes("forbidden") || msg.includes("invalid token") || msg.includes("token expired") || msg.includes("not authenticated")) {
1420
- return true;
1421
- }
1422
- const code = error.code;
1423
- if (!code) return false;
1424
- const upperCode = code.toUpperCase();
1425
- return upperCode === "UNAUTHORIZED" || upperCode === "FORBIDDEN" || upperCode === "401" || upperCode === "403" || upperCode.startsWith("AUTH_");
1418
+ if ("status" in error && error.status === 401) return true;
1419
+ return "code" in error && error.code === "UNAUTHORIZED";
1420
+ }
1421
+ function isAccessRefusal(error) {
1422
+ if (!(error instanceof Error)) return false;
1423
+ if ("status" in error && error.status === 403) return true;
1424
+ return "code" in error && (error.code === "FORBIDDEN" || error.code === "INSUFFICIENT_SCOPE");
1426
1425
  }
1427
1426
  var AUTH_HINT = 'Are you logged in? Use auth(action: "status") to check.';
1428
1427
 
@@ -1433,6 +1432,21 @@ function wrapUserData(s) {
1433
1432
  const neutralised = s.replace(/<\/user_data>/g, "</user_data_>");
1434
1433
  return `<user_data>${neutralised}</user_data>`;
1435
1434
  }
1435
+ var DISPLAY_TEXT_KEYS = /* @__PURE__ */ new Set([
1436
+ "name",
1437
+ "flowName",
1438
+ "summary"
1439
+ ]);
1440
+ function wrapListedRecord(value) {
1441
+ if (typeof value !== "object" || value === null || Array.isArray(value))
1442
+ return value;
1443
+ const fields = Object.entries(value);
1444
+ const out = {};
1445
+ for (const [key, field] of fields) {
1446
+ out[key] = DISPLAY_TEXT_KEYS.has(key) && typeof field === "string" ? wrapUserData(field) : field;
1447
+ }
1448
+ return out;
1449
+ }
1436
1450
  var STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
1437
1451
  "id",
1438
1452
  "flowId",
@@ -1451,7 +1465,6 @@ var keepStructural = (key) => STRUCTURAL_KEYS.has(key);
1451
1465
  function redactNestedStrings(value, opts) {
1452
1466
  return walk(value, opts);
1453
1467
  }
1454
- var DISPLAY_NAME_KEYS = /* @__PURE__ */ new Set(["name", "flowName"]);
1455
1468
  function redactDisplayNames(value) {
1456
1469
  return walkDisplay(value);
1457
1470
  }
@@ -1460,7 +1473,7 @@ function walkDisplay(value) {
1460
1473
  if (value && typeof value === "object") {
1461
1474
  const out = {};
1462
1475
  for (const [k, v] of Object.entries(value)) {
1463
- if (DISPLAY_NAME_KEYS.has(k) && typeof v === "string") {
1476
+ if (DISPLAY_TEXT_KEYS.has(k) && typeof v === "string") {
1464
1477
  out[k] = wrapUserData(v);
1465
1478
  } else {
1466
1479
  out[k] = walkDisplay(v);
@@ -1565,7 +1578,10 @@ async function flowLoadHandlerBody(client, runtime, input) {
1565
1578
  }
1566
1579
  );
1567
1580
  } catch (error) {
1568
- return mcpError9(error, isAuthError(error) ? AUTH_HINT : void 0);
1581
+ return mcpError9(
1582
+ error,
1583
+ isAuthenticationError(error) ? AUTH_HINT : void 0
1584
+ );
1569
1585
  }
1570
1586
  }
1571
1587
  try {
@@ -1664,7 +1680,7 @@ async function feedbackHandlerBody(client, input) {
1664
1680
  const isAnonymous = explicitAnonymous ?? anonymous ?? true;
1665
1681
  await client.submitFeedback(text, {
1666
1682
  anonymous: isAnonymous,
1667
- version: "4.7.1"
1683
+ version: "4.7.2-next-1791213015481"
1668
1684
  });
1669
1685
  return mcpResult8({ ok: true });
1670
1686
  } catch (error) {
@@ -1814,6 +1830,13 @@ import { z as z9 } from "zod";
1814
1830
  import { mcpResult as mcpResult10, mcpError as mcpError11 } from "@walkeros/core";
1815
1831
  var TITLE9 = "Authentication";
1816
1832
  var DESCRIPTION8 = "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.";
1833
+ var HOST_LOGIN_MESSAGE = "This connection is already authenticated by the host; no login needed.";
1834
+ 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.";
1835
+ var STILL_AUTHENTICATED = {
1836
+ config: "A newer session was stored while logging out and was kept. Call auth logout again to remove it.",
1837
+ env: "WALKEROS_TOKEN is still set for this server process, so calls stay authenticated. Remove it from the MCP server configuration.",
1838
+ host: HOST_LOGOUT_MESSAGE
1839
+ };
1817
1840
  var inputSchema9 = {
1818
1841
  action: z9.enum(["status", "login", "logout"]).describe("Authentication action to perform"),
1819
1842
  deviceCode: z9.string().optional().describe(
@@ -1852,10 +1875,20 @@ async function authHandlerBody(client, input) {
1852
1875
  const user = await client.whoami();
1853
1876
  return mcpResult10({
1854
1877
  authenticated: true,
1855
- ...fieldsOf(user)
1878
+ ...redactDisplayNames(fieldsOf(user))
1856
1879
  });
1857
1880
  }
1858
1881
  case "login": {
1882
+ if (client.credentialSource() === "host") {
1883
+ return mcpResult10(
1884
+ { authenticated: true, message: HOST_LOGIN_MESSAGE },
1885
+ {
1886
+ next: [
1887
+ 'Use auth with action "status" to see which account you are on'
1888
+ ]
1889
+ }
1890
+ );
1891
+ }
1859
1892
  if (deviceCode) {
1860
1893
  const poll = await client.pollForToken(deviceCode, {
1861
1894
  timeoutMs: 6e4
@@ -1900,15 +1933,23 @@ async function authHandlerBody(client, input) {
1900
1933
  });
1901
1934
  }
1902
1935
  case "logout": {
1903
- const { deleted } = await client.logout();
1904
- const hadEnvToken = typeof process.env.WALKEROS_TOKEN === "string" && process.env.WALKEROS_TOKEN.length > 0;
1905
- delete process.env.WALKEROS_TOKEN;
1936
+ if (client.credentialSource() === "host") {
1937
+ return mcpError11(new Error(HOST_LOGOUT_MESSAGE));
1938
+ }
1939
+ const { deleted, envCleared } = await client.logout();
1940
+ const remaining = client.credentialSource();
1941
+ if (remaining !== null) {
1942
+ return mcpResult10({
1943
+ loggedOut: false,
1944
+ message: STILL_AUTHENTICATED[remaining]
1945
+ });
1946
+ }
1906
1947
  let message;
1907
- if (deleted && hadEnvToken) {
1948
+ if (deleted && envCleared) {
1908
1949
  message = "Logged out. Config removed and WALKEROS_TOKEN cleared from process environment.";
1909
1950
  } else if (deleted) {
1910
1951
  message = "Logged out and config removed.";
1911
- } else if (hadEnvToken) {
1952
+ } else if (envCleared) {
1912
1953
  message = "No config found. WALKEROS_TOKEN cleared from process environment.";
1913
1954
  } else {
1914
1955
  message = "No config found, already logged out.";
@@ -2064,10 +2105,6 @@ var FRAME_MANAGE_REQUIREMENTS = {
2064
2105
  };
2065
2106
 
2066
2107
  // src/tools/project-manage.ts
2067
- function wrapProjectName(project) {
2068
- const name = stringField(project, "name");
2069
- return isRecord(project) && name !== void 0 ? { ...project, name: wrapUserData(name) } : project;
2070
- }
2071
2108
  var TITLE10 = "Project Management";
2072
2109
  var DESCRIPTION9 = "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.";
2073
2110
  var inputSchema10 = {
@@ -2125,17 +2162,19 @@ async function projectManageHandlerBody(client, input) {
2125
2162
  }
2126
2163
  );
2127
2164
  }
2128
- const safe = Array.isArray(projects) ? items.map(wrapProjectName) : { ...fieldsOf(projects), projects: items.map(wrapProjectName) };
2129
- return mcpResult11(safe);
2165
+ return mcpResult11({
2166
+ ...fieldsOf(projects),
2167
+ projects: items.map(wrapListedRecord)
2168
+ });
2130
2169
  }
2131
2170
  case "get": {
2132
2171
  const project = await client.getProject({ projectId });
2133
- return mcpResult11(wrapProjectName(project));
2172
+ return mcpResult11(wrapListedRecord(project));
2134
2173
  }
2135
2174
  case "create": {
2136
2175
  assertParam(name, "name", "create");
2137
2176
  const created = await client.createProject({ name });
2138
- return mcpResult11(wrapProjectName(created), {
2177
+ return mcpResult11(wrapListedRecord(created), {
2139
2178
  next: [
2140
2179
  'Use project_manage with action "set_default" to make this your active project'
2141
2180
  ]
@@ -2144,7 +2183,7 @@ async function projectManageHandlerBody(client, input) {
2144
2183
  case "update": {
2145
2184
  assertParam(name, "name", "update");
2146
2185
  const updated = await client.updateProject({ projectId, name });
2147
- return mcpResult11(wrapProjectName(updated));
2186
+ return mcpResult11(wrapListedRecord(updated));
2148
2187
  }
2149
2188
  case "delete": {
2150
2189
  const deleted = await client.deleteProject({ projectId });
@@ -2168,7 +2207,10 @@ async function projectManageHandlerBody(client, input) {
2168
2207
  );
2169
2208
  }
2170
2209
  } catch (error) {
2171
- return mcpError12(error, isAuthError(error) ? AUTH_HINT : void 0);
2210
+ return mcpError12(
2211
+ error,
2212
+ isAuthenticationError(error) ? AUTH_HINT : void 0
2213
+ );
2172
2214
  }
2173
2215
  }
2174
2216
  function registerProjectManageTool(server, client) {
@@ -2303,9 +2345,20 @@ function flowPageUrl(client, projectId, flowId) {
2303
2345
  if (flowId === void 0) return void 0;
2304
2346
  return links.flow({ baseUrl: client.appBaseUrl(), projectId, flowId });
2305
2347
  }
2306
- function safeSummary(flow) {
2307
- const name = stringField(flow, "name");
2308
- return isRecord(flow) && name !== void 0 ? { ...flow, name: wrapUserData(name) } : flow;
2348
+ function safeFlowPage(data) {
2349
+ if (Array.isArray(data)) return { flows: data.map(wrapListedRecord) };
2350
+ const flows = isRecord(data) ? data.flows : void 0;
2351
+ return isRecord(data) && Array.isArray(flows) ? { ...data, flows: flows.map(wrapListedRecord) } : redactDisplayNames(data);
2352
+ }
2353
+ function safeFlowGroup(group) {
2354
+ const safe = wrapListedRecord(group);
2355
+ if (!isRecord(safe)) return safe;
2356
+ const { project, flows } = safe;
2357
+ return {
2358
+ ...safe,
2359
+ ...project !== void 0 && { project: wrapListedRecord(project) },
2360
+ ...Array.isArray(flows) && { flows: flows.map(wrapListedRecord) }
2361
+ };
2309
2362
  }
2310
2363
  function safeDetail(flow) {
2311
2364
  const fields = { ...fieldsOf(flow) };
@@ -2490,9 +2543,7 @@ async function flowManageHandlerBody(client, input) {
2490
2543
  cursor,
2491
2544
  limit
2492
2545
  });
2493
- const flows = isRecord(data2) ? data2.flows : void 0;
2494
- const safe2 = isRecord(data2) && Array.isArray(flows) ? { ...data2, flows: flows.map(safeSummary) } : data2;
2495
- return mcpResult12(safe2);
2546
+ return mcpResult12(safeFlowPage(data2));
2496
2547
  }
2497
2548
  const data = await client.listAllFlows({
2498
2549
  sort,
@@ -2501,7 +2552,7 @@ async function flowManageHandlerBody(client, input) {
2501
2552
  cursor,
2502
2553
  limit
2503
2554
  });
2504
- const safe = Array.isArray(data) ? data.map(safeSummary) : data;
2555
+ const safe = Array.isArray(data) ? data.map(safeFlowGroup) : redactDisplayNames(data);
2505
2556
  return mcpResult12(
2506
2557
  { projects: safe },
2507
2558
  {
@@ -2732,7 +2783,10 @@ async function flowManageHandlerBody(client, input) {
2732
2783
  );
2733
2784
  }
2734
2785
  } catch (error) {
2735
- return mcpError13(error, isAuthError(error) ? AUTH_HINT : void 0);
2786
+ return mcpError13(
2787
+ error,
2788
+ isAuthenticationError(error) ? AUTH_HINT : void 0
2789
+ );
2736
2790
  }
2737
2791
  }
2738
2792
  function registerFlowManageTool(server, client) {
@@ -2994,7 +3048,10 @@ async function deployManageHandlerBody(client, input) {
2994
3048
  );
2995
3049
  }
2996
3050
  } catch (error) {
2997
- return mcpError14(error, isAuthError(error) ? AUTH_HINT : void 0);
3051
+ return mcpError14(
3052
+ error,
3053
+ isAuthenticationError(error) ? AUTH_HINT : void 0
3054
+ );
2998
3055
  }
2999
3056
  }
3000
3057
  function registerDeployTool(server, client) {
@@ -3126,7 +3183,10 @@ async function secretManageHandlerBody(client, input) {
3126
3183
  );
3127
3184
  }
3128
3185
  } catch (error) {
3129
- return mcpError15(error, isAuthError(error) ? AUTH_HINT : void 0);
3186
+ return mcpError15(
3187
+ error,
3188
+ isAuthenticationError(error) ? AUTH_HINT : void 0
3189
+ );
3130
3190
  }
3131
3191
  }
3132
3192
  function registerSecretManageTool(server, client) {
@@ -3241,7 +3301,10 @@ async function observeJourneysHandlerBody(client, input) {
3241
3301
  ]
3242
3302
  });
3243
3303
  } catch (error) {
3244
- return mcpError16(error, isAuthError(error) ? AUTH_HINT : void 0);
3304
+ return mcpError16(
3305
+ error,
3306
+ isAuthenticationError(error) ? AUTH_HINT : void 0
3307
+ );
3245
3308
  }
3246
3309
  }
3247
3310
  function registerObserveJourneysTool(server, client) {
@@ -3261,6 +3324,28 @@ function registerObserveJourneysTool(server, client) {
3261
3324
  // src/tools/observe-session.ts
3262
3325
  import { z as z15 } from "zod";
3263
3326
  import { mcpResult as mcpResult16, mcpError as mcpError17 } from "@walkeros/core";
3327
+
3328
+ // src/tools/feature-gate.ts
3329
+ var FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE";
3330
+ function codeOf(error) {
3331
+ if (!(error instanceof Error) || !("code" in error)) return void 0;
3332
+ const code = error.code;
3333
+ return typeof code === "string" ? code : void 0;
3334
+ }
3335
+ function isFeatureDenial(error) {
3336
+ return codeOf(error) === FEATURE_NOT_AVAILABLE;
3337
+ }
3338
+ function featureDenialHint(feature) {
3339
+ 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.`;
3340
+ }
3341
+ function errorHint(error, feature, notFoundHint) {
3342
+ if (isFeatureDenial(error)) return featureDenialHint(feature);
3343
+ if (isAuthenticationError(error)) return AUTH_HINT;
3344
+ if (codeOf(error) === "NOT_FOUND") return notFoundHint;
3345
+ return void 0;
3346
+ }
3347
+
3348
+ // src/tools/observe-session.ts
3264
3349
  var TITLE15 = "Observe Session";
3265
3350
  var DESCRIPTION14 = "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.";
3266
3351
  var HINT_SIMULATE_FIRST = "Simulate before preview: flow_simulate checks mapping with no browser.";
@@ -3418,7 +3503,8 @@ async function resolveSessionId(client, options) {
3418
3503
  });
3419
3504
  return result.sessionId;
3420
3505
  } catch (error) {
3421
- if (isAuthError(error)) throw error;
3506
+ if (isAuthenticationError(error) || isAccessRefusal(error) || isFeatureDenial(error))
3507
+ throw error;
3422
3508
  const detail = error instanceof Error ? error.message : String(error);
3423
3509
  throw new SessionResolutionError(
3424
3510
  `${SESSION_RESOLUTION_FAILED} (${detail})`,
@@ -3426,10 +3512,6 @@ async function resolveSessionId(client, options) {
3426
3512
  );
3427
3513
  }
3428
3514
  }
3429
- function resolveProjectId(client, projectId) {
3430
- return projectId ?? client.getDefaultProject();
3431
- }
3432
- var NO_DEFAULT_PROJECT_ERROR2 = "No project ID given and no default project set. Pass projectId or set one with project_manage set_default.";
3433
3515
  function createObserveSessionToolSpec(client) {
3434
3516
  return {
3435
3517
  name: "observe_session",
@@ -3456,9 +3538,9 @@ async function observeSessionHandlerBody(client, input) {
3456
3538
  if (!flowId) {
3457
3539
  return mcpError17(new Error("flowId is required for observe_session."));
3458
3540
  }
3459
- const resolvedProjectId = resolveProjectId(client, projectId);
3541
+ const resolvedProjectId = resolveDefaultProject(client, projectId);
3460
3542
  if (!resolvedProjectId) {
3461
- return mcpError17(new Error(NO_DEFAULT_PROJECT_ERROR2));
3543
+ return mcpError17(new Error(NO_DEFAULT_PROJECT_ERROR));
3462
3544
  }
3463
3545
  try {
3464
3546
  switch (action) {
@@ -3547,7 +3629,10 @@ async function observeSessionHandlerBody(client, input) {
3547
3629
  );
3548
3630
  }
3549
3631
  } catch (error) {
3550
- return mcpError17(error, isAuthError(error) ? AUTH_HINT : void 0);
3632
+ return mcpError17(
3633
+ error,
3634
+ isAuthenticationError(error) ? AUTH_HINT : void 0
3635
+ );
3551
3636
  }
3552
3637
  }
3553
3638
  function registerObserveSessionTool(server, client) {
@@ -3567,28 +3652,6 @@ function registerObserveSessionTool(server, client) {
3567
3652
  // src/tools/hub-manage.ts
3568
3653
  import { z as z16 } from "zod";
3569
3654
  import { mcpResult as mcpResult17, mcpError as mcpError18 } from "@walkeros/core";
3570
-
3571
- // src/tools/feature-gate.ts
3572
- var FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE";
3573
- function codeOf(error) {
3574
- if (!(error instanceof Error) || !("code" in error)) return void 0;
3575
- const code = error.code;
3576
- return typeof code === "string" ? code : void 0;
3577
- }
3578
- function isFeatureDenial(error) {
3579
- return codeOf(error) === FEATURE_NOT_AVAILABLE;
3580
- }
3581
- function featureDenialHint(feature) {
3582
- 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.`;
3583
- }
3584
- function errorHint(error, feature, notFoundHint) {
3585
- if (isFeatureDenial(error)) return featureDenialHint(feature);
3586
- if (isAuthError(error)) return AUTH_HINT;
3587
- if (codeOf(error) === "NOT_FOUND") return notFoundHint;
3588
- return void 0;
3589
- }
3590
-
3591
- // src/tools/hub-manage.ts
3592
3655
  var MAX_ANNOTATION_TEXT_LENGTH = 4e3;
3593
3656
  var MAX_ANCHOR_KEY_LENGTH = 255;
3594
3657
  var MAX_ANCHOR_LABEL_LENGTH = 255;
@@ -4541,7 +4604,7 @@ function registerReferenceResources(server, client) {
4541
4604
  "consent",
4542
4605
  "walkeros://reference/consent",
4543
4606
  {
4544
- description: "JSON Schema for walkerOS consent: destination-level, rule-level, and field-level consent gating",
4607
+ description: "JSON Schema for walkerOS consent: destination-level and field-level consent gating",
4545
4608
  mimeType: "application/json"
4546
4609
  },
4547
4610
  async () => ({
@@ -4783,7 +4846,7 @@ function registerSetupMappingPrompt(server) {
4783
4846
  "Policy and consent in mapping:",
4784
4847
  "- config.policy runs BEFORE mapping rules \u2014 use it to inject or redact fields on the event.",
4785
4848
  "- rule.policy runs after config.policy but before data transformation \u2014 use for event-specific pre-processing.",
4786
- "- config.consent gates ALL events to this destination. rule.consent gates specific event types.",
4849
+ "- config.consent gates ALL events to this destination. rule.consent is not enforced yet.",
4787
4850
  "- Individual value configs support consent: { marketing: true } for field-level gating."
4788
4851
  ].join("\n")
4789
4852
  }
@@ -4898,10 +4961,10 @@ Every component in a flow is a **step**: sources capture events, transformers pr
4898
4961
  - **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 } }\`.
4899
4962
  - **Contracts** define event schemas using entity-action keying. Can generate FROM mappings or scaffold mappings FROM contracts.
4900
4963
  - **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\`.
4901
- - **Consent** gates destinations, mapping rules, and individual fields. Privacy-first by design.
4964
+ - **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.
4902
4965
  - **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).
4903
4966
  - **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\`.
4904
- - **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.
4967
+ - **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\`.
4905
4968
  - **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.
4906
4969
  - **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.
4907
4970
 
@@ -5110,7 +5173,7 @@ import {
5110
5173
  updateProject,
5111
5174
  deleteProject,
5112
5175
  setDefaultProject,
5113
- getDefaultProject,
5176
+ resolveProjectId,
5114
5177
  listAllFlows,
5115
5178
  listFlows,
5116
5179
  getFlow,
@@ -5175,11 +5238,18 @@ var HttpToolClient = class {
5175
5238
  async deleteProject(options) {
5176
5239
  return deleteProject(options);
5177
5240
  }
5241
+ /** Refuses while `WALKEROS_PROJECT_ID` names another project (see the CLI). */
5178
5242
  setDefaultProject(projectId) {
5179
5243
  setDefaultProject(projectId);
5180
5244
  }
5245
+ /**
5246
+ * `WALKEROS_PROJECT_ID`, then the CLI config's default, through the same
5247
+ * resolution the CLI's own commands use. Read here, at the door that owns
5248
+ * this process's environment, never in the shared tool layer: a hosted door
5249
+ * runs in a server process whose variables are no person's selection.
5250
+ */
5181
5251
  getDefaultProject() {
5182
- return getDefaultProject();
5252
+ return resolveProjectId();
5183
5253
  }
5184
5254
  async listAllFlows(options) {
5185
5255
  return listAllFlows(options);
@@ -5247,8 +5317,8 @@ var HttpToolClient = class {
5247
5317
  /**
5248
5318
  * Observe session lifecycle over the CLI's authenticated boundary. The trio
5249
5319
  * routes through the same `apiFetch` as every other method here, so token
5250
- * resolution, base URL, and `ApiError` shaping (which `isAuthError` reads)
5251
- * stay identical to the rest of the client.
5320
+ * resolution, base URL, and `ApiError` shaping (which
5321
+ * `isAuthenticationError` reads) stay identical to the rest of the client.
5252
5322
  */
5253
5323
  async startObserveSession(options) {
5254
5324
  return startObserveSession(options);
@@ -5304,8 +5374,16 @@ var HttpToolClient = class {
5304
5374
  credentialSource() {
5305
5375
  return credentialSource();
5306
5376
  }
5377
+ /**
5378
+ * Revoke and drop the stored session, then clear a `WALKEROS_TOKEN` from
5379
+ * this process: the local door owns its environment, so a later call in the
5380
+ * same session no longer authenticates with it.
5381
+ */
5307
5382
  async logout() {
5308
- return logout();
5383
+ const result = await logout();
5384
+ const envCleared = Boolean(process.env.WALKEROS_TOKEN);
5385
+ delete process.env.WALKEROS_TOKEN;
5386
+ return { ...result, envCleared };
5309
5387
  }
5310
5388
  /**
5311
5389
  * The app this local door talks to: `WALKEROS_APP_URL`, then the CLI config
@@ -5339,7 +5417,7 @@ var HttpToolClient = class {
5339
5417
  async checkContract() {
5340
5418
  return compareContract({
5341
5419
  baseUrl: this.appBaseUrl(),
5342
- client: { type: "mcp", version: "4.7.1" }
5420
+ client: { type: "mcp", version: "4.7.2-next-1791213015481" }
5343
5421
  });
5344
5422
  }
5345
5423
  /** The live public OpenAPI document of `appBaseUrl()`, without a credential. */
@@ -5550,7 +5628,7 @@ function parseJson(content) {
5550
5628
  }
5551
5629
 
5552
5630
  // src/stdio.ts
5553
- setClientContext({ type: "mcp", version: "4.7.1" });
5631
+ setClientContext({ type: "mcp", version: "4.7.2-next-1791213015481" });
5554
5632
  process.on("uncaughtException", (err) => {
5555
5633
  const emitter = getMcpEmitterSingleton();
5556
5634
  if (emitter) {
@@ -5570,7 +5648,7 @@ process.on("unhandledRejection", (reason) => {
5570
5648
  async function main() {
5571
5649
  const server = createWalkerOSMcpServer({
5572
5650
  client: new HttpToolClient(),
5573
- version: "4.7.1",
5651
+ version: "4.7.2-next-1791213015481",
5574
5652
  runtime: createLocalRuntime()
5575
5653
  });
5576
5654
  const transport = new StdioServerTransport();
@@ -5581,7 +5659,7 @@ main().catch(async (error) => {
5581
5659
  try {
5582
5660
  const emitter = await createMcpEmitter({
5583
5661
  clientInfo: void 0,
5584
- packageVersion: "4.7.1"
5662
+ packageVersion: "4.7.2-next-1791213015481"
5585
5663
  });
5586
5664
  await emitter.emitError("startup");
5587
5665
  } catch {