@kontextmind/kxm 0.7.98 → 0.7.99

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.98",
14
+ "version": "0.7.99",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -365,6 +365,13 @@ All notable user-facing changes are documented here. The project follows [Semant
365
365
  - **Workflow prompts no longer point agents at `.kxm/config`**, a path KXM refuses.
366
366
  - **`kxm gate signal` and `kxm workflow wait` inside a KXM project reach the hub for hub
367
367
  runs.** They go to the local Runtime only for a run its store holds.
368
+ - **`kxm peer inbox` lists the requests waiting for a named CLI agent.** It returned
369
+ `{"messages":[]}` every time. The hub now serves `GET /v1/agents/:id/inbox`
370
+ (agent-authenticated, project-scoped): the caller's queued and delivered requests,
371
+ oldest first, acknowledging nothing. Run with a stable `KXM_AGENT_NAME` (for example
372
+ `codex`) to list requests peers queued for it while it was offline, then answer them
373
+ with `kxm peer reply`. The Pi extension's `kxm_inbox` tool now refuses instead of
374
+ returning an empty list, because Pi activates each inbound request as a turn itself.
368
375
 
369
376
  - **The Claude plugin's SessionStart hook is one bundled, read-only, project-scoped
370
377
  script.** The two shell hooks it replaces (`kxm session brief --status` and
@@ -210,7 +210,7 @@ CLI (run with the recipient's `KXM_AGENT_NAME`):
210
210
  kxm peer reply msg_779f5e0f22e04ac1af6078589a874971 "The plan is sound. Add a test for a zero discount."
211
211
  ```
212
212
 
213
- Only the recipient can reply, and only once. From the CLI, `kxm peer inbox` always returns an empty list, because a one-shot command has no long-running inbox. Use `kxm dash --screen inbox` to see pending requests.
213
+ Only the recipient can reply, and only once. From the CLI, `kxm peer inbox` lists the requests still waiting for the agent named by `KXM_AGENT_NAME`, including ones queued while it was offline, without acknowledging them. The default `cli-<pid>` name is a new agent on every call, so its list is empty.
214
214
 
215
215
  ## Choose a delivery mode
216
216
 
@@ -291,7 +291,7 @@ Errors about `workflowContext` are covered in [Peer provenance and quorum gates]
291
291
  | A request stays `delivered` | The recipient's turn, tool, or provider call is still running, or a Claude Code session restarted after acknowledging it. | Wait, or cancel and send it again with a new idempotency key. |
292
292
  | `kxm_fanout` returns `pending` | The local wait ended before a reply. | Use the returned message IDs with `kxm_get`, or repeat the exact call. |
293
293
  | Claude Code never sees requests | Channel mode is off or blocked by policy. | Use `kxm_inbox` and `kxm_reply`. |
294
- | `kxm peer inbox` is always empty | The CLI has no long-running inbox. | Use `kxm dash --screen inbox`. |
294
+ | `kxm peer inbox` is always empty | `KXM_AGENT_NAME` is unset, so each call registers a new `cli-<pid>` agent that nobody has addressed. | Set `KXM_AGENT_NAME` to the name peers send to. |
295
295
 
296
296
  For hub-level problems, see [Troubleshoot KXM](../operations/troubleshooting.md).
297
297
 
@@ -2397,18 +2397,21 @@ kxm peer fanout --targets reviewer critic --content "Independent review of PR 42
2397
2397
  kxm peer inbox
2398
2398
  ```
2399
2399
 
2400
- List inbound peer requests. From the CLI this always returns `{"messages":[]}`: the inbox lives in a long-running harness session, which a one-shot CLI call does not have. Use `kxm dash --screen inbox` to see pending requests.
2400
+ List the inbound peer requests addressed to this agent that still need a reply, oldest first, read from the hub (`GET /v1/agents/<agentId>/inbox`). Only a stable `KXM_AGENT_NAME` has an inbox: a registered name that is offline keeps its agent ID, so a later call as the same name lists what peers queued for it with `peer send --allow-offline`. The default `cli-<pid>` is a new agent on every call, and its list is always empty. Answer each request with `peer reply` under the same name.
2401
2401
 
2402
2402
  | Option | Argument | Default | Description |
2403
2403
  |---|---|---|---|
2404
2404
  | `--payload` | `<json>` | none | JSON payload |
2405
2405
 
2406
+ - Reads only. Listing acknowledges nothing, so a request stays `queued` for push delivery. Output key: `messages`, each a full message record (`id`, `fromName`, `content`, `status` `queued` or `delivered`, `expiresAt`).
2407
+ - The call registers the name while it runs, so it exits 1 (`command_failed`, `agent name already active in project`) when another session holds that name online.
2408
+
2406
2409
  ```bash
2407
- kxm peer inbox --json
2410
+ KXM_AGENT_NAME=codex kxm peer inbox --json
2408
2411
  ```
2409
2412
 
2410
2413
  ```text
2411
- {"schema":"kxm.cli-result.v1","messages":[]}
2414
+ {"schema":"kxm.cli-result.v1","messages":[{"id":"msg_1f0c…","project":"kxm","from":"agt_9d2e…","fromName":"reviewer","to":"agt_4b7a…","toName":"codex","content":"Review the retry loop in src/sync.ts","delivery":"followUp","hops":0,"maxHops":5,"seq":1,"createdAt":"2026-09-23T21:40:00.000Z","expiresAt":"2026-09-24T21:40:00.000Z","status":"queued"}]}
2412
2415
  ```
2413
2416
 
2414
2417
  ### `kxm peer reply`
@@ -3590,7 +3593,6 @@ These are behaviors of the current build that differ from what the help text or
3590
3593
 
3591
3594
  - `kxm routing benchmark` prints constant placeholder figures.
3592
3595
  - `kxm task sync` does not contact GitHub or Jira.
3593
- - `kxm peer inbox` always returns an empty list from the CLI.
3594
3596
  - `kxm context` subcommands crash with a stack trace when the hub is unreachable, and they ignore the persisted hub credential.
3595
3597
  - `kxm completion <shell>` generates a command list that includes a nonexistent `plan` command, omits `models`, `routes`, `explain`, and `ssh`, lists a nonexistent `goal get`, and omits `runs drive`, `runs receipt`, `runtime sync-retry`, and `improve report`.
3596
3598
  - `kxm backup` JSON shows `manifestSha256` redacted.
@@ -49,6 +49,7 @@ Operations routes carry no message bodies. `kxm dash` and `kxm tenant status` us
49
49
  | `POST` | `/v1/agents/register` | Project | Register or resume `name` in `project` with `purpose`, optional `model` and `host`. Returns the agent and a new `agentKey` (201 new, 200 resumed) |
50
50
  | `GET` | `/v1/agents` | Agent | Agents in your project; `?includeOffline=true` adds registered offline agents |
51
51
  | `POST` | `/v1/agents/<agentId>/heartbeat` | Agent | Renew your presence lease (clients send one every 10 seconds) |
52
+ | `GET` | `/v1/agents/<agentId>/inbox` | Agent | Your open inbound requests (`queued` or `delivered`), oldest first, as `{ "messages": [...] }`. Expires overdue requests first; acknowledges nothing and moves no delivery cursor |
52
53
  | `DELETE` | `/v1/agents/<agentId>` | Agent | Mark yourself offline (204) |
53
54
 
54
55
  Key errors: `duplicate_agent_name` (409, the name is online in the project), `invalid_agent_identity` (401). Presence (`online`, `stale`, `offline`) is computed from the hub's clock with a 30-second lease; agents never report their own presence.
@@ -24,7 +24,7 @@ flowchart LR
24
24
  | `kxm_fanout` | Peers | Yes | `kxm peer fanout` |
25
25
  | `kxm_await` | Peers | No | `kxm peer await` |
26
26
  | `kxm_cancel` | Peers | Yes | `kxm peer cancel` |
27
- | `kxm_inbox` | Peers | No | `kxm peer inbox` (always empty from the CLI) |
27
+ | `kxm_inbox` | Peers | No | `kxm peer inbox` (lists a named CLI agent's open requests; refused in Pi) |
28
28
  | `kxm_reply` | Peers | Yes | `kxm peer reply` |
29
29
  | `kxm_workflow_list` | Workflows | No | None; `kxm workflow list` reads the local database instead |
30
30
  | `kxm_workflow_get` | Workflows | No | None; `kxm workflow get` reads the local database instead |
@@ -162,8 +162,8 @@ Returns the message record with `status: "cancelled"`. Cancelling an already can
162
162
  Lists inbound requests that still need a reply. It takes no parameters.
163
163
 
164
164
  - **Claude Code:** returns `{ "messages": [...] }` from the session's inbox, which fills from the hub's event stream while the session is registered. Before returning, it re-reads each request and drops those already answered, cancelled or expired. This is pull mode; see [Pushed channel mode and pull mode](../../plugins/kxm/README.md#pushed-channel-mode-and-pull-mode).
165
- - **Pi:** always returns an empty list. The extension turns each inbound request into a model turn instead.
166
- - **CLI:** always returns an empty list, because a one-shot command holds no inbox.
165
+ - **Pi:** refuses. The extension turns each inbound request into a model turn itself, and that turn's final response is the reply, so listing would offer requests its own queue is about to activate.
166
+ - **CLI:** `kxm peer inbox` reads the agent's open requests from the hub (`GET /v1/agents/<agentId>/inbox`), acknowledging nothing. Run it with a stable `KXM_AGENT_NAME` to see requests queued for that name while it was offline; the default `cli-<pid>` is a new agent on every call, so its list is empty.
167
167
 
168
168
  ### `kxm_reply`
169
169
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.98",
3
+ "version": "0.7.99",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.98",
5
+ "version": "0.7.99",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -9508,7 +9508,10 @@ var init_commands = __esm({
9508
9508
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
9509
9509
  return { messages: [...context.inbox.values()] };
9510
9510
  }
9511
- return { messages: [] };
9511
+ if (context?.hubInbox) return { messages: await client.listInbox() };
9512
+ throw new Error(
9513
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
9514
+ );
9512
9515
  }
9513
9516
  },
9514
9517
  {
@@ -19626,6 +19626,15 @@ var HubClient = class {
19626
19626
  }
19627
19627
  }));
19628
19628
  }
19629
+ /** This agent's open inbound requests (queued or delivered), oldest first. A read: nothing
19630
+ * is acknowledged. */
19631
+ async listInbox() {
19632
+ if (!this.agent) throw new Error("hub client is not registered");
19633
+ const result = await this.request(
19634
+ `/v1/agents/${encodeURIComponent(this.agent.id)}/inbox`
19635
+ );
19636
+ return result.messages;
19637
+ }
19629
19638
  async getMessage(messageId) {
19630
19639
  const result = await this.request(`/v1/messages/${encodeURIComponent(messageId)}`);
19631
19640
  return result.message;
@@ -20322,7 +20331,10 @@ var AGENT_COMMANDS = [
20322
20331
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
20323
20332
  return { messages: [...context.inbox.values()] };
20324
20333
  }
20325
- return { messages: [] };
20334
+ if (context?.hubInbox) return { messages: await client.listInbox() };
20335
+ throw new Error(
20336
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
20337
+ );
20326
20338
  }
20327
20339
  },
