sdtk-brain-kit 0.1.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 +66 -0
- package/assets/atlas/doc_atlas_viewer_template.html +4868 -0
- package/assets/atlas/vendor/mermaid.min.js +2029 -0
- package/bin/sdtk-brain.js +88 -0
- package/package.json +28 -0
- package/scripts/brain-smoke.test.js +19 -0
- package/scripts/sync-shared-assets.js +24 -0
- package/src/commands/enrich.js +55 -0
- package/src/commands/init.js +108 -0
- package/src/commands/lint.js +50 -0
- package/src/commands/open.js +59 -0
- package/src/commands/operations.js +357 -0
- package/src/commands/search.js +94 -0
- package/src/commands/status.js +56 -0
- package/src/lib/args.js +76 -0
- package/src/lib/browser-open.js +32 -0
- package/src/lib/errors.js +29 -0
- package/src/lib/wiki-build.js +1101 -0
- package/src/lib/wiki-compile.js +2108 -0
- package/src/lib/wiki-discover.js +271 -0
- package/src/lib/wiki-enrich.js +264 -0
- package/src/lib/wiki-extract.js +1313 -0
- package/src/lib/wiki-flags.js +97 -0
- package/src/lib/wiki-ingest.js +198 -0
- package/src/lib/wiki-lint.js +930 -0
- package/src/lib/wiki-paths.js +256 -0
- package/src/lib/wiki-score.js +64 -0
- package/src/lib/wiki-search.js +213 -0
- package/templates/VAULT_CLAUDE.md +39 -0
- package/templates/VAULT_README.md +18 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parseFlags } = require("./args");
|
|
4
|
+
|
|
5
|
+
const BASE_FLAG_DEFS = {
|
|
6
|
+
"project-path": { type: "string" },
|
|
7
|
+
"output-dir": { type: "string" },
|
|
8
|
+
"scan-root": { type: "string" },
|
|
9
|
+
verbose: { type: "boolean" },
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const OPEN_FLAG_DEFS = {
|
|
13
|
+
...BASE_FLAG_DEFS,
|
|
14
|
+
host: { type: "string" },
|
|
15
|
+
port: { type: "string" },
|
|
16
|
+
"no-open": { type: "boolean" },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const INIT_FLAG_DEFS = {
|
|
20
|
+
...OPEN_FLAG_DEFS,
|
|
21
|
+
force: { type: "boolean" },
|
|
22
|
+
"no-build": { type: "boolean" },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const WATCH_FLAG_DEFS = {
|
|
26
|
+
...BASE_FLAG_DEFS,
|
|
27
|
+
port: { type: "string" },
|
|
28
|
+
"no-open": { type: "boolean" },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const LINT_FLAG_DEFS = {
|
|
32
|
+
"project-path": { type: "string" },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const PRUNE_FLAG_DEFS = {
|
|
36
|
+
"project-path": { type: "string" },
|
|
37
|
+
"dry-run": { type: "boolean" },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const DISCOVER_FLAG_DEFS = {
|
|
41
|
+
"project-path": { type: "string" },
|
|
42
|
+
plan: { type: "boolean" },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const EXTRACT_FLAG_DEFS = {
|
|
46
|
+
"project-path": { type: "string" },
|
|
47
|
+
"source-root": { type: "string" },
|
|
48
|
+
"dry-run": { type: "boolean" },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const COMPILE_FLAG_DEFS = {
|
|
52
|
+
"project-path": { type: "string" },
|
|
53
|
+
plan: { type: "string" },
|
|
54
|
+
"dry-run": { type: "boolean" },
|
|
55
|
+
apply: { type: "boolean" },
|
|
56
|
+
yes: { type: "boolean" },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function parseWikiFlags(args, defs) {
|
|
60
|
+
const scanRoots = [];
|
|
61
|
+
const filteredArgs = [];
|
|
62
|
+
let i = 0;
|
|
63
|
+
|
|
64
|
+
while (i < args.length) {
|
|
65
|
+
const arg = args[i];
|
|
66
|
+
if (arg === "--scan-root") {
|
|
67
|
+
i++;
|
|
68
|
+
if (i < args.length) {
|
|
69
|
+
scanRoots.push(args[i]);
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
72
|
+
} else if (arg.startsWith("--scan-root=")) {
|
|
73
|
+
scanRoots.push(arg.slice("--scan-root=".length));
|
|
74
|
+
i++;
|
|
75
|
+
} else {
|
|
76
|
+
filteredArgs.push(arg);
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const { flags, positional } = parseFlags(filteredArgs, defs);
|
|
82
|
+
flags["scan-root"] = scanRoots.length > 0 ? scanRoots : undefined;
|
|
83
|
+
return { flags, positional };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
BASE_FLAG_DEFS,
|
|
88
|
+
COMPILE_FLAG_DEFS,
|
|
89
|
+
DISCOVER_FLAG_DEFS,
|
|
90
|
+
EXTRACT_FLAG_DEFS,
|
|
91
|
+
INIT_FLAG_DEFS,
|
|
92
|
+
LINT_FLAG_DEFS,
|
|
93
|
+
OPEN_FLAG_DEFS,
|
|
94
|
+
PRUNE_FLAG_DEFS,
|
|
95
|
+
WATCH_FLAG_DEFS,
|
|
96
|
+
parseWikiFlags,
|
|
97
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { ValidationError } = require("./errors");
|
|
7
|
+
const {
|
|
8
|
+
assertWikiWorkspaceWritePath,
|
|
9
|
+
getWikiProvenanceIngestEventsPath,
|
|
10
|
+
getWikiProvenancePath,
|
|
11
|
+
getWikiRawDescriptorsPath,
|
|
12
|
+
getWikiRawPath,
|
|
13
|
+
getWikiRawSourcesPath,
|
|
14
|
+
isPathInsideOrEqual,
|
|
15
|
+
resolveProjectPath,
|
|
16
|
+
} = require("./wiki-paths");
|
|
17
|
+
|
|
18
|
+
const INGEST_SCHEMA_VERSION = 1;
|
|
19
|
+
|
|
20
|
+
function nowIso() {
|
|
21
|
+
return new Date().toISOString();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readJsonIfPresent(filePath, fallback) {
|
|
25
|
+
if (!fs.existsSync(filePath)) return fallback;
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
28
|
+
} catch (_) {
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function writeJson(filePath, payload, projectPath) {
|
|
34
|
+
assertWikiWorkspaceWritePath(filePath, projectPath);
|
|
35
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
36
|
+
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2) + "\n", "utf-8");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function rejectRemoteSource(sourceArg) {
|
|
40
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(sourceArg)) {
|
|
41
|
+
throw new ValidationError("Local project sources only. Remote URLs are not supported in BK-113.");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function toProjectRelative(projectPath, sourcePath) {
|
|
46
|
+
return path.relative(projectPath, sourcePath).split(path.sep).join("/");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function detectSourceType(sourcePath) {
|
|
50
|
+
const ext = path.extname(sourcePath).toLowerCase();
|
|
51
|
+
if (ext === ".md" || ext === ".markdown" || ext === ".mdx") return "markdown";
|
|
52
|
+
if (ext === ".txt") return "text";
|
|
53
|
+
return ext ? ext.slice(1) : "file";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fingerprintSource(sourcePath) {
|
|
57
|
+
const bytes = fs.readFileSync(sourcePath);
|
|
58
|
+
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function stableSourceId(relativePath) {
|
|
62
|
+
return `raw:${crypto.createHash("sha256").update(relativePath).digest("hex").slice(0, 24)}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ensureApprovedIngestDirs(projectPath) {
|
|
66
|
+
const rawRoot = getWikiRawPath(projectPath);
|
|
67
|
+
const rawDescriptorsRoot = getWikiRawDescriptorsPath(projectPath);
|
|
68
|
+
const provenanceRoot = getWikiProvenancePath(projectPath);
|
|
69
|
+
for (const target of [rawRoot, rawDescriptorsRoot, provenanceRoot]) {
|
|
70
|
+
assertWikiWorkspaceWritePath(target, projectPath);
|
|
71
|
+
fs.mkdirSync(target, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveLocalSource(projectPath, sourceArg) {
|
|
76
|
+
if (!sourceArg || !String(sourceArg).trim()) {
|
|
77
|
+
throw new ValidationError("Missing required --source <path>.");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
rejectRemoteSource(String(sourceArg));
|
|
81
|
+
const projectRoot = resolveProjectPath(projectPath);
|
|
82
|
+
const candidate = path.resolve(projectRoot, sourceArg);
|
|
83
|
+
|
|
84
|
+
if (!isPathInsideOrEqual(candidate, projectRoot)) {
|
|
85
|
+
throw new ValidationError(`Source must stay inside the project root: ${candidate}`);
|
|
86
|
+
}
|
|
87
|
+
if (!fs.existsSync(candidate)) {
|
|
88
|
+
throw new ValidationError(`Source does not exist: ${candidate}`);
|
|
89
|
+
}
|
|
90
|
+
if (!fs.statSync(candidate).isFile()) {
|
|
91
|
+
throw new ValidationError(`Source must be a file in BK-113: ${candidate}`);
|
|
92
|
+
}
|
|
93
|
+
return candidate;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function upsertRegistry(registry, record) {
|
|
97
|
+
const existing = Array.isArray(registry.sources) ? registry.sources : [];
|
|
98
|
+
const next = existing.filter((item) => item.sourceId !== record.sourceId);
|
|
99
|
+
next.push(record);
|
|
100
|
+
next.sort((a, b) => a.sourcePath.localeCompare(b.sourcePath));
|
|
101
|
+
return {
|
|
102
|
+
schemaVersion: INGEST_SCHEMA_VERSION,
|
|
103
|
+
product: "SDTK-BRAIN",
|
|
104
|
+
sources: next,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function appendIngestEvent(eventsPayload, event) {
|
|
109
|
+
const events = Array.isArray(eventsPayload.events) ? eventsPayload.events.slice() : [];
|
|
110
|
+
events.push(event);
|
|
111
|
+
return {
|
|
112
|
+
schemaVersion: INGEST_SCHEMA_VERSION,
|
|
113
|
+
product: "SDTK-BRAIN",
|
|
114
|
+
events,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function ingestLocalSource({ projectPath, sourceArg }) {
|
|
119
|
+
const projectRoot = resolveProjectPath(projectPath);
|
|
120
|
+
const sourcePath = resolveLocalSource(projectRoot, sourceArg);
|
|
121
|
+
const sourceStat = fs.statSync(sourcePath);
|
|
122
|
+
const relativeSourcePath = toProjectRelative(projectRoot, sourcePath);
|
|
123
|
+
const sourceId = stableSourceId(relativeSourcePath);
|
|
124
|
+
const sourceHash = fingerprintSource(sourcePath);
|
|
125
|
+
const ingestedAt = nowIso();
|
|
126
|
+
const descriptorPath = path.join(getWikiRawDescriptorsPath(projectRoot), `${sourceId.replace(/[:/]/g, "-")}.json`);
|
|
127
|
+
const registryPath = getWikiRawSourcesPath(projectRoot);
|
|
128
|
+
const eventsPath = getWikiProvenanceIngestEventsPath(projectRoot);
|
|
129
|
+
const descriptorRelative = toProjectRelative(projectRoot, descriptorPath);
|
|
130
|
+
const provenanceRelative = toProjectRelative(projectRoot, eventsPath);
|
|
131
|
+
|
|
132
|
+
ensureApprovedIngestDirs(projectRoot);
|
|
133
|
+
|
|
134
|
+
const descriptor = {
|
|
135
|
+
schemaVersion: INGEST_SCHEMA_VERSION,
|
|
136
|
+
product: "SDTK-BRAIN",
|
|
137
|
+
sourceId,
|
|
138
|
+
sourcePath: relativeSourcePath,
|
|
139
|
+
sourceType: detectSourceType(sourcePath),
|
|
140
|
+
sourceHash,
|
|
141
|
+
sizeBytes: sourceStat.size,
|
|
142
|
+
mtimeMs: Math.trunc(sourceStat.mtimeMs),
|
|
143
|
+
ingestedAt,
|
|
144
|
+
revision: sourceHash.slice(0, 16),
|
|
145
|
+
status: "ingested",
|
|
146
|
+
provenancePath: provenanceRelative,
|
|
147
|
+
};
|
|
148
|
+
writeJson(descriptorPath, descriptor, projectRoot);
|
|
149
|
+
|
|
150
|
+
const record = {
|
|
151
|
+
sourceId,
|
|
152
|
+
sourcePath: relativeSourcePath,
|
|
153
|
+
sourceType: descriptor.sourceType,
|
|
154
|
+
sourceHash,
|
|
155
|
+
sizeBytes: descriptor.sizeBytes,
|
|
156
|
+
mtimeMs: descriptor.mtimeMs,
|
|
157
|
+
ingestedAt,
|
|
158
|
+
revision: descriptor.revision,
|
|
159
|
+
status: descriptor.status,
|
|
160
|
+
descriptorPath: descriptorRelative,
|
|
161
|
+
provenancePath: provenanceRelative,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const registry = upsertRegistry(
|
|
165
|
+
readJsonIfPresent(registryPath, { schemaVersion: INGEST_SCHEMA_VERSION, product: "SDTK-BRAIN", sources: [] }),
|
|
166
|
+
record
|
|
167
|
+
);
|
|
168
|
+
writeJson(registryPath, registry, projectRoot);
|
|
169
|
+
|
|
170
|
+
const events = appendIngestEvent(
|
|
171
|
+
readJsonIfPresent(eventsPath, { schemaVersion: INGEST_SCHEMA_VERSION, product: "SDTK-BRAIN", events: [] }),
|
|
172
|
+
{
|
|
173
|
+
event: "ingest.recorded",
|
|
174
|
+
sourceId,
|
|
175
|
+
sourcePath: relativeSourcePath,
|
|
176
|
+
sourceHash,
|
|
177
|
+
descriptorPath: descriptorRelative,
|
|
178
|
+
recordedAt: ingestedAt,
|
|
179
|
+
status: "ingested",
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
writeJson(eventsPath, events, projectRoot);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
sourceId,
|
|
186
|
+
sourcePath: relativeSourcePath,
|
|
187
|
+
registryPath,
|
|
188
|
+
descriptorPath,
|
|
189
|
+
eventsPath,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = {
|
|
194
|
+
INGEST_SCHEMA_VERSION,
|
|
195
|
+
ingestLocalSource,
|
|
196
|
+
resolveLocalSource,
|
|
197
|
+
stableSourceId,
|
|
198
|
+
};
|