sdtk-brain-kit 0.1.1 → 0.2.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/README.md +3 -1
- package/package.json +1 -1
- package/src/commands/operations.js +27 -2
- package/src/lib/wiki-build.js +14 -1
- package/src/lib/wiki-compile.js +32 -3
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ layer (`wiki/`) that you — and your AI agent — can search, lint, and browse
|
|
|
6
6
|
a graph. The agent reading the vault (per its `CLAUDE.md` contract) is the
|
|
7
7
|
knowledge engine; this CLI provides the deterministic rails only.
|
|
8
8
|
|
|
9
|
-
Package version in this source snapshot: `0.
|
|
9
|
+
Package version in this source snapshot: `0.2.0`
|
|
10
10
|
CLI command: `sdtk-brain`
|
|
11
11
|
|
|
12
12
|
Standalone by design: not part of the `sdtk-kit` umbrella, installs no agent
|
|
@@ -38,6 +38,8 @@ sdtk-brain open # docs view + graph view (local viewer, no
|
|
|
38
38
|
sdtk-brain init [--vault <path>] scaffold a vault (refuses non-empty non-vault targets)
|
|
39
39
|
sdtk-brain ingest <file|dir> semantic extraction over raw sources (report-first)
|
|
40
40
|
sdtk-brain compile --mode safe [--apply] compile extraction into wiki/ pages
|
|
41
|
+
--skip-conflicts (with --apply) apply only the non-conflicting remainder;
|
|
42
|
+
drifted pages stay untouched + reported
|
|
41
43
|
sdtk-brain search [--json] "<q>" deterministic search over the vault wiki
|
|
42
44
|
sdtk-brain lint | maintain report-first hygiene (orphans, links, stale, contradictions)
|
|
43
45
|
sdtk-brain discover --plan gap-analysis plan
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdtk-brain-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Standalone local-first second-brain vault CLI: immutable raw/ sources compiled into a markdown wiki/ knowledge layer, maintained by rails (ingest, compile, lint, search, graph viewer) while your agent is the knowledge engine.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,7 @@ const COMPILE_FLAG_DEFS = {
|
|
|
23
23
|
"project-path": { type: "string" },
|
|
24
24
|
mode: { type: "string" },
|
|
25
25
|
apply: { type: "boolean" },
|
|
26
|
+
"skip-conflicts": { type: "boolean" },
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const QUERY_FLAG_DEFS = {
|
|
@@ -122,6 +123,16 @@ function cmdCompileHelp() {
|
|
|
122
123
|
Usage:
|
|
123
124
|
sdtk-brain compile --mode safe [--project-path <path>]
|
|
124
125
|
sdtk-brain compile --mode safe --apply [--project-path <path>]
|
|
126
|
+
sdtk-brain compile --mode safe --apply --skip-conflicts [--project-path <path>]
|
|
127
|
+
|
|
128
|
+
Options:
|
|
129
|
+
--mode safe Required. Safe mode is the only R1 mode.
|
|
130
|
+
--apply Apply the JSON sidecar (otherwise preview only).
|
|
131
|
+
--skip-conflicts With --apply: apply the non-conflicting remainder,
|
|
132
|
+
leave every existing-but-different file untouched,
|
|
133
|
+
and record the skipped list in .brain/reports.
|
|
134
|
+
--project-path <path> Vault directory (--vault works as an alias).
|
|
135
|
+
-h, --help Show this help.
|
|
125
136
|
|
|
126
137
|
Purpose:
|
|
127
138
|
Use the latest semantic extraction report to write a compile preview and JSON sidecar, then optionally apply the sidecar.
|
|
@@ -133,7 +144,8 @@ Scope:
|
|
|
133
144
|
|
|
134
145
|
Safety:
|
|
135
146
|
Safe mode is the only R1 mode.
|
|
136
|
-
--apply still uses the existing JSON sidecar contract
|
|
147
|
+
--apply still uses the existing JSON sidecar contract; without
|
|
148
|
+
--skip-conflicts it refuses atomically when any existing file differs.
|
|
137
149
|
No delete, archive, rewrite, raw/provenance mutation, source mutation, web fetch, Ask, or .brain-legacy-unused mutation.`);
|
|
138
150
|
return 0;
|
|
139
151
|
}
|
|
@@ -251,6 +263,9 @@ function cmdCompile(args) {
|
|
|
251
263
|
if (flags.help) return cmdCompileHelp();
|
|
252
264
|
ensureSafeMode(flags.mode, "compile");
|
|
253
265
|
const projectPath = ensureProjectPath(flags["project-path"]);
|
|
266
|
+
if (flags["skip-conflicts"] && !flags.apply) {
|
|
267
|
+
throw new ValidationError("--skip-conflicts only makes sense with --apply. No project files were changed.");
|
|
268
|
+
}
|
|
254
269
|
|
|
255
270
|
if (!flags.apply) {
|
|
256
271
|
const result = runCompileDryRunFromLatestExtraction(projectPath);
|
|
@@ -270,13 +285,23 @@ function cmdCompile(args) {
|
|
|
270
285
|
}
|
|
271
286
|
|
|
272
287
|
const sidecar = ensureApplySidecar(projectPath);
|
|
273
|
-
const result = runWikiCompileApply({
|
|
288
|
+
const result = runWikiCompileApply({
|
|
289
|
+
projectPath,
|
|
290
|
+
planArg: sidecar.sidecarPath,
|
|
291
|
+
skipConflicts: Boolean(flags["skip-conflicts"]),
|
|
292
|
+
});
|
|
274
293
|
console.log(`[brain] Compile apply plan: ${result.planPath}`);
|
|
275
294
|
if (sidecar.createdFreshSidecar) {
|
|
276
295
|
console.log(`[brain] Refreshed compile dry-run preview: ${sidecar.dryRun.reportPath}`);
|
|
277
296
|
}
|
|
278
297
|
console.log(`[brain] Created files: ${result.created.length}`);
|
|
279
298
|
console.log(`[brain] Unchanged files: ${result.unchanged.length}`);
|
|
299
|
+
if (result.skipped && result.skipped.length > 0) {
|
|
300
|
+
console.log(`[brain] Skipped ${result.skipped.length} conflicting file(s) (existing content differs): ${result.skipped.join(", ")}`);
|
|
301
|
+
if (result.skipReportPath) {
|
|
302
|
+
console.log(`[brain] Skip report: ${result.skipReportPath}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
280
305
|
console.log(`[brain] Scaffold created/skipped: ${result.scaffoldCreated.length}/${result.scaffoldSkipped.length}`);
|
|
281
306
|
console.log(`[brain] Source-quality warnings: ${result.sourceQualityWarningCount}`);
|
|
282
307
|
console.log("[brain] Canonical local wiki output is <project>/wiki; .brain remains internal state. No source files, raw sources, provenance descriptors, or atlas compatibility files were modified.");
|
package/src/lib/wiki-build.js
CHANGED
|
@@ -873,6 +873,7 @@ function _render_generated_page(doc, page_id, source_hash, generated) {
|
|
|
873
873
|
`title: ${_yaml_quote(doc.title || "")}`,
|
|
874
874
|
`family: ${_yaml_quote(doc.family || "")}`,
|
|
875
875
|
`role: ${_yaml_quote(doc.role || "")}`,
|
|
876
|
+
`trust_zone: ${_yaml_quote(doc.trust_zone || "medium")}`,
|
|
876
877
|
`generated_at: ${_yaml_quote(generated)}`,
|
|
877
878
|
"---",
|
|
878
879
|
"",
|
|
@@ -1021,7 +1022,7 @@ function write_wiki_pages_and_provenance(docs, state, root, generated, scan_root
|
|
|
1021
1022
|
// ---------------------------------------------------------------------------
|
|
1022
1023
|
// Top-level buildAtlas
|
|
1023
1024
|
// ---------------------------------------------------------------------------
|
|
1024
|
-
async function buildAtlas({ projectRoot, outputDir, scanRoots, excludes, verbose, workspaceRoot } = {}) {
|
|
1025
|
+
async function buildAtlas({ projectRoot, outputDir, scanRoots, excludes, verbose, workspaceRoot, archiveFrags } = {}) {
|
|
1025
1026
|
const generated = _now_utc();
|
|
1026
1027
|
const root = path.resolve(projectRoot);
|
|
1027
1028
|
const atlas_dir = path.resolve(outputDir);
|
|
@@ -1037,6 +1038,18 @@ async function buildAtlas({ projectRoot, outputDir, scanRoots, excludes, verbose
|
|
|
1037
1038
|
process.stdout.write("[atlas] Scanning markdown files...\n");
|
|
1038
1039
|
const [docs, state, stats] = build_docs_incremental(root, atlas_dir, generated, roots, frags);
|
|
1039
1040
|
|
|
1041
|
+
// BK-325: archive tier. Applied to EVERY doc after the incremental pass —
|
|
1042
|
+
// cache-reused docs carry the trust_zone of the build that cached them, so
|
|
1043
|
+
// re-deriving here keeps tiering correct when the config changes without a
|
|
1044
|
+
// reparse. Same path-fragment matching semantics as `excludes`.
|
|
1045
|
+
const archive_frags = Array.isArray(archiveFrags) ? archiveFrags.filter(Boolean) : [];
|
|
1046
|
+
for (const doc of docs) {
|
|
1047
|
+
const abs = path.join(root, doc.path);
|
|
1048
|
+
doc.trust_zone = archive_frags.length > 0 && _match_exclude(abs, root, archive_frags)
|
|
1049
|
+
? "archive"
|
|
1050
|
+
: "medium";
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1040
1053
|
process.stdout.write(`[atlas] Indexed ${docs.length} documents.\n`);
|
|
1041
1054
|
process.stdout.write(
|
|
1042
1055
|
`[atlas] Scan coverage: scanned ${stats.scanned_count !== undefined ? stats.scanned_count : docs.length}, ` +
|
package/src/lib/wiki-compile.js
CHANGED
|
@@ -1975,7 +1975,7 @@ function scaffoldCanonicalWikiStructure(projectPath) {
|
|
|
1975
1975
|
return { created, skipped };
|
|
1976
1976
|
}
|
|
1977
1977
|
|
|
1978
|
-
function runWikiCompileApply({ projectPath, planArg }) {
|
|
1978
|
+
function runWikiCompileApply({ projectPath, planArg, skipConflicts = false }) {
|
|
1979
1979
|
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
1980
1980
|
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
1981
1981
|
throw new ValidationError(`--project-path is not a valid directory: ${resolvedProjectPath}`);
|
|
@@ -2012,8 +2012,8 @@ function runWikiCompileApply({ projectPath, planArg }) {
|
|
|
2012
2012
|
}
|
|
2013
2013
|
}
|
|
2014
2014
|
|
|
2015
|
-
if (conflicts.length > 0) {
|
|
2016
|
-
throw new ValidationError(`Compile apply would overwrite ${conflicts.length} existing different file(s): ${conflicts.join(", ")}. No project files were changed.`);
|
|
2015
|
+
if (conflicts.length > 0 && !skipConflicts) {
|
|
2016
|
+
throw new ValidationError(`Compile apply would overwrite ${conflicts.length} existing different file(s): ${conflicts.join(", ")}. No project files were changed. Pass --skip-conflicts to apply the non-conflicting remainder and leave these files untouched.`);
|
|
2017
2017
|
}
|
|
2018
2018
|
|
|
2019
2019
|
const created = [];
|
|
@@ -2025,10 +2025,39 @@ function runWikiCompileApply({ projectPath, planArg }) {
|
|
|
2025
2025
|
}
|
|
2026
2026
|
|
|
2027
2027
|
const sourceQualitySummary = payload.source_quality_summary || emptySourceQualitySummary();
|
|
2028
|
+
// BK-327: when --skip-conflicts applied a partial plan, record the
|
|
2029
|
+
// decision durably so the skip list is auditable later.
|
|
2030
|
+
let skipReportPath = null;
|
|
2031
|
+
if (skipConflicts) {
|
|
2032
|
+
const reportsPath = getWikiReportsPath(resolvedProjectPath);
|
|
2033
|
+
assertWikiWorkspaceWritePath(reportsPath, resolvedProjectPath);
|
|
2034
|
+
fs.mkdirSync(reportsPath, { recursive: true });
|
|
2035
|
+
skipReportPath = path.join(reportsPath, `compile-apply-result-${todayStamp()}.json`);
|
|
2036
|
+
assertWikiWorkspaceWritePath(skipReportPath, resolvedProjectPath);
|
|
2037
|
+
fs.writeFileSync(
|
|
2038
|
+
skipReportPath,
|
|
2039
|
+
JSON.stringify(
|
|
2040
|
+
{
|
|
2041
|
+
generated_at: new Date().toISOString(),
|
|
2042
|
+
plan_path: planPath,
|
|
2043
|
+
mode: "skip_conflicts",
|
|
2044
|
+
created,
|
|
2045
|
+
unchanged_count: unchanged.length,
|
|
2046
|
+
skipped: conflicts,
|
|
2047
|
+
},
|
|
2048
|
+
null,
|
|
2049
|
+
2
|
|
2050
|
+
) + "\n",
|
|
2051
|
+
"utf-8"
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2028
2055
|
return {
|
|
2029
2056
|
planPath,
|
|
2030
2057
|
created,
|
|
2031
2058
|
unchanged,
|
|
2059
|
+
skipped: conflicts,
|
|
2060
|
+
skipReportPath,
|
|
2032
2061
|
scaffoldCreated: scaffold.created,
|
|
2033
2062
|
scaffoldSkipped: scaffold.skipped,
|
|
2034
2063
|
sourceQualityWarningCount: Number(sourceQualitySummary.warning_count || sourceQualitySummary.findings_count || 0),
|