@kontextmind/kxm 0.7.91 → 0.7.92
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 +8 -0
- package/docs/configuration.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +33 -16
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-context-memory/SKILL.md +6 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/memory.ts +43 -20
package/CHANGELOG.md
CHANGED
|
@@ -185,6 +185,14 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
185
185
|
none exist. The block is placed at the end of a file that has no markers yet, rather
|
|
186
186
|
than before a `## Do not` heading that only this repository uses.
|
|
187
187
|
|
|
188
|
+
- **`kxm memory sync` refuses malformed memory markers instead of eating text.** Sync
|
|
189
|
+
used to replace from the first `<!-- kxm:memory:start -->` to the first
|
|
190
|
+
`<!-- kxm:memory:end -->` wherever they appeared, so an orphan start marker got a new
|
|
191
|
+
block appended and the following sync deleted everything between the orphan and that
|
|
192
|
+
block; an end before its start duplicated text; a second block went stale. A file
|
|
193
|
+
must now hold exactly one start marker followed by one end marker, or neither.
|
|
194
|
+
Otherwise sync exits non-zero naming the file and the problem, and writes no file.
|
|
195
|
+
|
|
188
196
|
- **Release version surfaces cover workspace packages:** a merged PR no longer
|
|
189
197
|
breaks the release pipeline. `scripts/kxm-bump-version.mjs` now writes the
|
|
190
198
|
version into every package manifest under `packages/`, using the same package
|
package/docs/configuration.md
CHANGED
|
@@ -303,7 +303,7 @@ The current hub command groups are `agent`, `session`, `workflow`, `gate`, `hub`
|
|
|
303
303
|
| `kxm improve` | Bucket `.kxm/logs/telemetry.jsonl` events into a proposed-only improvement report; does not read the workflow journal |
|
|
304
304
|
| `kxm context get \| recall \| state \| episode \| promote \| explain \| wiki-compile \| wiki-lint` | Context operating system: role-aware packets, metadata search, temporal state, episodes, evidence-backed lineage (`explain`), wiki compile/lint |
|
|
305
305
|
| `kxm skills` | Governed skill candidate lifecycle |
|
|
306
|
-
| `kxm memory sync` | Regenerate the read-only project-memory block — authored facts from `.kxm/memory/` only — between `<!-- kxm:memory:start -->` and `<!-- kxm:memory:end -->` in whichever of `AGENTS.md`, `CLAUDE.md` and `GEMINI.md` already exist in the current directory. Text outside the markers is never rewritten; a file without markers gets the block appended. Missing files are reported as `missing` and **not created** — which harness a project uses is its own choice — and with none present sync exits 1 without writing. `--json` reports `updated`, `unchanged` and `missing` |
|
|
306
|
+
| `kxm memory sync` | Regenerate the read-only project-memory block — authored facts from `.kxm/memory/` only — between `<!-- kxm:memory:start -->` and `<!-- kxm:memory:end -->` in whichever of `AGENTS.md`, `CLAUDE.md` and `GEMINI.md` already exist in the current directory. Text outside the markers is never rewritten; a file without markers gets the block appended. Each file must hold exactly one start marker followed by exactly one end marker, or neither: an orphan marker, an end before its start, or a second block makes sync exit 1 naming the file and the problem, and **no file is written**, the well-formed ones included. Missing files are reported as `missing` and **not created** — which harness a project uses is its own choice — and with none present sync exits 1 without writing. `--json` reports `updated`, `unchanged` and `missing` |
|
|
307
307
|
|
|
308
308
|
Improvement telemetry is classified as `project` whenever a project or workflow identity is present, and as `cli` for unscoped operator behavior. Set `KXM_IMPROVE_TARGET=cli` or `KXM_IMPROVE_TARGET=project` only when an operator needs to override that generic classification; this changes report bucketing, not workflow state.
|
|
309
309
|
|
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.92",
|
|
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
|
@@ -33618,26 +33618,27 @@ function formatHarnessMemoryBlock(records) {
|
|
|
33618
33618
|
return contentLines.join("\n");
|
|
33619
33619
|
}
|
|
33620
33620
|
var HARNESS_INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"];
|
|
33621
|
-
function
|
|
33622
|
-
const
|
|
33623
|
-
|
|
33624
|
-
if (
|
|
33625
|
-
|
|
33626
|
-
|
|
33627
|
-
|
|
33628
|
-
|
|
33621
|
+
function memoryMarkerProblem(text) {
|
|
33622
|
+
const starts = text.split(MEMORY_MARKER_START).length - 1;
|
|
33623
|
+
const ends = text.split(MEMORY_MARKER_END).length - 1;
|
|
33624
|
+
if (starts > 1 || ends > 1) return `has ${starts} ${MEMORY_MARKER_START} and ${ends} ${MEMORY_MARKER_END} markers, not one block`;
|
|
33625
|
+
if (starts > ends) return `has ${MEMORY_MARKER_START} with no ${MEMORY_MARKER_END}`;
|
|
33626
|
+
if (ends > starts) return `has ${MEMORY_MARKER_END} with no ${MEMORY_MARKER_START}`;
|
|
33627
|
+
if (text.indexOf(MEMORY_MARKER_END) < text.indexOf(MEMORY_MARKER_START)) return `has ${MEMORY_MARKER_END} before ${MEMORY_MARKER_START}`;
|
|
33628
|
+
return void 0;
|
|
33629
|
+
}
|
|
33630
|
+
function withMemoryBlock(original, block) {
|
|
33631
|
+
const startIdx = original.indexOf(MEMORY_MARKER_START);
|
|
33632
|
+
if (startIdx === -1) {
|
|
33629
33633
|
const head = original.trimEnd();
|
|
33630
|
-
|
|
33634
|
+
return head ? `${head}
|
|
33631
33635
|
|
|
33632
33636
|
${block}
|
|
33633
33637
|
` : `${block}
|
|
33634
33638
|
`;
|
|
33635
33639
|
}
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
return true;
|
|
33639
|
-
}
|
|
33640
|
-
return false;
|
|
33640
|
+
const endIdx = original.indexOf(MEMORY_MARKER_END) + MEMORY_MARKER_END.length;
|
|
33641
|
+
return original.slice(0, startIdx) + block + original.slice(endIdx);
|
|
33641
33642
|
}
|
|
33642
33643
|
function syncHarnessMemory(repoRoot, options = {}) {
|
|
33643
33644
|
const root = resolve22(repoRoot);
|
|
@@ -33648,11 +33649,27 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
33648
33649
|
`none of ${HARNESS_INSTRUCTION_FILES.join(", ")} exists in ${root}; sync updates the instruction files a project already has and does not create them`
|
|
33649
33650
|
);
|
|
33650
33651
|
}
|
|
33652
|
+
const documents = present.map((name) => {
|
|
33653
|
+
const original = readFileSync24(join28(root, name), "utf8");
|
|
33654
|
+
return { name, original, problem: memoryMarkerProblem(original) };
|
|
33655
|
+
});
|
|
33656
|
+
const malformed = documents.filter((doc) => doc.problem !== void 0);
|
|
33657
|
+
if (malformed.length > 0) {
|
|
33658
|
+
throw new Error(
|
|
33659
|
+
`${malformed.map((doc) => `${doc.name} ${doc.problem}`).join("; ")}; wrote no file. Keep exactly one ${MEMORY_MARKER_START} followed by one ${MEMORY_MARKER_END} in each file, or delete both so sync appends a fresh block`
|
|
33660
|
+
);
|
|
33661
|
+
}
|
|
33651
33662
|
const block = formatHarnessMemoryBlock(loadAuthoredMemory(root));
|
|
33652
33663
|
const updated = [];
|
|
33653
33664
|
const unchanged = [];
|
|
33654
|
-
for (const name of
|
|
33655
|
-
(
|
|
33665
|
+
for (const { name, original } of documents) {
|
|
33666
|
+
const next = withMemoryBlock(original, block);
|
|
33667
|
+
if (next === original) {
|
|
33668
|
+
unchanged.push(name);
|
|
33669
|
+
} else {
|
|
33670
|
+
if (!options.dryRun) writeFileSync18(join28(root, name), next, "utf8");
|
|
33671
|
+
updated.push(name);
|
|
33672
|
+
}
|
|
33656
33673
|
}
|
|
33657
33674
|
return { updated, unchanged, missing };
|
|
33658
33675
|
}
|
|
@@ -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.92";
|
|
17186
17186
|
var inbox = /* @__PURE__ */ new Map();
|
|
17187
17187
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17188
17188
|
var meshClient;
|
package/plugins/kxm/package.json
CHANGED
|
@@ -57,6 +57,12 @@ never creates an instruction file. If the project has none of the three, sync
|
|
|
57
57
|
refuses; create the file your harness reads yourself rather than expecting KXM
|
|
58
58
|
to author it.
|
|
59
59
|
|
|
60
|
+
Each file must hold exactly one start marker followed by exactly one end
|
|
61
|
+
marker, or neither. An orphan marker, an end before its start, or a second
|
|
62
|
+
block makes sync refuse, name the file and the problem, and write no file at
|
|
63
|
+
all. Fix the markers by hand — keep one pair, or delete both so sync appends a
|
|
64
|
+
fresh block — rather than letting sync guess which text is yours.
|
|
65
|
+
|
|
60
66
|
Do not invent search, save, delete, list, or clear subcommands under memory.
|
|
61
67
|
Use context retrieval for discovery and reviewed authored changes for
|
|
62
68
|
corrections, respecting provenance and historical records.
|
|
@@ -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.92";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
|
@@ -323,26 +323,30 @@ export function formatHarnessMemoryBlock(records: MemoryRecord[]): string {
|
|
|
323
323
|
* carry KXM's words instead of the project's. */
|
|
324
324
|
const HARNESS_INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"] as const;
|
|
325
325
|
|
|
326
|
-
/**
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
326
|
+
/** What is wrong with the memory markers in `text`, or undefined when it has exactly one
|
|
327
|
+
* start marker followed by exactly one end marker, or neither. Any other shape has no single
|
|
328
|
+
* block to replace: an orphan start would make the next sync delete the project's text up to
|
|
329
|
+
* a later end, an end before its start would duplicate text, and a second block goes stale. */
|
|
330
|
+
function memoryMarkerProblem(text: string): string | undefined {
|
|
331
|
+
const starts = text.split(MEMORY_MARKER_START).length - 1;
|
|
332
|
+
const ends = text.split(MEMORY_MARKER_END).length - 1;
|
|
333
|
+
if (starts > 1 || ends > 1) return `has ${starts} ${MEMORY_MARKER_START} and ${ends} ${MEMORY_MARKER_END} markers, not one block`;
|
|
334
|
+
if (starts > ends) return `has ${MEMORY_MARKER_START} with no ${MEMORY_MARKER_END}`;
|
|
335
|
+
if (ends > starts) return `has ${MEMORY_MARKER_END} with no ${MEMORY_MARKER_START}`;
|
|
336
|
+
if (text.indexOf(MEMORY_MARKER_END) < text.indexOf(MEMORY_MARKER_START)) return `has ${MEMORY_MARKER_END} before ${MEMORY_MARKER_START}`;
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
340
339
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
/** `original` with its memory block replaced, or with one appended when it has no markers.
|
|
341
|
+
* Nothing outside the markers is rewritten. Markers must already pass `memoryMarkerProblem`. */
|
|
342
|
+
function withMemoryBlock(original: string, block: string): string {
|
|
343
|
+
const startIdx = original.indexOf(MEMORY_MARKER_START);
|
|
344
|
+
if (startIdx === -1) {
|
|
345
|
+
const head = original.trimEnd();
|
|
346
|
+
return head ? `${head}\n\n${block}\n` : `${block}\n`;
|
|
344
347
|
}
|
|
345
|
-
|
|
348
|
+
const endIdx = original.indexOf(MEMORY_MARKER_END) + MEMORY_MARKER_END.length;
|
|
349
|
+
return original.slice(0, startIdx) + block + original.slice(endIdx);
|
|
346
350
|
}
|
|
347
351
|
|
|
348
352
|
export function syncHarnessMemory(
|
|
@@ -358,11 +362,30 @@ export function syncHarnessMemory(
|
|
|
358
362
|
);
|
|
359
363
|
}
|
|
360
364
|
|
|
365
|
+
// Check every file before writing any: one malformed file leaves all of them untouched.
|
|
366
|
+
const documents = present.map((name) => {
|
|
367
|
+
const original = readFileSync(join(root, name), "utf8");
|
|
368
|
+
return { name, original, problem: memoryMarkerProblem(original) };
|
|
369
|
+
});
|
|
370
|
+
const malformed = documents.filter((doc) => doc.problem !== undefined);
|
|
371
|
+
if (malformed.length > 0) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`${malformed.map((doc) => `${doc.name} ${doc.problem}`).join("; ")}; wrote no file. `
|
|
374
|
+
+ `Keep exactly one ${MEMORY_MARKER_START} followed by one ${MEMORY_MARKER_END} in each file, or delete both so sync appends a fresh block`,
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
361
378
|
const block = formatHarnessMemoryBlock(loadAuthoredMemory(root));
|
|
362
379
|
const updated: string[] = [];
|
|
363
380
|
const unchanged: string[] = [];
|
|
364
|
-
for (const name of
|
|
365
|
-
(
|
|
381
|
+
for (const { name, original } of documents) {
|
|
382
|
+
const next = withMemoryBlock(original, block);
|
|
383
|
+
if (next === original) {
|
|
384
|
+
unchanged.push(name);
|
|
385
|
+
} else {
|
|
386
|
+
if (!options.dryRun) writeFileSync(join(root, name), next, "utf8");
|
|
387
|
+
updated.push(name);
|
|
388
|
+
}
|
|
366
389
|
}
|
|
367
390
|
return { updated, unchanged, missing };
|
|
368
391
|
}
|