@kontextmind/kxm 0.7.89 → 0.7.91
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 +11 -0
- package/docs/configuration.md +1 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +29 -68
- 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 +7 -1
- package/plugins/kxm/src/cli/context-skills.ts +8 -3
- package/plugins/kxm/src/cli.ts +1 -1
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/memory.ts +29 -49
package/CHANGELOG.md
CHANGED
|
@@ -174,6 +174,17 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
174
174
|
|
|
175
175
|
### Fixed
|
|
176
176
|
|
|
177
|
+
- **`kxm memory sync` no longer writes this repository's agent policy into other
|
|
178
|
+
projects.** A missing `CLAUDE.md` or `GEMINI.md` used to be created from a header
|
|
179
|
+
copied from KXM's own instruction files — the planner/architecture-critic role, the
|
|
180
|
+
Grok writer rotation, and Tracking admission rules — so every project that ran sync
|
|
181
|
+
inherited another project's development policy. Sync now touches only the
|
|
182
|
+
`AGENTS.md`, `CLAUDE.md` and `GEMINI.md` a project already has, replaces or appends
|
|
183
|
+
just the `<!-- kxm:memory:start -->`…`<!-- kxm:memory:end -->` block, reports
|
|
184
|
+
`updated`, `unchanged` and `missing` files, and exits non-zero without writing when
|
|
185
|
+
none exist. The block is placed at the end of a file that has no markers yet, rather
|
|
186
|
+
than before a `## Do not` heading that only this repository uses.
|
|
187
|
+
|
|
177
188
|
- **Release version surfaces cover workspace packages:** a merged PR no longer
|
|
178
189
|
breaks the release pipeline. `scripts/kxm-bump-version.mjs` now writes the
|
|
179
190
|
version into every package manifest under `packages/`, using the same package
|
package/docs/configuration.md
CHANGED
|
@@ -303,6 +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
307
|
|
|
307
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.
|
|
308
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.91",
|
|
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
|
@@ -33617,34 +33617,20 @@ function formatHarnessMemoryBlock(records) {
|
|
|
33617
33617
|
contentLines.push(MEMORY_MARKER_END);
|
|
33618
33618
|
return contentLines.join("\n");
|
|
33619
33619
|
}
|
|
33620
|
-
|
|
33621
|
-
|
|
33622
|
-
|
|
33623
|
-
|
|
33624
|
-
}
|
|
33625
|
-
let updated = "";
|
|
33620
|
+
var HARNESS_INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"];
|
|
33621
|
+
function updateHarnessDocument(filePath, block, dryRun = false) {
|
|
33622
|
+
const original = readFileSync24(filePath, "utf8");
|
|
33623
|
+
let updated;
|
|
33626
33624
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
33627
33625
|
const startIdx = original.indexOf(MEMORY_MARKER_START);
|
|
33628
33626
|
const endIdx = original.indexOf(MEMORY_MARKER_END) + MEMORY_MARKER_END.length;
|
|
33629
33627
|
updated = original.slice(0, startIdx) + block + original.slice(endIdx);
|
|
33630
|
-
} else if (original.length > 0) {
|
|
33631
|
-
const doNotIdx = original.indexOf("## Do not");
|
|
33632
|
-
if (doNotIdx !== -1) {
|
|
33633
|
-
updated = `${original.slice(0, doNotIdx).trimEnd()}
|
|
33634
|
-
|
|
33635
|
-
${block}
|
|
33636
|
-
|
|
33637
|
-
${original.slice(doNotIdx)}`;
|
|
33638
|
-
} else {
|
|
33639
|
-
updated = `${original.trimEnd()}
|
|
33640
|
-
|
|
33641
|
-
${block}
|
|
33642
|
-
`;
|
|
33643
|
-
}
|
|
33644
33628
|
} else {
|
|
33645
|
-
|
|
33629
|
+
const head = original.trimEnd();
|
|
33630
|
+
updated = head ? `${head}
|
|
33646
33631
|
|
|
33647
33632
|
${block}
|
|
33633
|
+
` : `${block}
|
|
33648
33634
|
`;
|
|
33649
33635
|
}
|
|
33650
33636
|
if (updated !== original) {
|
|
@@ -33655,51 +33641,20 @@ ${block}
|
|
|
33655
33641
|
}
|
|
33656
33642
|
function syncHarnessMemory(repoRoot, options = {}) {
|
|
33657
33643
|
const root = resolve22(repoRoot);
|
|
33658
|
-
const
|
|
33659
|
-
const
|
|
33660
|
-
|
|
33661
|
-
|
|
33662
|
-
|
|
33663
|
-
|
|
33664
|
-
const agentsExisted = existsSync26(agentsPath);
|
|
33665
|
-
if (updateHarnessDocument(agentsPath, block, agentsHeader, options.dryRun)) {
|
|
33666
|
-
if (agentsExisted) updated.push("AGENTS.md");
|
|
33667
|
-
else created.push("AGENTS.md");
|
|
33668
|
-
}
|
|
33669
|
-
const claudePath = join28(root, "CLAUDE.md");
|
|
33670
|
-
const claudeHeader = `# KXM (Claude)
|
|
33671
|
-
|
|
33672
|
-
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
33673
|
-
[\`plans/implementation-plan.md\`](plans/implementation-plan.md#tracking-working-tree-not-a-release).
|
|
33674
|
-
|
|
33675
|
-
You are the **planner / architecture critic** unless the human explicitly asks
|
|
33676
|
-
you to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`) \u2014 a starting
|
|
33677
|
-
rotation, not a sole writer. If \`grok\` is logged out, never bill Grok through another harness;
|
|
33678
|
-
use a relief route Tracking **admits**, or stop and name the limits hit. Your reviews are
|
|
33679
|
-
artifacts, not hub \`peer-reply\` evidence.
|
|
33680
|
-
`;
|
|
33681
|
-
const claudeExisted = existsSync26(claudePath);
|
|
33682
|
-
if (updateHarnessDocument(claudePath, block, claudeHeader, options.dryRun)) {
|
|
33683
|
-
if (claudeExisted) updated.push("CLAUDE.md");
|
|
33684
|
-
else created.push("CLAUDE.md");
|
|
33644
|
+
const present = HARNESS_INSTRUCTION_FILES.filter((name) => existsSync26(join28(root, name)));
|
|
33645
|
+
const missing = HARNESS_INSTRUCTION_FILES.filter((name) => !present.includes(name));
|
|
33646
|
+
if (present.length === 0) {
|
|
33647
|
+
throw new Error(
|
|
33648
|
+
`none of ${HARNESS_INSTRUCTION_FILES.join(", ")} exists in ${root}; sync updates the instruction files a project already has and does not create them`
|
|
33649
|
+
);
|
|
33685
33650
|
}
|
|
33686
|
-
const
|
|
33687
|
-
const
|
|
33688
|
-
|
|
33689
|
-
|
|
33690
|
-
|
|
33691
|
-
|
|
33692
|
-
Google goes through the \`antigravity\` **Pi provider** (Tracking \u2192 Decided,
|
|
33693
|
-
2026-09-15); \`agy\` stays a harness catalog/helper entry, not the admission path.
|
|
33694
|
-
Current admissions come from Tracking and \`kxm harness list\`. Starting rotation
|
|
33695
|
-
remains Grok.
|
|
33696
|
-
`;
|
|
33697
|
-
const geminiExisted = existsSync26(geminiPath);
|
|
33698
|
-
if (updateHarnessDocument(geminiPath, block, geminiHeader, options.dryRun)) {
|
|
33699
|
-
if (geminiExisted) updated.push("GEMINI.md");
|
|
33700
|
-
else created.push("GEMINI.md");
|
|
33651
|
+
const block = formatHarnessMemoryBlock(loadAuthoredMemory(root));
|
|
33652
|
+
const updated = [];
|
|
33653
|
+
const unchanged = [];
|
|
33654
|
+
for (const name of present) {
|
|
33655
|
+
(updateHarnessDocument(join28(root, name), block, options.dryRun) ? updated : unchanged).push(name);
|
|
33701
33656
|
}
|
|
33702
|
-
return { updated,
|
|
33657
|
+
return { updated, unchanged, missing };
|
|
33703
33658
|
}
|
|
33704
33659
|
|
|
33705
33660
|
// plugins/kxm/src/skills.ts
|
|
@@ -34460,16 +34415,22 @@ async function cmdMemorySync(runtime) {
|
|
|
34460
34415
|
printPlan(
|
|
34461
34416
|
runtime,
|
|
34462
34417
|
{ command: "memory sync", ...result },
|
|
34463
|
-
|
|
34464
|
-
"regenerate project memory
|
|
34418
|
+
result.updated.map((file) => ({ action: "write", target: join31(runtime.cwd, file) })),
|
|
34419
|
+
"regenerate the project memory block in the instruction files this project already has"
|
|
34465
34420
|
);
|
|
34466
34421
|
return 0;
|
|
34467
34422
|
}
|
|
34423
|
+
const lines = [
|
|
34424
|
+
...result.updated.length > 0 ? [`updated: ${result.updated.join(", ")}`] : [],
|
|
34425
|
+
...result.unchanged.length > 0 ? [`unchanged: ${result.unchanged.join(", ")}`] : [],
|
|
34426
|
+
...result.missing.length > 0 ? [`not present, not created: ${result.missing.join(", ")}`] : []
|
|
34427
|
+
];
|
|
34468
34428
|
print(
|
|
34469
34429
|
runtime.io,
|
|
34470
34430
|
runtime.json,
|
|
34471
34431
|
{ ok: true, command: "memory sync", ...result },
|
|
34472
|
-
`Synced project memory
|
|
34432
|
+
`Synced project memory
|
|
34433
|
+
${lines.join("\n")}`
|
|
34473
34434
|
);
|
|
34474
34435
|
return 0;
|
|
34475
34436
|
} catch (error) {
|
|
@@ -48574,7 +48535,7 @@ function createProgram(ctx, result) {
|
|
|
48574
48535
|
addGlobalOptions(memory.command("note").description("Record an evidence-based memory candidate (promoted via PR)")).argument("<fact>", "Summary of the observed fact or learning").option("--scope <scope>", "Scope: agent, project, run, or operator (default: project)").option("--kind <kind>", "Kind: decision, architecture, convention, policy, learning (default: learning)").option("--body <text>", "Detailed markdown context for the fact").action(async function memoryNoteAction(fact, options) {
|
|
48575
48536
|
result.code = await cmdMemoryNote(runtimeFrom(ctx, this), fact, options);
|
|
48576
48537
|
});
|
|
48577
|
-
addGlobalOptions(memory.command("sync").description("Regenerate memory
|
|
48538
|
+
addGlobalOptions(memory.command("sync").description("Regenerate the memory block in whichever of AGENTS.md, CLAUDE.md, and GEMINI.md exist; never creates them")).action(async function memorySyncAction() {
|
|
48578
48539
|
result.code = await cmdMemorySync(runtimeFrom(ctx, this));
|
|
48579
48540
|
});
|
|
48580
48541
|
const routing = addGlobalOptions(program2.command("routing").description("Model/harness routing telemetry and behavioral comparisons"));
|
|
@@ -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.91";
|
|
17186
17186
|
var inbox = /* @__PURE__ */ new Map();
|
|
17187
17187
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17188
17188
|
var meshClient;
|
package/plugins/kxm/package.json
CHANGED
|
@@ -38,7 +38,7 @@ kxm context state my-project "configuration.authority" --json
|
|
|
38
38
|
|---|---|---|
|
|
39
39
|
| `kxm memory brief` | Read active project memory facts | `--json` |
|
|
40
40
|
| `kxm memory note <fact>` | Record a candidate for reviewed promotion | `--scope`, `--kind`, `--body`, `--json` |
|
|
41
|
-
| `kxm memory sync` | Regenerate
|
|
41
|
+
| `kxm memory sync` | Regenerate the memory block in existing `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` | `--json` |
|
|
42
42
|
|
|
43
43
|
Scopes are `agent`, `project`, `run`, or `operator`. Kinds are `decision`,
|
|
44
44
|
`architecture`, `convention`, `policy`, or `learning`. Scope and kind labels
|
|
@@ -51,6 +51,12 @@ never elevate the candidate's authority.
|
|
|
51
51
|
4. Regenerate projections only as an authorized write, inspect their diff,
|
|
52
52
|
and run the existing verification gate.
|
|
53
53
|
|
|
54
|
+
`kxm memory sync` rewrites only the text between `<!-- kxm:memory:start -->`
|
|
55
|
+
and `<!-- kxm:memory:end -->` (appending that block when a file has none) and
|
|
56
|
+
never creates an instruction file. If the project has none of the three, sync
|
|
57
|
+
refuses; create the file your harness reads yourself rather than expecting KXM
|
|
58
|
+
to author it.
|
|
59
|
+
|
|
54
60
|
Do not invent search, save, delete, list, or clear subcommands under memory.
|
|
55
61
|
Use context retrieval for discovery and reviewed authored changes for
|
|
56
62
|
corrections, respecting provenance and historical records.
|
|
@@ -398,16 +398,21 @@ export async function cmdMemorySync(runtime: Runtime): Promise<number> {
|
|
|
398
398
|
printPlan(
|
|
399
399
|
runtime,
|
|
400
400
|
{ command: "memory sync", ...result },
|
|
401
|
-
|
|
402
|
-
"regenerate project memory
|
|
401
|
+
result.updated.map((file) => ({ action: "write", target: join(runtime.cwd, file) })),
|
|
402
|
+
"regenerate the project memory block in the instruction files this project already has",
|
|
403
403
|
);
|
|
404
404
|
return 0;
|
|
405
405
|
}
|
|
406
|
+
const lines = [
|
|
407
|
+
...(result.updated.length > 0 ? [`updated: ${result.updated.join(", ")}`] : []),
|
|
408
|
+
...(result.unchanged.length > 0 ? [`unchanged: ${result.unchanged.join(", ")}`] : []),
|
|
409
|
+
...(result.missing.length > 0 ? [`not present, not created: ${result.missing.join(", ")}`] : []),
|
|
410
|
+
];
|
|
406
411
|
print(
|
|
407
412
|
runtime.io,
|
|
408
413
|
runtime.json,
|
|
409
414
|
{ ok: true, command: "memory sync", ...result },
|
|
410
|
-
`Synced project memory
|
|
415
|
+
`Synced project memory\n${lines.join("\n")}`,
|
|
411
416
|
);
|
|
412
417
|
return 0;
|
|
413
418
|
} catch (error) {
|
package/plugins/kxm/src/cli.ts
CHANGED
|
@@ -1040,7 +1040,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
1040
1040
|
.action(async function memoryNoteAction(this: Command, fact: string, options: { scope?: string; kind?: string; body?: string }) {
|
|
1041
1041
|
result.code = await cmdMemoryNote(runtimeFrom(ctx, this), fact, options);
|
|
1042
1042
|
});
|
|
1043
|
-
addGlobalOptions(memory.command("sync").description("Regenerate memory
|
|
1043
|
+
addGlobalOptions(memory.command("sync").description("Regenerate the memory block in whichever of AGENTS.md, CLAUDE.md, and GEMINI.md exist; never creates them"))
|
|
1044
1044
|
.action(async function memorySyncAction(this: Command) {
|
|
1045
1045
|
result.code = await cmdMemorySync(runtimeFrom(ctx, this));
|
|
1046
1046
|
});
|
|
@@ -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.91";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
|
@@ -318,28 +318,24 @@ export function formatHarnessMemoryBlock(records: MemoryRecord[]): string {
|
|
|
318
318
|
return contentLines.join("\n");
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
/**
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
321
|
+
/** Instruction files `kxm memory sync` projects memory into. Sync never creates one:
|
|
322
|
+
* which harness a project uses is the project's choice, and a file KXM wrote would
|
|
323
|
+
* carry KXM's words instead of the project's. */
|
|
324
|
+
const HARNESS_INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"] as const;
|
|
325
|
+
|
|
326
|
+
/** Replace the marker-delimited block, or append one when the file has none. Nothing
|
|
327
|
+
* outside the markers is rewritten. Returns whether the block changed the file; `dryRun`
|
|
328
|
+
* answers without writing. */
|
|
329
|
+
export function updateHarnessDocument(filePath: string, block: string, dryRun = false): boolean {
|
|
330
|
+
const original = readFileSync(filePath, "utf8");
|
|
331
|
+
let updated: string;
|
|
329
332
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
330
333
|
const startIdx = original.indexOf(MEMORY_MARKER_START);
|
|
331
334
|
const endIdx = original.indexOf(MEMORY_MARKER_END) + MEMORY_MARKER_END.length;
|
|
332
335
|
updated = original.slice(0, startIdx) + block + original.slice(endIdx);
|
|
333
|
-
} else if (original.length > 0) {
|
|
334
|
-
// If "## Do not" exists, insert before it; else append to end
|
|
335
|
-
const doNotIdx = original.indexOf("## Do not");
|
|
336
|
-
if (doNotIdx !== -1) {
|
|
337
|
-
updated = `${original.slice(0, doNotIdx).trimEnd()}\n\n${block}\n\n${original.slice(doNotIdx)}`;
|
|
338
|
-
} else {
|
|
339
|
-
updated = `${original.trimEnd()}\n\n${block}\n`;
|
|
340
|
-
}
|
|
341
336
|
} else {
|
|
342
|
-
|
|
337
|
+
const head = original.trimEnd();
|
|
338
|
+
updated = head ? `${head}\n\n${block}\n` : `${block}\n`;
|
|
343
339
|
}
|
|
344
340
|
|
|
345
341
|
if (updated !== original) {
|
|
@@ -349,40 +345,24 @@ export function updateHarnessDocument(filePath: string, block: string, defaultHe
|
|
|
349
345
|
return false;
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
export function syncHarnessMemory(
|
|
348
|
+
export function syncHarnessMemory(
|
|
349
|
+
repoRoot: string,
|
|
350
|
+
options: { dryRun?: boolean } = {},
|
|
351
|
+
): { updated: string[]; unchanged: string[]; missing: string[] } {
|
|
353
352
|
const root = resolve(repoRoot);
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
// 1. AGENTS.md
|
|
361
|
-
const agentsPath = join(root, "AGENTS.md");
|
|
362
|
-
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
363
|
-
const agentsExisted = existsSync(agentsPath);
|
|
364
|
-
if (updateHarnessDocument(agentsPath, block, agentsHeader, options.dryRun)) {
|
|
365
|
-
if (agentsExisted) updated.push("AGENTS.md");
|
|
366
|
-
else created.push("AGENTS.md");
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// 2. CLAUDE.md
|
|
370
|
-
const claudePath = join(root, "CLAUDE.md");
|
|
371
|
-
const claudeHeader = `# KXM (Claude)\n\nFollow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:\n[\`plans/implementation-plan.md\`](plans/implementation-plan.md#tracking-working-tree-not-a-release).\n\nYou are the **planner / architecture critic** unless the human explicitly asks\nyou to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`) — a starting\nrotation, not a sole writer. If \`grok\` is logged out, never bill Grok through another harness;\nuse a relief route Tracking **admits**, or stop and name the limits hit. Your reviews are\nartifacts, not hub \`peer-reply\` evidence.\n`;
|
|
372
|
-
const claudeExisted = existsSync(claudePath);
|
|
373
|
-
if (updateHarnessDocument(claudePath, block, claudeHeader, options.dryRun)) {
|
|
374
|
-
if (claudeExisted) updated.push("CLAUDE.md");
|
|
375
|
-
else created.push("CLAUDE.md");
|
|
353
|
+
const present = HARNESS_INSTRUCTION_FILES.filter((name) => existsSync(join(root, name)));
|
|
354
|
+
const missing = HARNESS_INSTRUCTION_FILES.filter((name) => !present.includes(name));
|
|
355
|
+
if (present.length === 0) {
|
|
356
|
+
throw new Error(
|
|
357
|
+
`none of ${HARNESS_INSTRUCTION_FILES.join(", ")} exists in ${root}; sync updates the instruction files a project already has and does not create them`,
|
|
358
|
+
);
|
|
376
359
|
}
|
|
377
360
|
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
if (geminiExisted) updated.push("GEMINI.md");
|
|
384
|
-
else created.push("GEMINI.md");
|
|
361
|
+
const block = formatHarnessMemoryBlock(loadAuthoredMemory(root));
|
|
362
|
+
const updated: string[] = [];
|
|
363
|
+
const unchanged: string[] = [];
|
|
364
|
+
for (const name of present) {
|
|
365
|
+
(updateHarnessDocument(join(root, name), block, options.dryRun) ? updated : unchanged).push(name);
|
|
385
366
|
}
|
|
386
|
-
|
|
387
|
-
return { updated, created };
|
|
367
|
+
return { updated, unchanged, missing };
|
|
388
368
|
}
|