mdkg 0.1.3 → 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.
@@ -3,13 +3,13 @@ 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.resolveBundleImportsIndexPath = resolveBundleImportsIndexPath;
7
- exports.buildBundleImportsIndex = buildBundleImportsIndex;
8
- exports.writeBundleImportsIndex = writeBundleImportsIndex;
9
- exports.isBundleImportsIndexStale = isBundleImportsIndexStale;
10
- exports.mergeBundleImportsIntoIndex = mergeBundleImportsIntoIndex;
11
- exports.importWarnings = importWarnings;
12
- exports.buildImportedCapabilityRecords = buildImportedCapabilityRecords;
6
+ exports.resolveSubgraphsIndexPath = resolveSubgraphsIndexPath;
7
+ exports.buildSubgraphsIndex = buildSubgraphsIndex;
8
+ exports.writeSubgraphsIndex = writeSubgraphsIndex;
9
+ exports.isSubgraphsIndexStale = isSubgraphsIndexStale;
10
+ exports.mergeSubgraphsIntoIndex = mergeSubgraphsIntoIndex;
11
+ exports.subgraphWarnings = subgraphWarnings;
12
+ exports.buildSubgraphCapabilityRecords = buildSubgraphCapabilityRecords;
13
13
  const crypto_1 = __importDefault(require("crypto"));
14
14
  const fs_1 = __importDefault(require("fs"));
15
15
  const path_1 = __importDefault(require("path"));
@@ -17,7 +17,7 @@ const child_process_1 = require("child_process");
17
17
  const paths_1 = require("../core/paths");
18
18
  const atomic_1 = require("../util/atomic");
19
19
  const zip_1 = require("../util/zip");
20
- const IMPORTS_CACHE_VERSION = 1;
20
+ const SUBGRAPHS_CACHE_VERSION = 1;
21
21
  const MANIFEST_ENTRY = "manifest.json";
22
22
  const GLOBAL_INDEX_ENTRY = ".mdkg/index/global.json";
23
23
  const SKILLS_INDEX_ENTRY = ".mdkg/index/skills.json";
