@kontextmind/kxm 0.7.71 → 0.7.73

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.
@@ -8,6 +8,8 @@ var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
8
8
  var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
9
9
  var MAX_BODY_BYTES = 256 * 1024;
10
10
  var MAX_AGENT_HOST_CHARS = 64;
11
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
12
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
11
13
 
12
14
  // plugins/kxm/src/workflow.ts
13
15
  function canonicalWorkflowEvidenceKey(value) {
@@ -219,6 +221,37 @@ var HubClient = class {
219
221
  );
220
222
  return result.message;
221
223
  }
224
+ // ----- Fenced leases over shared resources (P3) -----
225
+ /**
226
+ * Take or extend the lease over `resource` inside this client's project.
227
+ *
228
+ * The returned `fencingToken` is the whole point: hold it, present it on every
229
+ * renewal, and present it again before committing anything shared. A hub that
230
+ * has moved past it refuses, and the caller must stop rather than retry —
231
+ * another holder owns the resource now. Rejects `HubHttpError` with code
232
+ * `lease_held` when a live holder has it.
233
+ */
234
+ async acquireLease(resource, ttlMs) {
235
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/acquire`, {
236
+ method: "POST",
237
+ body: JSON.stringify(ttlMs === void 0 ? {} : { ttlMs })
238
+ });
239
+ }
240
+ /** Extend a lease this client holds. The token never changes on renewal; a
241
+ * `lease_superseded` or `lease_expired` refusal means it is gone. */
242
+ async renewLease(resource, fencingToken, ttlMs) {
243
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/renew`, {
244
+ method: "POST",
245
+ body: JSON.stringify(ttlMs === void 0 ? { fencingToken } : { fencingToken, ttlMs })
246
+ });
247
+ }
248
+ /** Give the resource back. */
249
+ async releaseLease(resource, fencingToken) {
250
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/release`, {
251
+ method: "POST",
252
+ body: JSON.stringify({ fencingToken })
253
+ });
254
+ }
222
255
  async listWorkflows() {
223
256
  const result = await this.request("/v1/workflows");
224
257
  return result.runs;
@@ -384,46 +417,78 @@ var HubClient = class {
384
417
  await this.register();
385
418
  }
386
419
  async request(path, init = {}, includeIdentity = true) {
387
- const requestTimeoutMs = this.options.requestTimeoutMs ?? 15e3;
388
- const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
389
- const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
390
- let response;
420
+ return await hubJsonRequest(this.options, path, init, this.headers(includeIdentity));
421
+ }
422
+ };
423
+ async function hubJsonRequest(options, path, init, headers) {
424
+ const requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
425
+ const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
426
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
427
+ let response;
428
+ try {
429
+ response = await (options.fetchImpl ?? fetch)(`${options.serverUrl.replace(/\/$/, "")}${path}`, {
430
+ ...init,
431
+ signal,
432
+ headers: { ...headers, ...init.headers ?? {} }
433
+ });
434
+ } catch (error) {
435
+ if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
436
+ throw error;
437
+ }
438
+ const text = await response.text();
439
+ let body = {};
440
+ if (text) {
391
441
  try {
392
- response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path}`, {
393
- ...init,
394
- signal,
395
- headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
396
- });
397
- } catch (error) {
398
- if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
399
- throw error;
442
+ body = JSON.parse(text);
443
+ } catch {
444
+ throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
400
445
  }
401
- const text = await response.text();
402
- let body = {};
403
- if (text) {
404
- try {
405
- body = JSON.parse(text);
406
- } catch {
407
- throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
408
- }
409
- }
410
- if (!response.ok) {
411
- const extras = {};
412
- for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
413
- if (typeof body[key] === "string") extras[key] = body[key];
414
- }
415
- throw new HubHttpError(
416
- response.status,
417
- String(body.error ?? `HTTP ${response.status}`),
418
- typeof body.code === "string" ? body.code : void 0,
419
- response.headers.get("x-request-id") ?? void 0,
420
- Object.keys(extras).length > 0 ? extras : void 0
421
- );
446
+ }
447
+ if (!response.ok) {
448
+ const extras = {};
449
+ for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
450
+ if (typeof body[key] === "string") extras[key] = body[key];
422
451
  }
