mdkg 0.1.2 → 0.1.4

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 (46) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +31 -15
  3. package/dist/cli.js +182 -85
  4. package/dist/commands/archive.js +20 -8
  5. package/dist/commands/bundle.js +7 -7
  6. package/dist/commands/capability.js +118 -4
  7. package/dist/commands/checkpoint.js +31 -5
  8. package/dist/commands/doctor.js +61 -24
  9. package/dist/commands/index.js +12 -23
  10. package/dist/commands/init.js +7 -1
  11. package/dist/commands/list.js +1 -1
  12. package/dist/commands/new.js +33 -7
  13. package/dist/commands/next.js +1 -1
  14. package/dist/commands/node_card.js +1 -1
  15. package/dist/commands/pack.js +1 -1
  16. package/dist/commands/search.js +1 -1
  17. package/dist/commands/show.js +1 -1
  18. package/dist/commands/subgraph.js +312 -0
  19. package/dist/commands/task.js +21 -7
  20. package/dist/commands/upgrade.js +51 -4
  21. package/dist/commands/validate.js +12 -6
  22. package/dist/commands/work.js +44 -12
  23. package/dist/core/config.js +110 -39
  24. package/dist/graph/capabilities_index_cache.js +2 -2
  25. package/dist/graph/index_cache.js +14 -14
  26. package/dist/graph/indexer.js +1 -1
  27. package/dist/graph/reindex.js +46 -0
  28. package/dist/graph/skills_index_cache.js +2 -2
  29. package/dist/graph/sqlite_index.js +293 -0
  30. package/dist/graph/{bundle_imports.js → subgraphs.js} +216 -142
  31. package/dist/graph/visibility.js +3 -3
  32. package/dist/init/AGENT_START.md +5 -1
  33. package/dist/init/CLI_COMMAND_MATRIX.md +21 -7
  34. package/dist/init/README.md +20 -10
  35. package/dist/init/config.json +6 -2
  36. package/dist/init/core/rule-1-mdkg-conventions.md +2 -1
  37. package/dist/init/core/rule-3-cli-contract.md +32 -24
  38. package/dist/init/core/rule-4-repo-safety-and-ignores.md +28 -12
  39. package/dist/init/core/rule-5-release-and-versioning.md +4 -3
  40. package/dist/init/init-manifest.json +10 -10
  41. package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +1 -1
  42. package/dist/util/argparse.js +2 -0
  43. package/dist/util/atomic.js +44 -0
  44. package/dist/util/lock.js +72 -0
  45. package/package.json +13 -9
  46. package/dist/commands/bundle_import.js +0 -243
package/CHANGELOG.md CHANGED
@@ -4,6 +4,57 @@ All notable changes to mdkg are documented here.
4
4
 
5
5
  This project follows a pragmatic changelog style inspired by Keep a Changelog. Versions use npm package versions.
6
6
 
7
+ mdkg is pre-v1 public alpha software. Command, graph, cache, bundle, and DAL contracts may change quickly while the project converges on a stable v1 surface.
8
+
9
+ ## 0.1.4 - Unreleased
10
+
11
+ ### Added
12
+
13
+ - Added `mdkg subgraph add/list/show/rm/enable/disable/verify/refresh` as the public read-only child graph orchestration command family.
14
+ - Added `subgraphs` config with multi-source bundle transport, advisory visibility, read permissions, source metadata, and a default 60 minute freshness policy.
15
+ - Added `.mdkg/index/subgraphs.json` as the derived subgraph projection and health cache.
16
+ - Added `mdkg capability resolve [query] [--requires <capability>] [--fresh-only] [--json]` for deterministic local plus subgraph capability ranking.
17
+ - Added packed-package `smoke:subgraph` coverage for root, child, and grandchild orchestration flows.
18
+
19
+ ### Changed
20
+
21
+ - Replaced the public `mdkg bundle import ...` surface with `mdkg subgraph ...`; legacy calls now exit with migration guidance.
22
+ - `mdkg upgrade --apply` migrates legacy `bundle_imports` config into `subgraphs`.
23
+ - Read commands, `pack`, and capability discovery now project enabled child bundles as read-only subgraph qids such as `child_repo:work.example`.
24
+ - `mdkg index`, SQLite cache rebuilds, `doctor`, and `validate` now use subgraph naming and metadata instead of bundle-import naming.
25
+ - Stale subgraphs remain usable for planning reads with warnings, fail `mdkg subgraph verify`, and are excluded from `capability resolve --fresh-only`.
26
+ - Public/internal subgraphs require public bundle profiles and public bundle creation fails closed on private/internal subgraph references.
27
+
28
+ ### Fixed
29
+
30
+ - Mutation commands now reject subgraph qids with explicit guidance to update the source workspace for the owning subgraph.
31
+ - Seeded init docs, command matrix, and release skills now teach `subgraph` and `capability resolve` instead of onboarding users through `bundle import`.
32
+
33
+ ## 0.1.3 - 2026-05-20
34
+
35
+ ### Added
36
+
37
+ - Added first-class SQLite access cache support using Node's built-in `node:sqlite`; no third-party SQLite package is introduced.
38
+ - Added `.mdkg/index/mdkg.sqlite` as a rebuildable derived cache for nodes, edges, skills, capabilities, archives, bundle imports, source hashes, and schema metadata when `index.backend` is `sqlite`.
39
+ - Added fresh init defaults for `index.backend: sqlite`, `index.sqlite_path`, `index.sqlite_commit_warning_bytes`, and `index.lock_timeout_ms`.
40
+ - Added a shared mutation lock plus atomic writes for mdkg mutations and index writes.
41
+ - Added SQLite transactional id reservation for numeric node/checkpoint ids in SQLite mode.
42
+ - Added `npm run smoke:sqlite` and `npm run smoke:parallel` packed/temp-repo coverage.
43
+
44
+ ### Changed
45
+
46
+ - Raised the required Node runtime to `>=24.15.0`.
47
+ - Existing workspaces that are migrated from older configs remain on `index.backend: json` until they explicitly opt in to SQLite.
48
+ - Init ignore policy now keeps JSON indexes, temp files, lock directories, WAL, SHM, and journal files ignored while allowing `.mdkg/index/mdkg.sqlite` to be committed by intentional repo policy.
49
+ - `mdkg index` continues to write JSON compatibility indexes and also rebuilds SQLite when enabled.
50
+ - `mdkg doctor` and `mdkg validate` now report SQLite cache health when SQLite mode is enabled.
51
+ - README and seeded docs now state that mdkg is pre-v1 public alpha software and cache/DAL contracts may churn before v1.
52
+
53
+ ### Fixed
54
+
55
+ - Removed the accidental self-dependency on `mdkg` from package metadata.
56
+ - Hardened parallel `mdkg new`, checkpoint, task, work, archive, bundle import config, and index writes against naming conflicts and partial cache writes.
57
+
7
58
  ## 0.1.2 - 2026-05-19
