@kontextmind/kxm 0.7.69 → 0.7.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +7 -0
- package/docs/test-matrix.md +1 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +50 -20
- package/plugins/kxm/dist/client.js +16 -3
- package/plugins/kxm/dist/core.js +31 -6
- package/plugins/kxm/dist/extension.js +33 -9
- package/plugins/kxm/dist/mcp-server.js +34 -10
- package/plugins/kxm/dist/server.js +65 -22
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm/references/protocol.md +6 -0
- package/plugins/kxm/skills/kxm-peer/SKILL.md +5 -2
- package/plugins/kxm/src/cli.ts +3 -1
- package/plugins/kxm/src/client.ts +24 -2
- package/plugins/kxm/src/commands.ts +16 -4
- package/plugins/kxm/src/hub.ts +55 -17
- package/plugins/kxm/src/local-snapshot.ts +10 -2
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/protocol.ts +42 -1
- package/plugins/kxm/src/store.ts +5 -2
- package/plugins/kxm/src/tui.ts +20 -4
- package/scripts/emit-codex-artifacts.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
|
+
- **`kxm peer send --allow-offline` queues to a registered offline peer.**
|
|
10
|
+
`POST /v1/messages` accepts `allowOffline: true` (also `kxm_send.allowOffline`): a
|
|
11
|
+
registered agent in the same project is stored `queued` instead of `target_not_found`,
|
|
12
|
+
real-time `publish` is skipped, and the existing reconnect cursor delivers the message
|
|
13
|
+
once on resumption. Unknown names still fail closed. TTL expiry is unchanged; queued
|
|
14
|
+
messages are not evidence unless `workflowContext` was hub-authorized at send.
|
|
15
|
+
|
|
9
16
|
- **Per-tenant hosting operations, and a backup that covers the whole state set.**
|
|
10
17
|
`docs/operations.md` gained a *Per-tenant hosted deployment* section (one tenant = one box
|
|
11
18
|
= one hub; loopback-only hub and supervisor; the tenant's proxy owns TLS and the browser
|
package/docs/test-matrix.md
CHANGED
|
@@ -22,6 +22,7 @@ npm run verify
|
|
|
22
22
|
| All delivery modes, message fields, hop limits, and validation | `test/core/hub-api.test.ts`, `test/core/protocol.test.ts` |
|
|
23
23
|
| Queue, acknowledgement, visibility, reply, and authorization | `test/core/hub-api.test.ts`, `test/core/hub.test.ts` |
|
|
24
24
|
| Queued/delivered replay after recipient restart reuses one message record | `test/core/hub.test.ts`, `test/core/extension.test.ts`, `test/core/mcp.test.ts` |
|
|
25
|
+
| Known-offline peer send with `allowOffline` queues, delivers once on resumption, and expires unread by TTL | `test/core/hub-api.test.ts` |
|
|
25
26
|
| One-to-three-peer fanout, recoverable local timeouts/aborts, exact retries, and partial-error collection | `test/core/client.test.ts`, `test/core/hub-api.test.ts`, `test/core/extension.test.ts`, `test/core/mcp.test.ts` |
|
|
26
27
|
| TTL expiry, sender cancellation, and terminal retention | `test/core/hub-api.test.ts` |
|
|
27
28
|
| Terminal inbound cleanup and next-request activation | `test/core/extension.test.ts`, `test/core/mcp.test.ts` |
|
package/package.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.7.71",
|
|
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",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -18350,9 +18350,7 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
18350
18350
|
|
|
18351
18351
|
// plugins/kxm/src/client.ts
|
|
18352
18352
|
import { createHash as createHash3 } from "node:crypto";
|
|
18353
|
-
|
|
18354
|
-
// plugins/kxm/src/workflow.ts
|
|
18355
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
18353
|
+
import { hostname } from "node:os";
|
|
18356
18354
|
|
|
18357
18355
|
// plugins/kxm/src/protocol.ts
|
|
18358
18356
|
import { randomUUID } from "node:crypto";
|
|
@@ -18361,6 +18359,7 @@ var MIN_MESSAGE_TTL_MS = 1e3;
|
|
|
18361
18359
|
var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
18362
18360
|
var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
|
|
18363
18361
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
18362
|
+
var MAX_AGENT_HOST_CHARS = 64;
|
|
18364
18363
|
var ProtocolError = class extends Error {
|
|
18365
18364
|
statusCode;
|
|
18366
18365
|
code;
|
|
@@ -18453,6 +18452,7 @@ function validateTerminalReceipt(value) {
|
|
|
18453
18452
|
}
|
|
18454
18453
|
|
|
18455
18454
|
// plugins/kxm/src/workflow.ts
|
|
18455
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
18456
18456
|
var PROMOTABLE_JOURNAL_CATEGORIES = ["skill-candidate", "hypothesis", "experiment"];
|
|
18457
18457
|
var WORKFLOW_TERMINAL_TARGET = "$terminal";
|
|
18458
18458
|
function normalizeOutcomeValue(value, field) {
|
|
@@ -19200,6 +19200,13 @@ var MeshWaitError = class extends Error {
|
|
|
19200
19200
|
this.waitStatus = waitStatus;
|
|
19201
19201
|
}
|
|
19202
19202
|
};
|
|
19203
|
+
function defaultHostLabel() {
|
|
19204
|
+
try {
|
|
19205
|
+
return hostname().trim().slice(0, MAX_AGENT_HOST_CHARS) || void 0;
|
|
19206
|
+
} catch {
|
|
19207
|
+
return void 0;
|
|
19208
|
+
}
|
|
19209
|
+
}
|
|
19203
19210
|
function completedFanoutResult(target, message) {
|
|
19204
19211
|
if (message.status === "queued" || message.status === "delivered") {
|
|
19205
19212
|
throw new Error(`message ${message.id} is not complete`);
|
|
@@ -19289,8 +19296,11 @@ var HubClient = class {
|
|
|
19289
19296
|
this.onEvent = void 0;
|
|
19290
19297
|
this.eventLoop = void 0;
|
|
19291
19298
|
}
|
|
19292
|
-
|
|
19293
|
-
|
|
19299
|
+
/** Online peers of this client's project. `includeOffline` also returns
|
|
19300
|
+
* registered members whose lease the hub has already retired. */
|
|
19301
|
+
async listAgents(options = {}) {
|
|
19302
|
+
const path4 = options.includeOffline ? "/v1/agents?includeOffline=true" : "/v1/agents";
|
|
19303
|
+
const result = await this.request(path4);
|
|
19294
19304
|
return result.agents;
|
|
19295
19305
|
}
|
|
19296
19306
|
async send(options) {
|
|
@@ -19530,7 +19540,8 @@ var HubClient = class {
|
|
|
19530
19540
|
name: this.options.name,
|
|
19531
19541
|
purpose: this.options.purpose,
|
|
19532
19542
|
project: this.options.project,
|
|
19533
|
-
model: this.options.model
|
|
19543
|
+
model: this.options.model,
|
|
19544
|
+
host: this.options.host ?? defaultHostLabel()
|
|
19534
19545
|
})
|
|
19535
19546
|
}, false);
|
|
19536
19547
|
this.agent = registration.agent;
|
|
@@ -19770,14 +19781,19 @@ var AGENT_COMMANDS = [
|
|
|
19770
19781
|
group: "peer",
|
|
19771
19782
|
verb: "list",
|
|
19772
19783
|
label: "List hub peers",
|
|
19773
|
-
description: "List
|
|
19784
|
+
description: "List peer agents in this project's hub pool with their names, purposes, host label, and hub-clocked presence (online, stale, offline). Registered offline peers are listed only when includeOffline is set.",
|
|
19774
19785
|
parameters: {
|
|
19775
19786
|
type: "object",
|
|
19776
|
-
properties: {
|
|
19787
|
+
properties: {
|
|
19788
|
+
includeOffline: {
|
|
19789
|
+
type: "boolean",
|
|
19790
|
+
description: "Also list registered peers whose hub lease has expired"
|
|
19791
|
+
}
|
|
19792
|
+
},
|
|
19777
19793
|
additionalProperties: false
|
|
19778
19794
|
},
|
|
19779
|
-
async execute(client) {
|
|
19780
|
-
return { agents: await client.listAgents() };
|
|
19795
|
+
async execute(client, args) {
|
|
19796
|
+
return { agents: await client.listAgents({ includeOffline: args.includeOffline === true }) };
|
|
19781
19797
|
}
|
|
19782
19798
|
},
|
|
19783
19799
|
{
|
|
@@ -19817,7 +19833,12 @@ var AGENT_COMMANDS = [
|
|
|
19817
19833
|
required: ["runId", "stageId", "requirementKey", "attempt"],
|
|
19818
19834
|
additionalProperties: false
|
|
19819
19835
|
},
|
|
19820
|
-
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" }
|
|
19836
|
+
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" },
|
|
19837
|
+
allowOffline: {
|
|
19838
|
+
type: "boolean",
|
|
19839
|
+
default: false,
|
|
19840
|
+
description: "Queue the request if the target is a registered offline agent in this project"
|
|
19841
|
+
}
|
|
19821
19842
|
},
|
|
19822
19843
|
required: ["target", "content"],
|
|
19823
19844
|
additionalProperties: false
|
|
@@ -19834,7 +19855,8 @@ var AGENT_COMMANDS = [
|
|
|
19834
19855
|
...correlationId ? { correlationId } : {},
|
|
19835
19856
|
...idempotencyKey ? { idempotencyKey } : {},
|
|
19836
19857
|
...workflowContext ? { workflowContext } : {},
|
|
19837
|
-
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {}
|
|
19858
|
+
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {},
|
|
19859
|
+
...args.allowOffline === true ? { allowOffline: true } : {}
|
|
19838
19860
|
});
|
|
19839
19861
|
return { messageId: message.id, status: message.status, target: message.toName };
|
|
19840
19862
|
}
|
|
@@ -26182,8 +26204,8 @@ function printWorker(runtime, worker, payload, text, outcome) {
|
|
|
26182
26204
|
}
|
|
26183
26205
|
function hostMode(runtime) {
|
|
26184
26206
|
try {
|
|
26185
|
-
const
|
|
26186
|
-
if (
|
|
26207
|
+
const hostname2 = new URL(runtime.serverUrl).hostname;
|
|
26208
|
+
if (hostname2 === "127.0.0.1" || hostname2 === "localhost" || hostname2 === "::1") return "local";
|
|
26187
26209
|
} catch {
|
|
26188
26210
|
}
|
|
26189
26211
|
return "hub";
|
|
@@ -43081,6 +43103,13 @@ function meshTuiTheme(color) {
|
|
|
43081
43103
|
function visibleAgents(snapshot) {
|
|
43082
43104
|
return snapshot.agents.filter((agent) => agent.model !== "tui");
|
|
43083
43105
|
}
|
|
43106
|
+
function presenceCell(agent, theme, width = 7) {
|
|
43107
|
+
const presence = agent.presence ?? "n/a";
|
|
43108
|
+
const cell = pad(presence, width);
|
|
43109
|
+
if (presence === "online") return theme.success(cell);
|
|
43110
|
+
if (presence === "stale") return theme.warning(cell);
|
|
43111
|
+
return theme.dim(cell);
|
|
43112
|
+
}
|
|
43084
43113
|
function panelMetric(snapshot, panel) {
|
|
43085
43114
|
if (panel === "agents") {
|
|
43086
43115
|
const agents = visibleAgents(snapshot);
|
|
@@ -43131,7 +43160,7 @@ function listLines(snapshot, view, theme) {
|
|
|
43131
43160
|
const now = Date.parse(snapshot.fetchedAt);
|
|
43132
43161
|
const mark = (index) => cursor(theme, index === view.selected, "list", view.pane);
|
|
43133
43162
|
if (view.tab === "agents") {
|
|
43134
|
-
return visibleAgents(snapshot).map((agent, index) => `${mark(index)}${pad(agent.name, 14)} ${agent
|
|
43163
|
+
return visibleAgents(snapshot).map((agent, index) => `${mark(index)}${pad(agent.name, 14)} ${presenceCell(agent, theme)} ${pad(agent.host ?? "-", 12)} ${pad(agent.model ?? "-", 14)} ${pad(age(agent.lastSeenAt, now), 4)}`);
|
|
43135
43164
|
}
|
|
43136
43165
|
if (view.tab === "tasks" || view.tab === "workflows") {
|
|
43137
43166
|
const runs = view.tab === "tasks" ? snapshot.runs.filter((run) => run.status === "running" || run.status === "waiting") : snapshot.runs;
|
|
@@ -43169,9 +43198,10 @@ function detailLines(snapshot, view, theme) {
|
|
|
43169
43198
|
const related = snapshot.openMessages.filter((message) => message.fromName === agent.name || message.toName === agent.name);
|
|
43170
43199
|
return [
|
|
43171
43200
|
theme.accent(agent.name),
|
|
43172
|
-
`${agent
|
|
43201
|
+
`${presenceCell(agent, theme, (agent.presence ?? "n/a").length)} ${agent.model ?? "-"}`,
|
|
43202
|
+
`host ${agent.host ?? "-"}`,
|
|
43173
43203
|
agent.purpose,
|
|
43174
|
-
`seen ${age(agent.lastSeenAt, now)} ago`,
|
|
43204
|
+
`seen ${age(agent.lastSeenAt, now)} ago \xB7 lease ${agent.leaseExpiresAt?.slice(11, 19) ?? "n/a"} UTC`,
|
|
43175
43205
|
"",
|
|
43176
43206
|
theme.dim("Open work"),
|
|
43177
43207
|
...related.length === 0 ? [theme.dim("none")] : related.map((message) => `${message.status} ${message.fromName} \u2192 ${message.toName} ${age(message.createdAt, now)}`)
|
|
@@ -43480,7 +43510,7 @@ async function runMeshTui(input) {
|
|
|
43480
43510
|
}
|
|
43481
43511
|
if (!useOpsStream && identity) {
|
|
43482
43512
|
try {
|
|
43483
|
-
const listed = await input.fetchImpl(`${base}/v1/agents`, { headers: headers(identity) });
|
|
43513
|
+
const listed = await input.fetchImpl(`${base}/v1/agents?includeOffline=true`, { headers: headers(identity) });
|
|
43484
43514
|
if (listed.ok) {
|
|
43485
43515
|
const body = await readJson(listed);
|
|
43486
43516
|
const byId = new Map(local.agents.map((agent) => [agent.id, agent]));
|
|
@@ -47738,10 +47768,10 @@ function createProgram(ctx, result) {
|
|
|
47738
47768
|
});
|
|
47739
47769
|
const peer = addGlobalOptions(program2.command("peer").description("Peer agent messaging and coordination"));
|
|
47740
47770
|
peer.helpCommand("help", "Show peer help");
|
|
47741
|
-
addGlobalOptions(peer.command("list").description("List
|
|
47771
|
+
addGlobalOptions(peer.command("list").description("List peer agents in this project's hub pool with host and presence")).option("--include-offline", "Also list registered peers whose hub lease has expired").option("--payload <json>", "JSON payload").action(async function peerListAction(opts) {
|
|
47742
47772
|
result.code = await dispatchAgentCliCommand(runtimeFrom(ctx, this), "kxm_list", opts ?? {});
|
|
47743
47773
|
});
|
|
47744
|
-
addGlobalOptions(peer.command("send [target] [content]").description("Send a focused request to a peer agent")).option("--target <name>", "Peer name or agent ID").option("--content <text>", "Focused request content").option("--delivery <mode>", "steer, followUp, or nextTurn").option("--correlation-id <id>", "Task grouping ID").option("--idempotency-key <key>", "Deduplication key").option("--workflow-context <json>", "Workflow context JSON").option("--ttl-ms <ms>", "Message TTL in milliseconds").option("--payload <json>", "JSON payload").action(async function peerSendAction(target, content, opts) {
|
|
47774
|
+
addGlobalOptions(peer.command("send [target] [content]").description("Send a focused request to a peer agent")).option("--target <name>", "Peer name or agent ID").option("--content <text>", "Focused request content").option("--delivery <mode>", "steer, followUp, or nextTurn").option("--correlation-id <id>", "Task grouping ID").option("--idempotency-key <key>", "Deduplication key").option("--workflow-context <json>", "Workflow context JSON").option("--ttl-ms <ms>", "Message TTL in milliseconds").option("--allow-offline", "Queue the request if the target is registered but offline").option("--payload <json>", "JSON payload").action(async function peerSendAction(target, content, opts) {
|
|
47745
47775
|
const options = { ...opts, ...target ? { target } : {}, ...content ? { content } : {} };
|
|
47746
47776
|
result.code = await dispatchAgentCliCommand(runtimeFrom(ctx, this), "kxm_send", options);
|
|
47747
47777
|
});
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// plugins/kxm/src/client.ts
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import { hostname } from "node:os";
|
|
3
4
|
|
|
4
5
|
// plugins/kxm/src/protocol.ts
|
|
5
6
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
6
7
|
var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
7
8
|
var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
|
|
8
9
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
10
|
+
var MAX_AGENT_HOST_CHARS = 64;
|
|
9
11
|
|
|
10
12
|
// plugins/kxm/src/workflow.ts
|
|
11
13
|
function canonicalWorkflowEvidenceKey(value) {
|
|
@@ -21,6 +23,13 @@ var MeshWaitError = class extends Error {
|
|
|
21
23
|
this.waitStatus = waitStatus;
|
|
22
24
|
}
|
|
23
25
|
};
|
|
26
|
+
function defaultHostLabel() {
|
|
27
|
+
try {
|
|
28
|
+
return hostname().trim().slice(0, MAX_AGENT_HOST_CHARS) || void 0;
|
|
29
|
+
} catch {
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
24
33
|
function completedFanoutResult(target, message) {
|
|
25
34
|
if (message.status === "queued" || message.status === "delivered") {
|
|
26
35
|
throw new Error(`message ${message.id} is not complete`);
|
|
@@ -110,8 +119,11 @@ var HubClient = class {
|
|
|
110
119
|
this.onEvent = void 0;
|
|
111
120
|
this.eventLoop = void 0;
|
|
112
121
|
}
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
/** Online peers of this client's project. `includeOffline` also returns
|
|
123
|
+
* registered members whose lease the hub has already retired. */
|
|
124
|
+
async listAgents(options = {}) {
|
|
125
|
+
const path = options.includeOffline ? "/v1/agents?includeOffline=true" : "/v1/agents";
|
|
126
|
+
const result = await this.request(path);
|
|
115
127
|
return result.agents;
|
|
116
128
|
}
|
|
117
129
|
async send(options) {
|
|
@@ -351,7 +363,8 @@ var HubClient = class {
|
|
|
351
363
|
name: this.options.name,
|
|
352
364
|
purpose: this.options.purpose,
|
|
353
365
|
project: this.options.project,
|
|
354
|
-
model: this.options.model
|
|
366
|
+
model: this.options.model,
|
|
367
|
+
host: this.options.host ?? defaultHostLabel()
|
|
355
368
|
})
|
|
356
369
|
}, false);
|
|
357
370
|
this.agent = registration.agent;
|
package/plugins/kxm/dist/core.js
CHANGED
|
@@ -12,6 +12,17 @@ var DEFAULT_RATE_LIMIT_MAX = 600;
|
|
|
12
12
|
var DEFAULT_RATE_LIMIT_WINDOW_MS = 6e4;
|
|
13
13
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
14
14
|
var MAX_CONTENT_CHARS = 32e3;
|
|
15
|
+
var MAX_AGENT_HOST_CHARS = 64;
|
|
16
|
+
function agentPresenceView(agent, staleAfterMs = DEFAULT_STALE_AFTER_MS, now = Date.now()) {
|
|
17
|
+
const lastSeenMs = Date.parse(agent.lastSeenAt);
|
|
18
|
+
const leaseExpiresAtMs = (Number.isFinite(lastSeenMs) ? lastSeenMs : 0) + staleAfterMs;
|
|
19
|
+
const leaseExpiresAt = new Date(leaseExpiresAtMs).toISOString();
|
|
20
|
+
if (!agent.online) return { leaseExpiresAt, presence: "offline" };
|
|
21
|
+
return { leaseExpiresAt, presence: now < leaseExpiresAtMs ? "online" : "stale" };
|
|
22
|
+
}
|
|
23
|
+
function toAgentRecord(agent, staleAfterMs, now) {
|
|
24
|
+
return { ...agent, ...agentPresenceView(agent, staleAfterMs, now) };
|
|
25
|
+
}
|
|
15
26
|
var ProtocolError = class extends Error {
|
|
16
27
|
statusCode;
|
|
17
28
|
code;
|
|
@@ -945,14 +956,19 @@ var AGENT_COMMANDS = [
|
|
|
945
956
|
group: "peer",
|
|
946
957
|
verb: "list",
|
|
947
958
|
label: "List hub peers",
|
|
948
|
-
description: "List
|
|
959
|
+
description: "List peer agents in this project's hub pool with their names, purposes, host label, and hub-clocked presence (online, stale, offline). Registered offline peers are listed only when includeOffline is set.",
|
|
949
960
|
parameters: {
|
|
950
961
|
type: "object",
|
|
951
|
-
properties: {
|
|
962
|
+
properties: {
|
|
963
|
+
includeOffline: {
|
|
964
|
+
type: "boolean",
|
|
965
|
+
description: "Also list registered peers whose hub lease has expired"
|
|
966
|
+
}
|
|
967
|
+
},
|
|
952
968
|
additionalProperties: false
|
|
953
969
|
},
|
|
954
|
-
async execute(client) {
|
|
955
|
-
return { agents: await client.listAgents() };
|
|
970
|
+
async execute(client, args) {
|
|
971
|
+
return { agents: await client.listAgents({ includeOffline: args.includeOffline === true }) };
|
|
956
972
|
}
|
|
957
973
|
},
|
|
958
974
|
{
|
|
@@ -992,7 +1008,12 @@ var AGENT_COMMANDS = [
|
|
|
992
1008
|
required: ["runId", "stageId", "requirementKey", "attempt"],
|
|
993
1009
|
additionalProperties: false
|
|
994
1010
|
},
|
|
995
|
-
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" }
|
|
1011
|
+
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" },
|
|
1012
|
+
allowOffline: {
|
|
1013
|
+
type: "boolean",
|
|
1014
|
+
default: false,
|
|
1015
|
+
description: "Queue the request if the target is a registered offline agent in this project"
|
|
1016
|
+
}
|
|
996
1017
|
},
|
|
997
1018
|
required: ["target", "content"],
|
|
998
1019
|
additionalProperties: false
|
|
@@ -1009,7 +1030,8 @@ var AGENT_COMMANDS = [
|
|
|
1009
1030
|
...correlationId ? { correlationId } : {},
|
|
1010
1031
|
...idempotencyKey ? { idempotencyKey } : {},
|
|
1011
1032
|
...workflowContext ? { workflowContext } : {},
|
|
1012
|
-
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {}
|
|
1033
|
+
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {},
|
|
1034
|
+
...args.allowOffline === true ? { allowOffline: true } : {}
|
|
1013
1035
|
});
|
|
1014
1036
|
return { messageId: message.id, status: message.status, target: message.toName };
|
|
1015
1037
|
}
|
|
@@ -2005,6 +2027,7 @@ export {
|
|
|
2005
2027
|
DEFAULT_RATE_LIMIT_WINDOW_MS,
|
|
2006
2028
|
DEFAULT_STALE_AFTER_MS,
|
|
2007
2029
|
LOG_LEVEL_PRIORITY,
|
|
2030
|
+
MAX_AGENT_HOST_CHARS,
|
|
2008
2031
|
MAX_BODY_BYTES,
|
|
2009
2032
|
MAX_CONTENT_CHARS,
|
|
2010
2033
|
MAX_CONTEXT_ITEM_IDS,
|
|
@@ -2020,6 +2043,7 @@ export {
|
|
|
2020
2043
|
TERMINAL_RECEIPT_SCHEMA,
|
|
2021
2044
|
WORKER_RESULT_SCHEMA,
|
|
2022
2045
|
WORKER_SCHEMA,
|
|
2046
|
+
agentPresenceView,
|
|
2023
2047
|
agentWorker,
|
|
2024
2048
|
behavioralConfigHash,
|
|
2025
2049
|
clearSessionTokenFromDisk,
|
|
@@ -2060,6 +2084,7 @@ export {
|
|
|
2060
2084
|
rotateLogFiles,
|
|
2061
2085
|
sessionTokenPath,
|
|
2062
2086
|
timingSafeStringCompare,
|
|
2087
|
+
toAgentRecord,
|
|
2063
2088
|
validateTerminalReceipt,
|
|
2064
2089
|
workerResult
|
|
2065
2090
|
};
|
|
@@ -14534,6 +14534,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
14534
14534
|
|
|
14535
14535
|
// plugins/kxm/src/client.ts
|
|
14536
14536
|
import { createHash } from "node:crypto";
|
|
14537
|
+
import { hostname } from "node:os";
|
|
14537
14538
|
|
|
14538
14539
|
// plugins/kxm/src/protocol.ts
|
|
14539
14540
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
@@ -14541,6 +14542,7 @@ var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
|
14541
14542
|
var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
|
|
14542
14543
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
14543
14544
|
var MAX_CONTENT_CHARS = 32e3;
|
|
14545
|
+
var MAX_AGENT_HOST_CHARS = 64;
|
|
14544
14546
|
|
|
14545
14547
|
// plugins/kxm/src/workflow.ts
|
|
14546
14548
|
function canonicalWorkflowEvidenceKey(value) {
|
|
@@ -14556,6 +14558,13 @@ var MeshWaitError = class extends Error {
|
|
|
14556
14558
|
this.waitStatus = waitStatus;
|
|
14557
14559
|
}
|
|
14558
14560
|
};
|
|
14561
|
+
function defaultHostLabel() {
|
|
14562
|
+
try {
|
|
14563
|
+
return hostname().trim().slice(0, MAX_AGENT_HOST_CHARS) || void 0;
|
|
14564
|
+
} catch {
|
|
14565
|
+
return void 0;
|
|
14566
|
+
}
|
|
14567
|
+
}
|
|
14559
14568
|
function completedFanoutResult(target, message) {
|
|
14560
14569
|
if (message.status === "queued" || message.status === "delivered") {
|
|
14561
14570
|
throw new Error(`message ${message.id} is not complete`);
|
|
@@ -14645,8 +14654,11 @@ var HubClient = class {
|
|
|
14645
14654
|
this.onEvent = void 0;
|
|
14646
14655
|
this.eventLoop = void 0;
|
|
14647
14656
|
}
|
|
14648
|
-
|
|
14649
|
-
|
|
14657
|
+
/** Online peers of this client's project. `includeOffline` also returns
|
|
14658
|
+
* registered members whose lease the hub has already retired. */
|
|
14659
|
+
async listAgents(options = {}) {
|
|
14660
|
+
const path = options.includeOffline ? "/v1/agents?includeOffline=true" : "/v1/agents";
|
|
14661
|
+
const result2 = await this.request(path);
|
|
14650
14662
|
return result2.agents;
|
|
14651
14663
|
}
|
|
14652
14664
|
async send(options) {
|
|
@@ -14886,7 +14898,8 @@ var HubClient = class {
|
|
|
14886
14898
|
name: this.options.name,
|
|
14887
14899
|
purpose: this.options.purpose,
|
|
14888
14900
|
project: this.options.project,
|
|
14889
|
-
model: this.options.model
|
|
14901
|
+
model: this.options.model,
|
|
14902
|
+
host: this.options.host ?? defaultHostLabel()
|
|
14890
14903
|
})
|
|
14891
14904
|
}, false);
|
|
14892
14905
|
this.agent = registration.agent;
|
|
@@ -15014,14 +15027,19 @@ var AGENT_COMMANDS = [
|
|
|
15014
15027
|
group: "peer",
|
|
15015
15028
|
verb: "list",
|
|
15016
15029
|
label: "List hub peers",
|
|
15017
|
-
description: "List
|
|
15030
|
+
description: "List peer agents in this project's hub pool with their names, purposes, host label, and hub-clocked presence (online, stale, offline). Registered offline peers are listed only when includeOffline is set.",
|
|
15018
15031
|
parameters: {
|
|
15019
15032
|
type: "object",
|
|
15020
|
-
properties: {
|
|
15033
|
+
properties: {
|
|
15034
|
+
includeOffline: {
|
|
15035
|
+
type: "boolean",
|
|
15036
|
+
description: "Also list registered peers whose hub lease has expired"
|
|
15037
|
+
}
|
|
15038
|
+
},
|
|
15021
15039
|
additionalProperties: false
|
|
15022
15040
|
},
|
|
15023
|
-
async execute(client) {
|
|
15024
|
-
return { agents: await client.listAgents() };
|
|
15041
|
+
async execute(client, args) {
|
|
15042
|
+
return { agents: await client.listAgents({ includeOffline: args.includeOffline === true }) };
|
|
15025
15043
|
}
|
|
15026
15044
|
},
|
|
15027
15045
|
{
|
|
@@ -15061,7 +15079,12 @@ var AGENT_COMMANDS = [
|
|
|
15061
15079
|
required: ["runId", "stageId", "requirementKey", "attempt"],
|
|
15062
15080
|
additionalProperties: false
|
|
15063
15081
|
},
|
|
15064
|
-
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" }
|
|
15082
|
+
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" },
|
|
15083
|
+
allowOffline: {
|
|
15084
|
+
type: "boolean",
|
|
15085
|
+
default: false,
|
|
15086
|
+
description: "Queue the request if the target is a registered offline agent in this project"
|
|
15087
|
+
}
|
|
15065
15088
|
},
|
|
15066
15089
|
required: ["target", "content"],
|
|
15067
15090
|
additionalProperties: false
|
|
@@ -15078,7 +15101,8 @@ var AGENT_COMMANDS = [
|
|
|
15078
15101
|
...correlationId ? { correlationId } : {},
|
|
15079
15102
|
...idempotencyKey ? { idempotencyKey } : {},
|
|
15080
15103
|
...workflowContext ? { workflowContext } : {},
|
|
15081
|
-
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {}
|
|
15104
|
+
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {},
|
|
15105
|
+
...args.allowOffline === true ? { allowOffline: true } : {}
|
|
15082
15106
|
});
|
|
15083
15107
|
return { messageId: message.id, status: message.status, target: message.toName };
|
|
15084
15108
|
}
|
|
@@ -15755,12 +15755,14 @@ var StdioServerTransport = class {
|
|
|
15755
15755
|
|
|
15756
15756
|
// plugins/kxm/src/client.ts
|
|
15757
15757
|
import { createHash } from "node:crypto";
|
|
15758
|
+
import { hostname } from "node:os";
|
|
15758
15759
|
|
|
15759
15760
|
// plugins/kxm/src/protocol.ts
|
|
15760
15761
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
15761
15762
|
var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
15762
15763
|
var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
|
|
15763
15764
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
15765
|
+
var MAX_AGENT_HOST_CHARS = 64;
|
|
15764
15766
|
|
|
15765
15767
|
// plugins/kxm/src/workflow.ts
|
|
15766
15768
|
function canonicalWorkflowEvidenceKey(value) {
|
|
@@ -15776,6 +15778,13 @@ var MeshWaitError = class extends Error {
|
|
|
15776
15778
|
this.waitStatus = waitStatus;
|
|
15777
15779
|
}
|
|
15778
15780
|
};
|
|
15781
|
+
function defaultHostLabel() {
|
|
15782
|
+
try {
|
|
15783
|
+
return hostname().trim().slice(0, MAX_AGENT_HOST_CHARS) || void 0;
|
|
15784
|
+
} catch {
|
|
15785
|
+
return void 0;
|
|
15786
|
+
}
|
|
15787
|
+
}
|
|
15779
15788
|
function completedFanoutResult(target, message) {
|
|
15780
15789
|
if (message.status === "queued" || message.status === "delivered") {
|
|
15781
15790
|
throw new Error(`message ${message.id} is not complete`);
|
|
@@ -15865,8 +15874,11 @@ var HubClient = class {
|
|
|
15865
15874
|
this.onEvent = void 0;
|
|
15866
15875
|
this.eventLoop = void 0;
|
|
15867
15876
|
}
|
|
15868
|
-
|
|
15869
|
-
|
|
15877
|
+
/** Online peers of this client's project. `includeOffline` also returns
|
|
15878
|
+
* registered members whose lease the hub has already retired. */
|
|
15879
|
+
async listAgents(options = {}) {
|
|
15880
|
+
const path = options.includeOffline ? "/v1/agents?includeOffline=true" : "/v1/agents";
|
|
15881
|
+
const result = await this.request(path);
|
|
15870
15882
|
return result.agents;
|
|
15871
15883
|
}
|
|
15872
15884
|
async send(options) {
|
|
@@ -16106,7 +16118,8 @@ var HubClient = class {
|
|
|
16106
16118
|
name: this.options.name,
|
|
16107
16119
|
purpose: this.options.purpose,
|
|
16108
16120
|
project: this.options.project,
|
|
16109
|
-
model: this.options.model
|
|
16121
|
+
model: this.options.model,
|
|
16122
|
+
host: this.options.host ?? defaultHostLabel()
|
|
16110
16123
|
})
|
|
16111
16124
|
}, false);
|
|
16112
16125
|
this.agent = registration.agent;
|
|
@@ -16325,14 +16338,19 @@ var AGENT_COMMANDS = [
|
|
|
16325
16338
|
group: "peer",
|
|
16326
16339
|
verb: "list",
|
|
16327
16340
|
label: "List hub peers",
|
|
16328
|
-
description: "List
|
|
16341
|
+
description: "List peer agents in this project's hub pool with their names, purposes, host label, and hub-clocked presence (online, stale, offline). Registered offline peers are listed only when includeOffline is set.",
|
|
16329
16342
|
parameters: {
|
|
16330
16343
|
type: "object",
|
|
16331
|
-
properties: {
|
|
16344
|
+
properties: {
|
|
16345
|
+
includeOffline: {
|
|
16346
|
+
type: "boolean",
|
|
16347
|
+
description: "Also list registered peers whose hub lease has expired"
|
|
16348
|
+
}
|
|
16349
|
+
},
|
|
16332
16350
|
additionalProperties: false
|
|
16333
16351
|
},
|
|
16334
|
-
async execute(client) {
|
|
16335
|
-
return { agents: await client.listAgents() };
|
|
16352
|
+
async execute(client, args) {
|
|
16353
|
+
return { agents: await client.listAgents({ includeOffline: args.includeOffline === true }) };
|
|
16336
16354
|
}
|
|
16337
16355
|
},
|
|
16338
16356
|
{
|
|
@@ -16372,7 +16390,12 @@ var AGENT_COMMANDS = [
|
|
|
16372
16390
|
required: ["runId", "stageId", "requirementKey", "attempt"],
|
|
16373
16391
|
additionalProperties: false
|
|
16374
16392
|
},
|
|
16375
|
-
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" }
|
|
16393
|
+
ttlMs: { type: "number", minimum: 1e3, maximum: 6048e5, description: "Message TTL in milliseconds" },
|
|
16394
|
+
allowOffline: {
|
|
16395
|
+
type: "boolean",
|
|
16396
|
+
default: false,
|
|
16397
|
+
description: "Queue the request if the target is a registered offline agent in this project"
|
|
16398
|
+
}
|
|
16376
16399
|
},
|
|
16377
16400
|
required: ["target", "content"],
|
|
16378
16401
|
additionalProperties: false
|
|
@@ -16389,7 +16412,8 @@ var AGENT_COMMANDS = [
|
|
|
16389
16412
|
...correlationId ? { correlationId } : {},
|
|
16390
16413
|
...idempotencyKey ? { idempotencyKey } : {},
|
|
16391
16414
|
...workflowContext ? { workflowContext } : {},
|
|
16392
|
-
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {}
|
|
16415
|
+
...typeof args.ttlMs === "number" ? { ttlMs: args.ttlMs } : {},
|
|
16416
|
+
...args.allowOffline === true ? { allowOffline: true } : {}
|
|
16393
16417
|
});
|
|
16394
16418
|
return { messageId: message.id, status: message.status, target: message.toName };
|
|
16395
16419
|
}
|
|
@@ -17121,7 +17145,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
|
|
|
17121
17145
|
}
|
|
17122
17146
|
|
|
17123
17147
|
// plugins/kxm/src/mcp-server.ts
|
|
17124
|
-
var VERSION = "0.7.
|
|
17148
|
+
var VERSION = "0.7.71";
|
|
17125
17149
|
var inbox = /* @__PURE__ */ new Map();
|
|
17126
17150
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17127
17151
|
var meshClient;
|