@kontextmind/kxm 0.7.175 → 0.7.176

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.175",
14
+ "version": "0.7.176",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.175",
3
+ "version": "0.7.176",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -77,9 +77,9 @@
77
77
  ]
78
78
  },
79
79
  "dependencies": {
80
- "@anthropic-ai/claude-agent-sdk": "0.3.283",
80
+ "@anthropic-ai/claude-agent-sdk": "0.3.289",
81
81
  "@earendil-works/pi-tui": "0.87.1",
82
- "@modelcontextprotocol/sdk": "1.30.1",
82
+ "@modelcontextprotocol/sdk": "1.32.0",
83
83
  "yaml": "^2.9.0"
84
84
  },
85
85
  "peerDependencies": {
@@ -96,9 +96,9 @@
96
96
  },
97
97
  "devDependencies": {
98
98
  "@earendil-works/pi-coding-agent": "0.87.1",
99
- "@modelcontextprotocol/sdk": "1.30.1",
99
+ "@modelcontextprotocol/sdk": "1.32.0",
100
100
  "@playwright/test": "1.63.0",
101
- "@types/node": "26.6.3",
101
+ "@types/node": "26.6.4",
102
102
  "ajv": "8.20.0",
103
103
  "commander": "15.0.0",
104
104
  "esbuild": "0.28.2",
@@ -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.175",
5
+ "version": "0.7.176",
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",
@@ -33758,6 +33758,9 @@ var Protocol = class {
33758
33758
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
33759
33759
  const handleTaskResult = async () => {
33760
33760
  const taskId = request.params.taskId;
33761
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
33762
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
33763
+ }
33761
33764
  if (this._taskMessageQueue) {
33762
33765
  let queuedMessage;
33763
33766
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -33788,12 +33791,12 @@ var Protocol = class {
33788
33791
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
33789
33792
  }
33790
33793
  if (!isTerminal(task.status)) {
33791
- await this._waitForTaskUpdate(taskId, extra.signal);
33794
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
33792
33795
  return await handleTaskResult();
33793
33796
  }
33794
33797
  if (isTerminal(task.status)) {
33795
33798
  const result2 = await this._taskStore.getTaskResult(taskId, extra.sessionId);
33796
- this._clearTaskQueue(taskId);
33799
+ this._clearTaskQueue(taskId, extra.sessionId);
33797
33800
  return {
33798
33801
  ...result2,
33799
33802
  _meta: {
@@ -33830,7 +33833,7 @@ var Protocol = class {
33830
33833
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
33831
33834
  }
33832
33835
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
33833
- this._clearTaskQueue(request.params.taskId);
33836
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
33834
33837
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
33835
33838
  if (!cancelledTask) {
33836
33839
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -33958,6 +33961,19 @@ var Protocol = class {
33958
33961
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
33959
33962
  const capturedTransport = this._transport;
33960
33963
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
33964
+ const sessionId = capturedTransport?.sessionId;
33965
+ const store = this._taskStore;
33966
+ let relatedTaskFound = true;
33967
+ let relatedTaskLookup;
33968
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
33969
+ relatedTaskFound = false;
33970
+ relatedTaskLookup = (async () => {
33971
+ if (!await store.getTask(relatedTaskId, sessionId)) {
33972
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
33973
+ }
33974
+ relatedTaskFound = true;
33975
+ })();
33976
+ }
33961
33977
  if (handler === void 0) {
33962
33978
  const errorResponse = {
33963
33979
  jsonrpc: "2.0",
@@ -33967,7 +33983,10 @@ var Protocol = class {
33967
33983
  message: "Method not found"
33968
33984
  }
33969
33985
  };
33970
- if (relatedTaskId && this._taskMessageQueue) {
33986
+ if (relatedTaskId && relatedTaskLookup) {
33987
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
33988
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
33989
+ } else if (relatedTaskId && this._taskMessageQueue) {
33971
33990
  this._enqueueTaskMessage(relatedTaskId, {
33972
33991
  type: "error",
33973
33992
  message: errorResponse,
@@ -34018,7 +34037,10 @@ var Protocol = class {
34018
34037
  closeSSEStream: extra?.closeSSEStream,
34019
34038
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
34020
34039
  };
34021
- Promise.resolve().then(() => {
34040
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
34041
+ if (relatedTaskLookup && abortController.signal.aborted) {
34042
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
34043
+ }
34022
34044
  if (taskCreationParams) {
34023
34045
  this.assertTaskHandlerCapability(request.method);
34024
34046
  }
@@ -34053,7 +34075,7 @@ var Protocol = class {
34053
34075
  ...error2["data"] !== void 0 && { data: error2["data"] }
34054
34076
  }
34055
34077
  };
34056
- if (relatedTaskId && this._taskMessageQueue) {
34078
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
34057
34079
  await this._enqueueTaskMessage(relatedTaskId, {
34058
34080
  type: "error",
34059
34081
  message: errorResponse,
@@ -34533,7 +34555,7 @@ var Protocol = class {
34533
34555
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
34534
34556
  }
34535
34557
  const maxQueueSize = this._options?.maxTaskQueueSize;
34536
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
34558
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
34537
34559
  }
34538
34560
  /**
34539
34561
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -34562,12 +34584,13 @@ var Protocol = class {
34562
34584
  * Uses polling to check for updates at the task's configured poll interval.
34563
34585
  * @param taskId The task ID to wait for
34564
34586
  * @param signal Abort signal to cancel the wait
34587
+ * @param sessionId Session of the request that waits, passed to the task store
34565
34588
  * @returns Promise that resolves when an update occurs or rejects if aborted
34566
34589
  */
34567
- async _waitForTaskUpdate(taskId, signal) {
34590
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
34568
34591
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
34569
34592
  try {
34570
- const task = await this._taskStore?.getTask(taskId);
34593
+ const task = await this._taskStore?.getTask(taskId, sessionId);
34571
34594
  if (task?.pollInterval) {
34572
34595
  interval = task.pollInterval;
34573
34596
  }
@@ -35446,6 +35469,42 @@ var ExperimentalMcpServerTasks = class {
35446
35469
  };
35447
35470
 
35448
35471
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
35472
+ function toolInputElementCount(value, max) {
35473
+ let count = 0;
35474
+ const stack = [value];
35475
+ while (stack.length > 0) {
35476
+ const node = stack.pop();
35477
+ if (node === null || typeof node !== "object")
35478
+ continue;
35479
+ if (Array.isArray(node)) {
35480
+ for (const child of node) {
35481
+ if (++count > max)
35482
+ return count;
35483
+ if (child !== null && typeof child === "object")
35484
+ stack.push(child);
35485
+ }
35486
+ } else {
35487
+ for (const key in node) {
35488
+ if (!Object.prototype.hasOwnProperty.call(node, key))
35489
+ continue;
35490
+ if (++count > max)
35491
+ return count;
35492
+ const child = node[key];
35493
+ if (child !== null && typeof child === "object")
35494
+ stack.push(child);
35495
+ }
35496
+ }
35497
+ }
35498
+ return count;
35499
+ }
35500
+ function resolveMaxToolInputElements(value) {
35501
+ if (value === void 0 || value === Infinity)
35502
+ return void 0;
35503
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
35504
+ throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
35505
+ }
35506
+ return value;
35507
+ }
35449
35508
  var McpServer = class {
35450
35509
  constructor(serverInfo, options) {
35451
35510
  this._registeredResources = {};
@@ -35457,6 +35516,7 @@ var McpServer = class {
35457
35516
  this._resourceHandlersInitialized = false;
35458
35517
  this._promptHandlersInitialized = false;
35459
35518
  this.server = new Server(serverInfo, options);
35519
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
35460
35520
  }
35461
35521
  /**
35462
35522
  * Access experimental features.
@@ -35587,12 +35647,15 @@ var McpServer = class {
35587
35647
  * Validates tool input arguments against the tool's input schema.
35588
35648
  */
35589
35649
  async validateToolInput(tool, args, toolName) {
35650
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
35651
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
35652
+ }
35590
35653
  if (!tool.inputSchema) {
35591
35654
  return void 0;
35592
35655
  }
35593
35656
  const inputObj = normalizeObjectSchema(tool.inputSchema);
35594
35657
  const schemaToParse = inputObj ?? tool.inputSchema;
35595
- const parseResult = await safeParseAsync2(schemaToParse, args);
35658
+ const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
35596
35659
  if (!parseResult.success) {
35597
35660
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
35598
35661
  const errorMessage = getParseErrorMessage(error2);
@@ -35830,7 +35893,7 @@ var McpServer = class {
35830
35893
  }
35831
35894
  if (prompt.argsSchema) {
35832
35895
  const argsObj = normalizeObjectSchema(prompt.argsSchema);
35833
- const parseResult = await safeParseAsync2(argsObj, request.params.arguments);
35896
+ const parseResult = await safeParseAsync2(argsObj, request.params.arguments ?? {});
35834
35897
  if (!parseResult.success) {
35835
35898
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
35836
35899
  const errorMessage = getParseErrorMessage(error2);
@@ -21387,6 +21387,9 @@ var Protocol = class {
21387
21387
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
21388
21388
  const handleTaskResult = async () => {
21389
21389
  const taskId = request.params.taskId;
21390
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
21391
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21392
+ }
21390
21393
  if (this._taskMessageQueue) {
21391
21394
  let queuedMessage;
21392
21395
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -21417,12 +21420,12 @@ var Protocol = class {
21417
21420
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21418
21421
  }
21419
21422
  if (!isTerminal(task.status)) {
21420
- await this._waitForTaskUpdate(taskId, extra.signal);
21423
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
21421
21424
  return await handleTaskResult();
21422
21425
  }
21423
21426
  if (isTerminal(task.status)) {
21424
21427
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
21425
- this._clearTaskQueue(taskId);
21428
+ this._clearTaskQueue(taskId, extra.sessionId);
21426
21429
  return {
21427
21430
  ...result,
21428
21431
  _meta: {
@@ -21459,7 +21462,7 @@ var Protocol = class {
21459
21462
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
21460
21463
  }
21461
21464
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
21462
- this._clearTaskQueue(request.params.taskId);
21465
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
21463
21466
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
21464
21467
  if (!cancelledTask) {
21465
21468
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -21587,6 +21590,19 @@ var Protocol = class {
21587
21590
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
21588
21591
  const capturedTransport = this._transport;
21589
21592
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
21593
+ const sessionId = capturedTransport?.sessionId;
21594
+ const store = this._taskStore;
21595
+ let relatedTaskFound = true;
21596
+ let relatedTaskLookup;
21597
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
21598
+ relatedTaskFound = false;
21599
+ relatedTaskLookup = (async () => {
21600
+ if (!await store.getTask(relatedTaskId, sessionId)) {
21601
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
21602
+ }
21603
+ relatedTaskFound = true;
21604
+ })();
21605
+ }
21590
21606
  if (handler === void 0) {
21591
21607
  const errorResponse = {
21592
21608
  jsonrpc: "2.0",
@@ -21596,7 +21612,10 @@ var Protocol = class {
21596
21612
  message: "Method not found"
21597
21613
  }
21598
21614
  };
21599
- if (relatedTaskId && this._taskMessageQueue) {
21615
+ if (relatedTaskId && relatedTaskLookup) {
21616
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
21617
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
21618
+ } else if (relatedTaskId && this._taskMessageQueue) {
21600
21619
  this._enqueueTaskMessage(relatedTaskId, {
21601
21620
  type: "error",
21602
21621
  message: errorResponse,
@@ -21647,7 +21666,10 @@ var Protocol = class {
21647
21666
  closeSSEStream: extra?.closeSSEStream,
21648
21667
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
21649
21668
  };
21650
- Promise.resolve().then(() => {
21669
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
21670
+ if (relatedTaskLookup && abortController.signal.aborted) {
21671
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
21672
+ }
21651
21673
  if (taskCreationParams) {
21652
21674
  this.assertTaskHandlerCapability(request.method);
21653
21675
  }
@@ -21682,7 +21704,7 @@ var Protocol = class {
21682
21704
  ...error2["data"] !== void 0 && { data: error2["data"] }
21683
21705
  }
21684
21706
  };
21685
- if (relatedTaskId && this._taskMessageQueue) {
21707
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
21686
21708
  await this._enqueueTaskMessage(relatedTaskId, {
21687
21709
  type: "error",
21688
21710
  message: errorResponse,
@@ -22162,7 +22184,7 @@ var Protocol = class {
22162
22184
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
22163
22185
  }
22164
22186
  const maxQueueSize = this._options?.maxTaskQueueSize;
22165
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
22187
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
22166
22188
  }
22167
22189
  /**
22168
22190
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -22191,12 +22213,13 @@ var Protocol = class {
22191
22213
  * Uses polling to check for updates at the task's configured poll interval.
22192
22214
  * @param taskId The task ID to wait for
22193
22215
  * @param signal Abort signal to cancel the wait
22216
+ * @param sessionId Session of the request that waits, passed to the task store
22194
22217
  * @returns Promise that resolves when an update occurs or rejects if aborted
22195
22218
  */
22196
- async _waitForTaskUpdate(taskId, signal) {
22219
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
22197
22220
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
22198
22221
  try {
22199
- const task = await this._taskStore?.getTask(taskId);
22222
+ const task = await this._taskStore?.getTask(taskId, sessionId);
22200
22223
  if (task?.pollInterval) {
22201
22224
  interval = task.pollInterval;
22202
22225
  }
@@ -25438,7 +25461,7 @@ function sessionTokenFixHint(policy) {
25438
25461
  }
25439
25462
 
25440
25463
  // plugins/kxm/src/mcp-server.ts
25441
- var VERSION = "0.7.175";
25464
+ var VERSION = "0.7.176";
25442
25465
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
25443
25466
  var inbox = /* @__PURE__ */ new Map();
25444
25467
  var notifiedInbox = /* @__PURE__ */ new Set();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.175",
3
+ "version": "0.7.176",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -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.175";
14
+ const VERSION = "0.7.176";
15
15
  const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
16
16
  const inbox = new Map<string, MessageRecord>();
17
17
  const notifiedInbox = new Set<string>();