423
- return body;
452
+ if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
453
+ throw new HubHttpError(
454
+ response.status,
455
+ String(body.error ?? `HTTP ${response.status}`),
456
+ typeof body.code === "string" ? body.code : void 0,
457
+ response.headers.get("x-request-id") ?? void 0,
458
+ Object.keys(extras).length > 0 ? extras : void 0
459
+ );
460
+ }
461
+ return body;
462
+ }
463
+ var RuntimeHubClient = class {
464
+ options;
465
+ constructor(options) {
466
+ this.options = options;
467
+ }
468
+ async heartbeat() {
469
+ const result = await this.request("/v1/runtime/presence", {
470
+ project: this.options.project,
471
+ runtimeId: this.options.runtimeId,
472
+ host: this.options.host ?? defaultHostLabel()
473
+ });
474
+ return result.presence;
475
+ }
476
+ /** Push already-derived `kxm.sync-event.v1` objects, in outbox order. */
477
+ async pushSyncEvents(events) {
478
+ return await this.request("/v1/sync/events", {
479
+ project: this.options.project,
480
+ runtimeId: this.options.runtimeId,
481
+ events
482
+ });
483
+ }
484
+ async request(path, body) {
485
+ const headers = { "content-type": "application/json" };
486
+ if (this.options.authToken) headers.authorization = `Bearer ${this.options.authToken}`;
487
+ return await hubJsonRequest(this.options, path, { method: "POST", body: JSON.stringify(body) }, headers);
424
488
  }
425
489
  };
426
490
  export {
427
491
  HubClient,
428
- HubHttpError
492
+ HubHttpError,
493
+ RuntimeHubClient
429
494
  };
@@ -13,6 +13,10 @@ var DEFAULT_RATE_LIMIT_WINDOW_MS = 6e4;
13
13
  var MAX_BODY_BYTES = 256 * 1024;
14
14
  var MAX_CONTENT_CHARS = 32e3;
15
15
  var MAX_AGENT_HOST_CHARS = 64;