@@ -38,8 +38,8 @@ function readJsonEntry(entries, entryPath) {
38
38
  function readBundleEntries(bundlePath) {
39
39
  return new Map((0, zip_1.readZipEntries)(fs_1.default.readFileSync(bundlePath)).map((entry) => [entry.name, entry.data]));
40
40
  }
41
- function resolveBundlePath(root, entry) {
42
- return path_1.default.resolve(root, entry.path);
41
+ function resolveBundlePath(root, source) {
42
+ return path_1.default.resolve(root, source.path);
43
43
  }
44
44
  function gitOutput(cwd, args) {
45
45
  const result = (0, child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: "pipe" });
@@ -49,13 +49,13 @@ function gitOutput(cwd, args) {
49
49
  const output = result.stdout.trim();
50
50
  return output.length > 0 ? output : null;
51
51
  }
52
- function sourcePathState(root, entry, manifest, warnings, errors) {
53
- if (!entry.source_path) {
52
+ function sourcePathState(root, subgraph, manifest, warnings, errors) {
53
+ if (!subgraph.source_path) {
54
54
  return false;
55
55
  }
56
- const sourceRoot = path_1.default.resolve(root, entry.source_path);
56
+ const sourceRoot = path_1.default.resolve(root, subgraph.source_path);
57
57
  if (!fs_1.default.existsSync(sourceRoot)) {
58
- errors.push(`source_path does not exist: ${entry.source_path}`);
58
+ errors.push(`source_path does not exist: ${subgraph.source_path}`);
59
59
  return false;
60
60
  }
61
61
  const currentHead = gitOutput(sourceRoot, ["rev-parse", "HEAD"]);
@@ -66,20 +66,17 @@ function sourcePathState(root, entry, manifest, warnings, errors) {
66
66
  stale = true;
67
67
  }
68
68
  if (currentStatus) {
69
- warnings.push(`source_path has uncommitted changes: ${entry.source_path}`);
69
+ warnings.push(`source_path has uncommitted changes: ${subgraph.source_path}`);
70
70
  stale = true;
71
71
  }
72
72
  return stale;
73
73
  }
74
- function ageState(bundlePath, entry, warnings) {
75
- if (entry.max_stale_seconds === undefined) {
76
- return false;
77
- }
74
+ function ageState(bundlePath, maxStaleSeconds, warnings) {
78
75
  const ageSeconds = Math.floor((Date.now() - fs_1.default.statSync(bundlePath).mtimeMs) / 1000);
79
- if (ageSeconds <= entry.max_stale_seconds) {
76
+ if (ageSeconds <= maxStaleSeconds) {
80
77
  return false;
81
78
  }
82
- warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${entry.max_stale_seconds}`);
79
+ warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${maxStaleSeconds}`);
83
80
  return true;
84
81
  }
85
82
  function remapTarget(target, qidMap) {
@@ -131,72 +128,147 @@ function entryHashErrors(entries, manifest) {
131
128
  }
132
129
  return errors;
133
130
  }
134
- function projectOneImport(root, alias, entry) {
135
- const bundlePath = resolveBundlePath(root, entry);
131
+ function projectOneSource(root, subgraph, source) {
132
+ const bundlePath = resolveBundlePath(root, source);
136
133
  const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
137
134
  const warnings = [];
138
135
  const errors = [];
139
- const nodes = {};
140
- const reverse_edges = {};
141
136
  let manifest;
142
- let sourceIndex;
137
+ let index;
138
+ let entries;
143
139
  let stale = false;
144
- if (!entry.enabled) {
140
+ if (!source.enabled) {
145
141
  return {
146
- health: {
147
- alias,
148
- path: entry.path,
142
+ source,
143
+ relativeBundlePath,
144
+ sourceHealth: {
145
+ label: source.label,
146
+ path: source.path,
149
147
  enabled: false,
150
- visibility: entry.visibility,
151
- expected_profile: entry.expected_profile,
148
+ expected_profile: source.expected_profile,
152
149
  stale: false,
153
150
  warning_count: 0,
154
151
  error_count: 0,
155
152
  warnings: [],
156
153
  errors: [],
157
154
  },
158
- nodes,
159
- reverse_edges,
160
155
  };
161
156
  }
162
157
  try {
163
158
  if (!fs_1.default.existsSync(bundlePath)) {
164
- throw new Error(`bundle not found: ${entry.path}`);
159
+ throw new Error(`bundle not found: ${source.path}`);
165
160
  }
166
- const entries = readBundleEntries(bundlePath);
161
+ entries = readBundleEntries(bundlePath);
167
162
  manifest = readJsonEntry(entries, MANIFEST_ENTRY);
168
- sourceIndex = readJsonEntry(entries, GLOBAL_INDEX_ENTRY);
163
+ index = readJsonEntry(entries, GLOBAL_INDEX_ENTRY);
169
164
  readJsonEntry(entries, SKILLS_INDEX_ENTRY);
170
165
  readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
171
166
  errors.push(...entryHashErrors(entries, manifest));
172
- if (manifest.profile !== entry.expected_profile) {
173
- errors.push(`expected ${entry.expected_profile} bundle but found ${manifest.profile}`);
167
+ if (manifest.profile !== source.expected_profile) {
168
+ errors.push(`expected ${source.expected_profile} bundle but found ${manifest.profile}`);
174
169
  }
175
- stale = sourcePathState(root, entry, manifest, warnings, errors) || stale;
176
- stale = ageState(bundlePath, entry, warnings) || stale;
177
- const idOwners = new Map();
178
- for (const node of Object.values(sourceIndex.nodes)) {
170
+ stale = sourcePathState(root, subgraph, manifest, warnings, errors) || stale;
171
+ stale = ageState(bundlePath, subgraph.max_stale_seconds, warnings) || stale;
172
+ }
173
+ catch (err) {
174
+ errors.push(err instanceof Error ? err.message : String(err));
175
+ }
176
+ return {
177
+ source,
178
+ relativeBundlePath,
179
+ manifest,
180
+ index,
181
+ entries,
182
+ sourceHealth: {
183
+ label: source.label,
184
+ path: source.path,
185
+ enabled: source.enabled,
186
+ expected_profile: source.expected_profile,
187
+ profile: manifest?.profile,
188
+ bundle_hash: manifest?.bundle_hash,
189
+ source_git_head: manifest?.source?.git_head ?? null,
190
+ stale,
191
+ warning_count: warnings.length,
192
+ error_count: errors.length,
193
+ warnings,
194
+ errors,
195
+ },
196
+ };
197
+ }
198
+ function projectOneSubgraph(root, alias, subgraph) {
199
+ const nodes = {};
200
+ const reverse_edges = {};
201
+ if (!subgraph.enabled) {
202
+ return {
203
+ health: {
204
+ alias,
205
+ enabled: false,
206
+ visibility: subgraph.visibility,
207
+ permissions: subgraph.permissions,
208
+ source_path: subgraph.source_path,
209
+ source_repo: subgraph.source_repo,
210
+ stale: false,
211
+ warning_count: 0,
212
+ error_count: 0,
213
+ warnings: [],
214
+ errors: [],
215
+ sources: subgraph.sources.map((source) => ({
216
+ label: source.label,
217
+ path: source.path,
218
+ enabled: source.enabled,
219
+ expected_profile: source.expected_profile,
220
+ stale: false,
221
+ warning_count: 0,
222
+ error_count: 0,
223
+ warnings: [],
224
+ errors: [],
225
+ })),
226
+ },
227
+ nodes,
228
+ reverse_edges,
229
+ };
230
+ }
231
+ const loadedSources = subgraph.sources.map((source) => projectOneSource(root, subgraph, source));
232
+ const warnings = loadedSources.flatMap((item) => item.sourceHealth.warnings);
233
+ const errors = loadedSources.flatMap((item) => item.sourceHealth.errors);
234
+ const stale = loadedSources.some((item) => item.sourceHealth.stale);
235
+ const idOwners = new Map();
236
+ for (const loaded of loadedSources) {
237
+ if (!loaded.source.enabled || loaded.sourceHealth.error_count > 0 || !loaded.index) {
238
+ continue;
239
+ }
240
+ for (const node of Object.values(loaded.index.nodes)) {
179
241
  const owners = idOwners.get(node.id) ?? [];
180
- owners.push(node.qid);
242
+ owners.push(`${loaded.source.label ?? loaded.source.path}:${node.qid}`);
181
243
  idOwners.set(node.id, owners);
182
244
  }
183
- for (const [id, owners] of idOwners.entries()) {
184
- if (owners.length > 1) {
185
- errors.push(`duplicate projected id ${id} from ${owners.join(", ")}; create per-workspace bundles or use portable unique ids`);
186
- }
245
+ }
246
+ for (const [id, owners] of idOwners.entries()) {
247
+ if (owners.length > 1) {
248
+ errors.push(`duplicate projected id ${id} from ${owners.join(", ")}; split sources into separate subgraphs or use portable unique ids`);
187
249
  }
188
- if (errors.length === 0) {
189
- const qidMap = new Map();
190
- for (const node of Object.values(sourceIndex.nodes)) {
250
+ }
251
+ if (errors.length === 0) {
252
+ const qidMap = new Map();
253
+ for (const loaded of loadedSources) {
254
+ if (!loaded.source.enabled || !loaded.index) {
255
+ continue;
256
+ }
257
+ for (const node of Object.values(loaded.index.nodes)) {
191
258
  qidMap.set(node.qid, `${alias}:${node.id}`);
192
259
  }
193
- for (const node of Object.values(sourceIndex.nodes)) {
260
+ }
261
+ for (const loaded of loadedSources) {
262
+ if (!loaded.source.enabled || !loaded.index) {
263
+ continue;
264
+ }
265
+ for (const node of Object.values(loaded.index.nodes)) {
194
266
  const projectedQid = qidMap.get(node.qid);
195
267
  const projected = {
196
268
  ...node,
197
269
  ws: alias,
198
270
  qid: projectedQid,
199
- path: `${relativeBundlePath}#${toPosixPath(node.path)}`,
271
+ path: `${loaded.relativeBundlePath}#${toPosixPath(node.path)}`,
200
272
  attributes: { ...(node.attributes ?? {}) },
201
273
  edges: {
202
274
  epic: remapTarget(node.edges.epic, qidMap),
@@ -210,18 +282,19 @@ function projectOneImport(root, alias, entry) {
210
282
  source: {
211
283
  imported: true,
212
284
  read_only: true,
213
- import_alias: alias,
285
+ subgraph_alias: alias,
214
286
  original_qid: node.qid,
215
287
  original_ws: node.ws,
216
288
  original_path: toPosixPath(node.path),
217
- bundle_path: relativeBundlePath,
218
- bundle_hash: manifest.bundle_hash,
219
- profile: manifest.profile,
220
- visibility: entry.visibility,
289
+ bundle_path: loaded.relativeBundlePath,
290
+ bundle_hash: loaded.manifest?.bundle_hash,
291
+ profile: loaded.manifest?.profile,
292
+ visibility: subgraph.visibility,
293
+ permissions: subgraph.permissions,
221
294
  stale,
222
295
  warnings: [...warnings],
223
- source_repo: entry.source_repo ?? manifest.source?.repo,
224
- source_git_head: manifest.source?.git_head ?? null,
296
+ source_repo: subgraph.source_repo ?? loaded.manifest?.source?.repo,
297
+ source_git_head: loaded.manifest?.source?.git_head ?? null,
225
298
  },
226
299
  };
227
300
  nodes[projected.qid] = projected;
@@ -229,46 +302,41 @@ function projectOneImport(root, alias, entry) {
229
302
  }
230
303
  }
231
304
  }
232
- catch (err) {
233
- errors.push(err instanceof Error ? err.message : String(err));
234
- }
235
305
  return {
236
306
  health: {
237
307
  alias,
238
- path: entry.path,
239
- enabled: entry.enabled,
240
- visibility: entry.visibility,
241
- expected_profile: entry.expected_profile,
242
- profile: manifest?.profile,
243
- bundle_hash: manifest?.bundle_hash,
244
- source_git_head: manifest?.source?.git_head ?? null,
245
- source_repo: entry.source_repo ?? manifest?.source?.repo,
308
+ enabled: subgraph.enabled,
309
+ visibility: subgraph.visibility,
310
+ permissions: subgraph.permissions,
311
+ source_path: subgraph.source_path,
312
+ source_repo: subgraph.source_repo,
246
313
  stale,
247
314
  warning_count: warnings.length,
248
315
  error_count: errors.length,
249
316
  warnings,
250
317
  errors,
318
+ sources: loadedSources.map((item) => item.sourceHealth),
251
319
  },
252
320
  nodes,
253
321
  reverse_edges,
254
322
  };
255
323
  }
256
- function resolveBundleImportsIndexPath(root) {
257
- return path_1.default.resolve(root, ".mdkg", "index", "imports.json");
324
+ function resolveSubgraphsIndexPath(root) {
325
+ return path_1.default.resolve(root, ".mdkg", "index", "subgraphs.json");
258
326
  }
259
- function buildBundleImportsIndex(root, config) {
260
- const imports = [];
327
+ function buildSubgraphsIndex(root, config) {
328
+ const subgraphs = [];
261
329
  const nodes = {};
262
330
  const reverse_edges = {};
263
331
  const workspaces = {};
264
- for (const alias of Object.keys(config.bundle_imports).sort()) {
265
- const entry = config.bundle_imports[alias];
266
- const projected = projectOneImport(root, alias, entry);
267
- imports.push(projected.health);
268
- if (!entry.enabled || projected.health.error_count > 0) {
332
+ for (const alias of Object.keys(config.subgraphs).sort()) {
333
+ const subgraph = config.subgraphs[alias];
334
+ const projected = projectOneSubgraph(root, alias, subgraph);
335
+ subgraphs.push(projected.health);
336
+ if (!subgraph.enabled || projected.health.error_count > 0) {
269
337
  continue;
270
338
  }
271
- workspaces[alias] = { path: `bundle:${entry.path}`, enabled: true };
339
+ workspaces[alias] = { path: `subgraph:${alias}`, enabled: true };
272
340
  Object.assign(nodes, projected.nodes);
273
341
  for (const [edgeKey, targets] of Object.entries(projected.reverse_edges)) {
274
342
  reverse_edges[edgeKey] = reverse_edges[edgeKey] ?? {};
@@ -285,44 +353,46 @@ function buildBundleImportsIndex(root, config) {
285
353
  meta: {
286
354
  tool: config.tool,
287
355
  schema_version: config.schema_version,
288
- cache_version: IMPORTS_CACHE_VERSION,
356
+ cache_version: SUBGRAPHS_CACHE_VERSION,
289
357
  generated_at: new Date().toISOString(),
290
358
  root,
291
- import_count: imports.length,
359
+ subgraph_count: subgraphs.length,
292
360
  node_count: Object.keys(nodes).length,
293
361
  },
294
- imports,
362
+ subgraphs,
295
363
  nodes,
296
364
  reverse_edges,
297
365
  },
298
366
  workspaces,
299
367
  };
300
368
  }
301
- function writeBundleImportsIndex(indexPath, index) {
369
+ function writeSubgraphsIndex(indexPath, index) {
302
370
  (0, atomic_1.atomicWriteFile)(indexPath, JSON.stringify(index, null, 2));
303
371
  }
304
- function isBundleImportsIndexStale(root, config) {
305
- const indexPath = resolveBundleImportsIndexPath(root);
372
+ function isSubgraphsIndexStale(root, config) {
373
+ const indexPath = resolveSubgraphsIndexPath(root);
306
374
  if (!fs_1.default.existsSync(indexPath)) {
307
- return Object.keys(config.bundle_imports).length > 0;
375
+ return Object.keys(config.subgraphs).length > 0;
308
376
  }
309
377
  const indexMtime = fs_1.default.statSync(indexPath).mtimeMs;
310
378
  const cfgPath = (0, paths_1.configPath)(root);
311
379
  if (fs_1.default.existsSync(cfgPath) && fs_1.default.statSync(cfgPath).mtimeMs > indexMtime) {
312
380
  return true;
313
381
  }
314
- for (const entry of Object.values(config.bundle_imports)) {
315
- const bundlePath = path_1.default.resolve(root, entry.path);
316
- if (!fs_1.default.existsSync(bundlePath)) {
317
- return true;
318
- }
319
- if (fs_1.default.statSync(bundlePath).mtimeMs > indexMtime) {
320
- return true;
382
+ for (const subgraph of Object.values(config.subgraphs)) {
383
+ for (const source of subgraph.sources) {
384
+ const bundlePath = path_1.default.resolve(root, source.path);
385
+ if (!fs_1.default.existsSync(bundlePath)) {
386
+ return true;
387
+ }
388
+ if (fs_1.default.statSync(bundlePath).mtimeMs > indexMtime) {
389
+ return true;
390
+ }
321
391
  }
322
392
  }
323
393
  return false;
324
394
  }
325
- function mergeBundleImportsIntoIndex(base, projection) {
395
+ function mergeSubgraphsIntoIndex(base, projection) {
326
396
  const nodes = { ...base.nodes, ...projection.index.nodes };
327
397
  const reverse_edges = JSON.parse(JSON.stringify(base.reverse_edges));
328
398
  for (const [edgeKey, targets] of Object.entries(projection.index.reverse_edges)) {
@@ -348,70 +418,74 @@ function mergeBundleImportsIntoIndex(base, projection) {
348
418
  reverse_edges,
349
419
  };
350
420
  }
351
- function importWarnings(projection) {
421
+ function subgraphWarnings(projection) {
352
422
  const warnings = [];
353
- for (const item of projection.index.imports) {
423
+ for (const item of projection.index.subgraphs) {
354
424
  for (const warning of item.warnings) {
355
- warnings.push(`bundle import ${item.alias}: ${warning}`);
425
+ warnings.push(`subgraph ${item.alias}: ${warning}`);
356
426
  }
357
427
  for (const error of item.errors) {
358
- warnings.push(`bundle import ${item.alias}: ${error}`);
428
+ warnings.push(`subgraph ${item.alias}: ${error}`);
359
429
  }
360
430
  }
361
431
  return warnings;
362
432
  }
363
- function buildImportedCapabilityRecords(root, config) {
433
+ function buildSubgraphCapabilityRecords(root, config) {
364
434
  const records = [];
365
435
  const warnings = [];
366
- for (const alias of Object.keys(config.bundle_imports).sort()) {
367
- const entry = config.bundle_imports[alias];
368
- if (!entry.enabled) {
436
+ for (const alias of Object.keys(config.subgraphs).sort()) {
437
+ const subgraph = config.subgraphs[alias];
438
+ if (!subgraph.enabled) {
369
439
  continue;
370
440
  }
371
- const projection = projectOneImport(root, alias, entry);
441
+ const projection = projectOneSubgraph(root, alias, subgraph);
372
442
  for (const warning of projection.health.warnings) {
373
- warnings.push(`bundle import ${alias}: ${warning}`);
443
+ warnings.push(`subgraph ${alias}: ${warning}`);
374
444
  }
375
445
  for (const error of projection.health.errors) {
376
- warnings.push(`bundle import ${alias}: ${error}`);
446
+ warnings.push(`subgraph ${alias}: ${error}`);
377
447
  }
378
448
  if (projection.health.error_count > 0) {
379
449
  continue;
380
450
  }
381
- try {
382
- const bundlePath = resolveBundlePath(root, entry);
383
- const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
384
- const entries = readBundleEntries(bundlePath);
385
- const capabilities = readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
386
- for (const record of capabilities.records ?? []) {
387
- const id = String(record.id ?? "");
388
- const originalQid = String(record.qid ?? id);
389
- const originalWorkspace = String(record.workspace ?? "");
390
- const originalPath = String(record.path ?? "");
391
- records.push({
392
- ...record,
393
- workspace: alias,
394
- visibility: entry.visibility,
395
- qid: `${alias}:${id}`,
396
- path: `${relativeBundlePath}#${originalPath}`,
397
- source: {
398
- imported: true,
399
- read_only: true,
400
- import_alias: alias,
401
- original_qid: originalQid,
402
- original_workspace: originalWorkspace,
403
- original_path: originalPath,
404
- bundle_path: relativeBundlePath,
405
- bundle_hash: projection.health.bundle_hash,
406
- profile: projection.health.profile,
407
- stale: projection.health.stale,
408
- warnings: [...projection.health.warnings],
409
- },
410
- });
451
+ for (const source of subgraph.sources) {
452
+ if (!source.enabled) {
453
+ continue;
454
+ }
455
+ try {
456
+ const bundlePath = resolveBundlePath(root, source);
457
+ const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
458
+ const entries = readBundleEntries(bundlePath);
459
+ const capabilities = readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
460
+ for (const record of capabilities.records ?? []) {
461
+ const id = String(record.id ?? "");
462
+ const originalQid = String(record.qid ?? id);
463
+ const originalWorkspace = String(record.workspace ?? "");
464
+ const originalPath = String(record.path ?? "");
465
+ records.push({
466
+ ...record,
467
+ workspace: alias,
468
+ visibility: subgraph.visibility,
469
+ qid: `${alias}:${id}`,
470
+ path: `${relativeBundlePath}#${originalPath}`,
471
+ source: {
472
+ imported: true,
473
+ read_only: true,
474
+ subgraph_alias: alias,
475
+ original_qid: originalQid,
476
+ original_workspace: originalWorkspace,
477
+ original_path: originalPath,
478
+ bundle_path: relativeBundlePath,
479
+ stale: projection.health.stale,
480
+ permissions: subgraph.permissions,
481
+ warnings: [...projection.health.warnings],
482
+ },
483
+ });
484
+ }
485
+ }
486
+ catch (err) {
487
+ warnings.push(`subgraph ${alias}: ${err instanceof Error ? err.message : String(err)}`);
411
488
  }
412
- }
413
- catch (err) {
414
- warnings.push(`bundle import ${alias}: ${err instanceof Error ? err.message : String(err)}`);
415
489
  }
416
490
  }
417
491
  return { records, warnings };
@@ -45,9 +45,9 @@ function effectiveNodeVisibility(node, config) {
45
45
  if (isVisibility(workspaceVisibility)) {
46
46
  return workspaceVisibility;
47
47
  }
48
- const importVisibility = config.bundle_imports[node.ws]?.visibility;
49
- if (isVisibility(importVisibility)) {
50
- return importVisibility;
48
+ const subgraphVisibility = config.subgraphs[node.ws]?.visibility;
49
+ if (isVisibility(subgraphVisibility)) {
50
+ return subgraphVisibility;
51
51
  }
52
52
  return "private";
53
53
  }
@@ -31,7 +31,8 @@ Agent operating prompt:
31
31
  - Treat work contracts, orders, and receipts as committed semantic mirrors only; never store raw secrets, credentials, live payment state, ledger mutations, or canonical marketplace state in mdkg.
32
32
  - Use `artifact://...` for external/runtime-managed artifacts and `archive://...` for committed mdkg archive sidecars.
33
33
  - Use `mdkg bundle create/list/show/verify` for explicit full `.mdkg` graph snapshot bundles.
34
- - Use `mdkg bundle import add/list/verify` to register child bundle snapshots as read-only planning context.
34
+ - Use `mdkg subgraph add/list/verify` to register child bundle snapshots as read-only planning context.
35
+ - Use `mdkg capability resolve` to rank local and subgraph capabilities for orchestration planning.
35
36
  - Use `mdkg pack <id> --visibility public|internal` only when you need a public-safe or internal-safe pack; no flag remains private-capable local behavior.
36
37
  - Mark archive sidecars public only with explicit `mdkg archive add --visibility public` intent.
37
38
  - Treat sidecar `.md` plus deterministic `.zip` caches as the commit-eligible archive record; validation and `mdkg archive verify` both check ZIP payload integrity.
@@ -92,6 +92,7 @@ Capability discovery:
92
92
  - `mdkg capability list [--kind <skill|spec|work|core|design>] [--visibility <private|internal|public>] [--json]`
93
93
  - `mdkg capability search "<query>" [--kind <kind>] [--visibility <level>] [--json]`
94
94
  - `mdkg capability show <id-or-qid-or-slug> [--json]`
95
+ - `mdkg capability resolve [query] [--requires <capability>] [--fresh-only] [--json]`
95
96
  - capability records are deterministic cache projections from Markdown
96
97
  - records include source hash, headings, refs, and `indexed_at`
97
98
  - normal task, epic, feat, bug, test, and checkpoint nodes are intentionally excluded
@@ -114,16 +115,24 @@ Graph snapshot bundles:
114
115
  - `mdkg bundle verify [bundle-path] [--json]`
115
116
  - `mdkg bundle show <bundle-path> [--json]`
116
117
  - `mdkg bundle list [--json]`
117
- - `mdkg bundle import add/list/rm/enable/disable/verify ...`
118
- - `mdkg bundle import add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--json]`
119
- - `mdkg bundle import verify [alias|--all] [--json]`
120
118
  - default output is `.mdkg/bundles/<profile>/<workspace-or-all>.mdkg.zip`
121
119
  - private bundles are explicit local graph transport artifacts
122
- - bundle imports are read-only planning views and use import-alias qids such as `child_repo:task-1`
123
120
  - repos that track archive caches or bundles should run `mdkg archive compress --all`, `mdkg archive verify --json`, `mdkg bundle create --profile private`, and `mdkg bundle verify .mdkg/bundles/private/all.mdkg.zip` before commit
124
121
  - public bundles include only public workspace content and public archive sidecars
125
- - public bundle creation fails when public records reference private graph, archive, or imported records
126
- - public/internal imports require public bundle profiles
122
+ - public bundle creation fails when public records reference private graph, archive, or subgraph records
123
+
124
+ Subgraph orchestration:
125
+ - `mdkg subgraph add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--json]`
126
+ - `mdkg subgraph list [--json]`
127
+ - `mdkg subgraph show <alias> [--json]`
128
+ - `mdkg subgraph rm <alias> [--json]`
129
+ - `mdkg subgraph enable <alias> [--json]`
130
+ - `mdkg subgraph disable <alias> [--json]`
131
+ - `mdkg subgraph verify [alias|--all] [--json]`
132
+ - `mdkg subgraph refresh [alias|--all] [--json]`
133
+ - subgraphs are read-only planning views and use subgraph-alias qids such as `child_repo:task-1`
134
+ - subgraph refresh reloads configured bundle sources only and never mutates child repos
135
+ - public/internal subgraphs require public bundle profiles
127
136
 
128
137
  Work semantic mirrors:
129
138
  - `mdkg work contract new "<title>" --id <work.id> --agent-id <agent.id> --kind <kind> --inputs <...> --outputs <...> [--required-capabilities <...>] [--pricing-model <...>] [--json]`
@@ -135,7 +144,7 @@ Work semantic mirrors:
135
144
  - work commands mutate mdkg semantic mirror files only; production order, receipt, feedback, dispute, payment, ledger, marketplace inventory, fulfillment, and execution state remains canonical outside mdkg
136
145
  - do not store raw secrets, credentials, live payment state, ledger mutations, or canonical marketplace state in work mirrors
137
146
  - `artifact://...` refs identify external/runtime-managed artifacts; `archive://...` refs identify committed mdkg archive sidecars
138
- - work update and artifact commands accept local ids or local qids; imported bundle qids are read-only and must be changed in their source workspace
147
+ - work update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace
139
148
 
140
149
  Discovery/show export flags:
141
150
  - `--json`
@@ -26,11 +26,11 @@ mdkg pack <id>
26
26
  mdkg capability search "..."
27
27
  mdkg archive list
28
28
  mdkg bundle create --profile private
29
- mdkg bundle import list --json
29
+ mdkg subgraph list --json
30
30
  mdkg validate
31
31
  ```
32
32
 
33
- This repo is already initialized. Use `mdkg upgrade` to preview safe scaffold updates, `mdkg new` to create work, `mdkg search`/`mdkg show` to inspect graph state, `mdkg capability ...` to inspect cached skill/spec/work/core/design capabilities, `mdkg archive ...` to register source/artifact sidecars, `mdkg work ...` to create work contract/order/receipt semantic mirrors, `mdkg bundle ...` to create full graph snapshot bundles and read-only child graph imports, `mdkg pack <id>` to build deterministic context, and `mdkg validate` before closeout.
33
+ This repo is already initialized. Use `mdkg upgrade` to preview safe scaffold updates, `mdkg new` to create work, `mdkg search`/`mdkg show` to inspect graph state, `mdkg capability ...` to inspect cached skill/spec/work/core/design capabilities, `mdkg capability resolve ...` to rank local and subgraph capabilities, `mdkg archive ...` to register source/artifact sidecars, `mdkg work ...` to create work contract/order/receipt semantic mirrors, `mdkg bundle ...` to create full graph snapshot bundles, `mdkg subgraph ...` to register read-only child graph planning views, `mdkg pack <id>` to build deterministic context, and `mdkg validate` before closeout.
34
34
 
35
35
  Agent workflow docs can use semantic ids:
36
36
 
@@ -87,16 +87,17 @@ mdkg bundle create --profile private
87
87
  mdkg bundle verify .mdkg/bundles/private/all.mdkg.zip
88
88
  ```
89
89
 
90
- Use this as a pre-commit recommendation only when the repo tracks archive caches or `.mdkg/bundles/`. Private bundles are local graph transport artifacts and may be tracked in private repos when configured. Public bundles require selected workspaces with `visibility: public` and fail closed when public records reference private graph, archive, or imported records.
90
+ Use this as a pre-commit recommendation only when the repo tracks archive caches or `.mdkg/bundles/`. Private bundles are local graph transport artifacts and may be tracked in private repos when configured. Public bundles require selected workspaces with `visibility: public` and fail closed when public records reference private graph, archive, or subgraph records.
91
91
 
92
- Register child bundle snapshots as read-only imports with:
92
+ Register child bundle snapshots as read-only subgraphs with:
93
93
 
94
94
  ```bash
95
- mdkg bundle import add child_repo child-repo/.mdkg/bundles/private/all.mdkg.zip --source-path child-repo
96
- mdkg bundle import verify child_repo --json
95
+ mdkg subgraph add child_repo child-repo/.mdkg/bundles/private/all.mdkg.zip --source-path child-repo
96
+ mdkg capability resolve "child capability" --json
97
+ mdkg subgraph verify child_repo --json
97
98
  ```
98
99
 
99
- Imported nodes use the import alias as their qid prefix and can be inspected or packed, but mutations must happen in the owning child repo.
100
+ Subgraph nodes use the subgraph alias as their qid prefix and can be inspected or packed, but mutations must happen in the owning child repo.
100
101
 
101
102
  ## Archive and Work Mirrors
102
103
 
@@ -118,7 +119,7 @@ mdkg work receipt new "example receipt" --id receipt.example-1 --work-order-id o
118
119
  ```
119
120
 
120
121
  Receipt statuses are `recorded`, `verified`, `rejected`, and `superseded`.
121
- Update and artifact commands accept local ids or local qids; imported bundle qids are read-only and must be changed in their source workspace.
122
+ Update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace.
122
123
 
123
124
  Production orders, receipts, feedback, disputes, payments, ledgers, marketplace inventory, fulfillment records, and execution state remain canonical outside mdkg. mdkg stores committed semantic mirrors and reviewable evidence. Do not store raw secrets, credentials, live payment state, ledger mutations, canonical marketplace state, or bulky raw payloads in these mirrors.
124
125