mdkg 0.1.1 → 0.1.3

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 (73) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +124 -18
  3. package/dist/cli.js +567 -15
  4. package/dist/commands/archive.js +486 -0
  5. package/dist/commands/bundle.js +743 -0
  6. package/dist/commands/bundle_import.js +255 -0
  7. package/dist/commands/capability.js +162 -0
  8. package/dist/commands/checkpoint.js +31 -5
  9. package/dist/commands/doctor.js +269 -9
  10. package/dist/commands/format.js +38 -9
  11. package/dist/commands/index.js +12 -12
  12. package/dist/commands/init.js +194 -63
  13. package/dist/commands/init_manifest.js +19 -6
  14. package/dist/commands/list.js +5 -2
  15. package/dist/commands/new.js +36 -7
  16. package/dist/commands/next.js +7 -0
  17. package/dist/commands/node_card.js +4 -1
  18. package/dist/commands/pack.js +62 -2
  19. package/dist/commands/query_output.js +1 -0
  20. package/dist/commands/search.js +5 -2
  21. package/dist/commands/show.js +7 -14
  22. package/dist/commands/skill_mirror.js +22 -0
  23. package/dist/commands/task.js +23 -6
  24. package/dist/commands/upgrade.js +24 -1
  25. package/dist/commands/validate.js +20 -1
  26. package/dist/commands/work.js +397 -0
  27. package/dist/commands/workspace.js +12 -2
  28. package/dist/core/config.js +115 -1
  29. package/dist/graph/agent_file_types.js +78 -5
  30. package/dist/graph/archive_file.js +125 -0
  31. package/dist/graph/archive_integrity.js +66 -0
  32. package/dist/graph/bundle_imports.js +418 -0
  33. package/dist/graph/capabilities_index_cache.js +103 -0
  34. package/dist/graph/capabilities_indexer.js +231 -0
  35. package/dist/graph/frontmatter.js +19 -0
  36. package/dist/graph/index_cache.js +23 -6
  37. package/dist/graph/indexer.js +4 -1
  38. package/dist/graph/node.js +23 -4
  39. package/dist/graph/node_body.js +37 -0
  40. package/dist/graph/reindex.js +46 -0
  41. package/dist/graph/skills_index_cache.js +2 -2
  42. package/dist/graph/skills_indexer.js +8 -3
  43. package/dist/graph/sqlite_index.js +293 -0
  44. package/dist/graph/validate_graph.js +83 -7
  45. package/dist/graph/visibility.js +214 -0
  46. package/dist/graph/workspace_files.js +22 -0
  47. package/dist/init/AGENT_START.md +24 -0
  48. package/dist/init/CLI_COMMAND_MATRIX.md +61 -3
  49. package/dist/init/README.md +70 -4
  50. package/dist/init/config.json +18 -2
  51. package/dist/init/core/guide.md +6 -2
  52. package/dist/init/core/rule-1-mdkg-conventions.md +2 -1
  53. package/dist/init/core/rule-3-cli-contract.md +72 -4
  54. package/dist/init/core/rule-4-repo-safety-and-ignores.md +47 -11
  55. package/dist/init/core/rule-5-release-and-versioning.md +4 -3
  56. package/dist/init/core/rule-6-templates-and-schemas.md +7 -0
  57. package/dist/init/init-manifest.json +21 -16
  58. package/dist/init/skills/default/build-pack-and-execute-task/SKILL.md +2 -1
  59. package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +26 -0
  60. package/dist/init/templates/default/archive.md +33 -0
  61. package/dist/init/templates/default/receipt.md +15 -1
  62. package/dist/init/templates/default/work.md +6 -1
  63. package/dist/init/templates/default/work_order.md +15 -1
  64. package/dist/pack/export_md.js +3 -0
  65. package/dist/pack/export_xml.js +3 -0
  66. package/dist/pack/order.js +1 -0
  67. package/dist/pack/pack.js +3 -13
  68. package/dist/util/argparse.js +30 -0
  69. package/dist/util/atomic.js +44 -0
  70. package/dist/util/lock.js +72 -0
  71. package/dist/util/refs.js +40 -0
  72. package/dist/util/zip.js +153 -0
  73. package/package.json +14 -5
@@ -7,6 +7,7 @@ exports.runInitCommand = runInitCommand;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const config_1 = require("../core/config");
10
+ const migrate_1 = require("../core/migrate");
10
11
  const errors_1 = require("../util/errors");
11
12
  const date_1 = require("../util/date");
12
13
  const version_1 = require("../core/version");
@@ -39,16 +40,28 @@ function listFiles(dir) {
39
40
  }
40
41
  return files;
41
42
  }