20328
20340
  {
@@ -49161,7 +49173,7 @@ async function dispatchAgentCliCommand(runtime, toolName, rawArgs) {
49161
49173
  let client;
49162
49174
  try {
49163
49175
  client = await ensureCliClient(runtime);
49164
- const output = await cmd.execute(client, args);
49176
+ const output = await cmd.execute(client, args, { hubInbox: true });
49165
49177
  const payload = output && typeof output === "object" ? output : { result: output };
49166
49178
  print(runtime.io, runtime.json, payload, JSON.stringify(output, null, 2));
49167
49179
  return 0;
@@ -262,6 +262,15 @@ var HubClient = class {
262
262
  }
263
263
  }));
264
264
  }
265
+ /** This agent's open inbound requests (queued or delivered), oldest first. A read: nothing
266
+ * is acknowledged. */
267
+ async listInbox() {
268
+ if (!this.agent) throw new Error("hub client is not registered");
269
+ const result = await this.request(
270
+ `/v1/agents/${encodeURIComponent(this.agent.id)}/inbox`
271
+ );
272
+ return result.messages;
273
+ }
265
274
  async getMessage(messageId) {
266
275
  const result = await this.request(`/v1/messages/${encodeURIComponent(messageId)}`);
267
276
  return result.message;
@@ -1284,7 +1284,10 @@ var AGENT_COMMANDS = [
1284
1284
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
1285
1285
  return { messages: [...context.inbox.values()] };
1286
1286
  }
1287
- return { messages: [] };
1287
+ if (context?.hubInbox) return { messages: await client.listInbox() };
1288
+ throw new Error(
1289
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
1290
+ );
1288
1291
  }
