@respira/wordpress-mcp-server 8.3.6 → 8.3.8

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/__tests__/429299b5-delete-post-empty-envelope.test.d.ts +46 -0
  3. package/dist/__tests__/429299b5-delete-post-empty-envelope.test.d.ts.map +1 -0
  4. package/dist/__tests__/429299b5-delete-post-empty-envelope.test.js +360 -0
  5. package/dist/__tests__/429299b5-delete-post-empty-envelope.test.js.map +1 -0
  6. package/dist/__tests__/agent-signature-clientinfo.test.js +11 -0
  7. package/dist/__tests__/agent-signature-clientinfo.test.js.map +1 -1
  8. package/dist/__tests__/stale-build-and-refresh-silence.test.d.ts +2 -0
  9. package/dist/__tests__/stale-build-and-refresh-silence.test.d.ts.map +1 -0
  10. package/dist/__tests__/stale-build-and-refresh-silence.test.js +76 -0
  11. package/dist/__tests__/stale-build-and-refresh-silence.test.js.map +1 -0
  12. package/dist/agent-signature.d.ts.map +1 -1
  13. package/dist/agent-signature.js +13 -0
  14. package/dist/agent-signature.js.map +1 -1
  15. package/dist/server.d.ts +14 -0
  16. package/dist/server.d.ts.map +1 -1
  17. package/dist/server.js +116 -20
  18. package/dist/server.js.map +1 -1
  19. package/dist/setup.d.ts.map +1 -1
  20. package/dist/setup.js +52 -3
  21. package/dist/setup.js.map +1 -1
  22. package/dist/types/index.d.ts +9 -0
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/dist/version-checker.d.ts +8 -0
  25. package/dist/version-checker.d.ts.map +1 -1
  26. package/dist/version-checker.js +39 -0
  27. package/dist/version-checker.js.map +1 -1
  28. package/dist/wordpress-client.d.ts +52 -6
  29. package/dist/wordpress-client.d.ts.map +1 -1
  30. package/dist/wordpress-client.js +107 -7
  31. package/dist/wordpress-client.js.map +1 -1
  32. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to Respira WordPress MCP Server will be documented in this f
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.3.7] - 2026-08-19
9
+
10
+ ### Fixed
11
+
12
+ - **`delete_post` answered with an empty response and deleted nothing.** The tool is approval-gated on the site, and the gate replies with a token and HTTP 202. 202 is a success, so the request resolved normally rather than raising, and the client method then discarded the body and returned nothing. What reached the caller was a response carrying only the site block: no error to react to, no token to use, and nothing in the activity log either. The body is now returned, so the token arrives and sending it back finishes the delete. `delete_media` had the same handshake broken one layer lower: the dispatcher never forwarded the token it had been given, so the site saw a first-time call every time and issued a new token, forever. Both dispatch sites now forward every parameter their schemas advertise.
13
+ - **`update_element` and `remove_element` rejected the two things the ambiguity error told you to use.** When several elements matched, the site refused to guess and suggested addressing the element by `path` or narrowing with `match_content`. Neither was in either tool's schema, so a strict client could not send them at all, and `find_element` did not declare `path` either. All three now accept them, and `find_element` also declares `text` and `admin_label`. Requires plugin 8.6.33, which makes both remedies actually resolve the ambiguity rather than merely being accepted.
14
+ - **`bulk_pages_operation` documented a rate limit six times stricter than the real one.** It said three runs an hour; the limit is twenty, and dry runs have never counted. Agents plan their work around that number. Corrected, along with the note that a list of search terms is now a supported shape rather than a 500.
15
+
16
+ ### Changed
17
+
18
+ - **`create_theme_builder_template` no longer assigns anything by default.** Omitting `assignments` used to mean site-wide, which on a body template replaced the content of every page. It now creates the template unassigned, and site-wide has to be requested. The schema documents `confirm_live_edit` for the case where an explicit site-wide assignment would claim a slot on a default template that already exists. Requires plugin 8.6.33.
19
+
8
20
  ## [8.3.6] - 2026-08-19
9
21
 