42
- function copySeedFile(src, dest, force, stats) {
43
+ function displayPath(root, filePath) {
44
+ const relPath = path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
45
+ return relPath.length > 0 ? relPath : ".";
46
+ }
47
+ function recordCreated(root, dest, stats) {
48
+ stats.created += 1;
49
+ stats.createdPaths.push(displayPath(root, dest));
50
+ }
51
+ function recordSkipped(root, dest, stats) {
52
+ stats.skipped += 1;
53
+ stats.skippedPaths.push(displayPath(root, dest));
54
+ }
55
+ function copySeedFile(root, src, dest, force, stats) {
43
56
  if (fs_1.default.existsSync(dest) && !force) {
44
- stats.skipped += 1;
57
+ recordSkipped(root, dest, stats);
45
58
  return;
46
59
  }
47
60
  fs_1.default.mkdirSync(path_1.default.dirname(dest), { recursive: true });
48
61
  fs_1.default.copyFileSync(src, dest);
49
- stats.created += 1;
62
+ recordCreated(root, dest, stats);
50
63
  }
51
- function copySeedDir(srcDir, destDir, force, stats) {
64
+ function copySeedDir(root, srcDir, destDir, force, stats) {
52
65
  if (!fs_1.default.existsSync(srcDir)) {
53
66
  return;
54
67
  }
@@ -56,7 +69,7 @@ function copySeedDir(srcDir, destDir, force, stats) {
56
69
  for (const filePath of files) {
57
70
  const relPath = path_1.default.relative(srcDir, filePath);
58
71
  const destPath = path_1.default.join(destDir, relPath);
59
- copySeedFile(filePath, destPath, force, stats);
72
+ copySeedFile(root, filePath, destPath, force, stats);
60
73
  }
61
74
  }
62
75
  function appendIgnoreEntries(filePath, entries) {
@@ -73,14 +86,14 @@ function appendIgnoreEntries(filePath, entries) {
73
86
  fs_1.default.writeFileSync(filePath, updated, "utf8");
74
87
  return true;
75
88
  }
76
- function writeFileIfMissing(filePath, content, force, stats) {
89
+ function writeFileIfMissing(root, filePath, content, force, stats) {
77
90
  if (fs_1.default.existsSync(filePath) && !force) {
78
- stats.skipped += 1;
91
+ recordSkipped(root, filePath, stats);
79
92
  return;
80
93
  }
81
94
  fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
82
95
  fs_1.default.writeFileSync(filePath, content, "utf8");
83
- stats.created += 1;
96
+ recordCreated(root, filePath, stats);
84
97
  }
85
98
  function soulTemplate(created) {
86
99
  return [
@@ -176,6 +189,48 @@ function seededInitEvent(nowIso) {
176
189
  };
177
190
  return `${JSON.stringify(event)}\n`;
178
191
  }
192
+ function listSeedSkillSlugs(seedDefaultSkills) {
193
+ if (!fs_1.default.existsSync(seedDefaultSkills)) {
194
+ return [];
195
+ }
196
+ return fs_1.default
197
+ .readdirSync(seedDefaultSkills, { withFileTypes: true })
198
+ .filter((entry) => entry.isDirectory() && fs_1.default.existsSync(path_1.default.join(seedDefaultSkills, entry.name, "SKILL.md")))
199
+ .map((entry) => entry.name.toLowerCase())
200
+ .sort();
201
+ }
202
+ function listExistingCanonicalSkillSlugs(root) {
203
+ const skillsDir = path_1.default.join(root, ".mdkg", "skills");
204
+ if (!fs_1.default.existsSync(skillsDir)) {
205
+ return [];
206
+ }
207
+ return fs_1.default
208
+ .readdirSync(skillsDir, { withFileTypes: true })
209
+ .filter((entry) => entry.isDirectory() && fs_1.default.existsSync(path_1.default.join(skillsDir, entry.name, "SKILL.md")))
210
+ .map((entry) => entry.name.toLowerCase())
211
+ .sort();
212
+ }
213
+ function preflightSeedConfig(seedConfig) {
214
+ const raw = JSON.parse(fs_1.default.readFileSync(seedConfig, "utf8"));
215
+ (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(raw).config);
216
+ }
217
+ function emitPartialInitFailure(root, stats, err) {
218
+ const message = err instanceof Error ? err.message : String(err);
219
+ console.error("mdkg init failed after partial writes");
220
+ console.error(`error: ${message}`);
221
+ console.error(`created: ${stats.created}`);
222
+ for (const created of stats.createdPaths) {
223
+ console.error(` created: ${created}`);
224
+ }
225
+ console.error(`skipped: ${stats.skipped}`);
226
+ for (const skipped of stats.skippedPaths) {
227
+ console.error(` skipped: ${skipped}`);
228
+ }
229
+ console.error("recovery:");
230
+ console.error(" inspect the created paths above");
231
+ console.error(" rerun `mdkg init --agent` after resolving the reported error");
232
+ console.error(` root: ${root}`);
233
+ }
179
234
  function parseCoreList(raw) {
180
235
  const lines = raw.split(/\r?\n/);
181
236
  const header = [];
@@ -224,9 +279,9 @@ function ensureCorePins(coreListPath, requiredPins) {
224
279
  function runInitCommand(options) {
225
280
  const root = path_1.default.resolve(options.root);
226
281
  const seedRoot = options.seedRoot ? path_1.default.resolve(options.seedRoot) : DEFAULT_SEED_SUBDIR;
227
- const createAgents = Boolean(options.createAgents || options.createLlm);
228
- const createClaude = Boolean(options.createClaude || options.createLlm);
229
- const createStartupDocs = Boolean(options.createLlm || options.agent);
282
+ const createAgents = Boolean(options.agent);
283
+ const createClaude = Boolean(options.agent);
284
+ const createStartupDocs = Boolean(options.agent);
230
285
  const force = Boolean(options.force);
231
286
  const seedConfig = path_1.default.join(seedRoot, "config.json");
232
287
  const seedCore = path_1.default.join(seedRoot, "core");
@@ -238,7 +293,13 @@ function runInitCommand(options) {
238
293
  const seedCliMatrix = path_1.default.join(seedRoot, "CLI_COMMAND_MATRIX.md");
239
294
  const seedReadme = path_1.default.join(seedRoot, "README.md");
240
295
  const seedDefaultSkills = path_1.default.join(seedRoot, "skills", "default");
241
- const seedManifest = (0, init_manifest_1.createInitManifest)(seedRoot, (0, version_1.readPackageVersion)());
296
+ const seedSoul = path_1.default.join(seedCore, "SOUL.md");
297
+ const seedHuman = path_1.default.join(seedCore, "HUMAN.md");
298
+ const seedManifest = (0, init_manifest_1.createInitManifest)(seedRoot, (0, version_1.readPackageVersion)(), {
299
+ includeAgentDocs: Boolean(options.agent),
300
+ includeStartupDocs: Boolean(options.agent),
301
+ includeDefaultSkills: Boolean(options.agent),
302
+ });
242
303
  if (!fs_1.default.existsSync(seedConfig) || !fs_1.default.existsSync(seedCore) || !fs_1.default.existsSync(seedTemplates)) {
243
304
  throw new errors_1.NotFoundError(`init assets not found at ${seedRoot} (try reinstalling mdkg)`);
244
305
  }
@@ -263,67 +324,137 @@ function runInitCommand(options) {
263
324
  if (options.agent && !fs_1.default.existsSync(seedDefaultSkills)) {
264
325
  throw new errors_1.NotFoundError(`init assets missing default skills at ${seedRoot}`);
265
326
  }
266
- const mdkgDir = path_1.default.join(root, ".mdkg");
267
- fs_1.default.mkdirSync(mdkgDir, { recursive: true });
268
- fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "work"), { recursive: true });
269
- fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "design"), { recursive: true });
270
- const stats = { created: 0, skipped: 0 };
271
- copySeedFile(seedConfig, path_1.default.join(mdkgDir, "config.json"), force, stats);
272
- copySeedFile(seedReadme, path_1.default.join(mdkgDir, "README.md"), force, stats);
273
- copySeedDir(seedCore, path_1.default.join(mdkgDir, "core"), force, stats);
274
- copySeedDir(seedTemplates, path_1.default.join(mdkgDir, "templates"), force, stats);
275
- if (createAgents) {
276
- copySeedFile(seedAgents, path_1.default.join(root, "AGENTS.md"), force, stats);
277
- }
278
- if (createClaude) {
279
- copySeedFile(seedClaude, path_1.default.join(root, "CLAUDE.md"), force, stats);
327
+ preflightSeedConfig(seedConfig);
328
+ if (options.agent) {
329
+ (0, skill_mirror_1.preflightSkillMirrorTargets)({
330
+ root,
331
+ slugs: [...listSeedSkillSlugs(seedDefaultSkills), ...listExistingCanonicalSkillSlugs(root)],
332
+ force,
333
+ });
280
334
  }
281
- if (createStartupDocs) {
282
- copySeedFile(seedLlms, path_1.default.join(root, "llms.txt"), force, stats);
283
- copySeedFile(seedAgentStart, path_1.default.join(root, "AGENT_START.md"), force, stats);
284
- copySeedFile(seedCliMatrix, path_1.default.join(root, "CLI_COMMAND_MATRIX.md"), force, stats);
335
+ const stats = {
336
+ created: 0,
337
+ skipped: 0,
338
+ createdPaths: [],
339
+ skippedPaths: [],
340
+ ignoreFilesUpdated: [],
341
+ manifestWritten: false,
342
+ registryRefreshed: false,
343
+ mirrorTargets: 0,
344
+ mirroredSkills: 0,
345
+ };
346
+ const mdkgDir = path_1.default.join(root, ".mdkg");
347
+ try {
348
+ fs_1.default.mkdirSync(mdkgDir, { recursive: true });
349
+ fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "work"), { recursive: true });
350
+ fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "design"), { recursive: true });
351
+ copySeedFile(root, seedConfig, path_1.default.join(mdkgDir, "config.json"), force, stats);
352
+ copySeedFile(root, seedReadme, path_1.default.join(mdkgDir, "README.md"), force, stats);
353
+ copySeedDir(root, seedCore, path_1.default.join(mdkgDir, "core"), force, stats);
354
+ copySeedDir(root, seedTemplates, path_1.default.join(mdkgDir, "templates"), force, stats);
355
+ if (createAgents) {
356
+ copySeedFile(root, seedAgents, path_1.default.join(root, "AGENTS.md"), force, stats);
357
+ }
358
+ if (createClaude) {
359
+ copySeedFile(root, seedClaude, path_1.default.join(root, "CLAUDE.md"), force, stats);
360
+ }
361
+ if (createStartupDocs) {
362
+ copySeedFile(root, seedLlms, path_1.default.join(root, "llms.txt"), force, stats);
363
+ copySeedFile(root, seedAgentStart, path_1.default.join(root, "AGENT_START.md"), force, stats);
364
+ copySeedFile(root, seedCliMatrix, path_1.default.join(root, "CLI_COMMAND_MATRIX.md"), force, stats);
365
+ }
366
+ if (options.agent) {
367
+ const today = (0, date_1.formatDate)(new Date());
368
+ const soulPath = path_1.default.join(mdkgDir, "core", "SOUL.md");
369
+ const humanPath = path_1.default.join(mdkgDir, "core", "HUMAN.md");
370
+ const skillsDir = path_1.default.join(mdkgDir, "skills");
371
+ const registryPath = path_1.default.join(skillsDir, "registry.md");
372
+ const eventsDir = path_1.default.join(mdkgDir, "work", "events");
373
+ const eventsPath = path_1.default.join(eventsDir, "events.jsonl");
374
+ fs_1.default.mkdirSync(skillsDir, { recursive: true });
375
+ fs_1.default.mkdirSync(eventsDir, { recursive: true });
376
+ copySeedDir(root, seedDefaultSkills, skillsDir, force, stats);
377
+ if (!fs_1.default.existsSync(seedSoul)) {
378
+ writeFileIfMissing(root, soulPath, soulTemplate(today), force, stats);
379
+ }
380
+ if (!fs_1.default.existsSync(seedHuman)) {
381
+ writeFileIfMissing(root, humanPath, humanTemplate(today), force, stats);
382
+ }
383
+ writeFileIfMissing(root, registryPath, (0, skill_support_1.registryTemplate)(), force, stats);
384
+ if (!fs_1.default.existsSync(eventsPath) || force) {
385
+ writeFileIfMissing(root, eventsPath, seededInitEvent(new Date().toISOString()), force, stats);
386
+ }
387
+ const coreListPath = path_1.default.join(mdkgDir, "core", "core.md");
388
+ ensureCorePins(coreListPath, [SOUL_PIN_ID, HUMAN_PIN_ID]);
389
+ (0, skill_mirror_1.scaffoldMirrorRoots)(root);
390
+ const config = (0, config_1.loadConfig)(root);
391
+ (0, skill_support_1.refreshSkillsRegistry)(root, config);
392
+ stats.registryRefreshed = true;
393
+ const mirrorResult = (0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true, force });
394
+ stats.mirrorTargets = mirrorResult.targets;
395
+ stats.mirroredSkills = mirrorResult.synced;
396
+ }
397
+ (0, init_manifest_1.writeInitManifest)(path_1.default.join(mdkgDir, init_manifest_1.INIT_MANIFEST_FILE), seedManifest);
398
+ stats.manifestWritten = true;
285
399
  }
286
- if (options.agent) {
287
- const today = (0, date_1.formatDate)(new Date());
288
- const soulPath = path_1.default.join(mdkgDir, "core", "SOUL.md");
289
- const humanPath = path_1.default.join(mdkgDir, "core", "HUMAN.md");
290
- const skillsDir = path_1.default.join(mdkgDir, "skills");
291
- const registryPath = path_1.default.join(skillsDir, "registry.md");
292
- const eventsDir = path_1.default.join(mdkgDir, "work", "events");
293
- const eventsPath = path_1.default.join(eventsDir, "events.jsonl");
294
- fs_1.default.mkdirSync(skillsDir, { recursive: true });
295
- fs_1.default.mkdirSync(eventsDir, { recursive: true });
296
- copySeedDir(seedDefaultSkills, skillsDir, force, stats);
297
- writeFileIfMissing(soulPath, soulTemplate(today), force, stats);
298
- writeFileIfMissing(humanPath, humanTemplate(today), force, stats);
299
- writeFileIfMissing(registryPath, (0, skill_support_1.registryTemplate)(), force, stats);
300
- if (!fs_1.default.existsSync(eventsPath) || force) {
301
- writeFileIfMissing(eventsPath, seededInitEvent(new Date().toISOString()), force, stats);
400
+ catch (err) {
401
+ if (stats.created > 0 || stats.skipped > 0) {
402
+ emitPartialInitFailure(root, stats, err);
302
403
  }
303
- const coreListPath = path_1.default.join(mdkgDir, "core", "core.md");
304
- ensureCorePins(coreListPath, [SOUL_PIN_ID, HUMAN_PIN_ID]);
305
- (0, skill_mirror_1.scaffoldMirrorRoots)(root);
306
- const config = (0, config_1.loadConfig)(root);
307
- (0, skill_support_1.refreshSkillsRegistry)(root, config);
308
- (0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true, force });
404
+ throw err;
309
405
  }
310
- (0, init_manifest_1.writeInitManifest)(path_1.default.join(mdkgDir, init_manifest_1.INIT_MANIFEST_FILE), seedManifest);
311
406
  const noUpdateIgnores = Boolean(options.noUpdateIgnores);
312
407
  const shouldUpdateGitignore = Boolean(options.updateGitignore || !noUpdateIgnores);
313
408
  const shouldUpdateNpmignore = Boolean(options.updateNpmignore || !noUpdateIgnores);
314
- if (shouldUpdateGitignore) {
315
- appendIgnoreEntries(path_1.default.join(root, ".gitignore"), [
316
- ".mdkg/index/",
317
- ".mdkg/pack/",
318
- ]);
319
- }
320
- if (shouldUpdateNpmignore) {
321
- appendIgnoreEntries(path_1.default.join(root, ".npmignore"), [".mdkg/", ".mdkg/index/", ".mdkg/pack/"]);
409
+ try {
410
+ if (shouldUpdateGitignore) {
411
+ if (appendIgnoreEntries(path_1.default.join(root, ".gitignore"), [
412
+ ".mdkg/index/*.json",
413
+ ".mdkg/index/*.tmp",
414
+ ".mdkg/index/*.lock",
415
+ ".mdkg/index/write.lock/",
416
+ ".mdkg/index/*.sqlite-wal",
417
+ ".mdkg/index/*.sqlite-shm",
418
+ ".mdkg/index/*.sqlite-journal",
419
+ ".mdkg/pack/",
420
+ ".mdkg/archive/**/source/",
421
+ ])) {
422
+ stats.ignoreFilesUpdated.push(".gitignore");
423
+ }
424
+ }
425
+ if (shouldUpdateNpmignore) {
426
+ if (appendIgnoreEntries(path_1.default.join(root, ".npmignore"), [".mdkg/", ".mdkg/index/", ".mdkg/pack/"])) {
427
+ stats.ignoreFilesUpdated.push(".npmignore");
428
+ }
429
+ }
430
+ if (options.updateDockerignore) {
431
+ if (appendIgnoreEntries(path_1.default.join(root, ".dockerignore"), [".mdkg/"])) {
432
+ stats.ignoreFilesUpdated.push(".dockerignore");
433
+ }
434
+ }
322
435
  }
323
- if (options.updateDockerignore) {
324
- appendIgnoreEntries(path_1.default.join(root, ".dockerignore"), [".mdkg/"]);
436
+ catch (err) {
437
+ if (stats.created > 0 || stats.skipped > 0) {
438
+ emitPartialInitFailure(root, stats, err);
439
+ }
440
+ throw err;
325
441
  }
326
442
  console.log(`mdkg init complete: ${stats.created} file(s) created, ${stats.skipped} skipped`);
443
+ if (stats.manifestWritten) {
444
+ console.log("managed manifest: .mdkg/init-manifest.json");
445
+ }
446
+ if (stats.ignoreFilesUpdated.length > 0) {
447
+ console.log(`ignore files updated: ${stats.ignoreFilesUpdated.join(", ")}`);
448
+ }
449
+ if (options.agent) {
450
+ console.log("agent bootstrap: AGENT_START.md, AGENTS.md, CLAUDE.md, llms.txt, CLI_COMMAND_MATRIX.md");
451
+ console.log("agent core pins: rule-soul, rule-human");
452
+ console.log("agent event log: .mdkg/work/events/events.jsonl");
453
+ console.log(`skill mirrors: ${stats.mirroredSkills} sync operation(s) across ${stats.mirrorTargets} target(s)`);
454
+ if (stats.registryRefreshed) {
455
+ console.log("skill registry: .mdkg/skills/registry.md");
456
+ }
457
+ }
327
458
  console.log("next:");
328
459
  if (createStartupDocs) {
329
460
  console.log(" read AGENT_START.md");
@@ -83,19 +83,32 @@ function seedSourcePath(seedRoot, file) {
83
83
  }
84
84
  return path_1.default.join(seedRoot, file.path);
85
85
  }
86
- function createInitManifest(seedRoot, mdkgVersion) {
86
+ function createInitManifest(seedRoot, mdkgVersion, options = {
87
+ includeAgentDocs: true,
88
+ includeStartupDocs: true,
89
+ includeDefaultSkills: true,
90
+ }) {
91
+ const includeAgentDocs = Boolean(options.includeAgentDocs);
92
+ const includeStartupDocs = Boolean(options.includeStartupDocs);
93
+ const includeDefaultSkills = Boolean(options.includeDefaultSkills);
87
94
  const files = [];
88
95
  addSeedFile(files, seedRoot, "config.json", ".mdkg/config.json", "config");
89
96
  addSeedFile(files, seedRoot, "README.md", ".mdkg/README.md", "mdkg_doc");
90
97
  addSeedDir(files, seedRoot, "core", ".mdkg/core", "core");
91
98
  addSeedDir(files, seedRoot, "templates", ".mdkg/templates", "template");
92
- for (const doc of AGENT_DOCS) {
93
- addSeedFile(files, seedRoot, doc, doc, "agent_doc");
99
+ if (includeAgentDocs) {
100
+ for (const doc of AGENT_DOCS) {
101
+ addSeedFile(files, seedRoot, doc, doc, "agent_doc");
102
+ }
103
+ }
104
+ if (includeStartupDocs) {
105
+ for (const doc of STARTUP_DOCS) {
106
+ addSeedFile(files, seedRoot, doc, doc, "startup_doc");
107
+ }
94
108
  }
95
- for (const doc of STARTUP_DOCS) {
96
- addSeedFile(files, seedRoot, doc, doc, "startup_doc");
109
+ if (includeDefaultSkills) {
110
+ addSeedDir(files, seedRoot, path_1.default.join("skills", "default"), ".mdkg/skills", "default_skill");
97
111
  }
98
- addSeedDir(files, seedRoot, path_1.default.join("skills", "default"), ".mdkg/skills", "default_skill");
99
112
  return {
100
113
  schema_version: exports.INIT_MANIFEST_SCHEMA_VERSION,
101
114
  tool: "mdkg",
@@ -18,14 +18,14 @@ function normalizeWorkspace(value) {
18
18
  function runListCommand(options) {
19
19
  const config = (0, config_1.loadConfig)(options.root);
20
20
  const ws = normalizeWorkspace(options.ws);
21
- if (ws && !config.workspaces[ws]) {
21
+ if (ws && !config.workspaces[ws] && !config.bundle_imports[ws]) {
22
22
  throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
23
23
  }
24
24
  const normalizedType = options.type?.toLowerCase();
25
25
  if (normalizedType === "skill") {
26
26
  throw new errors_1.UsageError("--type skill is no longer supported here; use `mdkg skill list`");
27
27
  }
28
- const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
28
+ const { index, rebuilt, stale, warnings } = (0, index_cache_1.loadIndex)({
29
29
  root: options.root,
30
30
  config,
31
31
  useCache: !options.noCache,
@@ -34,6 +34,9 @@ function runListCommand(options) {
34
34
  if (stale && !rebuilt && !options.noCache) {
35
35
  console.error("warning: index is stale; run mdkg index to refresh");
36
36
  }
37
+ for (const warning of warnings) {
38
+ console.error(`warning: ${warning}`);
39
+ }
37
40
  let epicQid;
38
41
  if (options.epic) {
39
42
  const resolved = (0, qid_1.resolveQid)(index, options.epic, ws);
@@ -16,6 +16,10 @@ const date_1 = require("../util/date");
16
16
  const errors_1 = require("../util/errors");
17
17
  const qid_1 = require("../util/qid");
18
18
  const id_1 = require("../util/id");
19
+ const atomic_1 = require("../util/atomic");
20
+ const lock_1 = require("../util/lock");
21
+ const sqlite_index_1 = require("../graph/sqlite_index");
22
+ const reindex_1 = require("../graph/reindex");
19
23
  const event_support_1 = require("./event_support");
20
24
  const DEC_ID_RE = /^dec-[0-9]+$/;
21
25
  const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
@@ -97,6 +101,9 @@ function slugifyTitle(title) {
97
101
  return slug.length > maxLen ? slug.slice(0, maxLen).replace(/-+$/g, "") : slug;
98
102
  }
99
103
  function nextIdForPrefix(index, ws, prefix) {
104
+ return `${prefix}-${maxIdForPrefix(index, ws, prefix) + 1}`;
105
+ }
106
+ function maxIdForPrefix(index, ws, prefix) {
100
107
  let max = 0;
101
108
  const pattern = new RegExp(`^${prefix}-(\\d+)$`);
102
109
  for (const node of Object.values(index)) {
@@ -112,7 +119,7 @@ function nextIdForPrefix(index, ws, prefix) {
112
119
  max = parsed;
113
120
  }
114
121
  }
115
- return `${prefix}-${max + 1}`;
122
+ return max;
116
123
  }
117
124
  function idPrefixForType(type) {
118
125
  if (type === "checkpoint") {
@@ -150,12 +157,15 @@ function ensureExists(index, value, ws, label) {
150
157
  throw new errors_1.NotFoundError((0, qid_1.formatResolveError)(label, value, resolved, ws));
151
158
  }
152
159
  }
153
- function runNewCommand(options) {
160
+ function runNewCommandLocked(options) {
154
161
  const title = options.title.trim();
155
162
  if (!title) {
156
163
  throw new errors_1.UsageError("title cannot be empty");
157
164
  }
158
165
  const type = options.type.toLowerCase();
166
+ if (type === "archive") {
167
+ throw new errors_1.UsageError("use `mdkg archive add <file>` to create archive sidecars");
168
+ }
159
169
  if (!node_1.ALLOWED_TYPES.has(type)) {
160
170
  throw new errors_1.UsageError(`type must be one of ${Array.from(node_1.ALLOWED_TYPES).join(", ")}`);
161
171
  }
@@ -178,7 +188,15 @@ function runNewCommand(options) {
178
188
  const prefix = idPrefixForType(type);
179
189
  const id = options.id !== undefined
180
190
  ? normalizeAgentFileId(options.id)
181
- : nextIdForPrefix(index.nodes, ws, prefix);
191
+ : (0, sqlite_index_1.isSqliteBackend)(config)
192
+ ? (0, sqlite_index_1.reserveSqliteNumericId)({
193
+ root: options.root,
194
+ config,
195
+ ws,
196
+ prefix,
197
+ currentMax: maxIdForPrefix(index.nodes, ws, prefix),
198
+ }) ?? nextIdForPrefix(index.nodes, ws, prefix)
199
+ : nextIdForPrefix(index.nodes, ws, prefix);
182
200
  if (index.nodes[`${ws}:${id}`]) {
183
201
  throw new errors_1.UsageError(`node already exists: ${ws}:${id}`);
184
202
  }
@@ -314,12 +332,19 @@ function runNewCommand(options) {
314
332
  created: today,
315
333
  updated: today,
316
334
  });
317
- fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
318
- fs_1.default.writeFileSync(filePath, content, "utf8");
335
+ try {
336
+ (0, atomic_1.writeFileExclusive)(filePath, content);
337
+ }
338
+ catch (err) {
339
+ const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "";
340
+ if (code === "EEXIST") {
341
+ throw new errors_1.UsageError(`node already exists: ${path_1.default.relative(options.root, filePath)}`);
342
+ }
343
+ throw err;
344
+ }
319
345
  if (config.index.auto_reindex && !noReindex) {
320
346
  const updatedIndex = (0, indexer_1.buildIndex)(options.root, config, { tolerant: config.index.tolerant });
321
- const outputPath = path_1.default.resolve(options.root, config.index.global_index_path);
322
- (0, index_cache_1.writeIndex)(outputPath, updatedIndex);
347
+ (0, reindex_1.writeDerivedIndexes)(options.root, config, updatedIndex);
323
348
  }
324
349
  (0, event_support_1.appendAutomaticEvent)({
325
350
  root: options.root,
@@ -351,3 +376,7 @@ function runNewCommand(options) {
351
376
  }
352
377
  console.log(`node created: ${receipt.qid} (${receipt.path})`);
353
378
  }
379
+ function runNewCommand(options) {
380
+ const config = (0, config_1.loadConfig)(options.root);
381
+ return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runNewCommandLocked(options));
382
+ }
@@ -21,6 +21,9 @@ function selectNextByPriority(index, ws, statusPreference, priorityMax) {
21
21
  if (ws && node.ws !== ws) {
22
22
  return false;
23
23
  }
24
+ if (node.source?.imported) {
25
+ return false;
26
+ }
24
27
  if (!NEXT_TYPES.has(node.type)) {
25
28
  return false;
26
29
  }
@@ -59,6 +62,10 @@ function runNextCommand(options) {
59
62
  throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("id", options.id, resolved, ws));
60
63
  }
61
64
  const node = index.nodes[resolved.qid];
65
+ if (node.source?.imported) {
66
+ console.error("no local next item: imported bundle nodes are read-only planning context");
67
+ return;
68
+ }
62
69
  const nextQid = node.edges.next;
63
70
  if (nextQid && index.nodes[nextQid]) {
64
71
  console.log((0, node_card_1.formatNodeCard)(index.nodes[nextQid]));
@@ -7,11 +7,14 @@ function formatStatusPriority(node) {
7
7
  return `${status}/${priority}`;
8
8
  }
9
9
  function formatNodeCard(node) {
10
+ const sourceLabel = node.source?.imported
11
+ ? ` | import:${node.source.import_alias}${node.source.stale ? ":stale" : ""} | read-only`
12
+ : "";
10
13
  return [
11
14
  node.qid,
12
15
  node.type,
13
16
  formatStatusPriority(node),
14
17
  node.title,
15
18
  node.path,
16
- ].join(" | ");
19
+ ].join(" | ") + sourceLabel;
17
20
  }
@@ -11,6 +11,7 @@ const index_cache_1 = require("../graph/index_cache");
11
11
  const frontmatter_1 = require("../graph/frontmatter");
12
12
  const skills_index_cache_1 = require("../graph/skills_index_cache");
13
13
  const node_1 = require("../graph/node");
14
+ const visibility_1 = require("../graph/visibility");
14
15
  const budget_1 = require("../pack/budget");
15
16
  const export_json_1 = require("../pack/export_json");
16
17
  const export_md_1 = require("../pack/export_md");
@@ -217,6 +218,53 @@ function applyNodeCountLimit(pack, maxNodes) {
217
218
  nodes: included,
218
219
  };
219
220
  }
221
+ function packNodeVisibility(node, index, config) {
222
+ const indexNode = index.nodes[node.qid];
223
+ if (indexNode) {
224
+ return (0, visibility_1.effectiveNodeVisibility)(indexNode, config);
225
+ }
226
+ return (0, visibility_1.normalizeVisibility)(config.workspaces[node.workspace]?.visibility, "workspace visibility");
227
+ }
228
+ function applyVisibilityFilter(pack, index, config, scope) {
229
+ if (scope === "private") {
230
+ return {
231
+ ...pack,
232
+ meta: {
233
+ ...pack.meta,
234
+ visibility: scope,
235
+ },
236
+ };
237
+ }
238
+ const includedNodes = pack.nodes.filter((node) => (0, visibility_1.isVisibleAt)(packNodeVisibility(node, index, config), scope));
239
+ if (includedNodes.length === 0 || includedNodes[0].qid !== pack.nodes[0]?.qid) {
240
+ throw new errors_1.ValidationError(`pack root ${pack.meta.root} is not visible at ${scope}`);
241
+ }
242
+ const includedQids = new Set(includedNodes.map((node) => node.qid));
243
+ const graphIncludedQids = new Set(includedNodes.filter((node) => Boolean(index.nodes[node.qid])).map((node) => node.qid));
244
+ const violations = (0, visibility_1.collectVisibilityViolations)(index, config, {
245
+ includedQids: graphIncludedQids,
246
+ scope,
247
+ });
248
+ if (violations.length > 0) {
249
+ throw new errors_1.ValidationError(`${scope} pack contains less-visible references:\n${(0, visibility_1.visibilityViolationMessages)(violations).join("\n")}`);
250
+ }
251
+ const dropped = pack.nodes
252
+ .filter((node) => !includedQids.has(node.qid))
253
+ .map((node) => node.qid);
254
+ return {
255
+ ...pack,
256
+ meta: {
257
+ ...pack.meta,
258
+ visibility: scope,
259
+ node_count: includedNodes.length,
260
+ truncated: {
261
+ ...pack.meta.truncated,
262
+ dropped: [...pack.meta.truncated.dropped, ...dropped],
263
+ },
264
+ },
265
+ nodes: includedNodes,
266
+ };
267
+ }
220
268
  function writeJsonFile(outPath, payload) {
221
269
  fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
222
270
  fs_1.default.writeFileSync(outPath, JSON.stringify(payload, null, 2), "utf8");
@@ -243,6 +291,9 @@ function printDryRunSummary(pack, stats, format) {
243
291
  console.log(`root: ${pack.meta.root}`);
244
292
  console.log(`profile: ${pack.meta.profile ?? "standard"}`);
245
293
  console.log(`body_mode: ${pack.meta.body_mode ?? "full"}`);
294
+ if (pack.meta.visibility) {
295
+ console.log(`visibility: ${pack.meta.visibility}`);
296
+ }
246
297
  console.log(`format: ${format}`);
247
298
  console.log(`nodes: ${pack.nodes.length}`);
248
299
  if (pack.meta.latest_checkpoint_qid) {
@@ -267,10 +318,10 @@ function printDryRunSummary(pack, stats, format) {
267
318
  function runPackCommand(options) {
268
319
  const config = (0, config_1.loadConfig)(options.root);
269
320
  const ws = normalizeWorkspace(options.ws);
270
- if (ws && !config.workspaces[ws]) {
321
+ if (ws && !config.workspaces[ws] && !config.bundle_imports[ws]) {
271
322
  throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
272
323
  }
273
- const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
324
+ const { index, rebuilt, stale, warnings } = (0, index_cache_1.loadIndex)({
274
325
  root: options.root,
275
326
  config,
276
327
  useCache: !options.noCache,
@@ -279,6 +330,9 @@ function runPackCommand(options) {
279
330
  if (stale && !rebuilt && !options.noCache) {
280
331
  console.error("warning: index is stale; run mdkg index to refresh");
281
332
  }
333
+ for (const warning of warnings) {
334
+ console.error(`warning: ${warning}`);
335
+ }
282
336
  const resolved = (0, qid_1.resolveQid)(index, options.id, ws);
283
337
  if (resolved.status !== "ok") {
284
338
  throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("id", options.id, resolved, ws));
@@ -291,6 +345,9 @@ function runPackCommand(options) {
291
345
  const edges = normalizeEdges([...config.pack.default_edges, ...extraEdges]);
292
346
  const skillsPolicy = resolveSkillsPolicy(options.skills);
293
347
  const skillsDepth = resolveSkillsDepth(options.skillsDepth);
348
+ const visibility = options.visibility
349
+ ? (0, visibility_1.normalizeVisibility)(options.visibility)
350
+ : undefined;
294
351
  let resolvedProfile;
295
352
  try {
296
353
  resolvedProfile = (0, profile_1.resolvePackProfile)({
@@ -350,6 +407,9 @@ function runPackCommand(options) {
350
407
  packWithSkills = appendSkillsToPack(packWithSkills, selectedEntries, skillsDepth, options.root);
351
408
  packWithSkills = applyNodeCountLimit(packWithSkills, config.pack.limits.max_nodes);
352
409
  }
410
+ if (visibility) {
411
+ packWithSkills = applyVisibilityFilter(packWithSkills, index, config, visibility);
412
+ }
353
413
  const templateHeadingMap = resolvedProfile.bodyMode === "summary"
354
414
  ? (0, headings_1.loadTemplateHeadingMap)(options.root, config, Array.from(node_1.ALLOWED_TYPES))
355
415
  : {};
@@ -36,6 +36,7 @@ function toNodeSummaryJson(node) {
36
36
  blocked_by: [...node.edges.blocked_by],
37
37
  blocks: [...node.edges.blocks],
38
38
  },
39
+ ...(node.source ? { source: node.source } : {}),
39
40
  };
40
41
  }
41
42
  function toNodeDetailJson(node, body) {