1289
1292
  },
1290
1293
  {
@@ -14842,6 +14842,15 @@ var HubClient = class {
14842
14842
  }
14843
14843
  }));
14844
14844
  }
14845
+ /** This agent's open inbound requests (queued or delivered), oldest first. A read: nothing
14846
+ * is acknowledged. */
14847
+ async listInbox() {
14848
+ if (!this.agent) throw new Error("hub client is not registered");
14849
+ const result2 = await this.request(
14850
+ `/v1/agents/${encodeURIComponent(this.agent.id)}/inbox`
14851
+ );
14852
+ return result2.messages;
14853
+ }
14845
14854
  async getMessage(messageId) {
14846
14855
  const result2 = await this.request(`/v1/messages/${encodeURIComponent(messageId)}`);
14847
14856
  return result2.message;
@@ -15408,7 +15417,10 @@ var AGENT_COMMANDS = [
15408
15417
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
15409
15418
  return { messages: [...context.inbox.values()] };
15410
15419
  }
15411
- return { messages: [] };
15420
+ if (context?.hubInbox) return { messages: await client.listInbox() };
15421
+ throw new Error(
15422
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
15423
+ );
15412
15424
  }
15413
15425
  },
15414
15426
  {
@@ -16042,6 +16042,15 @@ var HubClient = class {
16042
16042
  }
16043
16043
  }));
