@walkeros/mcp 4.7.2-next-1791147139360 → 4.7.2

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 CHANGED
@@ -148,11 +148,11 @@ Read these before writing a configuration by hand.
148
148
 
149
149
  ## Environment variables
150
150
 
151
- | Variable | Required | Default | Purpose |
152
- | --------------------- | -------- | ------------------------- | ------------------------------------------------------------------------- |
153
- | `WALKEROS_TOKEN` | No | none | Automation token (`wos_pat_...`), an alternative to the `auth` tool login |
154
- | `WALKEROS_PROJECT_ID` | No | none | Active project ID (`proj_...`) |
155
- | `WALKEROS_APP_URL` | No | `https://app.walkeros.io` | Base URL override |
151
+ | Variable | Required | Default | Purpose |
152
+ | --------------------- | -------- | ------------------------- | -------------------------------------------------------------------------- |
153
+ | `WALKEROS_TOKEN` | No | none | Automation token (`wos_pat_...`), an alternative to the `auth` tool login |
154
+ | `WALKEROS_PROJECT_ID` | No | none | Project (`proj_...`) for calls without `projectId`, ahead of `set_default` |
155
+ | `WALKEROS_APP_URL` | No | `https://app.walkeros.io` | Base URL override |
156
156
 
157
157
  ## Programmatic usage
158
158
 
@@ -193,6 +193,11 @@ AI SDK, call `createToolHandlers(client, version, runtime)` or import
193
193
  `TOOL_DEFINITIONS` and supply your own `ToolClient`. The stdio binary stays
194
194
  available as `@walkeros/mcp/stdio` and the `walkeros-mcp` bin entry.
195
195
 
196
+ A `ToolClient` served inside a host that authenticates every request itself
197
+ returns `'host'` from `credentialSource()`. The `auth` tool then reports the
198
+ connection as logged in, answers `login` with "no login needed" and refuses
199
+ `logout`, which never reaches the client: the connection ends in the host.
200
+
196
201
  A `ToolClient` may implement `checkContract()` and `openapiDocument()`. The
197
202
  `diagnostics` tool reports the first as its contract verdict, `unknown` when it
198
203
  is absent; the `walkeros://reference/openapi` resource serves the second.
package/dist/index.d.ts CHANGED
@@ -370,6 +370,8 @@ interface ToolClient {
370
370
  }): Promise<unknown>;
371
371
  setDefaultProject(projectId: string): void;
372
372
  getDefaultProject(): string | null;
