mdkg 0.4.2 → 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.
Files changed (70) hide show
  1. package/CHANGELOG.md +71 -15
  2. package/CLI_COMMAND_MATRIX.md +59 -2
  3. package/README.md +20 -2
  4. package/dist/cli.js +124 -2
  5. package/dist/command-contract.json +756 -2
  6. package/dist/commands/archive.js +31 -14
  7. package/dist/commands/bundle.js +180 -44
  8. package/dist/commands/capability.js +1 -0
  9. package/dist/commands/checkpoint.js +6 -5
  10. package/dist/commands/event_support.js +16 -7
  11. package/dist/commands/fix.js +11 -8
  12. package/dist/commands/git.js +41 -10
  13. package/dist/commands/goal.js +23 -23
  14. package/dist/commands/graph.js +64 -10
  15. package/dist/commands/handoff.js +4 -2
  16. package/dist/commands/init.js +28 -23
  17. package/dist/commands/loop.js +1668 -0
  18. package/dist/commands/loop_descriptors.js +219 -0
  19. package/dist/commands/mcp.js +101 -11
  20. package/dist/commands/new.js +49 -3
  21. package/dist/commands/pack.js +14 -7
  22. package/dist/commands/search.js +10 -1
  23. package/dist/commands/skill.js +12 -9
  24. package/dist/commands/skill_mirror.js +39 -31
  25. package/dist/commands/subgraph.js +59 -26
  26. package/dist/commands/task.js +77 -4
  27. package/dist/commands/upgrade.js +13 -15
  28. package/dist/commands/validate.js +20 -7
  29. package/dist/commands/work.js +44 -26
  30. package/dist/commands/workspace.js +10 -4
  31. package/dist/core/config.js +45 -17
  32. package/dist/core/filesystem_authority.js +281 -0
  33. package/dist/core/project_db_events.js +4 -0
  34. package/dist/core/project_db_materializer.js +2 -0
  35. package/dist/core/project_db_migrations.js +238 -181
  36. package/dist/core/project_db_snapshot.js +64 -14
  37. package/dist/core/workspace_path.js +7 -0
  38. package/dist/graph/archive_integrity.js +1 -1
  39. package/dist/graph/capabilities_index_cache.js +4 -1
  40. package/dist/graph/frontmatter.js +38 -0
  41. package/dist/graph/goal_scope.js +4 -1
  42. package/dist/graph/index_cache.js +37 -7
  43. package/dist/graph/loop_bindings.js +39 -0
  44. package/dist/graph/node.js +209 -1
  45. package/dist/graph/node_body.js +52 -6
  46. package/dist/graph/skills_index_cache.js +41 -6
  47. package/dist/graph/skills_indexer.js +5 -2
  48. package/dist/graph/sqlite_index.js +118 -105
  49. package/dist/graph/subgraphs.js +142 -5
  50. package/dist/graph/validate_graph.js +109 -13
  51. package/dist/graph/workspace_files.js +39 -9
  52. package/dist/init/AGENT_START.md +16 -0
  53. package/dist/init/CLI_COMMAND_MATRIX.md +14 -0
  54. package/dist/init/config.json +7 -1
  55. package/dist/init/init-manifest.json +49 -4
  56. package/dist/init/skills/default/pursue-mdkg-loop/SKILL.md +150 -0
  57. package/dist/init/templates/default/loop.md +160 -0
  58. package/dist/init/templates/loops/backend-api-cli-bloat-audit.loop.md +117 -0
  59. package/dist/init/templates/loops/design-frontend-ux-audit.loop.md +117 -0
  60. package/dist/init/templates/loops/duplicate-code-and-linting-audit.loop.md +114 -0
  61. package/dist/init/templates/loops/security-audit.loop.md +140 -0
  62. package/dist/init/templates/loops/tech-stack-best-practices-audit.loop.md +116 -0
  63. package/dist/init/templates/loops/test-ci-skill-infrastructure-audit.loop.md +116 -0
  64. package/dist/init/templates/loops/user-story-audit-and-recommendations.loop.md +116 -0
  65. package/dist/pack/order.js +3 -1
  66. package/dist/pack/pack.js +139 -6
  67. package/dist/templates/loader.js +9 -3
  68. package/dist/util/lock.js +10 -9
  69. package/dist/util/zip.js +163 -9
  70. package/package.json +8 -4