16044
16044
  }
16045
+ /** This agent's open inbound requests (queued or delivered), oldest first. A read: nothing
16046
+ * is acknowledged. */
16047
+ async listInbox() {
16048
+ if (!this.agent) throw new Error("hub client is not registered");
16049
+ const result = await this.request(
16050
+ `/v1/agents/${encodeURIComponent(this.agent.id)}/inbox`
16051
+ );
16052
+ return result.messages;
16053
+ }
16045
16054
  async getMessage(messageId) {
16046
16055
  const result = await this.request(`/v1/messages/${encodeURIComponent(messageId)}`);
16047
16056
  return result.message;
@@ -16700,7 +16709,10 @@ var AGENT_COMMANDS = [
16700
16709
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
16701
16710
  return { messages: [...context.inbox.values()] };
16702
16711
  }
16703
- return { messages: [] };
16712
+ if (context?.hubInbox) return { messages: await client.listInbox() };
16713
+ throw new Error(
16714
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
16715
+ );
16704
16716
  }
16705
16717
  },
16706
16718
  {
@@ -17296,7 +17308,7 @@ function sessionTokenFixHint(policy) {
17296
17308
  }
17297
17309
 
17298
17310
  // plugins/kxm/src/mcp-server.ts
17299
- var VERSION = "0.7.98";
17311
+ var VERSION = "0.7.99";
17300
17312
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
17301
17313
  var inbox = /* @__PURE__ */ new Map();
17302
17314
  var notifiedInbox = /* @__PURE__ */ new Set();
@@ -17223,7 +17223,10 @@ var AGENT_COMMANDS = [
17223
17223
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
17224
17224
  return { messages: [...context.inbox.values()] };
17225
17225
  }
17226
- return { messages: [] };
17226
+ if (context?.hubInbox) return { messages: await client.listInbox() };
17227
+ throw new Error(
17228
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply"
17229
+ );
17227
17230
  }