373
+ /** Every project's flows, as an array of `{ project: { id, name }, flows }`
374
+ * groups whose `flows` are the rows `listFlows` answers for that project. */
373
375
  listAllFlows(options?: {
374
376
  sort?: string;
375
377
  order?: 'asc' | 'desc';
@@ -524,15 +526,24 @@ interface ToolClient {
524
526
  timeoutMs?: number;
525
527
  }): Promise<DeviceLoginResult>;
526
528
  whoami(): Promise<unknown>;
527
- /** Where a credential would come from, without resolving or refreshing it. */
528
- credentialSource(): 'env' | 'config' | null;
529
+ /**
530
+ * Where a credential would come from, without resolving or refreshing it:
531
+ * `'env'` (`WALKEROS_TOKEN`), `'config'` (a stored login), `'host'` (the
532
+ * door is served inside a host that authenticates every request itself, so
533
+ * this process holds no login to start or end), or null (none).
534
+ */
535
+ credentialSource(): 'env' | 'config' | 'host' | null;
529
536
  /**
530
537
  * Retire the session. Where the credential was issued to this process, that
531
538
  * means revoking it with the server before dropping it locally; a plane
532
- * holding a bearer it did not issue reports nothing deleted.
539
+ * holding a bearer it did not issue reports nothing deleted. `envCleared`
540
+ * reports that the door also dropped a `WALKEROS_TOKEN` from its own process
541
+ * environment, which only a door that owns its process does. The `auth`
542
+ * tool never calls this on a `'host'` door.
533
543
  */
534
544
  logout(): Promise<{
535
545
  deleted: boolean;
546
+ envCleared?: boolean;
536
547
  }>;
537
548
  /**
538
549
  * The base URL of the walkerOS app this door talks to, without a trailing
@@ -762,7 +773,14 @@ declare class HttpToolClient implements ToolClient {
762
773
  deleteProject(options: {
763
774
  projectId?: string;
764
775
  }): Promise<unknown>;
776
+ /** Refuses while `WALKEROS_PROJECT_ID` names another project (see the CLI). */
765
777
  setDefaultProject(projectId: string): void;
778
+ /**
779
+ * `WALKEROS_PROJECT_ID`, then the CLI config's default, through the same
780
+ * resolution the CLI's own commands use. Read here, at the door that owns
781
+ * this process's environment, never in the shared tool layer: a hosted door
782
+ * runs in a server process whose variables are no person's selection.
783
+ */
766
784
  getDefaultProject(): string | null;
767
785
  listAllFlows(options?: {
768
786
  sort?: string;
@@ -906,8 +924,15 @@ declare class HttpToolClient implements ToolClient {
906
924
  }): Promise<DeviceLoginResult>;
907
925
  whoami(): Promise<unknown>;
908
926
  credentialSource(): 'env' | 'config' | null;
927
+ /**
928
+ * Revoke and drop the stored session, then clear a `WALKEROS_TOKEN` from
929
+ * this process: the local door owns its environment, so a later call in the
930
+ * same session no longer authenticates with it.
931
+ */
909
932
  logout(): Promise<{
910
933
  deleted: boolean;
934
+ superseded: boolean;
935
+ envCleared: boolean;
911
936
  }>;
912
937
  /**
913
938
  * The app this local door talks to: `WALKEROS_APP_URL`, then the CLI config
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.";
@@ -294,67 +394,6 @@ function isAccessRefusal(error) {
294
394
  }
295
395
  var AUTH_HINT = 'Are you logged in? Use auth(action: "status") to check.';
296
396
 
297
- // src/user-data.ts
298
- function wrapUserData(s) {
299
- const alreadyWrapped = s.startsWith("<user_data>") && s.endsWith("</user_data>") && s.slice(11, -12).indexOf("</user_data>") === -1;
300
- if (alreadyWrapped) return s;
301
- const neutralised = s.replace(/<\/user_data>/g, "</user_data_>");
302
- return `<user_data>${neutralised}</user_data>`;
303
- }
304
- var STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
305
- "id",
306
- "flowId",
307
- "projectId",
308
- "previewId",
309
- "version",
310
- "slug",
311
- "kind",
312
- "createdAt",
313
- "updatedAt",
314
- "deletedAt",
315
- "package",
316
- "platform"
317
- ]);
318
- var keepStructural = (key) => STRUCTURAL_KEYS.has(key);
319
- function redactNestedStrings(value, opts) {
320
- return walk(value, opts);
321
- }
322
- var DISPLAY_NAME_KEYS = /* @__PURE__ */ new Set(["name", "flowName"]);
323
- function redactDisplayNames(value) {
324
- return walkDisplay(value);
325
- }
326
- function walkDisplay(value) {
327
- if (Array.isArray(value)) return value.map(walkDisplay);
328
- if (value && typeof value === "object") {
329
- const out = {};
330
- for (const [k, v] of Object.entries(value)) {
331
- if (DISPLAY_NAME_KEYS.has(k) && typeof v === "string") {
332
- out[k] = wrapUserData(v);
333
- } else {
334
- out[k] = walkDisplay(v);
335
- }
336
- }
337
- return out;
338
- }
339
- return value;
340
- }
341
- function walk(value, opts) {
342
- if (typeof value === "string") return wrapUserData(value);
343
- if (Array.isArray(value)) return value.map((v) => walk(v, opts));
344
- if (value && typeof value === "object") {
345
- const out = {};
346
- for (const [k, v] of Object.entries(value)) {
347
- if (opts?.skip?.(k) && typeof v === "string") {
348
- out[k] = v;
349
- } else {
350
- out[k] = walk(v, opts);
351
- }
352
- }
353
- return out;
354
- }
355
- return value;
356
- }
357
-
358
397
  // src/action-requirements.ts
359
398
  function validateActionInput(toolName, action, input, map) {
360
399
  const rule = map[action];
@@ -474,10 +513,6 @@ var FRAME_MANAGE_REQUIREMENTS = {
474
513
  };
475
514
 
476
515
  // src/tools/project-manage.ts
477
- function wrapProjectName(project) {
478
- const name = stringField(project, "name");
479
- return isRecord(project) && name !== void 0 ? { ...project, name: wrapUserData(name) } : project;
480
- }
481
516
  var TITLE2 = "Project Management";
482
517
  var DESCRIPTION2 = "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.";
483
518
  var inputSchema2 = {
@@ -535,17 +570,19 @@ async function projectManageHandlerBody(client, input) {
535
570
  }
536
571
  );
537
572
  }
538
- const safe = Array.isArray(projects) ? items.map(wrapProjectName) : { ...fieldsOf(projects), projects: items.map(wrapProjectName) };
539
- return mcpResult2(safe);
573
+ return mcpResult2({
574
+ ...fieldsOf(projects),
575
+ projects: items.map(wrapListedRecord)
576
+ });
540
577
  }
541
578
  case "get": {
542
579
  const project = await client.getProject({ projectId });
543
- return mcpResult2(wrapProjectName(project));
580
+ return mcpResult2(wrapListedRecord(project));
544
581
  }
545
582
  case "create": {
546
583
  assertParam(name, "name", "create");
547
584
  const created = await client.createProject({ name });
548
- return mcpResult2(wrapProjectName(created), {
585
+ return mcpResult2(wrapListedRecord(created), {
549
586
  next: [
550
587
  'Use project_manage with action "set_default" to make this your active project'
551
588
  ]
@@ -554,7 +591,7 @@ async function projectManageHandlerBody(client, input) {
554
591
  case "update": {
555
592
  assertParam(name, "name", "update");
556
593
  const updated = await client.updateProject({ projectId, name });
557
- return mcpResult2(wrapProjectName(updated));
594
+ return mcpResult2(wrapListedRecord(updated));
558
595
  }
559
596
  case "delete": {
560
597
  const deleted = await client.deleteProject({ projectId });
@@ -725,9 +762,20 @@ function flowPageUrl(client, projectId, flowId) {
725
762
  if (flowId === void 0) return void 0;
726
763
  return links.flow({ baseUrl: client.appBaseUrl(), projectId, flowId });
727
764
  }
728
- function safeSummary(flow) {
729
- const name = stringField(flow, "name");
730
- 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
+ };
731
779
  }
732
780
  function safeDetail(flow) {
733
781
  const fields = { ...fieldsOf(flow) };
@@ -912,9 +960,7 @@ async function flowManageHandlerBody(client, input) {
912
960
  cursor,
913
961
  limit
914
962
  });
915
- const flows = isRecord(data2) ? data2.flows : void 0;
916
- const safe2 = isRecord(data2) && Array.isArray(flows) ? { ...data2, flows: flows.map(safeSummary) } : data2;
917
- return mcpResult3(safe2);
963
+ return mcpResult3(safeFlowPage(data2));
918
964
  }
919
965
  const data = await client.listAllFlows({
920
966
  sort,
@@ -923,7 +969,7 @@ async function flowManageHandlerBody(client, input) {
923
969
  cursor,
924
970
  limit
925
971
  });
926
- const safe = Array.isArray(data) ? data.map(safeSummary) : data;
972
+ const safe = Array.isArray(data) ? data.map(safeFlowGroup) : redactDisplayNames(data);
927
973
  return mcpResult3(
928
974
  { projects: safe },
929
975
  {
@@ -1883,10 +1929,6 @@ async function resolveSessionId(client, options) {
1883
1929
  );
1884
1930
  }
1885
1931
  }
1886
- function resolveProjectId(client, projectId) {
1887
- return projectId ?? client.getDefaultProject();
1888
- }
1889
- var NO_DEFAULT_PROJECT_ERROR2 = "No project ID given and no default project set. Pass projectId or set one with project_manage set_default.";
1890
1932
  function createObserveSessionToolSpec(client) {
1891
1933
  return {
1892
1934
  name: "observe_session",
@@ -1913,9 +1955,9 @@ async function observeSessionHandlerBody(client, input) {
1913
1955
  if (!flowId) {
1914
1956
  return mcpError8(new Error("flowId is required for observe_session."));
1915
1957
  }
1916
- const resolvedProjectId = resolveProjectId(client, projectId);
1958
+ const resolvedProjectId = resolveDefaultProject(client, projectId);
1917
1959
  if (!resolvedProjectId) {
1918
- return mcpError8(new Error(NO_DEFAULT_PROJECT_ERROR2));
1960
+ return mcpError8(new Error(NO_DEFAULT_PROJECT_ERROR));
1919
1961
  }
1920
1962
  try {
1921
1963
  switch (action) {
@@ -2899,7 +2941,7 @@ async function feedbackHandlerBody(client, input) {
2899
2941
  const isAnonymous = explicitAnonymous ?? anonymous ?? true;
2900
2942
  await client.submitFeedback(text, {
2901
2943
  anonymous: isAnonymous,
2902
- version: "4.7.2-next-1791147139360"
2944
+ version: "4.7.2"
2903
2945
  });
2904
2946
  return mcpResult10({ ok: true });
2905
2947
  } catch (error) {
@@ -3691,7 +3733,7 @@ var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
3691
3733
  var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
3692
3734
  var WALKEROS_JSON_PATH = "dist/walkerOS.json";
3693
3735
  var CACHE_TTL = 5 * 60 * 1e3;
3694
- var CLIENT_HEADER = "walkeros-mcp/4.7.2-next-1791147139360";
3736
+ var CLIENT_HEADER = "walkeros-mcp/4.7.2";
3695
3737
  function getPackageBaseUrl() {
3696
3738
  return process.env.WALKEROS_APP_URL || void 0;
3697
3739
  }
@@ -4983,7 +5025,7 @@ Every component in a flow is a **step**: sources capture events, transformers pr
4983
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.
4984
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).
4985
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\`.
4986
- - **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), and \`include\` apply. \`consent\` is not enforced at this position. 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\`.
4987
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.
4988
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.
4989
5031
 
@@ -5125,7 +5167,7 @@ import {
5125
5167
  updateProject,
5126
5168
  deleteProject,
5127
5169
  setDefaultProject,
5128
- getDefaultProject,
5170
+ resolveProjectId,
5129
5171
  listAllFlows,
5130
5172
  listFlows,
5131
5173
  getFlow,
@@ -5190,11 +5232,18 @@ var HttpToolClient = class {
5190
5232
  async deleteProject(options) {
5191
5233
  return deleteProject(options);
5192
5234
  }
5235
+ /** Refuses while `WALKEROS_PROJECT_ID` names another project (see the CLI). */
5193
5236
  setDefaultProject(projectId) {
5194
5237
  setDefaultProject(projectId);
5195
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
+ */
5196
5245
  getDefaultProject() {
5197
- return getDefaultProject();
5246
+ return resolveProjectId();
5198
5247
  }
5199
5248
  async listAllFlows(options) {
5200
5249
  return listAllFlows(options);
@@ -5319,8 +5368,16 @@ var HttpToolClient = class {
5319
5368
  credentialSource() {
5320
5369
  return credentialSource();
5321
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
+ */
5322
5376
  async logout() {
5323
- 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 };
5324
5381
  }
5325
5382
  /**
5326
5383
  * The app this local door talks to: `WALKEROS_APP_URL`, then the CLI config
@@ -5354,7 +5411,7 @@ var HttpToolClient = class {
5354
5411
  async checkContract() {
5355
5412
  return compareContract({
5356
5413
  baseUrl: this.appBaseUrl(),
5357
- client: { type: "mcp", version: "4.7.2-next-1791147139360" }
5414
+ client: { type: "mcp", version: "4.7.2" }
5358
5415
  });
5359
5416
  }
5360
5417
  /** The live public OpenAPI document of `appBaseUrl()`, without a credential. */