@viloforge/vfkb 0.5.0 → 0.6.0
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/dist/bundles/vfkb-mcp.mjs +1 -1
- package/dist/bundles/vfkb.mjs +29 -4
- package/dist/doctor.js +61 -1
- package/dist/init.js +1 -0
- package/dist/init.test.js +2 -2
- package/package.json +1 -1
|
@@ -32021,7 +32021,7 @@ function queryExplained(opts = {}) {
|
|
|
32021
32021
|
}
|
|
32022
32022
|
|
|
32023
32023
|
// src/version.ts
|
|
32024
|
-
var ENGINE_VERSION = true ? "0.
|
|
32024
|
+
var ENGINE_VERSION = true ? "0.6.0" : ownPackageVersion();
|
|
32025
32025
|
|
|
32026
32026
|
// src/mcp-server.ts
|
|
32027
32027
|
var SEARCH_DEFAULT_LIMIT = 25;
|
package/dist/bundles/vfkb.mjs
CHANGED
|
@@ -16091,8 +16091,8 @@ import { dirname as dirname5, join as join8 } from "node:path";
|
|
|
16091
16091
|
|
|
16092
16092
|
// src/version.ts
|
|
16093
16093
|
var SCHEMA_VERSION = 1;
|
|
16094
|
-
var ENGINE_VERSION = true ? "0.
|
|
16095
|
-
var ENGINE_COMMIT = true ? "
|
|
16094
|
+
var ENGINE_VERSION = true ? "0.6.0" : ownPackageVersion();
|
|
16095
|
+
var ENGINE_COMMIT = true ? "9921586" : "dev";
|
|
16096
16096
|
|
|
16097
16097
|
// src/manifest.ts
|
|
16098
16098
|
function manifestPath(brainDir2) {
|
|
@@ -16850,7 +16850,8 @@ function initProject(root, opts = {}) {
|
|
|
16850
16850
|
".vfkb/.sessions/",
|
|
16851
16851
|
".vfkb/.signals/",
|
|
16852
16852
|
".vfkb/.journal/",
|
|
16853
|
-
".vfkb/.lock"
|
|
16853
|
+
".vfkb/.lock",
|
|
16854
|
+
".vfkb/.write-probe-*"
|
|
16854
16855
|
];
|
|
16855
16856
|
const HEADER = [
|
|
16856
16857
|
"# vfkb \u2014 entries.jsonl + manifest.json (the ADR-0030 engine stamp) are committed;",
|
|
@@ -16925,7 +16926,8 @@ function approvalNotice(project) {
|
|
|
16925
16926
|
|
|
16926
16927
|
// src/doctor.ts
|
|
16927
16928
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
16928
|
-
import {
|
|
16929
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
16930
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, realpathSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
16929
16931
|
import { join as join14, dirname as dirname6, relative as relative3, resolve as resolve4, isAbsolute as isAbsolute2 } from "node:path";
|
|
16930
16932
|
function readJson2(path) {
|
|
16931
16933
|
if (!existsSync10(path)) return void 0;
|
|
@@ -17193,6 +17195,29 @@ function runDoctor(opts) {
|
|
|
17193
17195
|
add("engine drift", "warn", `brain last stamped by engine ${mf.engine_commit}, running ${runningCommit} \u2014 possible dual-clone drift`);
|
|
17194
17196
|
}
|
|
17195
17197
|
}
|
|
17198
|
+
{
|
|
17199
|
+
const probe = join14(brainDir2, `.write-probe-${process.pid}-${randomBytes3(4).toString("hex")}`);
|
|
17200
|
+
const payload = `vfkb write-probe ${process.pid} ${Date.now()}`;
|
|
17201
|
+
let failure;
|
|
17202
|
+
try {
|
|
17203
|
+
mkdirSync8(brainDir2, { recursive: true });
|
|
17204
|
+
writeFileSync6(probe, payload);
|
|
17205
|
+
if (readFileSync11(probe, "utf8") !== payload) failure = "wrote the probe file but read back different bytes";
|
|
17206
|
+
} catch (e) {
|
|
17207
|
+
failure = e.message;
|
|
17208
|
+
} finally {
|
|
17209
|
+
try {
|
|
17210
|
+
if (existsSync10(probe)) unlinkSync2(probe);
|
|
17211
|
+
} catch {
|
|
17212
|
+
}
|
|
17213
|
+
}
|
|
17214
|
+
const SCOPE = " \u2014 scope: this is the CLI/engine/filesystem path only; it does NOT check the MCP server, so it cannot tell you whether kb_* capture is reaching the brain (ADR-0065 \xA70: a hung MCP server loses a write with no error at all)";
|
|
17215
|
+
if (failure) {
|
|
17216
|
+
add("write-health (filesystem)", "fail", `cannot write to ${brainDir2}: ${failure}${SCOPE}`);
|
|
17217
|
+
} else {
|
|
17218
|
+
add("write-health (filesystem)", "ok", `round-trip verified in ${brainDir2}${SCOPE}`);
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17196
17221
|
{
|
|
17197
17222
|
const js = journalStatus(brainDir2);
|
|
17198
17223
|
if (js.suppressedInEntries > 0) {
|
package/dist/doctor.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// or inconsistent wiring, and the dual-clone drift signal (a brain last stamped by
|
|
4
4
|
// a different engine build). Deterministic; unit-tested (the inner gate per ADR-0023).
|
|
5
5
|
import { execFileSync } from 'node:child_process';
|
|
6
|
-
import {
|
|
6
|
+
import { randomBytes } from 'node:crypto';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync, unlinkSync } from 'node:fs';
|
|
7
8
|
import { join, dirname, relative, resolve, isAbsolute } from 'node:path';
|
|
8
9
|
import { SCHEMA_VERSION, ENGINE_VERSION, ENGINE_COMMIT } from './version.js';
|
|
9
10
|
import { journalStatus } from './journal.js';
|
|
@@ -438,6 +439,65 @@ export function runDoctor(opts) {
|
|
|
438
439
|
add('engine drift', 'warn', `brain last stamped by engine ${mf.engine_commit}, running ${runningCommit} — possible dual-clone drift`);
|
|
439
440
|
}
|
|
440
441
|
}
|
|
442
|
+
// 2a-bis. Write-health (ADR-0065 §2): can the engine actually write here?
|
|
443
|
+
//
|
|
444
|
+
// Round-trips a NON-entries file. `entries.jsonl` is append-only — there is no
|
|
445
|
+
// "append then remove" (the only delete is a tombstone, two permanent lines
|
|
446
|
+
// per doctor run), and a probe namespace inside it would dirty the working
|
|
447
|
+
// tree and grow the committed log on every invocation.
|
|
448
|
+
//
|
|
449
|
+
// SCOPE, and it is the whole difficulty. §0 observed that the failure which
|
|
450
|
+
// actually loses writes is a HUNG MCP server: the process is alive and mute,
|
|
451
|
+
// the call never returns, nothing errors (scenarios/probes/mcp-disconnect.md).
|
|
452
|
+
// Doctor is the CLI face and cannot see that at all. So a true "write-health
|
|
453
|
+
// ok" here is exactly the kind of statement a reader over-reads into "my
|
|
454
|
+
// capture is fine" — the 6ad98196b5a2 failure, where a diagnostic was made
|
|
455
|
+
// more CONFIDENT rather than more TRUE and an L4 went green because the claim
|
|
456
|
+
// became more quotable. The scope caveat below is therefore part of the
|
|
457
|
+
// behaviour, not decoration, and is pinned by test/doctor-write-health.test.ts.
|
|
458
|
+
{
|
|
459
|
+
// UNIQUE per run: with a fixed path, two doctors racing read each other's
|
|
460
|
+
// bytes and report "read back different bytes" — a false alarm of silent
|
|
461
|
+
// disk corruption, and report.ok=false exits 1 (reproduced: 4 processes x
|
|
462
|
+
// 200 runs, review of #228).
|
|
463
|
+
const probe = join(brainDir, `.write-probe-${process.pid}-${randomBytes(4).toString('hex')}`);
|
|
464
|
+
const payload = `vfkb write-probe ${process.pid} ${Date.now()}`;
|
|
465
|
+
let failure;
|
|
466
|
+
try {
|
|
467
|
+
mkdirSync(brainDir, { recursive: true });
|
|
468
|
+
writeFileSync(probe, payload);
|
|
469
|
+
// Read BACK: a write that silently no-ops (a full disk, an overlay that
|
|
470
|
+
// swallows writes) must not read as healthy.
|
|
471
|
+
if (readFileSync(probe, 'utf8') !== payload)
|
|
472
|
+
failure = 'wrote the probe file but read back different bytes';
|
|
473
|
+
}
|
|
474
|
+
catch (e) {
|
|
475
|
+
failure = e.message;
|
|
476
|
+
}
|
|
477
|
+
finally {
|
|
478
|
+
try {
|
|
479
|
+
if (existsSync(probe))
|
|
480
|
+
unlinkSync(probe);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
/* leaving the probe behind is not itself a write-health failure */
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
// §0 consequence #3 says a §2 design needs its own timeout or it inherits
|
|
487
|
+
// the hang. These are synchronous fs calls: on a wedged NFS/FUSE mount they
|
|
488
|
+
// block indefinitely and so does doctor. Named, not silently dropped — the
|
|
489
|
+
// bounded-round-trip requirement targets an MCP-probing design, which this
|
|
490
|
+
// deliberately is not.
|
|
491
|
+
const SCOPE = ' — scope: this is the CLI/engine/filesystem path only; it does NOT check the MCP server, ' +
|
|
492
|
+
'so it cannot tell you whether kb_* capture is reaching the brain (ADR-0065 §0: a hung MCP ' +
|
|
493
|
+
'server loses a write with no error at all)';
|
|
494
|
+
if (failure) {
|
|
495
|
+
add('write-health (filesystem)', 'fail', `cannot write to ${brainDir}: ${failure}${SCOPE}`);
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
add('write-health (filesystem)', 'ok', `round-trip verified in ${brainDir}${SCOPE}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
441
501
|
// 2b. Durable-capture journal (ADR-0064): what would recovery do, and is a
|
|
442
502
|
// redaction half-done? Read-only — recovery itself runs at session start.
|
|
443
503
|
{
|
package/dist/init.js
CHANGED
|
@@ -213,6 +213,7 @@ export function initProject(root, opts = {}) {
|
|
|
213
213
|
'.vfkb/.signals/',
|
|
214
214
|
'.vfkb/.journal/',
|
|
215
215
|
'.vfkb/.lock',
|
|
216
|
+
'.vfkb/.write-probe-*',
|
|
216
217
|
];
|
|
217
218
|
// The header the stanza should carry. The OLD one claimed "only
|
|
218
219
|
// .vfkb/entries.jsonl is committed", which is FALSE — manifest.json is
|
package/dist/init.test.js
CHANGED
|
@@ -66,7 +66,7 @@ describe('vfkb init (FR-1)', () => {
|
|
|
66
66
|
it('ignores every derived/operational path, including the lock', () => {
|
|
67
67
|
initProject(root, { project: 'demo' });
|
|
68
68
|
const gi = read('.gitignore');
|
|
69
|
-
for (const p of ['.vfkb/index-meta.json', '.vfkb/.sessions/', '.vfkb/.signals/', '.vfkb/.journal/', '.vfkb/.lock']) {
|
|
69
|
+
for (const p of ['.vfkb/index-meta.json', '.vfkb/.sessions/', '.vfkb/.signals/', '.vfkb/.journal/', '.vfkb/.lock', '.vfkb/.write-probe-*']) {
|
|
70
70
|
expect(gi, `missing ignore rule ${p}`).toContain(p);
|
|
71
71
|
}
|
|
72
72
|
});
|
|
@@ -96,7 +96,7 @@ describe('vfkb init (FR-1)', () => {
|
|
|
96
96
|
return false;
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
|
-
for (const p of ['.vfkb/.lock', '.vfkb/.journal/wal.jsonl', '.vfkb/index-meta.json', '.vfkb/.sessions/x', '.vfkb/.signals/y']) {
|
|
99
|
+
for (const p of ['.vfkb/.lock', '.vfkb/.journal/wal.jsonl', '.vfkb/index-meta.json', '.vfkb/.sessions/x', '.vfkb/.signals/y', '.vfkb/.write-probe-123-abc']) {
|
|
100
100
|
expect(ignored(p), `${p} should be ignored`).toBe(true);
|
|
101
101
|
}
|
|
102
102
|
// The brain and the ADR-0030 engine stamp MUST stay committable.
|
package/package.json
CHANGED