17228
17231
  },
17229
17232
  {
@@ -22526,6 +22529,14 @@ data: ${JSON.stringify({ type: "ops", project, topic: "agents", at: nowIso() })}
22526
22529
  json(response, 200, { agent: publicAgent(current, staleAfterMs) });
22527
22530
  return;
22528
22531
  }
22532
+ const inboxMatch = url.pathname.match(/^\/v1\/agents\/([^/]+)\/inbox$/);
22533
+ if (method === "GET" && inboxMatch) {
22534
+ const current = requireAgent(request, decodeURIComponent(inboxMatch[1]));
22535
+ requireProjectAuth(request, current.project);
22536
+ expireMessages();
22537
+ json(response, 200, { messages: store.getPendingMessages(current.id) });
22538
+ return;
22539
+ }
22529
22540
  const agentMatch = url.pathname.match(/^\/v1\/agents\/([^/]+)$/);
22530
22541
  if (method === "DELETE" && agentMatch) {
22531
22542
  const current = requireAgent(request, decodeURIComponent(agentMatch[1]));
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.98",
3
+ "version": "0.7.99",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -42,9 +42,11 @@ reading of its heartbeat lease: `online` holds the lease, `stale` has passed
42
42
  peer the hub has retired. Offline peers are listed only with
43
43
  `--include-offline`. The host label is a reading aid, never a permission.
44
44
 
45
- `kxm peer inbox` from a one-shot CLI call always returns an empty list,
46
- because the inbox lives in a long-running harness session. Use `kxm_inbox` in
47
- that session or `kxm dash --screen inbox`.
45
+ `kxm peer inbox` lists the requests addressed to the CLI agent's own name, so
46
+ run it with a stable `KXM_AGENT_NAME` and answer each with `kxm peer reply`
47
+ under that name. The default `cli-<pid>` is a new agent on every call, and its
48
+ inbox is always empty. In Claude Code, `kxm_inbox` lists the session's inbox; a
49
+ Pi session receives each request as a turn instead, and its `kxm_inbox` refuses.
48
50
 
49
51
  ## Examples
50
52
 
@@ -349,7 +349,9 @@ async function dispatchAgentCliCommand(
349
349
  let client: HubClient | undefined;
350
350
  try {
351
351
  client = await ensureCliClient(runtime);
352
- const output = await cmd.execute(client, args);
352
+ // A one-shot call keeps no inbox, so `peer inbox` reads this agent's open requests from
353
+ // the hub; with a stable KXM_AGENT_NAME those include ones queued while it was offline.
354
+ const output = await cmd.execute(client, args, { hubInbox: true });
353
355
  const payload = (output && typeof output === "object" ? output : { result: output }) as object;
354
356
  print(runtime.io, runtime.json, payload, JSON.stringify(output, null, 2));
355
357
  return 0;
@@ -325,6 +325,16 @@ export class HubClient {
325
325
  }));
326
326
  }
327
327
 
