@kontextmind/kxm 0.7.87 → 0.7.89
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/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +2 -2
- package/plugins/kxm/dist/core.js +2 -2
- package/plugins/kxm/dist/extension.js +2 -2
- package/plugins/kxm/dist/mcp-server.js +3 -3
- package/plugins/kxm/dist/server.js +22 -8
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/commands.ts +2 -2
- package/plugins/kxm/src/context/providers.ts +4 -0
- package/plugins/kxm/src/hub.ts +26 -8
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/state.ts +4 -1
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.89",
|
|
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
|
@@ -20436,8 +20436,8 @@ var AGENT_COMMANDS = [
|
|
|
20436
20436
|
summary: { type: "string", description: "Promotion summary" },
|
|
20437
20437
|
authority: {
|
|
20438
20438
|
type: "string",
|
|
20439
|
-
enum: ["
|
|
20440
|
-
description: "Authority class"
|
|
20439
|
+
enum: ["evidence", "hypothesis"],
|
|
20440
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most"
|
|
20441
20441
|
},
|
|
20442
20442
|
confidence: {
|
|
20443
20443
|
type: "string",
|
package/plugins/kxm/dist/core.js
CHANGED
|
@@ -1567,8 +1567,8 @@ var AGENT_COMMANDS = [
|
|
|
1567
1567
|
summary: { type: "string", description: "Promotion summary" },
|
|
1568
1568
|
authority: {
|
|
1569
1569
|
type: "string",
|
|
1570
|
-
enum: ["
|
|
1571
|
-
description: "Authority class"
|
|
1570
|
+
enum: ["evidence", "hypothesis"],
|
|
1571
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most"
|
|
1572
1572
|
},
|
|
1573
1573
|
confidence: {
|
|
1574
1574
|
type: "string",
|
|
@@ -15670,8 +15670,8 @@ var AGENT_COMMANDS = [
|
|
|
15670
15670
|
summary: { type: "string", description: "Promotion summary" },
|
|
15671
15671
|
authority: {
|
|
15672
15672
|
type: "string",
|
|
15673
|
-
enum: ["
|
|
15674
|
-
description: "Authority class"
|
|
15673
|
+
enum: ["evidence", "hypothesis"],
|
|
15674
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most"
|
|
15675
15675
|
},
|
|
15676
15676
|
confidence: {
|
|
15677
15677
|
type: "string",
|
|
@@ -16981,8 +16981,8 @@ var AGENT_COMMANDS = [
|
|
|
16981
16981
|
summary: { type: "string", description: "Promotion summary" },
|
|
16982
16982
|
authority: {
|
|
16983
16983
|
type: "string",
|
|
16984
|
-
enum: ["
|
|
16985
|
-
description: "Authority class"
|
|
16984
|
+
enum: ["evidence", "hypothesis"],
|
|
16985
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most"
|
|
16986
16986
|
},
|
|
16987
16987
|
confidence: {
|
|
16988
16988
|
type: "string",
|
|
@@ -17182,7 +17182,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
|
|
|
17182
17182
|
}
|
|
17183
17183
|
|
|
17184
17184
|
// plugins/kxm/src/mcp-server.ts
|
|
17185
|
-
var VERSION = "0.7.
|
|
17185
|
+
var VERSION = "0.7.89";
|
|
17186
17186
|
var inbox = /* @__PURE__ */ new Map();
|
|
17187
17187
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17188
17188
|
var meshClient;
|
|
@@ -17303,8 +17303,8 @@ var AGENT_COMMANDS = [
|
|
|
17303
17303
|
summary: { type: "string", description: "Promotion summary" },
|
|
17304
17304
|
authority: {
|
|
17305
17305
|
type: "string",
|
|
17306
|
-
enum: ["
|
|
17307
|
-
description: "Authority class"
|
|
17306
|
+
enum: ["evidence", "hypothesis"],
|
|
17307
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most"
|
|
17308
17308
|
},
|
|
17309
17309
|
confidence: {
|
|
17310
17310
|
type: "string",
|
|
@@ -18082,6 +18082,9 @@ var NativeStateProvider = class {
|
|
|
18082
18082
|
if (change?.schema !== "kxm.state-change-proposal.v1") {
|
|
18083
18083
|
throw new ProtocolError(400, "invalid state change proposal schema", "invalid_state_proposal");
|
|
18084
18084
|
}
|
|
18085
|
+
if (change.origin !== "peer" && change.origin !== "human") {
|
|
18086
|
+
throw new ProtocolError(400, "state change proposal origin must be peer or human", "invalid_state_proposal");
|
|
18087
|
+
}
|
|
18085
18088
|
const project = requireNonEmpty(change.project, "proposal project");
|
|
18086
18089
|
const key = requireNonEmpty(change.key, "proposal key");
|
|
18087
18090
|
const evidenceRefs = boundedRefs(change.evidenceRefs, "proposal evidenceRefs");
|
|
@@ -18091,7 +18094,7 @@ var NativeStateProvider = class {
|
|
|
18091
18094
|
project,
|
|
18092
18095
|
summary: change.summary,
|
|
18093
18096
|
provenance: {
|
|
18094
|
-
sourceType: change.
|
|
18097
|
+
sourceType: change.origin,
|
|
18095
18098
|
sourceRef: `proposed-by:${change.proposedBy}`
|
|
18096
18099
|
},
|
|
18097
18100
|
authority: change.authority,
|
|
@@ -20481,12 +20484,12 @@ function createMeshHub(options = {}) {
|
|
|
20481
20484
|
if (agent.project !== project) {
|
|
20482
20485
|
throw new ProtocolError(403, "context requests are limited to the agent's project", "context_isolation_violation");
|
|
20483
20486
|
}
|
|
20484
|
-
return { project, caller: agent.id };
|
|
20487
|
+
return { project, caller: agent.id, credential: "agent" };
|
|
20485
20488
|
}
|
|
20486
20489
|
requireAdminAuth(request);
|
|
20487
20490
|
const callerHeader = request.headers["x-kxm-caller-id"];
|
|
20488
20491
|
const caller = typeof callerHeader === "string" && callerHeader.trim() ? callerHeader.trim() : "kxm-admin";
|
|
20489
|
-
return { project, caller };
|
|
20492
|
+
return { project, caller, credential: "admin" };
|
|
20490
20493
|
}
|
|
20491
20494
|
function requireAdminAuth(request) {
|
|
20492
20495
|
if (!authToken2 && isLoopback(host2)) return;
|
|
@@ -21593,7 +21596,17 @@ data: ${JSON.stringify({ type: "ops", project, topic: "agents", at: nowIso() })}
|
|
|
21593
21596
|
const contextStateProposeMatch = url.pathname.match(/^\/v1\/context\/state\/propose$/);
|
|
21594
21597
|
if (method === "POST" && contextStateProposeMatch) {
|
|
21595
21598
|
const body = await readJson(request);
|
|
21596
|
-
const { project: callerProject, caller: callerId } = contextCallerProject(request, body.project);
|
|
21599
|
+
const { project: callerProject, caller: callerId, credential } = contextCallerProject(request, body.project);
|
|
21600
|
+
if (credential === "admin") requireConfiguredAdminAuth(request, "human-origin state proposals");
|
|
21601
|
+
if (body.proposedBy !== void 0 && body.proposedBy !== callerId) {
|
|
21602
|
+
logger({ event: "security_alert", alert: "state_proposer_mismatch", project: callerProject, callerId, credential });
|
|
21603
|
+
throw new ProtocolError(
|
|
21604
|
+
403,
|
|
21605
|
+
"proposedBy must name the authenticated caller",
|
|
21606
|
+
"state_proposer_mismatch"
|
|
21607
|
+
);
|
|
21608
|
+
}
|
|
21609
|
+
const origin = credential === "agent" ? "peer" : "human";
|
|
21597
21610
|
const proposalId = await stateProvider.propose({
|
|
21598
21611
|
schema: "kxm.state-change-proposal.v1",
|
|
21599
21612
|
project: callerProject,
|
|
@@ -21602,11 +21615,12 @@ data: ${JSON.stringify({ type: "ops", project, topic: "agents", at: nowIso() })}
|
|
|
21602
21615
|
authority: parseContextAuthority(body.authority),
|
|
21603
21616
|
confidence: parseContextConfidence(body.confidence),
|
|
21604
21617
|
evidenceRefs: boundedStringList(body.evidenceRefs, "evidenceRefs", 32),
|
|
21605
|
-
proposedBy:
|
|
21618
|
+
proposedBy: callerId,
|
|
21619
|
+
origin
|
|
21606
21620
|
});
|
|
21607
21621
|
counters.contextRequests += 1;
|
|
21608
21622
|
publishOps(callerProject, "workflows");
|
|
21609
|
-
logger({ event: "context_state_proposed", project: callerProject, proposalId, proposedBy: callerId });
|
|
21623
|
+
logger({ event: "context_state_proposed", project: callerProject, proposalId, proposedBy: callerId, origin });
|
|
21610
21624
|
json(response, 201, { proposalId });
|
|
21611
21625
|
return;
|
|
21612
21626
|
}
|
package/plugins/kxm/package.json
CHANGED
|
@@ -823,8 +823,8 @@ export const AGENT_COMMANDS: readonly AgentCommand[] = [
|
|
|
823
823
|
summary: { type: "string", description: "Promotion summary" },
|
|
824
824
|
authority: {
|
|
825
825
|
type: "string",
|
|
826
|
-
enum: ["
|
|
827
|
-
description: "Authority class",
|
|
826
|
+
enum: ["evidence", "hypothesis"],
|
|
827
|
+
description: "Authority class; an agent's proposal is peer origin, so evidence at most",
|
|
828
828
|
},
|
|
829
829
|
confidence: {
|
|
830
830
|
type: "string",
|
|
@@ -44,6 +44,10 @@ export interface StateChangeProposal {
|
|
|
44
44
|
confidence: ContextItem["confidence"];
|
|
45
45
|
evidenceRefs: string[];
|
|
46
46
|
proposedBy: string;
|
|
47
|
+
/** Origin of the credential the hub verified for the proposer: an agent
|
|
48
|
+
* key is `peer` (evidence at most), the administrative token `human`.
|
|
49
|
+
* Never inferred from `proposedBy`, which is a label, not a credential. */
|
|
50
|
+
origin: "peer" | "human";
|
|
47
51
|
supersedes?: string[];
|
|
48
52
|
}
|
|
49
53
|
|
package/plugins/kxm/src/hub.ts
CHANGED
|
@@ -601,9 +601,12 @@ export function createMeshHub(options: MeshHubOptions = {}): MeshHub {
|
|
|
601
601
|
|
|
602
602
|
/** Context callers authenticate either as a registered agent (project-
|
|
603
603
|
* scoped to their own project) or with the administrative token (single
|
|
604
|
-
* explicit project scope per request). Returns the validated project
|
|
605
|
-
*
|
|
606
|
-
function contextCallerProject(
|
|
604
|
+
* explicit project scope per request). Returns the validated project, a
|
|
605
|
+
* stable caller identity for provenance, and which credential proved it. */
|
|
606
|
+
function contextCallerProject(
|
|
607
|
+
request: IncomingMessage,
|
|
608
|
+
requested: unknown,
|
|
609
|
+
): { project: string; caller: string; credential: "agent" | "admin" } {
|
|
607
610
|
const project = requireString(requested, "project", { max: 200 });
|
|
608
611
|
const agentHeader = request.headers["x-kxm-agent-id"];
|
|
609
612
|
if (typeof agentHeader === "string" && agentHeader.trim()) {
|
|
@@ -612,14 +615,14 @@ export function createMeshHub(options: MeshHubOptions = {}): MeshHub {
|
|
|
612
615
|
if (agent.project !== project) {
|
|
613
616
|
throw new ProtocolError(403, "context requests are limited to the agent's project", "context_isolation_violation");
|
|
614
617
|
}
|
|
615
|
-
return { project, caller: agent.id };
|
|
618
|
+
return { project, caller: agent.id, credential: "agent" };
|
|
616
619
|
}
|
|
617
620
|
requireAdminAuth(request);
|
|
618
621
|
const callerHeader = request.headers["x-kxm-caller-id"];
|
|
619
622
|
const caller = typeof callerHeader === "string" && callerHeader.trim()
|
|
620
623
|
? callerHeader.trim()
|
|
621
624
|
: "kxm-admin";
|
|
622
|
-
return { project, caller };
|
|
625
|
+
return { project, caller, credential: "admin" };
|
|
623
626
|
}
|
|
624
627
|
|
|
625
628
|
function requireAdminAuth(request: IncomingMessage): void {
|
|
@@ -1829,7 +1832,21 @@ export function createMeshHub(options: MeshHubOptions = {}): MeshHub {
|
|
|
1829
1832
|
const contextStateProposeMatch = url.pathname.match(/^\/v1\/context\/state\/propose$/);
|
|
1830
1833
|
if (method === "POST" && contextStateProposeMatch) {
|
|
1831
1834
|
const body = await readJson(request);
|
|
1832
|
-
const { project: callerProject, caller: callerId } = contextCallerProject(request, body.project);
|
|
1835
|
+
const { project: callerProject, caller: callerId, credential } = contextCallerProject(request, body.project);
|
|
1836
|
+
// Origin follows the credential, never a name: an agent key proposes as
|
|
1837
|
+
// a peer, capped at evidence by the grant floor. Human origin can claim
|
|
1838
|
+
// policy, so it takes the configured administrative token with no
|
|
1839
|
+
// loopback bypass, as promotion does.
|
|
1840
|
+
if (credential === "admin") requireConfiguredAdminAuth(request, "human-origin state proposals");
|
|
1841
|
+
if (body.proposedBy !== undefined && body.proposedBy !== callerId) {
|
|
1842
|
+
logger({ event: "security_alert", alert: "state_proposer_mismatch", project: callerProject, callerId, credential });
|
|
1843
|
+
throw new ProtocolError(
|
|
1844
|
+
403,
|
|
1845
|
+
"proposedBy must name the authenticated caller",
|
|
1846
|
+
"state_proposer_mismatch",
|
|
1847
|
+
);
|
|
1848
|
+
}
|
|
1849
|
+
const origin = credential === "agent" ? "peer" : "human";
|
|
1833
1850
|
const proposalId = await stateProvider.propose({
|
|
1834
1851
|
schema: "kxm.state-change-proposal.v1",
|
|
1835
1852
|
project: callerProject,
|
|
@@ -1838,11 +1855,12 @@ export function createMeshHub(options: MeshHubOptions = {}): MeshHub {
|
|
|
1838
1855
|
authority: parseContextAuthority(body.authority),
|
|
1839
1856
|
confidence: parseContextConfidence(body.confidence),
|
|
1840
1857
|
evidenceRefs: boundedStringList(body.evidenceRefs, "evidenceRefs", 32),
|
|
1841
|
-
proposedBy:
|
|
1858
|
+
proposedBy: callerId,
|
|
1859
|
+
origin,
|
|
1842
1860
|
});
|
|
1843
1861
|
counters.contextRequests += 1;
|
|
1844
1862
|
publishOps(callerProject, "workflows");
|
|
1845
|
-
logger({ event: "context_state_proposed", project: callerProject, proposalId, proposedBy: callerId });
|
|
1863
|
+
logger({ event: "context_state_proposed", project: callerProject, proposalId, proposedBy: callerId, origin });
|
|
1846
1864
|
json(response, 201, { proposalId });
|
|
1847
1865
|
return;
|
|
1848
1866
|
}
|
|
@@ -8,7 +8,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
|
|
|
8
8
|
import { deliverInboxNotification } from "./inbox.ts";
|
|
9
9
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.7.
|
|
11
|
+
const VERSION = "0.7.89";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
package/plugins/kxm/src/state.ts
CHANGED
|
@@ -184,6 +184,9 @@ export class NativeStateProvider implements StateProvider {
|
|
|
184
184
|
if (change?.schema !== "kxm.state-change-proposal.v1") {
|
|
185
185
|
throw new ProtocolError(400, "invalid state change proposal schema", "invalid_state_proposal");
|
|
186
186
|
}
|
|
187
|
+
if (change.origin !== "peer" && change.origin !== "human") {
|
|
188
|
+
throw new ProtocolError(400, "state change proposal origin must be peer or human", "invalid_state_proposal");
|
|
189
|
+
}
|
|
187
190
|
const project = requireNonEmpty(change.project, "proposal project");
|
|
188
191
|
const key = requireNonEmpty(change.key, "proposal key");
|
|
189
192
|
const evidenceRefs = boundedRefs(change.evidenceRefs, "proposal evidenceRefs");
|
|
@@ -193,7 +196,7 @@ export class NativeStateProvider implements StateProvider {
|
|
|
193
196
|
project,
|
|
194
197
|
summary: change.summary,
|
|
195
198
|
provenance: {
|
|
196
|
-
sourceType: change.
|
|
199
|
+
sourceType: change.origin,
|
|
197
200
|
sourceRef: `proposed-by:${change.proposedBy}`,
|
|
198
201
|
},
|
|
199
202
|
authority: change.authority,
|