mdkg 0.1.6 → 0.1.7
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/CHANGELOG.md +30 -0
- package/README.md +54 -3
- package/dist/cli.js +208 -3
- package/dist/commands/bundle.js +6 -0
- package/dist/commands/checkpoint.js +1 -1
- package/dist/commands/db.js +560 -0
- package/dist/commands/doctor.js +18 -0
- package/dist/commands/format.js +10 -5
- package/dist/commands/index.js +16 -11
- package/dist/commands/init.js +3 -0
- package/dist/commands/new.js +17 -2
- package/dist/commands/subgraph.js +416 -0
- package/dist/commands/upgrade.js +43 -7
- package/dist/commands/work.js +21 -19
- package/dist/core/config.js +103 -0
- package/dist/core/project_db.js +108 -0
- package/dist/core/project_db_migrations.js +600 -0
- package/dist/core/project_db_snapshot.js +510 -0
- package/dist/graph/agent_file_types.js +14 -9
- package/dist/graph/node.js +2 -2
- package/dist/graph/skills_index_cache.js +1 -0
- package/dist/graph/sqlite_index.js +25 -0
- package/dist/graph/validate_graph.js +75 -63
- package/dist/init/AGENT_START.md +13 -1
- package/dist/init/CLI_COMMAND_MATRIX.md +37 -0
- package/dist/init/README.md +25 -0
- package/dist/init/config.json +11 -0
- package/dist/init/core/rule-3-cli-contract.md +7 -0
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +35 -2
- package/dist/init/init-manifest.json +7 -7
- package/dist/util/argparse.js +5 -0
- package/dist/util/refs.js +2 -2
- package/package.json +4 -2
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runDbIndexRebuildCommand = runDbIndexRebuildCommand;
|
|
7
|
+
exports.runDbInitCommand = runDbInitCommand;
|
|
8
|
+
exports.runDbMigrateCommand = runDbMigrateCommand;
|
|
9
|
+
exports.runDbVerifyCommand = runDbVerifyCommand;
|
|
10
|
+
exports.runDbStatsCommand = runDbStatsCommand;
|
|
11
|
+
exports.runDbSnapshotSealCommand = runDbSnapshotSealCommand;
|
|
12
|
+
exports.runDbSnapshotVerifyCommand = runDbSnapshotVerifyCommand;
|
|
13
|
+
exports.runDbSnapshotStatusCommand = runDbSnapshotStatusCommand;
|
|
14
|
+
exports.runDbSnapshotDumpCommand = runDbSnapshotDumpCommand;
|
|
15
|
+
exports.runDbSnapshotDiffCommand = runDbSnapshotDiffCommand;
|
|
16
|
+
exports.runDbIndexStatusCommand = runDbIndexStatusCommand;
|
|
17
|
+
exports.runDbIndexVerifyCommand = runDbIndexVerifyCommand;
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const config_1 = require("../core/config");
|
|
21
|
+
const migrate_1 = require("../core/migrate");
|
|
22
|
+
const paths_1 = require("../core/paths");
|
|
23
|
+
const project_db_1 = require("../core/project_db");
|
|
24
|
+
const project_db_migrations_1 = require("../core/project_db_migrations");
|
|
25
|
+
const project_db_snapshot_1 = require("../core/project_db_snapshot");
|
|
26
|
+
const version_1 = require("../core/version");
|
|
27
|
+
const index_1 = require("./index");
|
|
28
|
+
const capabilities_indexer_1 = require("../graph/capabilities_indexer");
|
|
29
|
+
const capabilities_indexer_2 = require("../graph/capabilities_indexer");
|
|
30
|
+
const capabilities_index_cache_1 = require("../graph/capabilities_index_cache");
|
|
31
|
+
const indexer_1 = require("../graph/indexer");
|
|
32
|
+
const staleness_1 = require("../graph/staleness");
|
|
33
|
+
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
34
|
+
const skills_index_cache_1 = require("../graph/skills_index_cache");
|
|
35
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
36
|
+
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
37
|
+
const atomic_1 = require("../util/atomic");
|
|
38
|
+
const lock_1 = require("../util/lock");
|
|
39
|
+
const errors_1 = require("../util/errors");
|
|
40
|
+
function rel(root, filePath) {
|
|
41
|
+
return path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
|
|
42
|
+
}
|
|
43
|
+
function fileSize(filePath) {
|
|
44
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return fs_1.default.statSync(filePath).size;
|
|
48
|
+
}
|
|
49
|
+
function readRawConfig(root) {
|
|
50
|
+
const filePath = (0, paths_1.configPath)(root);
|
|
51
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
52
|
+
throw new errors_1.NotFoundError(`config not found at ${filePath}`);
|
|
53
|
+
}
|
|
54
|
+
let parsed;
|
|
55
|
+
try {
|
|
56
|
+
parsed = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
throw new errors_1.UsageError(`failed to read config: ${err instanceof Error ? err.message : String(err)}`);
|
|
60
|
+
}
|
|
61
|
+
const migrated = (0, migrate_1.migrateConfig)(parsed).config;
|
|
62
|
+
(0, config_1.validateConfigSchema)(migrated);
|
|
63
|
+
if (typeof migrated !== "object" || migrated === null || Array.isArray(migrated)) {
|
|
64
|
+
throw new errors_1.UsageError("config must be a JSON object");
|
|
65
|
+
}
|
|
66
|
+
return { configPath: filePath, raw: migrated };
|
|
67
|
+
}
|
|
68
|
+
function writeRawConfig(filePath, raw) {
|
|
69
|
+
(0, atomic_1.atomicWriteFile)(filePath, `${JSON.stringify(raw, null, 2)}\n`);
|
|
70
|
+
}
|
|
71
|
+
function ensureDirectory(root, dirPath, created, unchanged) {
|
|
72
|
+
const relative = rel(root, dirPath);
|
|
73
|
+
if (fs_1.default.existsSync(dirPath)) {
|
|
74
|
+
if (!fs_1.default.statSync(dirPath).isDirectory()) {
|
|
75
|
+
throw new errors_1.ValidationError(`${relative} exists and is not a directory`);
|
|
76
|
+
}
|
|
77
|
+
unchanged.push(relative);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
fs_1.default.mkdirSync(dirPath, { recursive: true });
|
|
81
|
+
created.push(relative);
|
|
82
|
+
}
|
|
83
|
+
function writeJsonIfChanged(root, filePath, payload, created, unchanged, updated) {
|
|
84
|
+
const relative = rel(root, filePath);
|
|
85
|
+
if (fs_1.default.existsSync(filePath) && fs_1.default.statSync(filePath).isDirectory()) {
|
|
86
|
+
throw new errors_1.ValidationError(`${relative} exists and is not a file`);
|
|
87
|
+
}
|
|
88
|
+
const content = `${JSON.stringify(payload, null, 2)}\n`;
|
|
89
|
+
if (fs_1.default.existsSync(filePath)) {
|
|
90
|
+
const current = fs_1.default.readFileSync(filePath, "utf8");
|
|
91
|
+
if (current === content) {
|
|
92
|
+
unchanged.push(relative);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
(0, atomic_1.atomicWriteFile)(filePath, content);
|
|
96
|
+
updated.push(relative);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
(0, atomic_1.atomicWriteFile)(filePath, content);
|
|
100
|
+
created.push(relative);
|
|
101
|
+
}
|
|
102
|
+
function readJsonCache(filePath) {
|
|
103
|
+
try {
|
|
104
|
+
JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return err instanceof Error ? err.message : String(err);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function jsonCacheCheck(options) {
|
|
112
|
+
const exists = fs_1.default.existsSync(options.filePath);
|
|
113
|
+
const errors = [];
|
|
114
|
+
const warnings = [];
|
|
115
|
+
if (!exists) {
|
|
116
|
+
errors.push("cache file missing");
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const readError = readJsonCache(options.filePath);
|
|
120
|
+
if (readError) {
|
|
121
|
+
errors.push(`cache is unreadable: ${readError}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (exists && options.stale) {
|
|
125
|
+
warnings.push("cache is stale");
|
|
126
|
+
}
|
|
127
|
+
const ok = errors.length === 0 && warnings.length === 0;
|
|
128
|
+
return {
|
|
129
|
+
name: options.name,
|
|
130
|
+
ok,
|
|
131
|
+
level: errors.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "ok",
|
|
132
|
+
path: rel(options.root, options.filePath),
|
|
133
|
+
exists,
|
|
134
|
+
stale: exists ? options.stale : true,
|
|
135
|
+
size: fileSize(options.filePath),
|
|
136
|
+
detail: !exists
|
|
137
|
+
? "cache file missing"
|
|
138
|
+
: options.stale
|
|
139
|
+
? "cache is stale"
|
|
140
|
+
: "cache is present and fresh",
|
|
141
|
+
errors,
|
|
142
|
+
warnings,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function buildCurrentSqliteFingerprint(root, tolerant) {
|
|
146
|
+
const config = (0, config_1.loadConfig)(root);
|
|
147
|
+
const nodeIndex = (0, indexer_1.buildIndex)(root, config, { tolerant });
|
|
148
|
+
const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(root, config);
|
|
149
|
+
const capabilitiesIndex = (0, capabilities_indexer_2.buildCapabilitiesIndex)(root, config, nodeIndex);
|
|
150
|
+
const subgraphsIndex = (0, subgraphs_1.buildSubgraphsIndex)(root, config).index;
|
|
151
|
+
return (0, sqlite_index_1.sqliteSourceFingerprint)({
|
|
152
|
+
root,
|
|
153
|
+
nodeIndex,
|
|
154
|
+
skillsIndex,
|
|
155
|
+
capabilitiesIndex,
|
|
156
|
+
subgraphsIndex,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function sqliteCacheCheck(root, tolerant) {
|
|
160
|
+
const config = (0, config_1.loadConfig)(root);
|
|
161
|
+
if (!(0, sqlite_index_1.isSqliteBackend)(config)) {
|
|
162
|
+
return {
|
|
163
|
+
name: "sqlite",
|
|
164
|
+
ok: true,
|
|
165
|
+
level: "ok",
|
|
166
|
+
path: rel(root, (0, sqlite_index_1.resolveSqlitePath)(root, config)),
|
|
167
|
+
exists: false,
|
|
168
|
+
stale: false,
|
|
169
|
+
size: undefined,
|
|
170
|
+
detail: "SQLite backend disabled; JSON cache backend active",
|
|
171
|
+
errors: [],
|
|
172
|
+
warnings: [],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const health = (0, sqlite_index_1.sqliteHealth)(root, config);
|
|
176
|
+
const fatalWarnings = health.warnings.filter((warning) => /missing|stale/i.test(warning));
|
|
177
|
+
const errors = [...health.errors, ...fatalWarnings];
|
|
178
|
+
const warnings = health.warnings.filter((warning) => !fatalWarnings.includes(warning));
|
|
179
|
+
if (health.exists && errors.length === 0) {
|
|
180
|
+
try {
|
|
181
|
+
const meta = (0, sqlite_index_1.readSqliteIndexMeta)(root, config);
|
|
182
|
+
const expectedFingerprint = buildCurrentSqliteFingerprint(root, tolerant);
|
|
183
|
+
const actualFingerprint = meta.source_fingerprint;
|
|
184
|
+
if (!actualFingerprint) {
|
|
185
|
+
errors.push("SQLite cache missing source fingerprint; run mdkg index");
|
|
186
|
+
}
|
|
187
|
+
else if (actualFingerprint !== expectedFingerprint) {
|
|
188
|
+
errors.push("SQLite source fingerprint mismatch; run mdkg index");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
errors.push(`failed to verify SQLite source fingerprint: ${err instanceof Error ? err.message : String(err)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const ok = health.exists && errors.length === 0;
|
|
196
|
+
return {
|
|
197
|
+
name: "sqlite",
|
|
198
|
+
ok,
|
|
199
|
+
level: errors.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "ok",
|
|
200
|
+
path: rel(root, health.path),
|
|
201
|
+
exists: health.exists,
|
|
202
|
+
stale: fatalWarnings.some((warning) => /stale/i.test(warning)),
|
|
203
|
+
size: health.size,
|
|
204
|
+
detail: errors.length > 0
|
|
205
|
+
? errors.join("; ")
|
|
206
|
+
: warnings.length > 0
|
|
207
|
+
? warnings.join("; ")
|
|
208
|
+
: "SQLite cache is present and fresh",
|
|
209
|
+
errors,
|
|
210
|
+
warnings,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function collectDbIndexChecks(root, tolerant) {
|
|
214
|
+
const config = (0, config_1.loadConfig)(root);
|
|
215
|
+
return [
|
|
216
|
+
jsonCacheCheck({
|
|
217
|
+
root,
|
|
218
|
+
name: "global",
|
|
219
|
+
filePath: path_1.default.resolve(root, config.index.global_index_path),
|
|
220
|
+
stale: (0, staleness_1.isIndexStale)(root, config),
|
|
221
|
+
}),
|
|
222
|
+
jsonCacheCheck({
|
|
223
|
+
root,
|
|
224
|
+
name: "skills",
|
|
225
|
+
filePath: (0, skills_indexer_1.resolveSkillsIndexPath)(root),
|
|
226
|
+
stale: (0, skills_index_cache_1.isSkillsIndexStale)(root, config),
|
|
227
|
+
}),
|
|
228
|
+
jsonCacheCheck({
|
|
229
|
+
root,
|
|
230
|
+
name: "capabilities",
|
|
231
|
+
filePath: (0, capabilities_indexer_1.resolveCapabilitiesIndexPath)(root, config),
|
|
232
|
+
stale: (0, capabilities_index_cache_1.isCapabilitiesIndexStale)(root, config),
|
|
233
|
+
}),
|
|
234
|
+
jsonCacheCheck({
|
|
235
|
+
root,
|
|
236
|
+
name: "subgraphs",
|
|
237
|
+
filePath: (0, subgraphs_1.resolveSubgraphsIndexPath)(root),
|
|
238
|
+
stale: (0, subgraphs_1.isSubgraphsIndexStale)(root, config),
|
|
239
|
+
}),
|
|
240
|
+
sqliteCacheCheck(root, tolerant),
|
|
241
|
+
];
|
|
242
|
+
}
|
|
243
|
+
function dbIndexPayload(action, root, checks) {
|
|
244
|
+
const failures = checks.filter((check) => !check.ok);
|
|
245
|
+
return {
|
|
246
|
+
action,
|
|
247
|
+
ok: failures.length === 0,
|
|
248
|
+
backend: (0, config_1.loadConfig)(root).index.backend,
|
|
249
|
+
root,
|
|
250
|
+
checks,
|
|
251
|
+
failure_count: failures.length,
|
|
252
|
+
warnings: checks.flatMap((check) => check.warnings.map((warning) => `${check.name}: ${warning}`)),
|
|
253
|
+
errors: checks.flatMap((check) => check.errors.map((error) => `${check.name}: ${error}`)),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function printChecks(payload) {
|
|
257
|
+
for (const check of payload.checks) {
|
|
258
|
+
const location = check.path ? ` (${check.path})` : "";
|
|
259
|
+
console.log(`${check.level}: ${check.name}${location} - ${check.detail}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function runDbIndexRebuildCommand(options) {
|
|
263
|
+
const result = (0, index_1.rebuildDerivedIndexCaches)({ root: options.root, tolerant: options.tolerant });
|
|
264
|
+
if (options.json) {
|
|
265
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
266
|
+
const paths = {
|
|
267
|
+
global: rel(options.root, result.paths.nodes),
|
|
268
|
+
skills: rel(options.root, result.paths.skills),
|
|
269
|
+
capabilities: rel(options.root, result.paths.capabilities),
|
|
270
|
+
subgraphs: rel(options.root, result.paths.subgraphs),
|
|
271
|
+
};
|
|
272
|
+
if (result.paths.sqlite) {
|
|
273
|
+
paths.sqlite = rel(options.root, result.paths.sqlite);
|
|
274
|
+
}
|
|
275
|
+
console.log(JSON.stringify({
|
|
276
|
+
action: "db-index-rebuild",
|
|
277
|
+
ok: true,
|
|
278
|
+
backend: config.index.backend,
|
|
279
|
+
paths,
|
|
280
|
+
node_count: Object.keys(result.nodeIndex.nodes).length,
|
|
281
|
+
}, null, 2));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
console.log("db index rebuilt");
|
|
285
|
+
console.log(`index written: ${rel(options.root, result.paths.nodes)}`);
|
|
286
|
+
console.log(`skills index written: ${rel(options.root, result.paths.skills)}`);
|
|
287
|
+
console.log(`capabilities index written: ${rel(options.root, result.paths.capabilities)}`);
|
|
288
|
+
console.log(`subgraphs index written: ${rel(options.root, result.paths.subgraphs)}`);
|
|
289
|
+
if (result.paths.sqlite) {
|
|
290
|
+
console.log(`sqlite index written: ${rel(options.root, result.paths.sqlite)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function runDbInitCommandLocked(options) {
|
|
294
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
295
|
+
const layout = (0, project_db_1.resolveConfiguredProjectDbLayout)(options.root, config.db);
|
|
296
|
+
const created = [];
|
|
297
|
+
const unchanged = [];
|
|
298
|
+
const updated = [];
|
|
299
|
+
for (const dirPath of [
|
|
300
|
+
layout.db,
|
|
301
|
+
layout.schema,
|
|
302
|
+
layout.migrations,
|
|
303
|
+
layout.runtimeDir,
|
|
304
|
+
layout.stateDir,
|
|
305
|
+
layout.receipts,
|
|
306
|
+
]) {
|
|
307
|
+
ensureDirectory(options.root, dirPath, created, unchanged);
|
|
308
|
+
}
|
|
309
|
+
const manifest = {
|
|
310
|
+
tool: "mdkg",
|
|
311
|
+
kind: "project_db",
|
|
312
|
+
mdkg_version: (0, version_1.readPackageVersion)(),
|
|
313
|
+
schema_version: config.db.schema_version,
|
|
314
|
+
enabled: true,
|
|
315
|
+
layout: {
|
|
316
|
+
root_path: config.db.root_path,
|
|
317
|
+
schema_path: config.db.schema_path,
|
|
318
|
+
migrations_path: config.db.migrations_path,
|
|
319
|
+
runtime_path: config.db.runtime_path,
|
|
320
|
+
state_path: config.db.state_path,
|
|
321
|
+
receipts_path: config.db.receipts_path,
|
|
322
|
+
},
|
|
323
|
+
migration_table: config.db.migration_table,
|
|
324
|
+
runtime_database_created: false,
|
|
325
|
+
};
|
|
326
|
+
writeJsonIfChanged(options.root, layout.manifest, manifest, created, unchanged, updated);
|
|
327
|
+
const rawConfig = readRawConfig(options.root);
|
|
328
|
+
const nextConfig = { ...rawConfig.raw };
|
|
329
|
+
const nextDb = { ...config.db, enabled: true };
|
|
330
|
+
const currentDb = JSON.stringify(nextConfig.db ?? null);
|
|
331
|
+
const normalizedDb = JSON.stringify(nextDb);
|
|
332
|
+
const enabledBefore = config.db.enabled;
|
|
333
|
+
let config_updated = false;
|
|
334
|
+
if (currentDb !== normalizedDb) {
|
|
335
|
+
nextConfig.db = nextDb;
|
|
336
|
+
(0, config_1.validateConfigSchema)(nextConfig);
|
|
337
|
+
writeRawConfig(rawConfig.configPath, nextConfig);
|
|
338
|
+
updated.push(".mdkg/config.json");
|
|
339
|
+
config_updated = true;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
unchanged.push(".mdkg/config.json");
|
|
343
|
+
}
|
|
344
|
+
const receipt = {
|
|
345
|
+
action: "db-init",
|
|
346
|
+
ok: true,
|
|
347
|
+
enabled_before: enabledBefore,
|
|
348
|
+
enabled_after: true,
|
|
349
|
+
config_updated,
|
|
350
|
+
runtime_database_created: false,
|
|
351
|
+
paths: {
|
|
352
|
+
root: rel(options.root, layout.db),
|
|
353
|
+
schema: rel(options.root, layout.schema),
|
|
354
|
+
migrations: rel(options.root, layout.migrations),
|
|
355
|
+
runtime_dir: rel(options.root, layout.runtimeDir),
|
|
356
|
+
runtime_path: config.db.runtime_path,
|
|
357
|
+
state_dir: rel(options.root, layout.stateDir),
|
|
358
|
+
state_path: config.db.state_path,
|
|
359
|
+
receipts: rel(options.root, layout.receipts),
|
|
360
|
+
manifest: rel(options.root, layout.manifest),
|
|
361
|
+
},
|
|
362
|
+
created: created.sort(),
|
|
363
|
+
updated: updated.sort(),
|
|
364
|
+
unchanged: unchanged.sort(),
|
|
365
|
+
};
|
|
366
|
+
if (options.json) {
|
|
367
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
console.log("project db initialized");
|
|
371
|
+
for (const item of receipt.created) {
|
|
372
|
+
console.log(`created: ${item}`);
|
|
373
|
+
}
|
|
374
|
+
for (const item of receipt.updated) {
|
|
375
|
+
console.log(`updated: ${item}`);
|
|
376
|
+
}
|
|
377
|
+
if (receipt.created.length === 0 && receipt.updated.length === 0) {
|
|
378
|
+
console.log("project db already initialized");
|
|
379
|
+
}
|
|
380
|
+
console.log("runtime database created: false");
|
|
381
|
+
}
|
|
382
|
+
function runDbInitCommand(options) {
|
|
383
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
384
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runDbInitCommandLocked(options));
|
|
385
|
+
}
|
|
386
|
+
function runDbMigrateCommandLocked(options) {
|
|
387
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
388
|
+
const receipt = (0, project_db_migrations_1.runProjectDbMigrations)(options.root, config);
|
|
389
|
+
if (options.json) {
|
|
390
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
console.log("project db migrated");
|
|
394
|
+
console.log(`database: ${receipt.database}`);
|
|
395
|
+
console.log(`migration table: ${receipt.migration_table}`);
|
|
396
|
+
console.log(`applied: ${receipt.applied_count}`);
|
|
397
|
+
console.log(`already applied: ${receipt.skipped_count}`);
|
|
398
|
+
for (const migration of receipt.migrations) {
|
|
399
|
+
console.log(`${migration.status}: ${migration.ordinal} ${migration.key}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function runDbMigrateCommand(options) {
|
|
403
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
404
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runDbMigrateCommandLocked(options));
|
|
405
|
+
}
|
|
406
|
+
function printProjectDbChecks(payload) {
|
|
407
|
+
for (const check of payload.checks) {
|
|
408
|
+
const location = check.path ? ` (${check.path})` : "";
|
|
409
|
+
console.log(`${check.level}: ${check.name}${location} - ${check.detail}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function runDbVerifyCommand(options) {
|
|
413
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
414
|
+
const payload = (0, project_db_migrations_1.verifyProjectDb)(options.root, config);
|
|
415
|
+
if (options.json) {
|
|
416
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
printProjectDbChecks(payload);
|
|
420
|
+
}
|
|
421
|
+
if (!payload.ok) {
|
|
422
|
+
throw new errors_1.ValidationError(`db verify failed with ${payload.failure_count} issue(s)`);
|
|
423
|
+
}
|
|
424
|
+
if (!options.json) {
|
|
425
|
+
console.log("db verify ok");
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function runDbStatsCommand(options) {
|
|
429
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
430
|
+
const payload = (0, project_db_migrations_1.projectDbStats)(options.root, config);
|
|
431
|
+
if (options.json) {
|
|
432
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
console.log("project db stats");
|
|
436
|
+
console.log(`database: ${payload.database}`);
|
|
437
|
+
console.log(`db size: ${payload.db_size}`);
|
|
438
|
+
console.log(`migrations: ${payload.migration_count}`);
|
|
439
|
+
console.log(`latest migration: ${payload.latest_migration?.key ?? "(none)"}`);
|
|
440
|
+
console.log(`receipt files: ${payload.receipt_files.count}`);
|
|
441
|
+
console.log("tables:");
|
|
442
|
+
for (const table of payload.tables) {
|
|
443
|
+
console.log(` ${table.name}: ${table.row_count}`);
|
|
444
|
+
}
|
|
445
|
+
if (payload.transient_files.length > 0) {
|
|
446
|
+
console.log("transient files:");
|
|
447
|
+
for (const item of payload.transient_files) {
|
|
448
|
+
console.log(` ${item.path}: ${item.size}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function printSnapshotChecks(payload) {
|
|
453
|
+
for (const check of payload.checks) {
|
|
454
|
+
const location = check.path ? ` (${path_1.default.isAbsolute(check.path) ? rel(process.cwd(), check.path) : check.path})` : "";
|
|
455
|
+
console.log(`${check.level}: ${check.name}${location} - ${check.detail}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function runDbSnapshotSealCommandLocked(options) {
|
|
459
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
460
|
+
const payload = (0, project_db_snapshot_1.sealProjectDbSnapshot)(options.root, config);
|
|
461
|
+
if (options.json) {
|
|
462
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
console.log("db snapshot sealed");
|
|
466
|
+
console.log(`snapshot: ${payload.snapshot}`);
|
|
467
|
+
console.log(`manifest: ${payload.manifest}`);
|
|
468
|
+
console.log(`sha256: ${payload.new_snapshot_sha256}`);
|
|
469
|
+
console.log(`byte size: ${payload.byte_size}`);
|
|
470
|
+
if (payload.warnings.length > 0) {
|
|
471
|
+
console.log("warnings:");
|
|
472
|
+
for (const warning of payload.warnings) {
|
|
473
|
+
console.log(` ${warning}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function runDbSnapshotSealCommand(options) {
|
|
478
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
479
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runDbSnapshotSealCommandLocked(options));
|
|
480
|
+
}
|
|
481
|
+
function runDbSnapshotVerifyCommand(options) {
|
|
482
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
483
|
+
const payload = (0, project_db_snapshot_1.verifyProjectDbSnapshot)(options.root, config);
|
|
484
|
+
if (options.json) {
|
|
485
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
printSnapshotChecks(payload);
|
|
489
|
+
}
|
|
490
|
+
if (!payload.ok) {
|
|
491
|
+
throw new errors_1.ValidationError(`db snapshot verify failed with ${payload.failure_count} issue(s)`);
|
|
492
|
+
}
|
|
493
|
+
if (!options.json) {
|
|
494
|
+
console.log("db snapshot verify ok");
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
function runDbSnapshotStatusCommand(options) {
|
|
498
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
499
|
+
const payload = (0, project_db_snapshot_1.projectDbSnapshotStatus)(options.root, config);
|
|
500
|
+
if (options.json) {
|
|
501
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
printSnapshotChecks(payload);
|
|
505
|
+
console.log(`db snapshot status: ${payload.status}`);
|
|
506
|
+
}
|
|
507
|
+
function runDbSnapshotDumpCommand(options) {
|
|
508
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
509
|
+
const payload = (0, project_db_snapshot_1.dumpProjectDbSnapshot)(options.root, config, options.snapshot, options.output);
|
|
510
|
+
const { dump, ...receipt } = payload;
|
|
511
|
+
if (options.json) {
|
|
512
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (options.output) {
|
|
516
|
+
console.log("db snapshot dump written");
|
|
517
|
+
console.log(`output: ${receipt.output}`);
|
|
518
|
+
console.log(`sha256: ${receipt.sha256}`);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
process.stdout.write(dump);
|
|
522
|
+
}
|
|
523
|
+
function runDbSnapshotDiffCommand(options) {
|
|
524
|
+
const payload = (0, project_db_snapshot_1.diffProjectDbSnapshots)(options.root, options.left, options.right);
|
|
525
|
+
if (options.json) {
|
|
526
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
console.log(`db snapshot diff: ${payload.changed_count} change(s)`);
|
|
530
|
+
for (const line of payload.removed) {
|
|
531
|
+
console.log(`- ${line}`);
|
|
532
|
+
}
|
|
533
|
+
for (const line of payload.added) {
|
|
534
|
+
console.log(`+ ${line}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function runDbIndexStatusCommand(options) {
|
|
538
|
+
const payload = dbIndexPayload("db-index-status", options.root, collectDbIndexChecks(options.root, options.tolerant ?? false));
|
|
539
|
+
if (options.json) {
|
|
540
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
printChecks(payload);
|
|
544
|
+
console.log(payload.ok ? "db index status ok" : "db index status has issues");
|
|
545
|
+
}
|
|
546
|
+
function runDbIndexVerifyCommand(options) {
|
|
547
|
+
const payload = dbIndexPayload("db-index-verify", options.root, collectDbIndexChecks(options.root, options.tolerant ?? false));
|
|
548
|
+
if (options.json) {
|
|
549
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
printChecks(payload);
|
|
553
|
+
}
|
|
554
|
+
if (!payload.ok) {
|
|
555
|
+
throw new errors_1.ValidationError(`db index verify failed with ${payload.failure_count} issue(s)`);
|
|
556
|
+
}
|
|
557
|
+
if (!options.json) {
|
|
558
|
+
console.log("db index verify ok");
|
|
559
|
+
}
|
|
560
|
+
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -14,6 +14,7 @@ const node_1 = require("../graph/node");
|
|
|
14
14
|
const template_schema_1 = require("../graph/template_schema");
|
|
15
15
|
const visibility_1 = require("../graph/visibility");
|
|
16
16
|
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
17
|
+
const project_db_1 = require("../core/project_db");
|
|
17
18
|
const errors_1 = require("../util/errors");
|
|
18
19
|
const REQUIRED_NODE_MAJOR = 24;
|
|
19
20
|
const REQUIRED_NODE_MINOR = 15;
|
|
@@ -186,6 +187,22 @@ function runBundleStorageCheck(root, outputDir) {
|
|
|
186
187
|
detail: `${bundles.length} bundle(s) found; run \`mdkg bundle verify <path>\` to check freshness before handoff`,
|
|
187
188
|
};
|
|
188
189
|
}
|
|
190
|
+
function runProjectDbRuntimePolicyCheck(root) {
|
|
191
|
+
const files = (0, project_db_1.listProjectDbRuntimePolicyFiles)(root);
|
|
192
|
+
if (files.length === 0) {
|
|
193
|
+
return {
|
|
194
|
+
name: "project-db-runtime",
|
|
195
|
+
ok: true,
|
|
196
|
+
detail: "no active project DB runtime or transient files found",
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
name: "project-db-runtime",
|
|
201
|
+
ok: true,
|
|
202
|
+
level: "warn",
|
|
203
|
+
detail: `active project DB runtime/transient file(s) are local-only and should not be committed: ${files.join(", ")}`,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
189
206
|
function runSubgraphChecks(root, config) {
|
|
190
207
|
const projection = (0, subgraphs_1.buildSubgraphsIndex)(root, config);
|
|
191
208
|
if (projection.index.subgraphs.length === 0) {
|
|
@@ -298,6 +315,7 @@ function runDoctorCommand(options) {
|
|
|
298
315
|
results.push(runArchiveStorageCheck(options.root));
|
|
299
316
|
results.push(runArchiveLargeCacheCheck(options.root, config.archive.large_cache_warning_bytes));
|
|
300
317
|
results.push(runBundleStorageCheck(options.root, config.bundles.output_dir));
|
|
318
|
+
results.push(runProjectDbRuntimePolicyCheck(options.root));
|
|
301
319
|
results.push(runSqliteCheck(options.root, config));
|
|
302
320
|
results.push(...runSubgraphChecks(options.root, config));
|
|
303
321
|
results.push(runVisibilityPolicyCheck(options.root, config, options));
|
package/dist/commands/format.js
CHANGED
|
@@ -69,16 +69,21 @@ function sortList(values) {
|
|
|
69
69
|
function normalizeList(values, key, errors, filePath, allowPortableRefs = false) {
|
|
70
70
|
const trimmed = values.map((value) => normalizeScalar(value));
|
|
71
71
|
const shouldLowercase = !PRESERVE_CASE_LIST_KEYS.has(key);
|
|
72
|
-
const normalized = shouldLowercase
|
|
72
|
+
const normalized = shouldLowercase
|
|
73
|
+
? trimmed.map((value) => ((0, refs_1.isUriRef)(value) ? value : value.toLowerCase()))
|
|
74
|
+
: trimmed.map((value) => (EXTERNAL_REF_LIST_KEYS.has(key) && !(0, refs_1.isUriRef)(value) ? value.toLowerCase() : value));
|
|
73
75
|
for (const entry of normalized) {
|
|
74
76
|
if (!entry) {
|
|
75
77
|
errors.push(`${filePath}: ${key} entries must be non-empty`);
|
|
76
78
|
continue;
|
|
77
79
|
}
|
|
78
|
-
if (ID_LIST_KEYS.has(key) &&
|
|
80
|
+
if (ID_LIST_KEYS.has(key) && key === "refs" && !(0, refs_1.validatePortableOrUriRef)(entry)) {
|
|
81
|
+
errors.push(`${filePath}: ${key} entries must be portable ids, qids, or URI refs`);
|
|
82
|
+
}
|
|
83
|
+
else if (ID_LIST_KEYS.has(key) && key !== "refs" && !(allowPortableRefs ? (0, id_1.isPortableId)(entry) : isValidId(entry))) {
|
|
79
84
|
errors.push(`${filePath}: ${key} entries must match <prefix>-<number> or reserved id`);
|
|
80
85
|
}
|
|
81
|
-
if (ID_REF_LIST_KEYS.has(key) && !(
|
|
86
|
+
if (ID_REF_LIST_KEYS.has(key) && !(0, id_1.isPortableIdRef)(entry)) {
|
|
82
87
|
errors.push(`${filePath}: ${key} entries must be valid id references`);
|
|
83
88
|
}
|
|
84
89
|
if (EXTERNAL_REF_LIST_KEYS.has(key) && !(0, refs_1.validatePortableOrUriRef)(entry)) {
|
|
@@ -92,7 +97,7 @@ function normalizeList(values, key, errors, filePath, allowPortableRefs = false)
|
|
|
92
97
|
}
|
|
93
98
|
function normalizeIdRef(value, key, errors, filePath) {
|
|
94
99
|
const normalized = normalizeScalar(value).toLowerCase();
|
|
95
|
-
if (!(0, id_1.
|
|
100
|
+
if (!(0, id_1.isPortableIdRef)(normalized)) {
|
|
96
101
|
errors.push(`${filePath}: ${key} must be a valid id reference`);
|
|
97
102
|
}
|
|
98
103
|
return normalized;
|
|
@@ -104,7 +109,7 @@ function normalizeFrontmatterValue(key, value, schema, errors, filePath, type) {
|
|
|
104
109
|
errors.push(`${filePath}: ${key} must be a list`);
|
|
105
110
|
return [];
|
|
106
111
|
}
|
|
107
|
-
const allowPortableRefs = (0, agent_file_types_1.isAgentFileType)(type) || (0, archive_file_1.isArchiveType)(type);
|
|
112
|
+
const allowPortableRefs = (0, agent_file_types_1.isAgentFileType)(type) || (0, archive_file_1.isArchiveType)(type) || ID_REF_LIST_KEYS.has(key) || key === "refs";
|
|
108
113
|
return normalizeList(value, key, errors, filePath, allowPortableRefs);
|
|
109
114
|
}
|
|
110
115
|
if (expected === "boolean") {
|
package/dist/commands/index.js
CHANGED
|
@@ -3,21 +3,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.rebuildDerivedIndexCaches = rebuildDerivedIndexCaches;
|
|
7
|
+
exports.printIndexRebuildReceipt = printIndexRebuildReceipt;
|
|
6
8
|
exports.runIndexCommand = runIndexCommand;
|
|
7
9
|
const path_1 = __importDefault(require("path"));
|
|
8
10
|
const config_1 = require("../core/config");
|
|
9
11
|
const reindex_1 = require("../graph/reindex");
|
|
10
12
|
const lock_1 = require("../util/lock");
|
|
11
|
-
function
|
|
13
|
+
function rebuildDerivedIndexCaches(options) {
|
|
12
14
|
const config = (0, config_1.loadConfig)(options.root);
|
|
13
|
-
(0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}
|
|
15
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => (0, reindex_1.writeDerivedIndexes)(options.root, config, undefined, { tolerant: options.tolerant }));
|
|
16
|
+
}
|
|
17
|
+
function printIndexRebuildReceipt(root, result) {
|
|
18
|
+
console.log(`index written: ${path_1.default.relative(root, result.paths.nodes)}`);
|
|
19
|
+
console.log(`skills index written: ${path_1.default.relative(root, result.paths.skills)}`);
|
|
20
|
+
console.log(`capabilities index written: ${path_1.default.relative(root, result.paths.capabilities)}`);
|
|
21
|
+
console.log(`subgraphs index written: ${path_1.default.relative(root, result.paths.subgraphs)}`);
|
|
22
|
+
if (result.paths.sqlite) {
|
|
23
|
+
console.log(`sqlite index written: ${path_1.default.relative(root, result.paths.sqlite)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function runIndexCommand(options) {
|
|
27
|
+
printIndexRebuildReceipt(options.root, rebuildDerivedIndexCaches(options));
|
|
23
28
|
}
|