@kontextmind/kxm 0.7.112 → 0.7.115
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/.kxm/agents/implementer.yaml +1 -1
- package/.kxm/roles/writer.yaml +1 -1
- package/docs/contributing/assignment-runner.md +3 -3
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/scripts/assignment-run.d.mts +7 -0
- package/scripts/assignment-run.mjs +128 -1
- package/scripts/harness-run.mjs +2 -2
- package/scripts/native-critic.mjs +7 -7
package/.kxm/roles/writer.yaml
CHANGED
|
@@ -5,7 +5,7 @@ id: writer
|
|
|
5
5
|
# Effort default: medium for implementation (AGENTS.md). agy ids bake in the
|
|
6
6
|
# effort tier, so those entries carry no effort field.
|
|
7
7
|
roster:
|
|
8
|
-
- model: xai/grok-4.
|
|
8
|
+
- model: xai/grok-4.7
|
|
9
9
|
effort: medium
|
|
10
10
|
enabled: true
|
|
11
11
|
- model: openrouter/qwen/qwen3-coder-plus
|
|
@@ -33,7 +33,7 @@ permissions:
|
|
|
33
33
|
|
|
34
34
|
| Role | Admitted route (harness / model) | Vendor | Permission |
|
|
35
35
|
|---|---|---|---|
|
|
36
|
-
| `writer` | `grok` / `grok-4.
|
|
36
|
+
| `writer` | `grok` / `grok-4.7`; relief: `pi` / `openrouter/qwen/qwen3-coder-plus` | `xai`; `alibaba` | `edit` |
|
|
37
37
|
| `planner` | `claude` / `fable` | `anthropic` | `read-only` |
|
|
38
38
|
| `reviewer-arch` | `claude` / `fable` | `anthropic` | `read-only` |
|
|
39
39
|
| `reviewer-cli` | `codex` / `gpt-5.6-sol` | `openai` | `read-only` |
|
|
@@ -115,7 +115,7 @@ Write a closed `kxm.assignment.v1` manifest. Unknown keys are refused.
|
|
|
115
115
|
"assignment_id": "asg-writer-1",
|
|
116
116
|
"kind": "implement",
|
|
117
117
|
"harness": "grok",
|
|
118
|
-
"model": "grok-4.
|
|
118
|
+
"model": "grok-4.7",
|
|
119
119
|
"effort": "medium",
|
|
120
120
|
"permission": "edit",
|
|
121
121
|
"cwd": "/abs/kxm-fix-improve-sources",
|
|
@@ -247,7 +247,7 @@ then is that `BLOCK` resolved.
|
|
|
247
247
|
├── output-schema.json # the structured-output schema given to the harness
|
|
248
248
|
├── pre-dispatch.json # written before spawn (kxm.assignment-dispatch.v1)
|
|
249
249
|
├── completion.json # kxm.assignment-completion.v1, or refusal.json
|
|
250
|
-
├── routing-record.json #
|
|
250
|
+
├── routing-record.json # export with `node scripts/assignment-run.mjs routing-export --task-dir <abs>` and pass the JSONL to `kxm improve report --file` / `kxm routing report --file`
|
|
251
251
|
├── telemetry.jsonl # usage, latency and cost
|
|
252
252
|
├── runner-errors.jsonl # bounded failure codes
|
|
253
253
|
├── witness/ # latest.json and history/<receipt-id>.json
|
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.115",
|
|
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",
|
|
@@ -17313,7 +17313,7 @@ function sessionTokenFixHint(policy) {
|
|
|
17313
17313
|
}
|
|
17314
17314
|
|
|
17315
17315
|
// plugins/kxm/src/mcp-server.ts
|
|
17316
|
-
var VERSION = "0.7.
|
|
17316
|
+
var VERSION = "0.7.115";
|
|
17317
17317
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
17318
17318
|
var inbox = /* @__PURE__ */ new Map();
|
|
17319
17319
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
package/plugins/kxm/package.json
CHANGED
|
@@ -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.
|
|
14
|
+
const VERSION = "0.7.115";
|
|
15
15
|
const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
16
16
|
const inbox = new Map<string, MessageRecord>();
|
|
17
17
|
const notifiedInbox = new Set<string>();
|
|
@@ -339,6 +339,13 @@ export function changeReport(request: { taskDir: string }, deps?: Record<string,
|
|
|
339
339
|
ranking: "not-ranked";
|
|
340
340
|
orchestration_usage: "unavailable";
|
|
341
341
|
};
|
|
342
|
+
export const ROUTING_EXPORT_SCHEMA: "kxm.assignment-routing-export.v1";
|
|
343
|
+
export function exportAssignmentRoutingRecords(request: { taskDir: string }, deps?: Record<string, unknown>): {
|
|
344
|
+
schema: "kxm.assignment-routing-export.v1";
|
|
345
|
+
task_id: string;
|
|
346
|
+
records: Array<Record<string, any>>;
|
|
347
|
+
skipped: Array<{ assignment_id: string | null; reason: "acceptance_record_invalid" | "no_routing_record" | "routing_record_invalid" | "manifest_invalid" }>;
|
|
348
|
+
};
|
|
342
349
|
export function writeCurrentPlan(request: {
|
|
343
350
|
taskDir: string; plan: string; sha256: string; baseCommit: string; expectedGeneration: number; settledDecisions?: string[];
|
|
344
351
|
}, deps?: Record<string, unknown>): {
|
|
@@ -2330,7 +2330,7 @@ export async function observeAssignment(outputDir, deps = {}) {
|
|
|
2330
2330
|
return appended;
|
|
2331
2331
|
}
|
|
2332
2332
|
|
|
2333
|
-
const CLI_USAGE = "usage: assignment-run.mjs run --manifest <absolute-path> | observe --record-dir <absolute-path> | witness --record-dir <absolute-path> | accept --task-dir <absolute-path> --commit <commit> --record-dir <absolute-path> --critic <absolute-path> --critic <absolute-path> [--observed-pr <id>] [--observed-ci <id>] | attribute --task-dir <absolute-path> --record-dir <absolute-path> --class <orchestration|model|environment|unclassified> --explanation-file <absolute-path> | observe-cost --task-dir <absolute-path> --input <absolute-path> | plan-current --task-dir <absolute-path> --plan <absolute-path> --sha256 <hex64> --base-commit <commit> --expected-generation <n> | change-report --task-dir <absolute-path>";
|
|
2333
|
+
const CLI_USAGE = "usage: assignment-run.mjs run --manifest <absolute-path> | observe --record-dir <absolute-path> | witness --record-dir <absolute-path> | accept --task-dir <absolute-path> --commit <commit> --record-dir <absolute-path> --critic <absolute-path> --critic <absolute-path> [--observed-pr <id>] [--observed-ci <id>] | attribute --task-dir <absolute-path> --record-dir <absolute-path> --class <orchestration|model|environment|unclassified> --explanation-file <absolute-path> | observe-cost --task-dir <absolute-path> --input <absolute-path> | plan-current --task-dir <absolute-path> --plan <absolute-path> --sha256 <hex64> --base-commit <commit> --expected-generation <n> | change-report --task-dir <absolute-path> | routing-export --task-dir <absolute-path>";
|
|
2334
2334
|
|
|
2335
2335
|
const WITNESS_RECEIPT_KEYS = Object.freeze([
|
|
2336
2336
|
"schema",
|
|
@@ -4293,8 +4293,135 @@ export function writeCurrentPlan(request, deps = {}) {
|
|
|
4293
4293
|
} catch (error) { throw observationFailure(error, "plan_ref_invalid"); }
|
|
4294
4294
|
}
|
|
4295
4295
|
|
|
4296
|
+
export const ROUTING_EXPORT_SCHEMA = "kxm.assignment-routing-export.v1";
|
|
4297
|
+
|
|
4298
|
+
function contractExportable(contract) {
|
|
4299
|
+
return Boolean(contract)
|
|
4300
|
+
&& typeof contract === "object"
|
|
4301
|
+
&& !Array.isArray(contract)
|
|
4302
|
+
&& typeof contract.boundary === "string"
|
|
4303
|
+
&& Array.isArray(contract.deliverables)
|
|
4304
|
+
&& contract.witness
|
|
4305
|
+
&& typeof contract.witness === "object"
|
|
4306
|
+
&& !Array.isArray(contract.witness)
|
|
4307
|
+
&& typeof contract.witness.id === "string"
|
|
4308
|
+
&& Array.isArray(contract.deferred);
|
|
4309
|
+
}
|
|
4310
|
+
|
|
4311
|
+
export function exportAssignmentRoutingRecords(request, deps = {}) {
|
|
4312
|
+
const io = ioDeps(deps);
|
|
4313
|
+
const taskDir = observationTask(request.taskDir, io);
|
|
4314
|
+
const taskId = basename(taskDir);
|
|
4315
|
+
const skipped = [];
|
|
4316
|
+
const acceptedIds = new Set();
|
|
4317
|
+
const acceptedPath = join(taskDir, ACCEPTED_FILENAME);
|
|
4318
|
+
if (lstatOrNull(acceptedPath, io.lstatSync)) {
|
|
4319
|
+
try {
|
|
4320
|
+
const value = privateRecord(acceptedPath, io).value;
|
|
4321
|
+
const valid = value.schema === ACCEPTED_SCHEMA
|
|
4322
|
+
&& value.task_id === taskId
|
|
4323
|
+
&& typeof value.writer?.assignment_id === "string"
|
|
4324
|
+
&& Array.isArray(value.critics);
|
|
4325
|
+
if (!valid) throw new Error("acceptance invalid");
|
|
4326
|
+
acceptedIds.add(value.writer.assignment_id);
|
|
4327
|
+
for (const critic of value.critics) {
|
|
4328
|
+
if (typeof critic?.assignment_id === "string") acceptedIds.add(critic.assignment_id);
|
|
4329
|
+
}
|
|
4330
|
+
} catch {
|
|
4331
|
+
skipped.push({ assignment_id: null, reason: "acceptance_record_invalid" });
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
const collected = [];
|
|
4335
|
+
const dirs = listDirectAssignmentDirs(taskDir, io).sort((left, right) => left.assignment_id < right.assignment_id ? -1 : left.assignment_id > right.assignment_id ? 1 : 0);
|
|
4336
|
+
for (const { assignment_id, path } of dirs) {
|
|
4337
|
+
const routingPath = join(path, "routing-record.json");
|
|
4338
|
+
if (!lstatOrNull(routingPath, io.lstatSync)) {
|
|
4339
|
+
skipped.push({ assignment_id, reason: "no_routing_record" });
|
|
4340
|
+
continue;
|
|
4341
|
+
}
|
|
4342
|
+
let record;
|
|
4343
|
+
try {
|
|
4344
|
+
record = parseRoutingRecord(privateRecord(routingPath, io).value);
|
|
4345
|
+
if (record.workflowRunId !== assignment_id) throw new Error("workflowRunId");
|
|
4346
|
+
} catch {
|
|
4347
|
+
skipped.push({ assignment_id, reason: "routing_record_invalid" });
|
|
4348
|
+
continue;
|
|
4349
|
+
}
|
|
4350
|
+
let contract;
|
|
4351
|
+
try {
|
|
4352
|
+
const manifest = privateRecord(join(path, "manifest.json"), io).value;
|
|
4353
|
+
contract = manifest.contract;
|
|
4354
|
+
if (!contractExportable(contract)) throw new Error("contract");
|
|
4355
|
+
} catch {
|
|
4356
|
+
skipped.push({ assignment_id, reason: "manifest_invalid" });
|
|
4357
|
+
continue;
|
|
4358
|
+
}
|
|
4359
|
+
collected.push({ id: assignment_id, record, contract });
|
|
4360
|
+
}
|
|
4361
|
+
const supersededBy = new Map();
|
|
4362
|
+
for (const entry of collected) {
|
|
4363
|
+
const reworkOf = entry.record.providerMetadata?.rework_of;
|
|
4364
|
+
if (typeof reworkOf === "string" && !supersededBy.has(reworkOf)) supersededBy.set(reworkOf, entry.id);
|
|
4365
|
+
}
|
|
4366
|
+
const records = [];
|
|
4367
|
+
for (const entry of collected) {
|
|
4368
|
+
const kind = entry.record.stageId;
|
|
4369
|
+
const role = entry.record.agentRole;
|
|
4370
|
+
const askSha256 = sha256Bytes(Buffer.from(JSON.stringify(["kxm.assignment-ask.v1", kind, role])));
|
|
4371
|
+
const objectiveSha256 = sha256Bytes(Buffer.from(JSON.stringify([
|
|
4372
|
+
"kxm.assignment-brief.v1",
|
|
4373
|
+
kind,
|
|
4374
|
+
entry.contract.boundary,
|
|
4375
|
+
entry.contract.deliverables,
|
|
4376
|
+
entry.contract.witness.id,
|
|
4377
|
+
entry.contract.deferred,
|
|
4378
|
+
])));
|
|
4379
|
+
const finalOutcome = acceptedIds.has(entry.id) ? "accepted" : supersededBy.has(entry.id) ? "failed" : "pending";
|
|
4380
|
+
try {
|
|
4381
|
+
records.push(parseRoutingRecord({
|
|
4382
|
+
...entry.record,
|
|
4383
|
+
workflowRunId: taskId,
|
|
4384
|
+
finalOutcome,
|
|
4385
|
+
providerMetadata: {
|
|
4386
|
+
...entry.record.providerMetadata,
|
|
4387
|
+
workflowId: "assignment-runner",
|
|
4388
|
+
askSha256,
|
|
4389
|
+
objectiveSha256,
|
|
4390
|
+
stepWrites: WRITER_KINDS.includes(kind),
|
|
4391
|
+
assignmentId: entry.id,
|
|
4392
|
+
...(finalOutcome === "failed" ? { supersededBy: supersededBy.get(entry.id) } : {}),
|
|
4393
|
+
},
|
|
4394
|
+
}));
|
|
4395
|
+
} catch {
|
|
4396
|
+
skipped.push({ assignment_id: entry.id, reason: "routing_record_invalid" });
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
return { schema: ROUTING_EXPORT_SCHEMA, task_id: taskId, records, skipped };
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4296
4402
|
export async function main(argv = process.argv, io = { stdin: process.stdin, stdout: process.stdout, stderr: process.stderr }) {
|
|
4297
4403
|
const args = argv.slice(2).filter((arg) => arg !== "--");
|
|
4404
|
+
if (args[0] === "routing-export") {
|
|
4405
|
+
try {
|
|
4406
|
+
const values = {};
|
|
4407
|
+
for (let i = 1; i < args.length; i += 2) {
|
|
4408
|
+
if (args[i] !== "--task-dir" || values[args[i]] !== undefined || args[i + 1] === undefined) throw failClosed("invalid report/plan arguments", "manifest_invalid");
|
|
4409
|
+
values[args[i]] = args[i + 1];
|
|
4410
|
+
}
|
|
4411
|
+
if (values["--task-dir"] === undefined) throw failClosed("missing report/plan arguments", "manifest_invalid");
|
|
4412
|
+
const result = exportAssignmentRoutingRecords({ taskDir: values["--task-dir"] });
|
|
4413
|
+
for (const record of result.records) io.stdout.write(`${JSON.stringify(record)}\n`);
|
|
4414
|
+
io.stderr.write(`${JSON.stringify({ schema: result.schema, task_id: result.task_id, records: result.records.length, skipped: result.skipped })}\n`);
|
|
4415
|
+
process.exitCode = 0;
|
|
4416
|
+
return result;
|
|
4417
|
+
} catch (error) {
|
|
4418
|
+
const failure = observationFailure(error);
|
|
4419
|
+
io.stderr.write(`${failure.runnerCode}: assignment routing export refused\n`);
|
|
4420
|
+
process.exitCode = 1;
|
|
4421
|
+
throw failure;
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4298
4425
|
if (["change-report", "plan-current"].includes(args[0])) {
|
|
4299
4426
|
try {
|
|
4300
4427
|
const flags = args[0] === "change-report" ? ["--task-dir"] : ["--task-dir", "--plan", "--sha256", "--base-commit", "--expected-generation"];
|
package/scripts/harness-run.mjs
CHANGED
|
@@ -137,7 +137,7 @@ export const ROUTES = Object.freeze({
|
|
|
137
137
|
provider: "xai",
|
|
138
138
|
roles: Object.freeze(["writer"]),
|
|
139
139
|
permissions: Object.freeze(["edit"]),
|
|
140
|
-
models: Object.freeze(["grok-4.
|
|
140
|
+
models: Object.freeze(["grok-4.7"]),
|
|
141
141
|
efforts: Object.freeze(["low", "medium", "high"]),
|
|
142
142
|
auth: Object.freeze({ args: ["models"], loginHint: "grok (OAuth to auth.x.ai)" }),
|
|
143
143
|
},
|
|
@@ -153,7 +153,7 @@ export const ROUTES = Object.freeze({
|
|
|
153
153
|
provider: "anthropic",
|
|
154
154
|
roles: Object.freeze(["planner", "reviewer-arch"]),
|
|
155
155
|
permissions: Object.freeze(["read-only"]),
|
|
156
|
-
models: Object.freeze(["fable"]),
|
|
156
|
+
models: Object.freeze(["fable", "opus"]),
|
|
157
157
|
efforts: Object.freeze(["low", "medium", "high", "xhigh", "max"]),
|
|
158
158
|
auth: Object.freeze({ args: ["auth", "status"], loginHint: "claude auth login" }),
|
|
159
159
|
},
|
|
@@ -8,13 +8,13 @@ import { buildArgv } from "./harness-run.mjs";
|
|
|
8
8
|
|
|
9
9
|
// Launch intent only: these labels are not observed model identity or admission.
|
|
10
10
|
export function nativeCriticLaunch(harness) {
|
|
11
|
-
if (!["fable", "astra"].includes(harness)) {
|
|
12
|
-
throw new Error("usage: native-critic.mjs <fable|astra> <prompt>");
|
|
11
|
+
if (!["fable", "astra", "opus"].includes(harness)) {
|
|
12
|
+
throw new Error("usage: native-critic.mjs <fable|astra|opus> <prompt>");
|
|
13
13
|
}
|
|
14
|
-
const model = harness === "fable" ? "fable" : "gpt-6-astra";
|
|
15
|
-
const command = harness === "fable" ? "claude" : "codex";
|
|
16
|
-
const args = harness === "fable"
|
|
17
|
-
? ["-p", "--model", model, "--output-format", "json", "--no-session-persistence", "--tools", "Read,Glob,Grep", "--setting-sources", "user"]
|
|
14
|
+
const model = harness === "fable" ? "fable" : harness === "opus" ? "opus" : "gpt-6-astra";
|
|
15
|
+
const command = harness === "fable" || harness === "opus" ? "claude" : "codex";
|
|
16
|
+
const args = harness === "fable" || harness === "opus"
|
|
17
|
+
? ["-p", "--model", model, "--effort", "medium", "--output-format", "json", "--no-session-persistence", "--tools", "Read,Glob,Grep", "--setting-sources", "user"]
|
|
18
18
|
: buildArgv({ harness: "codex", model, effort: "low", permission: "read-only", prompt_file: "-" });
|
|
19
19
|
return { model, command, args };
|
|
20
20
|
}
|
|
@@ -36,7 +36,7 @@ async function main() {
|
|
|
36
36
|
mkdirSync(outDir, { recursive: true });
|
|
37
37
|
const client = new HubClient({ serverUrl, authToken: env.KXM_AUTH_TOKEN, name: `${harness}-critic`, purpose: "independent CLI critic", project: env.KXM_PROJECT || ".kxm", model });
|
|
38
38
|
const prompt = promptParts.join(" ");
|
|
39
|
-
const agent = await client.start(() => {});
|
|
39
|
+
const agent = await client.start(() => { });
|
|
40
40
|
const result = await new Promise((resolve) => {
|
|
41
41
|
const child = spawn(command, args, { env, stdio: ["pipe", "pipe", "pipe"], shell: false });
|
|
42
42
|
let stdout = "", stderr = "";
|