@viloforge/vfkb 0.4.1 → 0.5.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/broadcast.js +19 -8
- package/dist/bundles/vfkb-mcp.mjs +15 -1
- package/dist/bundles/vfkb.mjs +171 -104
- package/dist/cli.js +43 -4
- package/dist/docs-committed-brain-files.test.js +416 -0
- package/dist/engine.js +52 -1
- package/dist/hook-stdin-failopen.test.js +217 -0
- package/dist/init.js +47 -6
- package/dist/init.test.js +70 -1
- package/dist/manifest.js +40 -4
- package/package.json +1 -1
package/dist/broadcast.js
CHANGED
|
@@ -8,9 +8,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
8
8
|
import { existsSync, readFileSync } from 'node:fs';
|
|
9
9
|
import { basename, join, resolve } from 'node:path';
|
|
10
10
|
import { addEntry } from './engine.js';
|
|
11
|
-
import { writeManifest } from './manifest.js';
|
|
11
|
+
import { manifestNeedsStamp, writeManifest } from './manifest.js';
|
|
12
12
|
import { defaultProject } from './storage.js';
|
|
13
|
-
import { SCHEMA_VERSION } from './version.js';
|
|
13
|
+
import { ENGINE_COMMIT, SCHEMA_VERSION } from './version.js';
|
|
14
14
|
/** The resident-pin tags a broadcast record must never carry (ADR-0063 §1). */
|
|
15
15
|
const FORBIDDEN_TAGS = new Set(['handoff', 'next']);
|
|
16
16
|
function targetBrainDir(target) {
|
|
@@ -76,7 +76,14 @@ export function broadcast(text, targets, opts = {}) {
|
|
|
76
76
|
const repoDir = resolve(brain, '..');
|
|
77
77
|
const manifestPath = join(brain, 'manifest.json');
|
|
78
78
|
let healed = false;
|
|
79
|
-
|
|
79
|
+
let upgraded = false;
|
|
80
|
+
// #212 — the heal used to fire ONLY on absence, so a brain stamped by a
|
|
81
|
+
// dist-path build (engine_commit "dev") stayed unknown forever: nothing in
|
|
82
|
+
// any routine path ever re-stamped it, and doctor reported it against every
|
|
83
|
+
// real-sha engine. A running engine that knows its own commit is a genuine
|
|
84
|
+
// provenance upgrade for a brain that does not — unknown -> known.
|
|
85
|
+
const needsStamp = manifestNeedsStamp(brain, opts.engineCommit ?? ENGINE_COMMIT);
|
|
86
|
+
if (needsStamp) {
|
|
80
87
|
// §3's rule is "never bootstrap a WIRE-LESS brain". A brain with a live
|
|
81
88
|
// entries.jsonl is wired — the manifest is just missing because only
|
|
82
89
|
// `vfkb init` ever writes it (plugin-born brains, vfkb#193). Heal it
|
|
@@ -86,16 +93,20 @@ export function broadcast(text, targets, opts = {}) {
|
|
|
86
93
|
results.push({ target, ok: false, reason: `no brain (no entries.jsonl in ${brain}) — never bootstrap a wire-less brain (ADR-0063 §3)` });
|
|
87
94
|
continue;
|
|
88
95
|
}
|
|
96
|
+
const absent = !existsSync(manifestPath);
|
|
89
97
|
try {
|
|
90
|
-
writeManifest(brain);
|
|
98
|
+
writeManifest(brain, { engineCommit: opts.engineCommit, engineVersion: opts.engineVersion });
|
|
91
99
|
}
|
|
92
100
|
catch (err) {
|
|
93
101
|
// Per-target and loud, never a thrown abort — a heal failure on one
|
|
94
102
|
// target must not swallow the rest of a partial broadcast.
|
|
95
|
-
results.push({ target, ok: false, reason: `manifest heal failed: ${err.message}` });
|
|
103
|
+
results.push({ target, ok: false, reason: `manifest ${absent ? 'heal' : 'provenance upgrade'} failed: ${err.message}` });
|
|
96
104
|
continue;
|
|
97
105
|
}
|
|
98
|
-
|
|
106
|
+
if (absent)
|
|
107
|
+
healed = true;
|
|
108
|
+
else
|
|
109
|
+
upgraded = true;
|
|
99
110
|
}
|
|
100
111
|
let schema;
|
|
101
112
|
try {
|
|
@@ -116,12 +127,12 @@ export function broadcast(text, targets, opts = {}) {
|
|
|
116
127
|
process.env.VFKB_DATA_DIR = brain;
|
|
117
128
|
const e = addEntry('fact', stamped, { role: 'executor', tags: [...new Set(['cross-repo', ...extraTags])] });
|
|
118
129
|
written.add(brain);
|
|
119
|
-
results.push({ target, ok: true, id: e.id, posture: gitPosture(repoDir), ...(healed ? { healed } : {}) });
|
|
130
|
+
results.push({ target, ok: true, id: e.id, posture: gitPosture(repoDir), ...(healed ? { healed } : {}), ...(upgraded ? { upgraded } : {}) });
|
|
120
131
|
}
|
|
121
132
|
catch (err) {
|
|
122
133
|
// healed still reported on failure — the manifest stamp happened even
|
|
123
134
|
// though the record did not land (heal is never silent).
|
|
124
|
-
results.push({ target, ok: false, reason: err.message, ...(healed ? { healed } : {}) });
|
|
135
|
+
results.push({ target, ok: false, reason: err.message, ...(healed ? { healed } : {}), ...(upgraded ? { upgraded } : {}) });
|
|
125
136
|
}
|
|
126
137
|
finally {
|
|
127
138
|
if (prev === undefined)
|
|
@@ -30954,6 +30954,9 @@ var StdioServerTransport = class {
|
|
|
30954
30954
|
|
|
30955
30955
|
// src/engine.ts
|
|
30956
30956
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
30957
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
30958
|
+
import { dirname as dirname3, join as join6, resolve as resolvePath } from "node:path";
|
|
30959
|
+
import { fileURLToPath } from "node:url";
|
|
30957
30960
|
|
|
30958
30961
|
// src/storage.ts
|
|
30959
30962
|
import { basename, dirname as dirname2, join as join4, resolve } from "node:path";
|
|
@@ -31775,6 +31778,16 @@ function latestCrossRepo(all = readAll(), today = nowIso().slice(0, 10), superse
|
|
|
31775
31778
|
}
|
|
31776
31779
|
return latest;
|
|
31777
31780
|
}
|
|
31781
|
+
var CLI_FACES = ["vfkb.mjs", "cli.js", "cli.mjs"];
|
|
31782
|
+
function resolveCliFace(engineDir) {
|
|
31783
|
+
return CLI_FACES.map((f) => join6(engineDir, f)).find((p) => existsSync4(p));
|
|
31784
|
+
}
|
|
31785
|
+
function renderCaptureFallback(engineDir = dirname3(fileURLToPath(import.meta.url))) {
|
|
31786
|
+
const cli = resolveCliFace(engineDir);
|
|
31787
|
+
const target = cli ? `node "${cli}"` : `node <vfkb CLI not found beside the engine at ${engineDir} \u2014 locate vfkb.mjs or cli.js>`;
|
|
31788
|
+
return `capture fallback: if the kb_* tools error or disappear, the CLI still writes (same engine, separate process; journaled per ADR-0064) \u2014
|
|
31789
|
+
VFKB_DATA_DIR="${resolvePath(brainDir())}" ${target} add <type> "\u2026" [--tags a,b] [--why "\u2026"]`;
|
|
31790
|
+
}
|
|
31778
31791
|
function renderContextBundle(project = defaultProject(), budget = SESSION_BUDGET_CHARS) {
|
|
31779
31792
|
const all = readAll();
|
|
31780
31793
|
const today = nowIso().slice(0, 10);
|
|
@@ -31813,6 +31826,7 @@ function renderContextBundle(project = defaultProject(), budget = SESSION_BUDGET
|
|
|
31813
31826
|
`;
|
|
31814
31827
|
}
|
|
31815
31828
|
body += renderContextMap() + "\n\n";
|
|
31829
|
+
body += renderCaptureFallback() + "\n\n";
|
|
31816
31830
|
const kept = [];
|
|
31817
31831
|
let keptLen = 0;
|
|
31818
31832
|
let dropped = 0;
|
|
@@ -32007,7 +32021,7 @@ function queryExplained(opts = {}) {
|
|
|
32007
32021
|
}
|
|
32008
32022
|
|
|
32009
32023
|
// src/version.ts
|
|
32010
|
-
var ENGINE_VERSION = true ? "0.
|
|
32024
|
+
var ENGINE_VERSION = true ? "0.5.0" : ownPackageVersion();
|
|
32011
32025
|
|
|
32012
32026
|
// src/mcp-server.ts
|
|
32013
32027
|
var SEARCH_DEFAULT_LIMIT = 25;
|