16
+ var MIN_LEASE_TTL_MS = 5e3;
17
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
18
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
19
+ var MAX_LEASE_RESOURCE_CHARS = 200;
16
20
  function agentPresenceView(agent, staleAfterMs = DEFAULT_STALE_AFTER_MS, now = Date.now()) {
17
21
  const lastSeenMs = Date.parse(agent.lastSeenAt);
18
22
  const leaseExpiresAtMs = (Number.isFinite(lastSeenMs) ? lastSeenMs : 0) + staleAfterMs;
@@ -23,6 +27,7 @@ function agentPresenceView(agent, staleAfterMs = DEFAULT_STALE_AFTER_MS, now = D
23
27
  function toAgentRecord(agent, staleAfterMs, now) {
24
28
  return { ...agent, ...agentPresenceView(agent, staleAfterMs, now) };
25
29
  }
30
+ var MAX_SYNC_BATCH_EVENTS = 100;
26
31
  var ProtocolError = class extends Error {
27
32
  statusCode;
28
33
  code;
@@ -2017,6 +2022,7 @@ export {
2017
2022
  AGENT_COMMANDS,
2018
2023
  AGENT_COMMANDS_MAP,
2019
2024
  BEHAVIORAL_HASH_VERSION,
2025
+ DEFAULT_LEASE_TTL_MS,
2020
2026
  DEFAULT_LOG_MAX_BYTES,
2021
2027
  DEFAULT_LOG_MAX_FILES,
2022
2028
  DEFAULT_MAX_HOPS,
@@ -2031,9 +2037,13 @@ export {
2031
2037
  MAX_BODY_BYTES,
2032
2038
  MAX_CONTENT_CHARS,
2033
2039
  MAX_CONTEXT_ITEM_IDS,
2040
+ MAX_LEASE_RESOURCE_CHARS,
2041
+ MAX_LEASE_TTL_MS,
2034
2042
  MAX_MESSAGE_TTL_MS,
2035
2043
  MAX_PROVIDER_METADATA_FIELDS,
2036
2044
  MAX_SKILL_REFS,
2045
+ MAX_SYNC_BATCH_EVENTS,
2046
+ MIN_LEASE_TTL_MS,
2037
2047
  MIN_MESSAGE_RETENTION_MS,
2038
2048
  MIN_MESSAGE_TTL_MS,
2039
2049
  ProtocolError,
@@ -14543,6 +14543,8 @@ var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
14543
14543
  var MAX_BODY_BYTES = 256 * 1024;
14544
14544
  var MAX_CONTENT_CHARS = 32e3;
14545
14545
  var MAX_AGENT_HOST_CHARS = 64;
14546
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
14547
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
14546
14548
 
14547
14549
  // plugins/kxm/src/workflow.ts
14548
14550
  function canonicalWorkflowEvidenceKey(value) {
@@ -14754,6 +14756,37 @@ var HubClient = class {
14754
14756
  );
14755
14757
  return result2.message;
14756
14758
  }
14759
+ // ----- Fenced leases over shared resources (P3) -----
14760
+ /**
14761
+ * Take or extend the lease over `resource` inside this client's project.
14762
+ *
14763
+ * The returned `fencingToken` is the whole point: hold it, present it on every
14764
+ * renewal, and present it again before committing anything shared. A hub that
14765
+ * has moved past it refuses, and the caller must stop rather than retry —
14766
+ * another holder owns the resource now. Rejects `HubHttpError` with code
14767
+ * `lease_held` when a live holder has it.
14768
+ */
14769
+ async acquireLease(resource, ttlMs) {
14770
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/acquire`, {
14771
+ method: "POST",
14772
+ body: JSON.stringify(ttlMs === void 0 ? {} : { ttlMs })
14773
+ });
14774
+ }
14775
+ /** Extend a lease this client holds. The token never changes on renewal; a
14776
+ * `lease_superseded` or `lease_expired` refusal means it is gone. */
14777
+ async renewLease(resource, fencingToken, ttlMs) {
14778
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/renew`, {
14779
+ method: "POST",
14780
+ body: JSON.stringify(ttlMs === void 0 ? { fencingToken } : { fencingToken, ttlMs })
14781
+ });
14782
+ }
14783
+ /** Give the resource back. */
14784
+ async releaseLease(resource, fencingToken) {
14785
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/release`, {
14786
+ method: "POST",
14787
+ body: JSON.stringify({ fencingToken })
14788
+ });
14789
+ }
14757
14790
  async listWorkflows() {
14758
14791
  const result2 = await this.request("/v1/workflows");
14759
14792
  return result2.runs;
@@ -14919,45 +14952,49 @@ var HubClient = class {
14919
14952
  await this.register();
14920
14953
  }
14921
14954
  async request(path, init = {}, includeIdentity = true) {
14922
- const requestTimeoutMs = this.options.requestTimeoutMs ?? 15e3;
14923
- const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
14924
- const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
14925
- let response;
14955
+ return await hubJsonRequest(this.options, path, init, this.headers(includeIdentity));
14956
+ }
14957
+ };
14958
+ async function hubJsonRequest(options, path, init, headers) {
14959
+ const requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
14960
+ const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
14961
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
14962
+ let response;
14963
+ try {
14964
+ response = await (options.fetchImpl ?? fetch)(`${options.serverUrl.replace(/\/$/, "")}${path}`, {
14965
+ ...init,
14966
+ signal,
14967
+ headers: { ...headers, ...init.headers ?? {} }
14968
+ });
14969
+ } catch (error2) {
14970
+ if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
14971
+ throw error2;
14972
+ }
14973
+ const text = await response.text();
14974
+ let body = {};
14975
+ if (text) {
14926
14976
  try {
14927
- response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path}`, {
14928
- ...init,
14929
- signal,
14930
- headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
14931
- });
14932
- } catch (error2) {
14933
- if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
14934
- throw error2;
14935
- }
14936
- const text = await response.text();
14937
- let body = {};
14938
- if (text) {
14939
- try {
14940
- body = JSON.parse(text);
14941
- } catch {
14942
- throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
14943
- }
14944
- }
14945
- if (!response.ok) {
14946
- const extras = {};
14947
- for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
14948
- if (typeof body[key] === "string") extras[key] = body[key];
14949
- }
14950
- throw new HubHttpError(
14951
- response.status,
14952
- String(body.error ?? `HTTP ${response.status}`),
14953
- typeof body.code === "string" ? body.code : void 0,
14954
- response.headers.get("x-request-id") ?? void 0,
14955
- Object.keys(extras).length > 0 ? extras : void 0
14956
- );
14977
+ body = JSON.parse(text);
14978
+ } catch {
14979
+ throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
14957
14980
  }
14958
- return body;
14959
14981
  }
14960
- };
14982
+ if (!response.ok) {
14983
+ const extras = {};
14984
+ for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
14985
+ if (typeof body[key] === "string") extras[key] = body[key];
14986
+ }
14987
+ if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
14988
+ throw new HubHttpError(
14989
+ response.status,
14990
+ String(body.error ?? `HTTP ${response.status}`),
14991
+ typeof body.code === "string" ? body.code : void 0,
14992
+ response.headers.get("x-request-id") ?? void 0,
14993
+ Object.keys(extras).length > 0 ? extras : void 0
14994
+ );
14995
+ }
14996
+ return body;
14997
+ }
14961
14998
 
14962
14999
  // plugins/kxm/src/commands.ts