@@ -9,9 +9,9 @@ exports.projectDbStats = projectDbStats;
9
9
  const crypto_1 = __importDefault(require("crypto"));
10
10
  const fs_1 = __importDefault(require("fs"));
11
11
  const path_1 = __importDefault(require("path"));
12
+ const filesystem_authority_1 = require("./filesystem_authority");
12
13
  const project_db_1 = require("./project_db");
13
14
  const version_1 = require("./version");
14
- const atomic_1 = require("../util/atomic");
15
15
  const errors_1 = require("../util/errors");
16
16
  const FOUNDATION_MIGRATION_SQL = `
17
17
  CREATE TABLE IF NOT EXISTS project_meta (
@@ -219,46 +219,71 @@ function checksumContent(content) {
219
219
  }
220
220
  function assertDirectory(root, dirPath, label) {
221
221
  const relative = rel(root, dirPath);
222
- if (!fs_1.default.existsSync(dirPath)) {
223
- throw new errors_1.ValidationError(`${label} missing at ${relative}; run mdkg db init`);
222
+ try {
223
+ (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: relative, operation: "read" }, ({ absolutePath }) => {
224
+ if (!fs_1.default.existsSync(absolutePath)) {
225
+ throw new errors_1.ValidationError(`${label} missing at ${relative}; run mdkg db init`);
226
+ }
227
+ if (!fs_1.default.lstatSync(absolutePath).isDirectory()) {
228
+ throw new errors_1.ValidationError(`${relative} exists and is not a directory`);
229
+ }
230
+ });
224
231
  }
225
- if (!fs_1.default.statSync(dirPath).isDirectory()) {
226
- throw new errors_1.ValidationError(`${relative} exists and is not a directory`);
232
+ catch (error) {
233
+ if (error instanceof errors_1.ValidationError) {
234
+ throw error;
235
+ }
236
+ throw new errors_1.ValidationError(`${relative} is not a safe contained directory: ${error instanceof Error ? error.message : String(error)}`);
227
237
  }
228
238
  }
229
239
  function directoryCheck(root, dirPath, name) {
230
240
  const relative = rel(root, dirPath);
231
- if (!fs_1.default.existsSync(dirPath)) {
232
- return {
233
- name,
234
- ok: false,
235
- level: "fail",
236
- path: relative,
237
- detail: `${name} missing`,
238
- errors: [`${relative} missing; run mdkg db init`],
239
- warnings: [],
240
- };
241
+ try {
242
+ return (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: relative, operation: "read" }, ({ absolutePath }) => {
243
+ if (!fs_1.default.existsSync(absolutePath)) {
244
+ return {
245
+ name,
246
+ ok: false,
247
+ level: "fail",
248
+ path: relative,
249
+ detail: `${name} missing`,
250
+ errors: [`${relative} missing; run mdkg db init`],
251
+ warnings: [],
252
+ };
253
+ }
254
+ if (!fs_1.default.lstatSync(absolutePath).isDirectory()) {
255
+ return {
256
+ name,
257
+ ok: false,
258
+ level: "fail",
259
+ path: relative,
260
+ detail: `${name} is not a directory`,
261
+ errors: [`${relative} exists and is not a directory`],
262
+ warnings: [],
263
+ };
264
+ }
265
+ return {
266
+ name,
267
+ ok: true,
268
+ level: "ok",
269
+ path: relative,
270
+ detail: `${name} exists`,
271
+ errors: [],
272
+ warnings: [],
273
+ };
274
+ });
241
275
  }
242
- if (!fs_1.default.statSync(dirPath).isDirectory()) {
276
+ catch (error) {
243
277
  return {
244
278
  name,
245
279
  ok: false,
246
280
  level: "fail",
247
281
  path: relative,
248
- detail: `${name} is not a directory`,
249
- errors: [`${relative} exists and is not a directory`],
282
+ detail: `${name} is not safely contained`,
283
+ errors: [`${relative} is not safely contained: ${error instanceof Error ? error.message : String(error)}`],
250
284
  warnings: [],
251
285
  };
252
286
  }
253
- return {
254
- name,
255
- ok: true,
256
- level: "ok",
257
- path: relative,
258
- detail: `${name} exists`,
259
- errors: [],
260
- warnings: [],
261
- };
262
287
  }
263
288
  function assertProjectDbReady(root, config) {
264
289
  if (!config.db.enabled) {
@@ -274,31 +299,42 @@ function assertProjectDbReady(root, config) {
274
299
  assertDirectory(root, layout.runtimeDir, "project db runtime directory");
275
300
  assertDirectory(root, layout.stateDir, "project db state directory");
276
301
  assertDirectory(root, layout.receipts, "project db receipts directory");
277
- if (fs_1.default.existsSync(layout.runtimeFile) && fs_1.default.statSync(layout.runtimeFile).isDirectory()) {
278
- throw new errors_1.ValidationError(`${rel(root, layout.runtimeFile)} exists and is not a file`);
302
+ try {
303
+ (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: config.db.runtime_path, operation: "replace" }, ({ absolutePath }) => {
304
+ if (fs_1.default.existsSync(absolutePath) && fs_1.default.lstatSync(absolutePath).isDirectory()) {
305
+ throw new errors_1.ValidationError(`${rel(root, absolutePath)} exists and is not a file`);
306
+ }
307
+ });
308
+ }
309
+ catch (error) {
310
+ if (error instanceof errors_1.ValidationError) {
311
+ throw error;
312
+ }
313
+ throw new errors_1.ValidationError(`project db runtime path is not safely contained: ${error instanceof Error ? error.message : String(error)}`);
279
314
  }
280
315
  }
281
316
  function ensureMigrationFiles(root, config) {
282
317
  const layout = (0, project_db_1.resolveConfiguredProjectDbLayout)(root, config.db);
283
318
  const created = [];
284
319
  const unchanged = [];
320
+ const missing = [];
285
321
  for (const migration of BUILTIN_MIGRATIONS) {
286
322
  const filePath = path_1.default.join(layout.migrations, migration.filename);
287
323
  const expectedContent = `${migration.sql.trim()}\n`;
288
324
  const relative = rel(root, filePath);
289
- if (fs_1.default.existsSync(filePath)) {
290
- if (fs_1.default.statSync(filePath).isDirectory()) {
291
- throw new errors_1.ValidationError(`${relative} exists and is not a file`);
292
- }
293
- const current = fs_1.default.readFileSync(filePath, "utf8");
325
+ if ((0, filesystem_authority_1.containedPathExists)({ root, relativePath: relative })) {
326
+ const current = (0, filesystem_authority_1.readContainedFile)({ root, relativePath: relative });
294
327
  if (checksumContent(current) !== checksumContent(expectedContent)) {
295
328
  throw new errors_1.ValidationError(`migration file checksum drift at ${relative}`);
296
329
  }
297
330
  unchanged.push(relative);
298
331
  continue;
299
332
  }
300
- (0, atomic_1.atomicWriteFile)(filePath, expectedContent);
301
- created.push(relative);
333
+ missing.push({ relative, expectedContent });
334
+ }
335
+ for (const item of missing) {
336
+ (0, filesystem_authority_1.atomicReplaceContainedFile)({ root, relativePath: item.relative }, item.expectedContent);
337
+ created.push(item.relative);
302
338
  }
303
339
  return { created, unchanged };
304
340
  }
@@ -309,17 +345,18 @@ function checkMigrationFiles(root, config) {
309
345
  const filePath = path_1.default.join(layout.migrations, migration.filename);
310
346
  const relative = rel(root, filePath);
311
347
  const expectedContent = `${migration.sql.trim()}\n`;
312
- if (!fs_1.default.existsSync(filePath)) {
313
- errors.push(`${relative} missing; run mdkg db migrate`);
314
- continue;
315
- }
316
- if (fs_1.default.statSync(filePath).isDirectory()) {
317
- errors.push(`${relative} exists and is not a file`);
318
- continue;
348
+ try {
349
+ if (!(0, filesystem_authority_1.containedPathExists)({ root, relativePath: relative })) {
350
+ errors.push(`${relative} missing; run mdkg db migrate`);
351
+ continue;
352
+ }
353
+ const current = (0, filesystem_authority_1.readContainedFile)({ root, relativePath: relative });
354
+ if (checksumContent(current) !== checksumContent(expectedContent)) {
355
+ errors.push(`migration file checksum drift at ${relative}`);
356
+ }
319
357
  }
320
- const current = fs_1.default.readFileSync(filePath, "utf8");
321
- if (checksumContent(current) !== checksumContent(expectedContent)) {
322
- errors.push(`migration file checksum drift at ${relative}`);
358
+ catch (error) {
359
+ errors.push(`${relative} is not safely contained: ${error instanceof Error ? error.message : String(error)}`);
323
360
  }
324
361
  }
325
362
  return {
@@ -509,83 +546,84 @@ function runProjectDbMigrations(root, config) {
509
546
  assertProjectDbReady(root, config);
510
547
  const migrationFiles = ensureMigrationFiles(root, config);
511
548
  const layout = (0, project_db_1.resolveConfiguredProjectDbLayout)(root, config.db);
512
- fs_1.default.mkdirSync(path_1.default.dirname(layout.runtimeFile), { recursive: true });
513
549
  const DatabaseSync = loadDatabaseCtor();
514
- const db = new DatabaseSync(layout.runtimeFile);
515
550
  const statuses = [];
516
551
  let appliedCount = 0;
517
- try {
518
- db.exec("PRAGMA foreign_keys = ON;");
519
- db.exec("PRAGMA synchronous = FULL;");
520
- assertIntegrity(db);
521
- db.exec(createMigrationTableSql(config.db.migration_table));
522
- db.exec("BEGIN IMMEDIATE");
552
+ (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: config.db.runtime_path, operation: "replace", createParents: true }, ({ absolutePath }) => {
553
+ const db = new DatabaseSync(absolutePath);
523
554
  try {
524
- const applied = readAppliedMigrations(db, config.db.migration_table);
525
- const knownKeys = new Set(BUILTIN_MIGRATIONS.map((migration) => migration.key));
526
- for (const appliedKey of applied.keys()) {
527
- if (!knownKeys.has(appliedKey)) {
528
- throw new errors_1.ValidationError(`project DB contains unsupported migration ${appliedKey}`);
529
- }
530
- }
531
- const now = Date.now();
532
- for (const migration of BUILTIN_MIGRATIONS) {
533
- const checksum = checksumMigration(migration);
534
- const row = applied.get(migration.key);
535
- if (row) {
536
- if (row.ordinal !== migration.ordinal) {
537
- throw new errors_1.ValidationError(`migration order drift for ${migration.key}`);
555
+ db.exec("PRAGMA foreign_keys = ON;");
556
+ db.exec("PRAGMA synchronous = FULL;");
557
+ assertIntegrity(db);
558
+ db.exec(createMigrationTableSql(config.db.migration_table));
559
+ db.exec("BEGIN IMMEDIATE");
560
+ try {
561
+ const applied = readAppliedMigrations(db, config.db.migration_table);
562
+ const knownKeys = new Set(BUILTIN_MIGRATIONS.map((migration) => migration.key));
563
+ for (const appliedKey of applied.keys()) {
564
+ if (!knownKeys.has(appliedKey)) {
565
+ throw new errors_1.ValidationError(`project DB contains unsupported migration ${appliedKey}`);
538
566
  }
539
- if (row.checksum !== checksum) {
540
- throw new errors_1.ValidationError(`migration checksum drift for ${migration.key}`);
567
+ }
568
+ const now = Date.now();
569
+ for (const migration of BUILTIN_MIGRATIONS) {
570
+ const checksum = checksumMigration(migration);
571
+ const row = applied.get(migration.key);
572
+ if (row) {
573
+ if (row.ordinal !== migration.ordinal) {
574
+ throw new errors_1.ValidationError(`migration order drift for ${migration.key}`);
575
+ }
576
+ if (row.checksum !== checksum) {
577
+ throw new errors_1.ValidationError(`migration checksum drift for ${migration.key}`);
578
+ }
579
+ statuses.push({
580
+ key: migration.key,
581
+ ordinal: migration.ordinal,
582
+ checksum,
583
+ status: "already_applied",
584
+ applied_at_ms: row.applied_at_ms,
585
+ });
586
+ continue;
541
587
  }
588
+ db.exec(migration.sql);
589
+ const appliedAt = now + appliedCount;
590
+ db
591
+ .prepare(`INSERT INTO ${config.db.migration_table} (migration_key, ordinal, checksum, applied_at_ms, mdkg_version) VALUES (?, ?, ?, ?, ?)`)
592
+ .run(migration.key, migration.ordinal, checksum, appliedAt, (0, version_1.readPackageVersion)());
542
593
  statuses.push({
543
594
  key: migration.key,
544
595
  ordinal: migration.ordinal,
545
596
  checksum,
546
- status: "already_applied",
547
- applied_at_ms: row.applied_at_ms,
597
+ status: "applied",
598
+ applied_at_ms: appliedAt,
548
599
  });
549
- continue;
600
+ appliedCount += 1;
550
601
  }
551
- db.exec(migration.sql);
552
- const appliedAt = now + appliedCount;
553
- db
554
- .prepare(`INSERT INTO ${config.db.migration_table} (migration_key, ordinal, checksum, applied_at_ms, mdkg_version) VALUES (?, ?, ?, ?, ?)`)
555
- .run(migration.key, migration.ordinal, checksum, appliedAt, (0, version_1.readPackageVersion)());
556
- statuses.push({
557
- key: migration.key,
558
- ordinal: migration.ordinal,
559
- checksum,
560
- status: "applied",
561
- applied_at_ms: appliedAt,
562
- });
563
- appliedCount += 1;
602
+ syncProjectMeta(db, config);
603
+ db.exec("COMMIT");
564
604
  }
565
- syncProjectMeta(db, config);
566
- db.exec("COMMIT");
605
+ catch (err) {
606
+ try {
607
+ db.exec("ROLLBACK");
608
+ }
609
+ catch {
610
+ // ignore rollback failures when no transaction is active
611
+ }
612
+ throw err;
613
+ }
614
+ assertIntegrity(db);
567
615
  }
568
616
  catch (err) {
569
- try {
570
- db.exec("ROLLBACK");
617
+ if (err instanceof errors_1.ValidationError) {
618
+ throw err;
571
619
  }
572
- catch {
573
- // ignore rollback failures when no transaction is active
574
- }
575
- throw err;
620
+ const message = err instanceof Error ? err.message : String(err);
621
+ throw new errors_1.ValidationError(`project DB migration failed: ${message}`);
576
622
  }
577
- assertIntegrity(db);
578
- }
579
- catch (err) {
580
- if (err instanceof errors_1.ValidationError) {
581
- throw err;
623
+ finally {
624
+ db.close();
582
625
  }
583
- const message = err instanceof Error ? err.message : String(err);
584
- throw new errors_1.ValidationError(`project DB migration failed: ${message}`);
585
- }
586
- finally {
587
- db.close();
588
- }
626
+ });
589
627
  return {
590
628
  action: "db-migrate",
591
629
  ok: true,
@@ -628,36 +666,51 @@ function verifyProjectDb(root, config) {
628
666
  checks.push(directoryCheck(root, layout.stateDir, "project db state directory"));
629
667
  checks.push(directoryCheck(root, layout.receipts, "project db receipts directory"));
630
668
  const databasePath = rel(root, layout.runtimeFile);
631
- if (!fs_1.default.existsSync(layout.runtimeFile)) {
632
- checks.push({
633
- name: "runtime-database",
634
- ok: false,
635
- level: "fail",
636
- path: databasePath,
637
- detail: "runtime database missing",
638
- errors: [`${databasePath} missing; run mdkg db migrate`],
639
- warnings: [],
669
+ try {
670
+ (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: config.db.runtime_path, operation: "read" }, ({ absolutePath }) => {
671
+ if (!fs_1.default.existsSync(absolutePath)) {
672
+ checks.push({
673
+ name: "runtime-database",
674
+ ok: false,
675
+ level: "fail",
676
+ path: databasePath,
677
+ detail: "runtime database missing",
678
+ errors: [`${databasePath} missing; run mdkg db migrate`],
679
+ warnings: [],
680
+ });
681
+ }
682
+ else if (fs_1.default.lstatSync(absolutePath).isDirectory()) {
683
+ checks.push({
684
+ name: "runtime-database",
685
+ ok: false,
686
+ level: "fail",
687
+ path: databasePath,
688
+ detail: "runtime database path is not a file",
689
+ errors: [`${databasePath} exists and is not a file`],
690
+ warnings: [],
691
+ });
692
+ }
693
+ else {
694
+ checks.push({
695
+ name: "runtime-database",
696
+ ok: true,
697
+ level: "ok",
698
+ path: databasePath,
699
+ detail: "runtime database exists",
700
+ errors: [],
701
+ warnings: [],
702
+ });
703
+ }
640
704
  });
641
705
  }
642
- else if (fs_1.default.statSync(layout.runtimeFile).isDirectory()) {
706
+ catch (error) {
643
707
  checks.push({
644
708
  name: "runtime-database",
645
709
  ok: false,
646
710
  level: "fail",
647
711
  path: databasePath,
648
- detail: "runtime database path is not a file",
649
- errors: [`${databasePath} exists and is not a file`],
650
- warnings: [],
651
- });
652
- }
653
- else {
654
- checks.push({
655
- name: "runtime-database",
656
- ok: true,
657
- level: "ok",
658
- path: databasePath,
659
- detail: "runtime database exists",
660
- errors: [],
712
+ detail: "runtime database is not safely contained",
713
+ errors: [`${databasePath} is not safely contained: ${error instanceof Error ? error.message : String(error)}`],
661
714
  warnings: [],
662
715
  });
663
716
  }
@@ -667,14 +720,16 @@ function verifyProjectDb(root, config) {
667
720
  checks.push(checkMigrationFiles(root, config));
668
721
  const DatabaseSync = loadDatabaseCtor();
669
722
  try {
670
- const db = new DatabaseSync(layout.runtimeFile);
671
- try {
672
- checks.push(integrityCheck(db));
673
- checks.push(migrationTableCheck(db, config));
674
- }
675
- finally {
676
- db.close();
677
- }
723
+ (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: config.db.runtime_path, operation: "read" }, ({ absolutePath }) => {
724
+ const db = new DatabaseSync(absolutePath);
725
+ try {
726
+ checks.push(integrityCheck(db));
727
+ checks.push(migrationTableCheck(db, config));
728
+ }
729
+ finally {
730
+ db.close();
731
+ }
732
+ });
678
733
  }
679
734
  catch (err) {
680
735
  const message = err instanceof Error ? err.message : String(err);
@@ -712,49 +767,51 @@ function projectDbStats(root, config) {
712
767
  }
713
768
  const layout = (0, project_db_1.resolveConfiguredProjectDbLayout)(root, config.db);
714
769
  const DatabaseSync = loadDatabaseCtor();
715
- const db = new DatabaseSync(layout.runtimeFile);
716
- try {
717
- const applied = readAppliedMigrations(db, config.db.migration_table);
718
- const migrationStatuses = BUILTIN_MIGRATIONS
719
- .map((migration) => {
720
- const row = applied.get(migration.key);
721
- return row
722
- ? {
723
- key: migration.key,
724
- ordinal: migration.ordinal,
725
- checksum: row.checksum,
726
- status: "already_applied",
727
- applied_at_ms: row.applied_at_ms,
728
- }
729
- : undefined;
730
- })
731
- .filter((item) => item !== undefined);
732
- const latestMigration = migrationStatuses[migrationStatuses.length - 1] ?? null;
733
- const receiptFiles = walkFiles(layout.receipts);
734
- return {
735
- action: "db-stats",
736
- ok: true,
737
- enabled: config.db.enabled,
738
- database: rel(root, layout.runtimeFile),
739
- schema_version: config.db.schema_version,
740
- migration_table: config.db.migration_table,
741
- db_size: fs_1.default.statSync(layout.runtimeFile).size,
742
- transient_files: transientFiles(root, layout.runtimeFile),
743
- migration_count: migrationStatuses.length,
744
- latest_migration: latestMigration,
745
- tables: tableCounts(db),
746
- state_snapshot: {
747
- path: rel(root, layout.stateFile),
748
- exists: fs_1.default.existsSync(layout.stateFile),
749
- size: fs_1.default.existsSync(layout.stateFile) ? fs_1.default.statSync(layout.stateFile).size : 0,
750
- },
751
- receipt_files: {
752
- path: rel(root, layout.receipts),
753
- count: receiptFiles.length,
754
- },
755
- };
756
- }
757
- finally {
758
- db.close();
759
- }
770
+ return (0, filesystem_authority_1.withContainedPathSink)({ root, relativePath: config.db.runtime_path, operation: "read" }, ({ absolutePath }) => {
771
+ const db = new DatabaseSync(absolutePath);
772
+ try {
773
+ const applied = readAppliedMigrations(db, config.db.migration_table);
774
+ const migrationStatuses = BUILTIN_MIGRATIONS
775
+ .map((migration) => {
776
+ const row = applied.get(migration.key);
777
+ return row
778
+ ? {
779
+ key: migration.key,
780
+ ordinal: migration.ordinal,
781
+ checksum: row.checksum,
782
+ status: "already_applied",
783
+ applied_at_ms: row.applied_at_ms,
784
+ }
785
+ : undefined;
786
+ })
787
+ .filter((item) => item !== undefined);
788
+ const latestMigration = migrationStatuses[migrationStatuses.length - 1] ?? null;
789
+ const receiptFiles = walkFiles(layout.receipts);
790
+ return {
791
+ action: "db-stats",
792
+ ok: true,
793
+ enabled: config.db.enabled,
794
+ database: rel(root, absolutePath),
795
+ schema_version: config.db.schema_version,
796
+ migration_table: config.db.migration_table,
797
+ db_size: fs_1.default.statSync(absolutePath).size,
798
+ transient_files: transientFiles(root, absolutePath),
799
+ migration_count: migrationStatuses.length,
800
+ latest_migration: latestMigration,
801
+ tables: tableCounts(db),
802
+ state_snapshot: {
803
+ path: rel(root, layout.stateFile),
804
+ exists: fs_1.default.existsSync(layout.stateFile),
805
+ size: fs_1.default.existsSync(layout.stateFile) ? fs_1.default.statSync(layout.stateFile).size : 0,
806
+ },
807
+ receipt_files: {
808
+ path: rel(root, layout.receipts),
809
+ count: receiptFiles.length,
810
+ },
811
+ };
812
+ }
813
+ finally {
814
+ db.close();
815
+ }
816
+ });
760
817
  }