8
59
 
9
60
  ### Added
package/README.md CHANGED
@@ -9,11 +9,14 @@ It is built for:
9
9
 
10
10
  mdkg stays deliberately boring:
11
11
  - repo-native under `.mdkg/`
12
- - TypeScript + Node.js 18+
13
- - zero runtime dependencies
14
- - no required sqlite, daemon, hosted index, or vector DB
12
+ - TypeScript + Node.js `>=24.15.0`
13
+ - zero third-party runtime dependencies
14
+ - first-class rebuildable SQLite cache through built-in `node:sqlite`
15
+ - no daemon, hosted index, or vector DB
15
16
 
16
- Current package version in source: `0.1.2`
17
+ Current package version in source: `0.1.4`
18
+
19
+ mdkg is still pre-v1 public alpha software. The public package is usable, but graph, cache, bundle, and DAL contracts may continue to change quickly while the project converges on a stable v1 surface.
17
20
 
18
21
  ## The product shape
19
22
 
@@ -107,20 +110,21 @@ mdkg bundle verify .mdkg/bundles/private/all.mdkg.zip
107
110
  mdkg bundle list --json
108
111
  ```
109
112
 
110
- Bundles are explicit graph transport artifacts, separate from task context packs. Before a commit in repos that track archives or bundles, refresh compressed archive caches first, then create the private bundle so the committed graph state is self-consistent. Private bundles are the default and may be committed in private repos when configured. Public bundles require at least one selected workspace with `visibility: public` and include only public workspace content and public archive sidecars; bundle creation fails if public content points at private graph, archive, or imported bundle records.
113
+ Bundles are explicit graph transport artifacts, separate from task context packs. Before a commit in repos that track archives or bundles, refresh compressed archive caches first, then create the private bundle so the committed graph state is self-consistent. Private bundles are the default and may be committed in private repos when configured. Public bundles require at least one selected workspace with `visibility: public` and include only public workspace content and public archive sidecars; bundle creation fails if public content points at private graph, archive, or subgraph records.
111
114
 
112
- Import a child repo bundle as a read-only planning view:
115
+ Register a child repo bundle as a read-only subgraph planning view:
113
116
 
114
117
  ```bash
115
- mdkg bundle import add child_repo child-repo/.mdkg/bundles/private/all.mdkg.zip --source-path child-repo
116
- mdkg bundle import list --json
118
+ mdkg subgraph add child_repo child-repo/.mdkg/bundles/private/all.mdkg.zip --source-path child-repo
119
+ mdkg subgraph list --json
117
120
  mdkg search "child capability"
118
121
  mdkg show child_repo:work.example
119
122
  mdkg pack child_repo:work.example --dry-run --stats
120
- mdkg bundle import verify child_repo --json
123
+ mdkg capability resolve "child capability" --json
124
+ mdkg subgraph verify child_repo --json
121
125
  ```
122
126
 
123
- Imported bundle nodes are projected under the import alias, for example `child_repo:task-1`. They are available to `list`, `search`, `show`, `pack`, and capability discovery, but remain read-only; mutate the child repo and refresh its bundle to change imported content. Stale imports warn during planning reads and fail `mdkg bundle import verify`. Public or internal imports must be backed by public bundle profiles; private imports stay private planning context.
127
+ Subgraph nodes are projected under the subgraph alias, for example `child_repo:task-1`. They are available to `list`, `search`, `show`, `pack`, capability discovery, and `capability resolve`, but remain read-only; mutate the child repo and refresh its bundle to change subgraph content. Stale subgraphs warn during planning reads and fail `mdkg subgraph verify`. Public or internal subgraphs must be backed by public bundle profiles; private subgraphs stay private planning context.
124
128
 
125
129
  Validate before handoff or commit:
126
130
 
@@ -155,7 +159,7 @@ mdkg work artifact add receipt.generate-image-1 ./outputs/image.png --id archive
155
159
  ```