328
+ /** This agent's open inbound requests (queued or delivered), oldest first. A read: nothing
329
+ * is acknowledged. */
330
+ async listInbox(): Promise<MessageRecord[]> {
331
+ if (!this.agent) throw new Error("hub client is not registered");
332
+ const result = await this.request<{ messages: MessageRecord[] }>(
333
+ `/v1/agents/${encodeURIComponent(this.agent.id)}/inbox`,
334
+ );
335
+ return result.messages;
336
+ }
337
+
328
338
  async getMessage(messageId: string): Promise<MessageRecord> {
329
339
  const result = await this.request<{ message: MessageRecord }>(`/v1/messages/${encodeURIComponent(messageId)}`);
330
340
  return result.message;
@@ -72,8 +72,12 @@ export interface SessionTokenPayload {
72
72
 
73
73
  export interface CommandExecutionContext {
74
74
  signal?: AbortSignal | undefined;
75
+ /** An event-fed inbox the caller keeps (the MCP server); `kxm_inbox` reconciles it. */
75
76
  inbox?: Map<string, MessageRecord> | undefined;
76
77
  notifiedInbox?: Set<string> | undefined;
78
+ /** The caller keeps no inbox and reads its open requests from the hub (a one-shot CLI
79
+ * call). A caller with neither this nor `inbox` activates inbound requests itself (Pi). */
80
+ hubInbox?: boolean | undefined;
77
81
  /** Inbound requests this session is handling: the Pi extension's active request, the MCP
78
82
  * server's open inbox. A request sent meanwhile is one more hop along their chain. */
79
83
  handling?: readonly Pick<MessageRecord, "hops" | "maxHops">[] | undefined;
@@ -452,7 +456,12 @@ export const AGENT_COMMANDS: readonly AgentCommand[] = [
452
456
  await reconcileInbox(client, context.inbox, context.notifiedInbox);
453
457
  return { messages: [...context.inbox.values()] };
454
458
  }
455
- return { messages: [] };
459
+ if (context?.hubInbox) return { messages: await client.listInbox() };
460
+ // Listing would offer requests this session's own activation queue is about to hand
461
+ // it as turns, and an empty list would hide them, so it refuses.
462
+ throw new Error(
463
+ "kxm_inbox is not available in this session: it activates each inbound request as a turn, and that turn's final response is the reply",
464
+ );
456
465
  },
457
466
  },
458
467
  {
@@ -898,6 +898,7 @@ export default function piMeshExtension(pi: ExtensionAPI): void | Promise<void>
898
898
  throw new Error(`tool_policy_denied: ${policy.detail ?? policy.error}`);
899
899
  }
900
900
  // A request sent while handling the active inbound request continues its hop chain.
901
+ // No inbox and no hubInbox: `pending` owns activation, so kxm_inbox refuses here.
901
902
  const handling = activeInbound ? [activeInbound] : [];
902
903
  return result(
903
904
  await workflowCall(() =>
@@ -2520,6 +2520,18 @@ export function createMeshHub(options: MeshHubOptions = {}): MeshHub {
2520
2520
  return;
2521
2521
  }
2522
2522
 
2523
+ // An agent's open inbound requests, queued or delivered, in delivery order. A read
2524
+ // for a caller that holds no event-fed inbox of its own (a one-shot CLI call): it
2525
+ // acknowledges nothing and moves no cursor, so push delivery is unchanged.
2526
+ const inboxMatch = url.pathname.match(/^\/v1\/agents\/([^/]+)\/inbox$/);
2527
+ if (method === "GET" && inboxMatch) {
2528
+ const current = requireAgent(request, decodeURIComponent(inboxMatch[1]!));
2529
+ requireProjectAuth(request, current.project);
2530
+ expireMessages();
2531
+ json(response, 200, { messages: store.getPendingMessages(current.id) });
2532
+ return;
2533
+ }
2534
+
2523
2535
  const agentMatch = url.pathname.match(/^\/v1\/agents\/([^/]+)$/);
2524
2536
  if (method === "DELETE" && agentMatch) {
2525
2537
  const current = requireAgent(request, decodeURIComponent(agentMatch[1]!));
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
11
11
  import type { HubEvent, MessageRecord } from "./protocol.ts";
12
12
  import { sessionTokenFixHint } from "./session-token-hint.ts";
13
13
 
14
- const VERSION = "0.7.98";
14
+ const VERSION = "0.7.99";
15
15
  const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
16
16
  const inbox = new Map<string, MessageRecord>();
17
17
  const notifiedInbox = new Set<string>();