10
22
  ### Added
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Regression test for ticket 429299b5: "respira_delete_post silently does
3
+ * nothing and returns an empty response" (smartgard.ai, plugin 8.6.31 /
4
+ * mcp 8.3.5).
5
+ *
6
+ * Reported symptom: `delete_post` on a genuine Respira-created duplicate came
7
+ * back with a body whose ONLY content was the site block —
8
+ *
9
+ * {"site":{"id":"env-site","name":"WordPress (from env)", ... }}
10
+ *
11
+ * — no success flag, no error, no approval token. The post was untouched, and
12
+ * `list_activity` had no entry for either attempt, which read like the call
13
+ * had been stopped inside the MCP server and never dispatched.
14
+ *
15
+ * Two independent defects, both in this package:
16
+ *
17
+ * 1. `WordPressClient.deletePost()` was `Promise<void>` and threw
18
+ * `response.data` away. The WP approval gate answers a first-time
19
+ * destructive call with `respira_approval_required` at HTTP **202** — a
20
+ * 2xx, so axios resolves rather than throws — carrying
21
+ * `data.approval_request.approval_token`. That entire body was discarded,
22
+ * `undefined` reached `withSiteContext`, which wraps a non-object as
23
+ * `{ result, site }`, and `JSON.stringify` drops the `undefined` key. What
24
+ * the agent received was literally `{"site":{...}}`. This is the same bug
25
+ * `deletePage` had and fixed in v6.11.12; posts were never brought along.
26
+ *
27
+ * 2. `wordpress_delete_media` dispatched as `client.deleteMedia(args.id)`,
28
+ * dropping the `approval_token` the schema advertises and the agent sends.
29
+ * The plugin therefore saw a fresh first call every time and dutifully
30
+ * minted a new token — a token that only ever yields another token.
31
+ * Ticket 927aa7ed fixed the client METHOD and tested the client method, so
32
+ * it passed green against a tool that was still broken end to end. That is
33
+ * why the assertions below run through the dispatcher.
34
+ *
35
+ * The fake site here implements the plugin's real approval semantics
36
+ * (Respira_Tool_Governance): mint on a tokenless call, execute on a call that
37
+ * echoes a known token, and count how many tokens were ever minted so a
38
+ * mint-instead-of-validate loop fails loudly.
39
+ *
40
+ * Mock-adapter plumbing mirrors acf-site-id-routing.test.ts and
41
+ * delete-media-approval-token.test.ts.
42
+ *
43
+ * @since 8.3.7 (ticket 429299b5)
44
+ */
45
+ export {};
46
+ //# sourceMappingURL=429299b5-delete-post-empty-envelope.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"429299b5-delete-post-empty-envelope.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/429299b5-delete-post-empty-envelope.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG"}
@@ -0,0 +1,360 @@
1
+ /**
2
+ * Regression test for ticket 429299b5: "respira_delete_post silently does
3
+ * nothing and returns an empty response" (smartgard.ai, plugin 8.6.31 /
4
+ * mcp 8.3.5).
5
+ *
6
+ * Reported symptom: `delete_post` on a genuine Respira-created duplicate came
7
+ * back with a body whose ONLY content was the site block —
8
+ *
9
+ * {"site":{"id":"env-site","name":"WordPress (from env)", ... }}
10
+ *
11
+ * — no success flag, no error, no approval token. The post was untouched, and
12
+ * `list_activity` had no entry for either attempt, which read like the call
13
+ * had been stopped inside the MCP server and never dispatched.
14
+ *
15
+ * Two independent defects, both in this package:
16
+ *
17
+ * 1. `WordPressClient.deletePost()` was `Promise<void>` and threw
18
+ * `response.data` away. The WP approval gate answers a first-time
19
+ * destructive call with `respira_approval_required` at HTTP **202** — a
20
+ * 2xx, so axios resolves rather than throws — carrying
21
+ * `data.approval_request.approval_token`. That entire body was discarded,
22
+ * `undefined` reached `withSiteContext`, which wraps a non-object as
23
+ * `{ result, site }`, and `JSON.stringify` drops the `undefined` key. What
24
+ * the agent received was literally `{"site":{...}}`. This is the same bug
25
+ * `deletePage` had and fixed in v6.11.12; posts were never brought along.
26
+ *
27
+ * 2. `wordpress_delete_media` dispatched as `client.deleteMedia(args.id)`,
28
+ * dropping the `approval_token` the schema advertises and the agent sends.
29
+ * The plugin therefore saw a fresh first call every time and dutifully
30
+ * minted a new token — a token that only ever yields another token.
31
+ * Ticket 927aa7ed fixed the client METHOD and tested the client method, so
32
+ * it passed green against a tool that was still broken end to end. That is
33
+ * why the assertions below run through the dispatcher.
34
+ *
35
+ * The fake site here implements the plugin's real approval semantics
36
+ * (Respira_Tool_Governance): mint on a tokenless call, execute on a call that
37
+ * echoes a known token, and count how many tokens were ever minted so a
38
+ * mint-instead-of-validate loop fails loudly.
39
+ *
40
+ * Mock-adapter plumbing mirrors acf-site-id-routing.test.ts and
41
+ * delete-media-approval-token.test.ts.
42
+ *
43
+ * @since 8.3.7 (ticket 429299b5)
44
+ */
45
+ import { test } from 'node:test';
46
+ import assert from 'node:assert/strict';
47
+ import axios from 'axios';
48
+ import { readFileSync } from 'node:fs';
49
+ import { RespiraWordPressServer } from '../server.js';
50
+ const callLog = [];
51
+ let currentHandler = null;
52
+ const originalAdapter = axios.defaults.adapter;
53
+ function installMockAdapter() {
54
+ callLog.length = 0;
55
+ axios.defaults.adapter = ((config) => {
56
+ callLog.push({
57
+ method: (config.method || 'get').toLowerCase(),
58
+ url: config.url,
59
+ params: config.params,
60
+ });
61
+ if (!currentHandler) {
62
+ return Promise.reject(new Error('no mock handler installed'));
63
+ }
64
+ const r = currentHandler(config);
65
+ const response = {
66
+ status: r.status,
67
+ statusText: 'OK',
68
+ headers: { 'content-type': 'application/json' },
69
+ config,
70
+ data: r.data,
71
+ request: {},
72
+ };
73
+ // Mirror axios' own validateStatus default: 2xx resolves, everything else
74
+ // rejects. The 202 approval gate resolving rather than throwing is the
75
+ // whole reason defect 1 was invisible, so the mock must not smooth it over.
76
+ if (r.status >= 200 && r.status < 300) {
77
+ return Promise.resolve(response);
78
+ }
79
+ const err = new Error(`Request failed with status code ${r.status}`);
80
+ err.isAxiosError = true;
81
+ err.response = response;
82
+ err.config = config;
83
+ return Promise.reject(err);
84
+ });
85
+ }
86
+ function restoreAdapter() {
87
+ axios.defaults.adapter = originalAdapter;
88
+ currentHandler = null;
89
+ }
90
+ const SITE = {
91
+ id: 'env-site',
92
+ name: 'WordPress (from env)',
93
+ url: 'https://smartgard.ai',
94
+ apiKey: 'respira_test_key',
95
+ default: true,
96
+ };
97
+ function approvalGatedSite(opts) {
98
+ const site = { minted: [], consumed: [], deleted: [], handler: null };
99
+ site.handler = (config) => {
100
+ const url = config.url || '';
101
+ const method = (config.method || 'get').toLowerCase();
102
+ const params = config.params || {};
103
+ if (method === 'delete' && opts.pathRe.test(url)) {
104
+ const id = Number(url.split('/').pop());
105
+ const token = params.approval_token;
106
+ if (token) {
107
+ if (!site.minted.includes(token)) {
108
+ // The plugin returns 403 respira_invalid_approval_token here.
109
+ return {
110
+ status: 403,
111
+ data: {
112
+ code: 'respira_invalid_approval_token',
113
+ message: 'Approval token is invalid or has expired. Request approval again.',
114
+ data: { status: 403 },
115
+ },
116
+ };
117
+ }
118
+ site.consumed.push(token);
119
+ site.deleted.push(id);
120
+ return { status: 200, data: { success: true, message: 'Post deleted successfully.' } };
121
+ }
122
+ // No token: mint one and refuse. HTTP 202 — a 2xx, deliberately.
123
+ const fresh = `tok-${site.minted.length + 1}`;
124
+ site.minted.push(fresh);
125
+ return {
126
+ status: 202,
127
+ data: {
128
+ code: 'respira_approval_required',
129
+ message: `The "${opts.toolName}" tool requires explicit approval before execution.`,
130
+ data: {
131
+ status: 202,
132
+ approval_request: {
133
+ tool_name: opts.toolName,
134
+ predicted_effect: `Permanently delete ${opts.toolName.replace('delete_', '')} ID ${id}.`,
135
+ approval_token: fresh,
136
+ expires_in: 600,
137
+ },
138
+ },
139
+ },
140
+ };
141
+ }
142
+ // Any probe (version negotiation, compatibility) answers harmlessly.
143
+ return { status: 200, data: {} };
144
+ };
145
+ return site;
146
+ }
147
+ /** Run a tool the way production does: dispatch, then wrap in the site envelope. */
148
+ async function callTool(server, name, args) {
149
+ const result = await server.dispatchToolCall(name, args);
150
+ return server.withSiteContext(result, args);
151
+ }
152
+ /** The exact failure shape the customer saw. */
153
+ function isBareSiteEnvelope(value) {
154
+ if (!value || typeof value !== 'object') {
155
+ return false;
156
+ }
157
+ const serialized = JSON.parse(JSON.stringify(value));
158
+ const keys = Object.keys(serialized);
159
+ return keys.length === 1 && keys[0] === 'site';
160
+ }
161
+ // -----------------------------------------------------------------------------
162
+ // delete_post
163
+ // -----------------------------------------------------------------------------
164
+ test('delete_post never returns a bare site envelope (429299b5)', async () => {
165
+ installMockAdapter();
166
+ try {
167
+ const site = approvalGatedSite({ pathRe: /^\/posts\/\d+$/, toolName: 'delete_post' });
168
+ currentHandler = site.handler;
169
+ const server = new RespiraWordPressServer([SITE]);
170
+ const result = await callTool(server, 'wordpress_delete_post', { id: 102058 });
171
+ assert.equal(isBareSiteEnvelope(result), false, 'delete_post returned {"site":{...}} and nothing else — the exact 429299b5 symptom');
172
+ assert.ok(result.site, 'the site block should still be present');
173
+ }
174
+ finally {
175
+ restoreAdapter();
176
+ }
177
+ });
178
+ test('delete_post surfaces the approval request as an actionable payload (429299b5)', async () => {
179
+ installMockAdapter();
180
+ try {
181
+ const site = approvalGatedSite({ pathRe: /^\/posts\/\d+$/, toolName: 'delete_post' });
182
+ currentHandler = site.handler;
183
+ const server = new RespiraWordPressServer([SITE]);
184
+ const result = await callTool(server, 'wordpress_delete_post', { id: 102058 });
185
+ assert.equal(result.code, 'respira_approval_required');
186
+ assert.ok(result.message, 'a refusal must carry a message an agent can relay');
187
+ const token = result?.data?.approval_request?.approval_token;
188
+ assert.equal(token, 'tok-1', 'the approval token must reach the caller; discarding it is what made the tool unusable');
189
+ assert.equal(result.data.approval_request.tool_name, 'delete_post', 'the payload must name the tool the token is bound to');
190
+ }
191
+ finally {
192
+ restoreAdapter();
193
+ }
194
+ });
195
+ test('the delete_post approval token completes the delete instead of minting another (429299b5)', async () => {
196
+ installMockAdapter();
197
+ try {
198
+ const site = approvalGatedSite({ pathRe: /^\/posts\/\d+$/, toolName: 'delete_post' });
199
+ currentHandler = site.handler;
200
+ const server = new RespiraWordPressServer([SITE]);
201
+ const first = await callTool(server, 'wordpress_delete_post', { id: 102058 });
202
+ const token = first.data.approval_request.approval_token;
203
+ const second = await callTool(server, 'wordpress_delete_post', {
204
+ id: 102058,
205
+ approval_token: token,
206
+ });
207
+ assert.equal(second.success, true, 'the second call must complete the delete');
208
+ assert.equal(isBareSiteEnvelope(second), false);
209
+ assert.deepEqual(site.consumed, [token], 'the site must have executed against the echoed token');
210
+ assert.deepEqual(site.deleted, [102058], 'the post must actually be gone');
211
+ assert.equal(site.minted.length, 1, 'a second token was minted — the token was not forwarded, so this is the unbreakable loop again');
212
+ }
213
+ finally {
214
+ restoreAdapter();
215
+ }
216
+ });
217
+ test('delete_post forwards the token verbatim on the wire (429299b5)', async () => {
218
+ installMockAdapter();
219
+ try {
220
+ const site = approvalGatedSite({ pathRe: /^\/posts\/\d+$/, toolName: 'delete_post' });
221
+ site.minted.push('tok-1'); // pretend an earlier call already handed this out
222
+ currentHandler = site.handler;
223
+ const server = new RespiraWordPressServer([SITE]);
224
+ await callTool(server, 'wordpress_delete_post', { id: 7, approval_token: 'tok-1' });
225
+ const deletes = callLog.filter((c) => c.method === 'delete' && /^\/posts\//.test(c.url));
226
+ assert.equal(deletes.length, 1);
227
+ assert.equal(deletes[0].params?.approval_token, 'tok-1');
228
+ }
229
+ finally {
230
+ restoreAdapter();
231
+ }
232
+ });
233
+ test('delete_post refuses structurally, never silently (429299b5)', async () => {
234
+ installMockAdapter();
235
+ try {
236
+ // A refusal the plugin raises at 403: not a duplicate, direct editing off.
237
+ currentHandler = (config) => {
238
+ if ((config.method || '').toLowerCase() === 'delete') {
239
+ return {
240
+ status: 403,
241
+ data: {
242
+ code: 'respira_not_duplicate',
243
+ message: 'Cannot delete original post (ID: 100952). Only Respira duplicates can be deleted.',
244
+ data: { status: 403, original_id: 100952, instructions: ['Duplicate it first.'] },
245
+ },
246
+ };
247
+ }
248
+ return { status: 200, data: {} };
249
+ };
250
+ const server = new RespiraWordPressServer([SITE]);
251
+ await assert.rejects(() => callTool(server, 'wordpress_delete_post', { id: 100952 }), (err) => {
252
+ // A thrown coded error is a structured refusal: the agent gets the
253
+ // plugin's reason. What must never happen is a resolved empty envelope.
254
+ assert.match(String(err.message), /Only Respira duplicates can be deleted/);
255
+ return true;
256
+ }, 'a 403 refusal must surface as an error, not resolve into an empty envelope');
257
+ }
258
+ finally {
259
+ restoreAdapter();
260
+ }
261
+ });
262
+ test('delete_post does not smuggle confirm_live_edit in behind force (429299b5)', async () => {
263
+ installMockAdapter();
264
+ try {
265
+ const site = approvalGatedSite({ pathRe: /^\/posts\/\d+$/, toolName: 'delete_post' });
266
+ currentHandler = site.handler;
267
+ const server = new RespiraWordPressServer([SITE]);
268
+ await callTool(server, 'wordpress_delete_post', { id: 5, force: true });
269
+ const forced = callLog.filter((c) => c.method === 'delete').pop();
270
+ assert.equal(forced?.params?.force, true);
271
+ assert.equal(forced?.params?.confirm_live_edit, undefined, 'force alone must not be escalated into "yes, delete the live original"');
272
+ await callTool(server, 'wordpress_delete_post', { id: 5, force: true, confirm_live_edit: true });
273
+ const confirmed = callLog.filter((c) => c.method === 'delete').pop();
274
+ assert.equal(confirmed?.params?.confirm_live_edit, true, 'explicit confirmation must reach the site');
275
+ }
276
+ finally {
277
+ restoreAdapter();
278
+ }
279
+ });
280
+ // -----------------------------------------------------------------------------
281
+ // delete_media (the second defect in the same ticket)
282
+ // -----------------------------------------------------------------------------
283
+ test('delete_media completes on the returned token rather than looping (429299b5)', async () => {
284
+ installMockAdapter();
285
+ try {
286
+ const site = approvalGatedSite({ pathRe: /^\/media\/\d+$/, toolName: 'delete_media' });
287
+ currentHandler = site.handler;
288
+ const server = new RespiraWordPressServer([SITE]);
289
+ const first = await callTool(server, 'wordpress_delete_media', { id: 4242 });
290
+ assert.equal(isBareSiteEnvelope(first), false);
291
+ const token = first?.data?.approval_request?.approval_token;
292
+ assert.equal(token, 'tok-1', 'the first call must hand back a token');
293
+ const second = await callTool(server, 'wordpress_delete_media', {
294
+ id: 4242,
295
+ approval_token: token,
296
+ });
297
+ assert.equal(second.success, true);
298
+ assert.equal(site.minted.length, 1, 'the dispatcher dropped approval_token again: the site minted a second token instead of executing');
299
+ assert.deepEqual(site.deleted, [4242]);
300
+ }
301
+ finally {
302
+ restoreAdapter();
303
+ }
304
+ });
305
+ test('delete_media forwards force from the dispatcher (429299b5)', async () => {
306
+ installMockAdapter();
307
+ try {
308
+ const site = approvalGatedSite({ pathRe: /^\/media\/\d+$/, toolName: 'delete_media' });
309
+ site.minted.push('tok-1'); // pretend an earlier call already handed this out
310
+ currentHandler = site.handler;
311
+ const server = new RespiraWordPressServer([SITE]);
312
+ await callTool(server, 'wordpress_delete_media', {
313
+ id: 9,
314
+ force: true,
315
+ approval_token: 'tok-1',
316
+ });
317
+ const del = callLog.filter((c) => c.method === 'delete' && /^\/media\//.test(c.url)).pop();
318
+ assert.equal(del?.params?.force, true, 'force is in the schema and must reach the site');
319
+ assert.equal(del?.params?.approval_token, 'tok-1');
320
+ }
321
+ finally {
322
+ restoreAdapter();
323
+ }
324
+ });
325
+ // -----------------------------------------------------------------------------
326
+ // The envelope rule itself
327
+ // -----------------------------------------------------------------------------
328
+ test('a bodyless 2xx delete still produces a structured result, not an empty envelope (429299b5)', async () => {
329
+ installMockAdapter();
330
+ try {
331
+ currentHandler = (config) => {
332
+ if ((config.method || '').toLowerCase() === 'delete') {
333
+ return { status: 204, data: '' };
334
+ }
335
+ return { status: 200, data: {} };
336
+ };
337
+ const server = new RespiraWordPressServer([SITE]);
338
+ const result = await callTool(server, 'wordpress_delete_post', { id: 1 });
339
+ assert.equal(isBareSiteEnvelope(result), false);
340
+ assert.equal(result.success, true);
341
+ assert.equal(result.body_was_empty, true);
342
+ assert.match(String(result.message), /no response body/);
343
+ }
344
+ finally {
345
+ restoreAdapter();
346
+ }
347
+ });
348
+ // getTools() runs capability negotiation against the live site, so the schema
349
+ // is asserted against the SOURCE instead — same approach as
350
+ // woo-card-tools-forward-fse-params.test.ts.
351
+ test('the delete_post schema documents the approval round-trip (429299b5)', () => {
352
+ const src = readFileSync(`${process.cwd()}/src/server.ts`, 'utf8');
353
+ const start = src.indexOf("name: 'wordpress_delete_post',");
354
+ assert.notEqual(start, -1, 'wordpress_delete_post must be registered');
355
+ const block = src.slice(start, src.indexOf('destructiveHint', start));
356
+ assert.match(block, /approval_token:/, 'the agent cannot complete the handshake without a declared approval_token param');
357
+ assert.match(block, /confirm_live_edit:/, 'the plugin requires confirm_live_edit alongside force; the schema must say so');
358
+ assert.match(block, /respira_approval_required/, 'the description must name the code an agent has to branch on');
359
+ });
360
+ //# sourceMappingURL=429299b5-delete-post-empty-envelope.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"429299b5-delete-post-empty-envelope.test.js","sourceRoot":"","sources":["../../src/__tests__/429299b5-delete-post-empty-envelope.test.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,17 @@ test('claude-code self-identification stays claude-code', () => {
21
21
  setMcpClientInfo('claude-code', '2.0.0');
22
22
  assert.strictEqual(detectRespiraAgentSignature().client, 'claude-code');
23
23
  });