156
160
 
157
161
  Receipt statuses are `recorded`, `verified`, `rejected`, and `superseded`.
158
- Update and artifact commands accept local ids or local qids; imported bundle qids are read-only and must be changed in their source workspace.
162
+ Update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace.
159
163
 
160
164
  Update structured task state and evidence while keeping body and narrative edits in markdown:
161
165
 
@@ -202,10 +206,11 @@ mdkg lives under a hidden root directory:
202
206
  - `.mdkg/skills/` Agent Skills packages
203
207
  - `.mdkg/archive/` sidecar metadata plus deterministic compressed source/artifact caches
204
208
  - `.mdkg/bundles/` optional committed full graph snapshot bundles
205
- - `.mdkg/index/imports.json` generated read-only bundle import cache
209
+ - `.mdkg/index/mdkg.sqlite` optional committed, rebuildable SQLite access cache
210
+ - `.mdkg/index/subgraphs.json` generated read-only subgraph projection cache
206
211
  - `.agents/skills/` Codex/OpenAI-facing mirrored skills
207
212
  - `.claude/skills/` Claude-facing mirrored skills
208
- - `.mdkg/index/` generated cache files
213
+ - `.mdkg/index/*.json` generated JSON compatibility cache files
209
214
 
210
215
  ## Primary commands
211
216
 
@@ -292,6 +297,14 @@ The capability cache is not the full graph and is not source of truth. Normal ta
292
297
 
293
298
  Capability records aggregate enabled registered workspaces and include deterministic source metadata such as `workspace`, `visibility`, `kind`, `id`, `qid`, `path`, headings, refs, source hash, and `indexed_at`. Workspace `visibility` also feeds mdkg's export safety checks for public/internal packs and public bundles. This is a CLI safety layer, not secret scanning, body redaction, or a replacement for private git hosting.
294
299
 
300
+ ## Index backends and parallel safety
301
+
302
+ Fresh `mdkg init` workspaces default to `index.backend: sqlite`, which writes `.mdkg/index/mdkg.sqlite` as a rebuildable access cache using Node's built-in `node:sqlite`. Existing workspaces that are migrated from older configs default to `index.backend: json` until they opt in. Markdown files, archive sidecars, bundle manifests, and config remain source of truth in both modes.
303
+
304
+ `mdkg index` still writes JSON compatibility caches (`global.json`, `skills.json`, `capabilities.json`, and subgraph projections when configured). In SQLite mode it also rebuilds the SQLite cache with nodes, edges, skills, capabilities, archive metadata, subgraphs, source hashes, and schema metadata. Deleting the SQLite file is recoverable with `mdkg index`.
305
+
306
+ Mutating commands use a workspace mutation lock plus atomic writes. SQLite mode additionally reserves numeric ids in a SQLite transaction before writing Markdown so parallel `mdkg new` and checkpoint calls avoid naming conflicts. Skipped ids after failed writes are acceptable because Markdown remains canonical.
307
+
295
308
  ## Agent workflow files
296
309
 
297
310
  mdkg recognizes a small set of canonical agent workflow documents:
@@ -323,10 +336,12 @@ By default, init/upgrade ignore generated raw archive source copies with `.mdkg/
323
336
 
324
337
  This release includes:
325
338
  - `init --agent`
326
- - default ignore updates with `--no-update-ignores` for `.mdkg/index/`, `.mdkg/pack/`, and raw archive source copies
339
+ - default ignore updates with `--no-update-ignores` for generated JSON index/temp/lock files, `.mdkg/pack/`, and raw archive source copies
327
340
  - root-only published init seed config
328
341
  - skills indexing and search/show/list support
329
342
  - JSON capability cache for skills, `SPEC.md`, `WORK.md`, core docs, and design docs
343
+ - SQLite index backend for fresh workspaces using built-in `node:sqlite`
344
+ - mutation locking and atomic writes for parallel mdkg calls
330
345
  - optional `skills: [...]` on work items
331
346
  - pack-time skill inclusion
332
347
  - latest-checkpoint resolver + index hint
@@ -360,7 +375,8 @@ Design and decision records live in the internal graph under `.mdkg/design/`.
360
375
  mdkg is not a secret store.
361
376
 
362
377
  Use these defaults:
363
- - keep `.mdkg/index/` gitignored
378
+ - keep generated `.mdkg/index/*.json`, temp, lock, WAL, SHM, and journal files gitignored
379
+ - commit `.mdkg/index/mdkg.sqlite` only when the repo intentionally tracks a reasonably sized rebuildable access cache
364
380
  - keep `.mdkg/pack/` gitignored
365
381
  - keep `.mdkg/archive/**/source/` gitignored unless a repo intentionally commits raw local copies
366
382
  - commit archive sidecar `.md` metadata and deterministic `.zip` caches when they are needed for reviewable evidence
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ const doctor_1 = require("./commands/doctor");
21
21
  const capability_1 = require("./commands/capability");
22
22
  const archive_1 = require("./commands/archive");
23
23
  const bundle_1 = require("./commands/bundle");
24
- const bundle_import_1 = require("./commands/bundle_import");
24
+ const subgraph_1 = require("./commands/subgraph");
25
25
  const checkpoint_1 = require("./commands/checkpoint");
26
26
  const init_1 = require("./commands/init");
27
27
  const new_1 = require("./commands/new");
@@ -60,9 +60,10 @@ function printUsage(log) {
60
60
  log(" search Search nodes by query");
61
61
  log(" pack Generate a context pack");
62
62
  log(" skill Create, list, show, search, and validate skills");
63
- log(" capability List, search, and show cached capability surfaces");
63
+ log(" capability List, search, show, and resolve cached capability surfaces");
64
64
  log(" archive Add, list, show, verify, and compress archive sidecars");
65
65
  log(" bundle Create, list, show, and verify full graph snapshot bundles");
66
+ log(" subgraph Register and verify read-only child graph snapshots");
66
67
  log(" work Create and update work contracts, orders, receipts, and artifacts");
67
68
  log(" task Start, update, and complete task-like nodes");
68
69
  log(" next Suggest the next work item");
@@ -171,6 +172,8 @@ function printIndexHelp(log) {
171
172
  log(" - .mdkg/index/global.json");
172
173
  log(" - .mdkg/index/skills.json");
173
174
  log(" - .mdkg/index/capabilities.json");
175
+ log(" - .mdkg/index/subgraphs.json when subgraphs are configured");
176
+ log(" - .mdkg/index/mdkg.sqlite when index.backend is sqlite");
174
177
  printGlobalOptions(log);
175
178
  }
176
179
  function printShowHelp(log) {
@@ -320,14 +323,23 @@ function printCapabilityHelp(log, subcommand) {
320
323
  log(" mdkg capability show <id-or-qid-or-slug> [--json]");
321
324
  printGlobalOptions(log);
322
325
  return;
326
+ case "resolve":
327
+ log("Usage:");
328
+ log(' mdkg capability resolve [query] [--requires <capability>] [--fresh-only] [--json]');
329
+ log("\nNotes:");
330
+ log(" Resolves local and subgraph capabilities with deterministic ranking.");
331
+ printGlobalOptions(log);
332
+ return;
323
333
  default:
324
334
  log("Usage:");
325
335
  log(" mdkg capability list [--kind <kind>] [--visibility <level>] [--json]");
326
336
  log(' mdkg capability search "<query>" [--kind <kind>] [--visibility <level>] [--json]');
327
337
  log(" mdkg capability show <id-or-qid-or-slug> [--json]");
338
+ log(' mdkg capability resolve [query] [--requires <capability>] [--fresh-only] [--json]');
328
339
  log("\nNotes:");
329
340
  log(" Capability records are deterministic cache projections from Markdown.");
330
341
  log(" Cached kinds: skill, spec, work, core, design.");
342
+ log(" Resolve includes read-only subgraph capability records when configured.");
331
343
  printGlobalOptions(log);
332
344
  }
333
345
  }
@@ -373,12 +385,8 @@ function printBundleHelp(log, subcommand) {
373
385
  switch ((subcommand ?? "").toLowerCase()) {
374
386
  case "import":
375
387
  log("Usage:");
376
- log(" mdkg bundle import add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--source-repo <ref>] [--max-stale-seconds <seconds>] [--json]");
377
- log(" mdkg bundle import list [--json]");
378
- log(" mdkg bundle import rm <alias> [--json]");
379
- log(" mdkg bundle import enable <alias> [--json]");
380
- log(" mdkg bundle import disable <alias> [--json]");
381
- log(" mdkg bundle import verify [alias|--all] [--json]");
388
+ log(" mdkg subgraph add/list/show/rm/enable/disable/verify/refresh ...");
389
+ log("\n`mdkg bundle import` has been replaced by `mdkg subgraph`.");
382
390
  break;
383
391
  case "create":
384
392
  log("Usage:");
@@ -402,15 +410,66 @@ function printBundleHelp(log, subcommand) {
402
410
  log(" mdkg bundle verify [bundle-path] [--json]");
403
411
  log(" mdkg bundle show <bundle-path> [--json]");
404
412
  log(" mdkg bundle list [--json]");
405
- log(" mdkg bundle import add/list/rm/enable/disable/verify ...");
406
413
  log("\nNotes:");
407
414
  log(" - bundles are explicit full .mdkg graph snapshots, not task context packs");
408
- log(" - bundle imports are read-only graph views projected under their import alias");
415
+ log(" - use `mdkg subgraph ...` to register bundle snapshots as read-only planning views");
409
416
  log(" - private is the default profile; public bundles fail closed on private refs");
410
417
  log(" - .mdkg/bundles/ is commit-eligible when your repo tracks snapshot bundles");
411
418
  }
412
419
  printGlobalOptions(log);
413
420
  }
421
+ function printSubgraphHelp(log, subcommand) {
422
+ switch ((subcommand ?? "").toLowerCase()) {
423
+ case "add":
424
+ log("Usage:");
425
+ log(" mdkg subgraph add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--source-repo <ref>] [--max-stale-seconds <seconds>] [--json]");
426
+ break;
427
+ case "list":
428
+ log("Usage:");
429
+ log(" mdkg subgraph list [--json]");
430
+ break;
431
+ case "show":
432
+ log("Usage:");
433
+ log(" mdkg subgraph show <alias> [--json]");
434
+ break;
435
+ case "rm":
436
+ case "remove":
437
+ log("Usage:");
438
+ log(" mdkg subgraph rm <alias> [--json]");
439
+ break;
440
+ case "enable":
441
+ log("Usage:");
442
+ log(" mdkg subgraph enable <alias> [--json]");
443
+ break;
444
+ case "disable":
445
+ log("Usage:");
446
+ log(" mdkg subgraph disable <alias> [--json]");
447
+ break;
448
+ case "verify":
449
+ log("Usage:");
450
+ log(" mdkg subgraph verify [alias|--all] [--json]");
451
+ break;
452
+ case "refresh":
453
+ log("Usage:");
454
+ log(" mdkg subgraph refresh [alias|--all] [--json]");
455
+ break;
456
+ default:
457
+ log("Usage:");
458
+ log(" mdkg subgraph add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--source-repo <ref>] [--max-stale-seconds <seconds>] [--json]");
459
+ log(" mdkg subgraph list [--json]");
460
+ log(" mdkg subgraph show <alias> [--json]");
461
+ log(" mdkg subgraph rm <alias> [--json]");
462
+ log(" mdkg subgraph enable <alias> [--json]");
463
+ log(" mdkg subgraph disable <alias> [--json]");
464
+ log(" mdkg subgraph verify [alias|--all] [--json]");
465
+ log(" mdkg subgraph refresh [alias|--all] [--json]");
466
+ log("\nNotes:");
467
+ log(" - subgraphs are read-only graph views backed by explicit bundle snapshots");
468
+ log(" - default permissions are read-only and default freshness is 3600 seconds");
469
+ log(" - refresh reloads configured bundle sources only; it does not build child bundles");
470
+ }
471
+ printGlobalOptions(log);
472
+ }
414
473
  function printWorkHelp(log, subcommand) {
415
474
  switch ((subcommand ?? "").toLowerCase()) {
416
475
  case "contract":
@@ -442,7 +501,7 @@ function printWorkHelp(log, subcommand) {
442
501
  log(" - production order, receipt, feedback, dispute, payment, ledger, marketplace inventory, fulfillment, and execution state remains canonical outside mdkg");
443
502
  log(" - do not store raw secrets, credentials, live payment state, ledger mutations, or canonical marketplace state in work mirrors");
444
503
  log(" - artifact:// refs identify external/runtime-managed artifacts; archive:// refs identify committed mdkg archive sidecars");
445
- log(" - update and artifact commands accept local ids or local qids; imported bundle qids are read-only");
504
+ log(" - update and artifact commands accept local ids or local qids; subgraph qids are read-only");
446
505
  }
447
506
  printGlobalOptions(log);
448
507
  }
@@ -544,6 +603,7 @@ function printDoctorHelp(log) {
544
603
  log(" - Bundle import health and staleness");
545
604
  log(" - Index load/rebuild health");
546
605
  log(" - Capability cache load/rebuild health");
606
+ log(" - SQLite cache health when enabled");
547
607
  log("\nOptions:");
548
608
  log(" --json Emit machine-readable JSON output");
549
609
  printGlobalOptions(log);
@@ -596,6 +656,9 @@ function printCommandHelp(log, command, subcommand) {
596
656
  case "bundle":
597
657
  printBundleHelp(log, subcommand);
598
658
  return;
659
+ case "subgraph":
660
+ printSubgraphHelp(log, subcommand);
661
+ return;
599
662
  case "work":
600
663
  printWorkHelp(log, subcommand);
601
664
  return;
@@ -868,8 +931,20 @@ function runCapabilitySubcommand(parsed, root) {
868
931
  (0, capability_1.runCapabilityShowCommand)({ root, id, json, noCache, noReindex });
869
932
  return 0;
870
933
  }
934
+ case "resolve": {
935
+ const query = parsed.positionals.slice(2).join(" ") || undefined;
936
+ const kind = requireFlagValue("--kind", parsed.flags["--kind"]);
937
+ const visibility = requireFlagValue("--visibility", parsed.flags["--visibility"]);
938
+ const requires = requireFlagValue("--requires", parsed.flags["--requires"]);
939
+ const freshOnly = parseBooleanFlag("--fresh-only", parsed.flags["--fresh-only"]);
940
+ const json = parseBooleanFlag("--json", parsed.flags["--json"]);
941
+ const noCache = parseBooleanFlag("--no-cache", parsed.flags["--no-cache"]);
942
+ const noReindex = parseBooleanFlag("--no-reindex", parsed.flags["--no-reindex"]);
943
+ (0, capability_1.runCapabilityResolveCommand)({ root, query, kind, visibility, requires, freshOnly, json, noCache, noReindex });
944
+ return 0;
945
+ }
871
946
  default:
872
- throw new errors_1.UsageError("capability requires list/search/show");
947
+ throw new errors_1.UsageError("capability requires list/search/show/resolve");
873
948
  }
874
949
  }
875
950
  function runArchiveSubcommand(parsed, root) {
@@ -941,78 +1016,7 @@ function runBundleSubcommand(parsed, root) {
941
1016
  const subcommand = (parsed.positionals[1] ?? "").toLowerCase();
942
1017
  switch (subcommand) {
943
1018
  case "import": {
944
- const action = (parsed.positionals[2] ?? "").toLowerCase();
945
- const json = parseBooleanFlag("--json", parsed.flags["--json"]);
946
- switch (action) {
947
- case "add": {
948
- const alias = parsed.positionals[3];
949
- const bundlePath = parsed.positionals[4];
950
- if (!alias || !bundlePath || parsed.positionals.length > 5) {
951
- throw new errors_1.UsageError("bundle import add requires <alias> <bundle-path>");
952
- }
953
- const visibility = requireFlagValue("--visibility", parsed.flags["--visibility"]);
954
- const profile = requireFlagValue("--profile", parsed.flags["--pack-profile"]);
955
- const sourcePath = requireFlagValue("--source-path", parsed.flags["--source-path"]);
956
- const sourceRepo = requireFlagValue("--source-repo", parsed.flags["--source-repo"]);
957
- const maxStaleRaw = requireFlagValue("--max-stale-seconds", parsed.flags["--max-stale-seconds"]);
958
- const maxStaleSeconds = maxStaleRaw === undefined ? undefined : Number.parseInt(maxStaleRaw, 10);
959
- (0, bundle_import_1.runBundleImportAddCommand)({
960
- root,
961
- alias,
962
- bundlePath,
963
- visibility,
964
- profile,
965
- sourcePath,
966
- sourceRepo,
967
- maxStaleSeconds,
968
- json,
969
- });
970
- return 0;
971
- }
972
- case "list": {
973
- if (parsed.positionals.length > 3) {
974
- throw new errors_1.UsageError("bundle import list does not accept positional arguments");
975
- }
976
- (0, bundle_import_1.runBundleImportListCommand)({ root, json });
977
- return 0;
978
- }
979
- case "rm":
980
- case "remove": {
981
- const alias = parsed.positionals[3];
982
- if (!alias || parsed.positionals.length > 4) {
983
- throw new errors_1.UsageError("bundle import rm requires <alias>");
984
- }
985
- (0, bundle_import_1.runBundleImportRemoveCommand)({ root, alias, json });
986
- return 0;
987
- }
988
- case "enable": {
989
- const alias = parsed.positionals[3];
990
- if (!alias || parsed.positionals.length > 4) {
991
- throw new errors_1.UsageError("bundle import enable requires <alias>");
992
- }
993
- (0, bundle_import_1.runBundleImportEnableCommand)({ root, alias, json });
994
- return 0;
995
- }
996
- case "disable": {
997
- const alias = parsed.positionals[3];
998
- if (!alias || parsed.positionals.length > 4) {
999
- throw new errors_1.UsageError("bundle import disable requires <alias>");
1000
- }
1001
- (0, bundle_import_1.runBundleImportDisableCommand)({ root, alias, json });
1002
- return 0;
1003
- }
1004
- case "verify": {
1005
- if (parsed.positionals.length > 4) {
1006
- throw new errors_1.UsageError("bundle import verify accepts at most one alias");
1007
- }
1008
- const alias = parsed.positionals[3];
1009
- const all = parseBooleanFlag("--all", parsed.flags["--all"]);
1010
- (0, bundle_import_1.runBundleImportVerifyCommand)({ root, alias, all, json });
1011
- return 0;
1012
- }
1013
- default:
1014
- throw new errors_1.UsageError("bundle import requires add/list/rm/enable/disable/verify");
1015
- }
1019
+ throw new errors_1.UsageError("mdkg bundle import has been replaced by mdkg subgraph; run `mdkg upgrade --apply` to migrate legacy bundle_imports config");
1016
1020
  }
1017
1021
  case "create": {
1018
1022
  if (parsed.positionals.length > 2) {
@@ -1052,7 +1056,98 @@ function runBundleSubcommand(parsed, root) {
1052
1056
  return 0;
1053
1057
  }
1054
1058
  default:
1055
- throw new errors_1.UsageError("bundle requires create/list/show/verify/import");
1059
+ throw new errors_1.UsageError("bundle requires create/list/show/verify");
1060
+ }
1061
+ }
1062
+ function runSubgraphSubcommand(parsed, root) {
1063
+ const subcommand = (parsed.positionals[1] ?? "").toLowerCase();
1064
+ const json = parseBooleanFlag("--json", parsed.flags["--json"]);
1065
+ switch (subcommand) {
1066
+ case "add": {
1067
+ const alias = parsed.positionals[2];
1068
+ const bundlePath = parsed.positionals[3];
1069
+ if (!alias || !bundlePath || parsed.positionals.length > 4) {
1070
+ throw new errors_1.UsageError("subgraph add requires <alias> <bundle-path>");
1071
+ }
1072
+ const visibility = requireFlagValue("--visibility", parsed.flags["--visibility"]);
1073
+ const profile = requireFlagValue("--profile", parsed.flags["--pack-profile"]);
1074
+ const sourcePath = requireFlagValue("--source-path", parsed.flags["--source-path"]);
1075
+ const sourceRepo = requireFlagValue("--source-repo", parsed.flags["--source-repo"]);
1076
+ const maxStaleRaw = requireFlagValue("--max-stale-seconds", parsed.flags["--max-stale-seconds"]);
1077
+ const maxStaleSeconds = maxStaleRaw === undefined ? undefined : Number.parseInt(maxStaleRaw, 10);
1078
+ (0, subgraph_1.runSubgraphAddCommand)({
1079
+ root,
1080
+ alias,
1081
+ bundlePath,
1082
+ visibility,
1083
+ profile,
1084
+ sourcePath,
1085
+ sourceRepo,
1086
+ maxStaleSeconds,
1087
+ json,
1088
+ });
1089
+ return 0;
1090
+ }
1091
+ case "list": {
1092
+ if (parsed.positionals.length > 2) {
1093
+ throw new errors_1.UsageError("subgraph list does not accept positional arguments");
1094
+ }
1095
+ (0, subgraph_1.runSubgraphListCommand)({ root, json });
1096
+ return 0;
1097
+ }
1098
+ case "show": {
1099
+ const alias = parsed.positionals[2];
1100
+ if (!alias || parsed.positionals.length > 3) {
1101
+ throw new errors_1.UsageError("subgraph show requires <alias>");
1102
+ }
1103
+ (0, subgraph_1.runSubgraphShowCommand)({ root, alias, json });
1104
+ return 0;
1105
+ }
1106
+ case "rm":
1107
+ case "remove": {
1108
+ const alias = parsed.positionals[2];
1109
+ if (!alias || parsed.positionals.length > 3) {
1110
+ throw new errors_1.UsageError("subgraph rm requires <alias>");
1111
+ }
1112
+ (0, subgraph_1.runSubgraphRemoveCommand)({ root, alias, json });
1113
+ return 0;
1114
+ }
1115
+ case "enable": {
1116
+ const alias = parsed.positionals[2];
1117
+ if (!alias || parsed.positionals.length > 3) {
1118
+ throw new errors_1.UsageError("subgraph enable requires <alias>");
1119
+ }
1120
+ (0, subgraph_1.runSubgraphEnableCommand)({ root, alias, json });
1121
+ return 0;
1122
+ }
1123
+ case "disable": {
1124
+ const alias = parsed.positionals[2];
1125
+ if (!alias || parsed.positionals.length > 3) {
1126
+ throw new errors_1.UsageError("subgraph disable requires <alias>");
1127
+ }
1128
+ (0, subgraph_1.runSubgraphDisableCommand)({ root, alias, json });
1129
+ return 0;
1130
+ }
1131
+ case "verify": {
1132
+ if (parsed.positionals.length > 3) {
1133
+ throw new errors_1.UsageError("subgraph verify accepts at most one alias");
1134
+ }
1135
+ const alias = parsed.positionals[2];
1136
+ const all = parseBooleanFlag("--all", parsed.flags["--all"]);
1137
+ (0, subgraph_1.runSubgraphVerifyCommand)({ root, alias, all, json });
1138
+ return 0;
1139
+ }
1140
+ case "refresh": {
1141
+ if (parsed.positionals.length > 3) {
1142
+ throw new errors_1.UsageError("subgraph refresh accepts at most one alias");
1143
+ }
1144
+ const alias = parsed.positionals[2];
1145
+ const all = parseBooleanFlag("--all", parsed.flags["--all"]);
1146
+ (0, subgraph_1.runSubgraphRefreshCommand)({ root, alias, all, json });
1147
+ return 0;
1148
+ }
1149
+ default:
1150
+ throw new errors_1.UsageError("subgraph requires add/list/show/rm/enable/disable/verify/refresh");
1056
1151
  }
1057
1152
  }
1058
1153
  function runWorkSubcommand(parsed, root) {
@@ -1564,6 +1659,8 @@ function runCommand(parsed, root, runtime) {
1564
1659
  return runArchiveSubcommand(parsed, root);
1565
1660
  case "bundle":
1566
1661
  return runBundleSubcommand(parsed, root);
1662
+ case "subgraph":
1663
+ return runSubgraphSubcommand(parsed, root);
1567
1664
  case "work":
1568
1665
  return runWorkSubcommand(parsed, root);
1569
1666
  case "task":
@@ -3,10 +3,10 @@ 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.runArchiveAddCommand = runArchiveAddCommand;
7
6
  exports.runArchiveListCommand = runArchiveListCommand;
8
7
  exports.runArchiveShowCommand = runArchiveShowCommand;
9
8
  exports.runArchiveVerifyCommand = runArchiveVerifyCommand;
9
+ exports.runArchiveAddCommand = runArchiveAddCommand;
10
10
  exports.runArchiveCompressCommand = runArchiveCompressCommand;
11
11
  const fs_1 = __importDefault(require("fs"));
12
12
  const path_1 = __importDefault(require("path"));
@@ -15,11 +15,14 @@ const frontmatter_1 = require("../graph/frontmatter");
15
15
  const archive_integrity_1 = require("../graph/archive_integrity");
16
16
  const indexer_1 = require("../graph/indexer");
17
17
  const index_cache_1 = require("../graph/index_cache");
18
+ const reindex_1 = require("../graph/reindex");
18
19
  const visibility_1 = require("../graph/visibility");
19
20
  const date_1 = require("../util/date");
20
21
  const errors_1 = require("../util/errors");
21
22
  const id_1 = require("../util/id");
22
23
  const refs_1 = require("../util/refs");
24
+ const atomic_1 = require("../util/atomic");
25
+ const lock_1 = require("../util/lock");
23
26
  const zip_1 = require("../util/zip");
24
27
  const event_support_1 = require("./event_support");
25
28
  const ARCHIVE_KINDS = new Set(["source", "artifact"]);
@@ -124,8 +127,7 @@ function maybeReindex(root) {
124
127
  if (!config.index.auto_reindex) {
125
128
  return;
126
129
  }
127
- const outputPath = path_1.default.resolve(root, config.index.global_index_path);
128
- (0, index_cache_1.writeIndex)(outputPath, (0, indexer_1.buildIndex)(root, config, { tolerant: config.index.tolerant }));
130
+ (0, reindex_1.writeDerivedIndexes)(root, config, (0, indexer_1.buildIndex)(root, config, { tolerant: config.index.tolerant }));
129
131
  }
130
132
  function resolveArchiveNode(root, id, ws) {
131
133
  const config = (0, config_1.loadConfig)(root);
@@ -174,7 +176,7 @@ function stringAttribute(value) {
174
176
  function writeArchiveSidecar(sidecarPath, frontmatter, body) {
175
177
  const lines = (0, frontmatter_1.formatFrontmatter)(frontmatter);
176
178
  const content = ["---", ...lines, "---", body.trimStart()].join("\n");
177
- fs_1.default.writeFileSync(sidecarPath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
179
+ (0, atomic_1.atomicWriteFile)(sidecarPath, content.endsWith("\n") ? content : `${content}\n`);
178
180
  }
179
181
  function verifyArchiveSidecar(root, ws, sidecarPath) {
180
182
  const relativePath = toPosixPath(path_1.default.relative(root, sidecarPath));
@@ -276,7 +278,7 @@ function loadArchiveVerifyResults(options) {
276
278
  }
277
279
  return results;
278
280
  }
279
- function runArchiveAddCommand(options) {
281
+ function runArchiveAddCommandLocked(options) {
280
282
  const config = (0, config_1.loadConfig)(options.root);
281
283
  const ws = normalizeWorkspace(options.ws);
282
284
  const workspace = config.workspaces[ws];
@@ -311,7 +313,7 @@ function runArchiveAddCommand(options) {
311
313
  fs_1.default.copyFileSync(sourcePath, rawPath);
312
314
  const rawData = fs_1.default.readFileSync(rawPath);
313
315
  const zipData = (0, zip_1.createDeterministicZip)(basename, rawData);
314
- fs_1.default.writeFileSync(zipPath, zipData);
316
+ (0, atomic_1.atomicWriteFile)(zipPath, zipData);
315
317
  const frontmatter = {
316
318
  id,
317
319
  type: "archive",
@@ -423,7 +425,7 @@ function runArchiveVerifyCommand(options) {
423
425
  throw new errors_1.ValidationError("archive verification failed");
424
426
  }
425
427
  }
426
- function runArchiveCompressCommand(options) {
428
+ function runArchiveCompressCommandLocked(options) {
427
429
  if (!options.all && !options.id) {
428
430
  throw new errors_1.UsageError("archive compress requires <id-or-archive-uri> or --all");
429
431
  }
@@ -441,7 +443,7 @@ function runArchiveCompressCommand(options) {
441
443
  }
442
444
  const rawData = fs_1.default.readFileSync(rawPath);
443
445
  const zipData = (0, zip_1.createDeterministicZip)(path_1.default.basename(rawPath), rawData);
444
- fs_1.default.writeFileSync(zipPath, zipData);
446
+ (0, atomic_1.atomicWriteFile)(zipPath, zipData);
445
447
  const parsed = (0, frontmatter_1.parseFrontmatter)(fs_1.default.readFileSync(sidecarPath, "utf8"), sidecarPath);
446
448
  const nextFrontmatter = {
447
449
  ...parsed.frontmatter,
@@ -472,3 +474,13 @@ function runArchiveCompressCommand(options) {
472
474
  }
473
475
  console.log(`archive compressed: ${updated.length}`);
474
476
  }
477
+ function withArchiveLock(root, fn) {
478
+ const config = (0, config_1.loadConfig)(root);
479
+ return (0, lock_1.withMutationLock)(root, config.index.lock_timeout_ms, fn);
480
+ }
481
+ function runArchiveAddCommand(options) {
482
+ return withArchiveLock(options.root, () => runArchiveAddCommandLocked(options));
483
+ }
484
+ function runArchiveCompressCommand(options) {
485
+ return withArchiveLock(options.root, () => runArchiveCompressCommandLocked(options));
486
+ }