14963
15000
  function requiredString(value, name) {
@@ -15763,6 +15763,8 @@ var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
15763
15763
  var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
15764
15764
  var MAX_BODY_BYTES = 256 * 1024;
15765
15765
  var MAX_AGENT_HOST_CHARS = 64;
15766
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
15767
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
15766
15768
 
15767
15769
  // plugins/kxm/src/workflow.ts
15768
15770
  function canonicalWorkflowEvidenceKey(value) {
@@ -15974,6 +15976,37 @@ var HubClient = class {
15974
15976
  );
15975
15977
  return result.message;
15976
15978
  }
15979
+ // ----- Fenced leases over shared resources (P3) -----
15980
+ /**
15981
+ * Take or extend the lease over `resource` inside this client's project.
15982
+ *
15983
+ * The returned `fencingToken` is the whole point: hold it, present it on every
15984
+ * renewal, and present it again before committing anything shared. A hub that
15985
+ * has moved past it refuses, and the caller must stop rather than retry —
15986
+ * another holder owns the resource now. Rejects `HubHttpError` with code
15987
+ * `lease_held` when a live holder has it.
15988
+ */
15989
+ async acquireLease(resource, ttlMs) {
15990
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/acquire`, {
15991
+ method: "POST",
15992
+ body: JSON.stringify(ttlMs === void 0 ? {} : { ttlMs })
15993
+ });
15994
+ }
15995
+ /** Extend a lease this client holds. The token never changes on renewal; a
15996
+ * `lease_superseded` or `lease_expired` refusal means it is gone. */
15997
+ async renewLease(resource, fencingToken, ttlMs) {
15998
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/renew`, {
15999
+ method: "POST",
16000
+ body: JSON.stringify(ttlMs === void 0 ? { fencingToken } : { fencingToken, ttlMs })
16001
+ });
16002
+ }
16003
+ /** Give the resource back. */
16004
+ async releaseLease(resource, fencingToken) {
16005
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/release`, {
16006
+ method: "POST",
16007
+ body: JSON.stringify({ fencingToken })
16008
+ });
16009
+ }
15977
16010
  async listWorkflows() {
15978
16011
  const result = await this.request("/v1/workflows");
15979
16012
  return result.runs;
@@ -16139,45 +16172,49 @@ var HubClient = class {
16139
16172
  await this.register();
16140
16173
  }
16141
16174
  async request(path, init = {}, includeIdentity = true) {
16142
- const requestTimeoutMs = this.options.requestTimeoutMs ?? 15e3;
16143
- const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
16144
- const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
16145
- let response;
16175
+ return await hubJsonRequest(this.options, path, init, this.headers(includeIdentity));
16176
+ }
16177
+ };
16178
+ async function hubJsonRequest(options, path, init, headers) {
16179
+ const requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
16180
+ const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
16181
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
16182
+ let response;
16183
+ try {
16184
+ response = await (options.fetchImpl ?? fetch)(`${options.serverUrl.replace(/\/$/, "")}${path}`, {
16185
+ ...init,
16186
+ signal,
16187
+ headers: { ...headers, ...init.headers ?? {} }
16188
+ });
16189
+ } catch (error2) {
16190
+ if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
16191
+ throw error2;
16192
+ }
16193
+ const text = await response.text();
16194
+ let body = {};
16195
+ if (text) {
16146
16196
  try {
16147
- response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path}`, {
16148
- ...init,
16149
- signal,
16150
- headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
16151
- });
16152
- } catch (error2) {
16153
- if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
16154
- throw error2;
16155
- }
16156
- const text = await response.text();
16157
- let body = {};
16158
- if (text) {
16159
- try {
16160
- body = JSON.parse(text);
16161
- } catch {
16162
- throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
16163
- }
16197
+ body = JSON.parse(text);
16198
+ } catch {
16199
+ throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
16164
16200
  }
16165
- if (!response.ok) {
16166
- const extras = {};
16167
- for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
16168
- if (typeof body[key] === "string") extras[key] = body[key];
16169
- }
16170
- throw new HubHttpError(
16171
- response.status,
16172
- String(body.error ?? `HTTP ${response.status}`),
16173
- typeof body.code === "string" ? body.code : void 0,
16174
- response.headers.get("x-request-id") ?? void 0,
16175
- Object.keys(extras).length > 0 ? extras : void 0
16176
- );
16201
+ }
16202
+ if (!response.ok) {
16203
+ const extras = {};
16204
+ for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
16205
+ if (typeof body[key] === "string") extras[key] = body[key];
16177
16206
  }
16178
- return body;
16207
+ if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
16208
+ throw new HubHttpError(
16209
+ response.status,
16210
+ String(body.error ?? `HTTP ${response.status}`),
16211
+ typeof body.code === "string" ? body.code : void 0,
16212
+ response.headers.get("x-request-id") ?? void 0,
16213
+ Object.keys(extras).length > 0 ? extras : void 0
16214
+ );
16179
16215
  }
16180
- };
16216
+ return body;
16217
+ }
16181
16218
 
16182
16219
  // plugins/kxm/src/hub-env.ts
16183
16220
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
@@ -17145,7 +17182,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
17145
17182
  }
17146
17183
 
17147
17184
  // plugins/kxm/src/mcp-server.ts
17148
- var VERSION = "0.7.71";
17185
+ var VERSION = "0.7.73";
17149
17186
  var inbox = /* @__PURE__ */ new Map();
17150
17187
  var notifiedInbox = /* @__PURE__ */ new Set();
17151
17188
  var meshClient;