24
+ test('hermes agent normalizes to hermes however it names itself', () => {
25
+ setMcpClientInfo('hermes', '0.1');
26
+ assert.strictEqual(detectRespiraAgentSignature().client, 'hermes');
27
+ setMcpClientInfo('Hermes Agent 0.5 (desktop)', '0.5');
28
+ const sig = detectRespiraAgentSignature();
29
+ assert.strictEqual(sig.client, 'hermes');
30
+ assert.strictEqual(sig.source, 'client-info');
31
+ assert.strictEqual(sig.version, '0.5');
32
+ setMcpClientInfo('hermes-probe', '0.1');
33
+ assert.strictEqual(detectRespiraAgentSignature().client, 'hermes');
34
+ });
24
35
  test('unknown but self-declared clients keep their sanitized name', () => {
25
36
  setMcpClientInfo('SomeNew Agent!', null);
26
37
  const sig = detectRespiraAgentSignature();
@@ -1 +1 @@
1
- {"version":3,"file":"agent-signature-clientinfo.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-signature-clientinfo.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;IAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAEnC,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACjD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,CAAC,WAAW,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAC1E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,gBAAgB,CAAC,gBAAgB,EAAE,IAAW,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,eAAe,CAAC;IACnD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC1C,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"agent-signature-clientinfo.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-signature-clientinfo.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;IAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAEnC,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACjD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,CAAC,WAAW,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAC1E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,MAAM,CAAC,WAAW,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEnE,gBAAgB,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEvC,gBAAgB,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,WAAW,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,gBAAgB,CAAC,gBAAgB,EAAE,IAAW,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,eAAe,CAAC;IACnD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC1C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stale-build-and-refresh-silence.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale-build-and-refresh-silence.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/stale-build-and-refresh-silence.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { readFileSync } from 'node:fs';
4
+ import { RespiraVersionChecker } from '../version-checker.js';
5
+ /**
6
+ * Two silences that cost a customer an afternoon, reported 2026-08-20.
7
+ *
8
+ * She added sites on the dashboard and Claude never saw them. Only deleting
9
+ * and reinstalling the connector worked, so she and her AI concluded the
10
+ * connector had a bug. They were right, and it had been fixed eleven days
11
+ * earlier in 8.2.4. She was running 7.1.2.
12
+ *
13
+ * The update notice fired on every single tool call the whole time. It said
14
+ * "a newer MCP version is available", which is true, generic, and ignorable.
15
+ * It never said that the thing she was fighting was the thing the update
16
+ * fixed, so there was nothing to connect the two.
17
+ *
18
+ * The second silence is the same shape one layer down: when the site list
19
+ * cannot be refreshed at all, the refresh returned 0 exactly as it does when
20
+ * there is genuinely nothing new. "Your new site is missing" and "I never
21
+ * looked" were indistinguishable.
22
+ */
23
+ const PKG = '@respira/wordpress-mcp-server';
24
+ test('a build predating the site-refresh fix is told what it is missing', () => {
25
+ const checker = new RespiraVersionChecker(PKG, '7.1.2');
26
+ const missing = checker.missingFixesFor('7.1.2');
27
+ assert.ok(missing.length > 0, 'a 7.1.2 build must be told it is missing behaviour');
28
+ const joined = missing.join(' ');
29
+ // Phrased as the symptom she would recognise, not as a changelog entry.
30
+ assert.match(joined, /added on the dashboard do not appear/i);
31
+ assert.match(joined, /deleted and reinstalled/i);
32
+ });
33
+ test('the symptom is named, not just the version number', () => {
34
+ const checker = new RespiraVersionChecker(PKG, '7.1.2');
35
+ const joined = checker.missingFixesFor('7.1.2').join(' ');
36
+ // The whole failure was a notice that described itself instead of the user's
37
+ // problem. Guard against sliding back to that.
38
+ assert.ok(!/^\s*a newer (mcp )?version is available/i.test(joined), 'the gap text must describe the user-visible symptom, not restate that an update exists');
39
+ });
40
+ test('a current build is told nothing, so the notice stays meaningful', () => {
41
+ const checker = new RespiraVersionChecker(PKG, '99.0.0');
42
+ assert.deepEqual(checker.missingFixesFor('99.0.0'), []);
43
+ });
44
+ test('gaps apply by version order, not by listing order', () => {
45
+ const checker = new RespiraVersionChecker(PKG, '8.2.4');
46
+ const at824 = checker.missingFixesFor('8.2.4');
47
+ const at712 = checker.missingFixesFor('7.1.2');
48
+ // 8.2.4 already HAS the site-refresh fix, so it must not be told it lacks it.
49
+ assert.ok(!at824.join(' ').match(/added on the dashboard do not appear/i), '8.2.4 must not be told it is missing its own fix');
50
+ assert.ok(at712.length > at824.length, 'an older build is missing strictly more');
51
+ });
52
+ test('the notice leads with the missing behaviour when there is any', () => {
53
+ const src = readFileSync(new URL('../../src/server.ts', import.meta.url), 'utf8');
54
+ assert.match(src, /missing behaviour you may be working around right now/, 'the message must lead with consequence, not with the version delta');
55
+ assert.match(src, /missing_fixes: update\.missingFixes/, 'the payload must carry the list');
56
+ });
57
+ test('a refresh that could not run is reported, not silently treated as empty', () => {
58
+ const src = readFileSync(new URL('../../src/server.ts', import.meta.url), 'utf8');
59
+ // Every bail-out branch must record a cause.
60
+ for (const status of ['no_account_token', 'unreachable', 'backend_error', 'disabled']) {
61
+ assert.ok(src.includes(`this.lastSiteRefreshStatus = '${status}'`), `the ${status} branch must record why the refresh produced nothing`);
62
+ }
63
+ // And the success path must clear it, or one failure would poison every
64
+ // later response.
65
+ assert.ok(src.includes("this.lastSiteRefreshStatus = 'ok'"), 'a successful refresh must clear the status');
66
+ });
67
+ test('list_sites explains the silence, and stays quiet when healthy', () => {
68
+ const src = readFileSync(new URL('../../src/server.ts', import.meta.url), 'utf8');
69
+ assert.ok(src.includes('describeSiteRefreshStatus()'), 'list_sites must consult the refresh status');
70
+ assert.ok(src.includes('...(refreshNotice ? { site_refresh: refreshNotice } : {})'), 'the notice must be attached only when there is something to say');
71
+ // A healthy refresh must add no noise, or the signal stops being read.
72
+ assert.match(src, /case 'never_run':\s*\n\s*case 'ok':\s*\n\s*default:\s*\n\s*return null;/, 'ok and never_run must produce no notice');
73
+ // The no-token case is the permanent one, so it must name the fix.
74
+ assert.match(src, /npx @respira\/wordpress-mcp-server --setup/, 'the permanent case must name the action');
75
+ });
76
+ //# sourceMappingURL=stale-build-and-refresh-silence.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale-build-and-refresh-silence.test.js","sourceRoot":"","sources":["../../src/__tests__/stale-build-and-refresh-silence.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-signature.d.ts","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;CACzD;AAkCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAQvE;AAgHD,wBAAgB,2BAA2B,IAAI,qBAAqB,CA4BnE;AAiBD,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB/D"}
1
+ {"version":3,"file":"agent-signature.d.ts","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;CACzD;AAuCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAQvE;AAuHD,wBAAgB,2BAA2B,IAAI,qBAAqB,CA4BnE;AAiBD,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB/D"}
@@ -43,6 +43,12 @@ function normalizeClientInfoName(raw) {
43
43
  return n.includes('antigravity') ? 'antigravity' : 'gemini';
44
44
  if (n.includes('opencode'))
45
45
  return 'opencode';
46
+ // Hermes Agent (Nous Research). It already arrives as a bare "hermes" over
47
+ // stdio, so this branch is not what makes it attributable today: it is what
48
+ // keeps it attributable when the name grows ("Hermes Agent 0.5 (desktop)",
49
+ // "hermes-probe"), instead of minting a new slug per release.
50
+ if (n.includes('hermes'))
51
+ return 'hermes';
46
52
  // Unknown but self-declared: keep the sanitized raw name rather than
47
53
  // guessing. It surfaces new clients in telemetry instead of hiding them.
48
54
  return sanitizeHeaderToken(n);
@@ -142,6 +148,13 @@ function detectClientFromHeuristics() {
142
148
  return 'copilot';
143
149
  if (fingerprint.includes('gemini'))
144
150
  return 'gemini';
151
+ // No hermes branch on purpose. Hermes Agent spawns stdio MCP servers through
152
+ // _build_safe_env(), which copies only PATH/HOME/USER/LANG/LC_ALL/TERM/SHELL/
153
+ // TMPDIR, XDG_*, Windows location vars, and user-declared secrets: no
154
+ // HERMES_* marker survives. It also rewrites argv to
155
+ // `python -m tools.mcp_stdio_watchdog <real command>`, so the ps parent does
156
+ // not name Hermes either. There is nothing real to match on, and inventing a
157
+ // pattern would only mislabel someone else. clientInfo covers it instead.
145
158
  return 'unknown';
146
159
  }
147
160
  function detectVersion(client) {