mdkg 0.1.1 → 0.1.2

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 (65) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +105 -14
  3. package/dist/cli.js +564 -15
  4. package/dist/commands/archive.js +474 -0
  5. package/dist/commands/bundle.js +743 -0
  6. package/dist/commands/bundle_import.js +243 -0
  7. package/dist/commands/capability.js +162 -0
  8. package/dist/commands/doctor.js +223 -0
  9. package/dist/commands/format.js +38 -9
  10. package/dist/commands/index.js +11 -0
  11. package/dist/commands/init.js +188 -63
  12. package/dist/commands/init_manifest.js +19 -6
  13. package/dist/commands/list.js +5 -2
  14. package/dist/commands/new.js +3 -0
  15. package/dist/commands/next.js +7 -0
  16. package/dist/commands/node_card.js +4 -1
  17. package/dist/commands/pack.js +62 -2
  18. package/dist/commands/query_output.js +1 -0
  19. package/dist/commands/search.js +5 -2
  20. package/dist/commands/show.js +7 -14
  21. package/dist/commands/skill_mirror.js +22 -0
  22. package/dist/commands/task.js +3 -0
  23. package/dist/commands/upgrade.js +24 -1
  24. package/dist/commands/validate.js +14 -1
  25. package/dist/commands/work.js +365 -0
  26. package/dist/commands/workspace.js +12 -2
  27. package/dist/core/config.js +100 -1
  28. package/dist/graph/agent_file_types.js +78 -5
  29. package/dist/graph/archive_file.js +125 -0
  30. package/dist/graph/archive_integrity.js +66 -0
  31. package/dist/graph/bundle_imports.js +418 -0
  32. package/dist/graph/capabilities_index_cache.js +103 -0
  33. package/dist/graph/capabilities_indexer.js +231 -0
  34. package/dist/graph/frontmatter.js +19 -0
  35. package/dist/graph/index_cache.js +21 -4
  36. package/dist/graph/indexer.js +4 -1
  37. package/dist/graph/node.js +23 -4
  38. package/dist/graph/node_body.js +37 -0
  39. package/dist/graph/skills_indexer.js +8 -3
  40. package/dist/graph/validate_graph.js +83 -7
  41. package/dist/graph/visibility.js +214 -0
  42. package/dist/graph/workspace_files.js +22 -0
  43. package/dist/init/AGENT_START.md +21 -0
  44. package/dist/init/CLI_COMMAND_MATRIX.md +56 -3
  45. package/dist/init/README.md +59 -2
  46. package/dist/init/config.json +13 -1
  47. package/dist/init/core/guide.md +6 -2
  48. package/dist/init/core/rule-3-cli-contract.md +71 -4
  49. package/dist/init/core/rule-4-repo-safety-and-ignores.md +20 -0
  50. package/dist/init/core/rule-6-templates-and-schemas.md +7 -0
  51. package/dist/init/init-manifest.json +19 -14
  52. package/dist/init/skills/default/build-pack-and-execute-task/SKILL.md +2 -1
  53. package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +26 -0
  54. package/dist/init/templates/default/archive.md +33 -0
  55. package/dist/init/templates/default/receipt.md +15 -1
  56. package/dist/init/templates/default/work.md +6 -1
  57. package/dist/init/templates/default/work_order.md +15 -1
  58. package/dist/pack/export_md.js +3 -0
  59. package/dist/pack/export_xml.js +3 -0
  60. package/dist/pack/order.js +1 -0
  61. package/dist/pack/pack.js +3 -13
  62. package/dist/util/argparse.js +30 -0
  63. package/dist/util/refs.js +40 -0
  64. package/dist/util/zip.js +153 -0
  65. package/package.json +8 -2
@@ -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) {
@@ -54,14 +54,14 @@ function runSearchCommand(options) {
54
54
  }
55
55
  const config = (0, config_1.loadConfig)(options.root);
56
56
  const ws = normalizeWorkspace(options.ws);
57
- if (ws && !config.workspaces[ws]) {
57
+ if (ws && !config.workspaces[ws] && !config.bundle_imports[ws]) {
58
58
  throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
59
59
  }
60
60
  const normalizedType = options.type?.toLowerCase();
61
61
  if (normalizedType === "skill") {
62
62
  throw new errors_1.UsageError("--type skill is no longer supported here; use `mdkg skill search`");
63
63
  }
64
- const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
64
+ const { index, rebuilt, stale, warnings } = (0, index_cache_1.loadIndex)({
65
65
  root: options.root,
66
66
  config,
67
67
  useCache: !options.noCache,
@@ -70,6 +70,9 @@ function runSearchCommand(options) {
70
70
  if (stale && !rebuilt && !options.noCache) {
71
71
  console.error("warning: index is stale; run mdkg index to refresh");
72
72
  }
73
+ for (const warning of warnings) {
74
+ console.error(`warning: ${warning}`);
75
+ }
73
76
  const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
74
77
  const nodeResults = (0, filter_1.filterNodes)(Object.values(index.nodes), {
75
78
  ws,
@@ -1,14 +1,9 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.runShowCommand = runShowCommand;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
4
  const config_1 = require("../core/config");
10
5
  const index_cache_1 = require("../graph/index_cache");
11
- const frontmatter_1 = require("../graph/frontmatter");
6
+ const node_body_1 = require("../graph/node_body");
12
7
  const errors_1 = require("../util/errors");
13
8
  const qid_1 = require("../util/qid");
14
9
  const node_card_1 = require("./node_card");
@@ -34,14 +29,14 @@ function formatAttributeLine(key, value) {
34
29
  function runShowCommand(options) {
35
30
  const config = (0, config_1.loadConfig)(options.root);
36
31
  const ws = normalizeWorkspace(options.ws);
37
- if (ws && !config.workspaces[ws]) {
32
+ if (ws && !config.workspaces[ws] && !config.bundle_imports[ws]) {
38
33
  throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
39
34
  }
40
35
  const normalizedId = options.id.toLowerCase();
41
36
  if (normalizedId.startsWith("skill:") || normalizedId.startsWith("root:skill:")) {
42
37
  throw new errors_1.UsageError(`generic skill show is no longer supported; use \`mdkg skill show ${options.id.replace(/^root:skill:|^skill:/i, "")}\``);
43
38
  }
44
- const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
39
+ const { index, rebuilt, stale, warnings } = (0, index_cache_1.loadIndex)({
45
40
  root: options.root,
46
41
  config,
47
42
  useCache: !options.noCache,
@@ -50,19 +45,17 @@ function runShowCommand(options) {
50
45
  if (stale && !rebuilt && !options.noCache) {
51
46
  console.error("warning: index is stale; run mdkg index to refresh");
52
47
  }
48
+ for (const warning of warnings) {
49
+ console.error(`warning: ${warning}`);
50
+ }
53
51
  const resolved = (0, qid_1.resolveQid)(index, options.id, ws);
54
52
  if (resolved.status !== "ok") {
55
53
  throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("id", options.id, resolved, ws));
56
54
  }
57
55
  const node = index.nodes[resolved.qid];
58
- const filePath = path_1.default.resolve(options.root, node.path);
59
56
  let body = "";
60
57
  if (!options.metaOnly) {
61
- if (!fs_1.default.existsSync(filePath)) {
62
- throw new errors_1.NotFoundError(`file not found for ${node.qid}: ${node.path}`);
63
- }
64
- const content = fs_1.default.readFileSync(filePath, "utf8");
65
- body = (0, frontmatter_1.parseFrontmatter)(content, filePath).body.trimEnd();
58
+ body = (0, node_body_1.readNodeBody)(options.root, node);
66
59
  }
67
60
  const format = options.format ?? (options.json ? "json" : undefined);
68
61
  if (format) {
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.syncSkillMirrors = syncSkillMirrors;
7
+ exports.preflightSkillMirrorTargets = preflightSkillMirrorTargets;
7
8
  exports.shouldMaintainSkillMirrors = shouldMaintainSkillMirrors;
8
9
  exports.auditSkillMirrors = auditSkillMirrors;
9
10
  exports.scaffoldMirrorRoots = scaffoldMirrorRoots;
@@ -271,6 +272,27 @@ function syncSkillMirrors(options) {
271
272
  }
272
273
  return { synced, pruned, targets: touchedTargets };
273
274
  }
275
+ function preflightSkillMirrorTargets(options) {
276
+ if (options.force) {
277
+ return;
278
+ }
279
+ const slugs = Array.from(new Set(options.slugs.map((value) => value.trim().toLowerCase()).filter(Boolean)));
280
+ if (slugs.length === 0) {
281
+ return;
282
+ }
283
+ for (const target of resolveMirrorTargets(options.root)) {
284
+ if (!fs_1.default.existsSync(target.rootDir) && !fs_1.default.existsSync(target.skillsRoot)) {
285
+ continue;
286
+ }
287
+ const managed = readManifest(target);
288
+ for (const slug of slugs) {
289
+ const destDir = path_1.default.join(target.skillsRoot, slug);
290
+ if (fs_1.default.existsSync(destDir) && !managed.has(slug)) {
291
+ throw new errors_1.UsageError(`${path_1.default.relative(options.root, destDir)} already exists and is not mdkg-managed; rerun \`mdkg init --agent --force\` or \`mdkg skill sync --force\` to replace it`);
292
+ }
293
+ }
294
+ }
295
+ }
274
296
  function shouldMaintainSkillMirrors(root) {
275
297
  return shouldCreateMirrorRoots(root);
276
298
  }
@@ -107,6 +107,9 @@ function loadMutableTaskNode(root, idOrQid, wsHint) {
107
107
  if (!node) {
108
108
  throw new errors_1.NotFoundError(`task not found: ${idOrQid}`);
109
109
  }
110
+ if (node.source?.imported) {
111
+ throw new errors_1.UsageError(`cannot mutate read-only imported node ${node.qid}; update the source workspace for bundle import ${node.source.import_alias}`);
112
+ }
110
113
  if (!MUTABLE_TASK_TYPES.has(node.type)) {
111
114
  throw new errors_1.UsageError(`mdkg task only supports task, bug, and test nodes; use markdown editing for ${node.type}:${node.id}`);
112
115
  }
@@ -18,6 +18,7 @@ const skill_mirror_1 = require("./skill_mirror");
18
18
  const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
19
19
  const PROTECTED_CORE_DOCS = new Set([".mdkg/core/SOUL.md", ".mdkg/core/HUMAN.md"]);
20
20
  const CREATE_ONLY_PRESERVED = new Set([".mdkg/core/core.md"]);
21
+ const ARCHIVE_RAW_IGNORE_ENTRIES = [".mdkg/archive/**/source/"];
21
22
  function seededInitEvent(nowIso) {
22
23
  const event = {
23
24
  ts: nowIso,
@@ -107,7 +108,7 @@ function buildKnownHashes(manifests) {
107
108
  return hashes;
108
109
  }
109
110
  function shouldIncludeFile(file, agentWorkspace) {
110
- if (file.category === "default_skill") {
111
+ if (file.category === "agent_doc" || file.category === "startup_doc" || file.category === "default_skill") {
111
112
  return agentWorkspace;
112
113
  }
113
114
  return file.category !== "config";
@@ -254,6 +255,27 @@ function ensureAgentRuntimeFiles(root, dryRun, summary, changes) {
254
255
  summary.unchanged += 1;
255
256
  }
256
257
  }
258
+ function ensureArchiveIgnorePolicy(root, dryRun, summary, changes) {
259
+ const ignorePath = path_1.default.join(root, ".gitignore");
260
+ const raw = fs_1.default.existsSync(ignorePath) ? fs_1.default.readFileSync(ignorePath, "utf8") : "";
261
+ const lines = raw.split(/\r?\n/);
262
+ const existing = new Set(lines.map((line) => line.trim()).filter(Boolean));
263
+ const additions = ARCHIVE_RAW_IGNORE_ENTRIES.filter((entry) => !existing.has(entry));
264
+ if (additions.length === 0) {
265
+ summary.unchanged += 1;
266
+ return;
267
+ }
268
+ record(summary, changes, {
269
+ path: ".gitignore",
270
+ category: "ignore_policy",
271
+ action: fs_1.default.existsSync(ignorePath) ? "update" : "create",
272
+ reason: "ignore raw local archive source copies while keeping sidecars and zip caches commit-eligible",
273
+ });
274
+ if (!dryRun) {
275
+ const suffix = raw.length === 0 || raw.endsWith("\n") ? "" : "\n";
276
+ writeFile(ignorePath, `${raw}${suffix}${additions.join("\n")}\n`);
277
+ }
278
+ }
257
279
  function isWritableChange(change) {
258
280
  return change.action === "create" || change.action === "update" || change.action === "migrate" || change.action === "sync";
259
281
  }
@@ -353,6 +375,7 @@ function runUpgradeCommand(options) {
353
375
  if (agentWorkspace) {
354
376
  ensureAgentRuntimeFiles(root, dryRun, summary, changes);
355
377
  }
378
+ ensureArchiveIgnorePolicy(root, dryRun, summary, changes);
356
379
  const applySideEffects = buildApplySideEffects({
357
380
  existingManifest,
358
381
  agentWorkspace,
@@ -12,6 +12,8 @@ const node_1 = require("../graph/node");
12
12
  const skills_indexer_1 = require("../graph/skills_indexer");
13
13
  const workspace_files_1 = require("../graph/workspace_files");
14
14
  const validate_graph_1 = require("../graph/validate_graph");
15
+ const bundle_imports_1 = require("../graph/bundle_imports");
16
+ const visibility_1 = require("../graph/visibility");
15
17
  const errors_1 = require("../util/errors");
16
18
  const skill_mirror_1 = require("./skill_mirror");
17
19
  const RECOMMENDED_HEADINGS = {
@@ -268,6 +270,16 @@ function runValidateCommand(options) {
268
270
  nodes,
269
271
  reverse_edges: {},
270
272
  };
273
+ const importProjection = (0, bundle_imports_1.buildBundleImportsIndex)(options.root, config);
274
+ for (const item of importProjection.index.imports) {
275
+ for (const warning of item.warnings) {
276
+ warnings.push(`bundle import ${item.alias}: ${warning}`);
277
+ }
278
+ for (const error of item.errors) {
279
+ errors.push(`bundle import ${item.alias}: ${error}`);
280
+ }
281
+ }
282
+ const validationIndex = (0, bundle_imports_1.mergeBundleImportsIntoIndex)(index, importProjection);
271
283
  let knownSkills = new Set();
272
284
  try {
273
285
  const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
@@ -284,11 +296,12 @@ function runValidateCommand(options) {
284
296
  const message = err instanceof Error ? err.message : "unknown skill validation error";
285
297
  errors.push(message);
286
298
  }
287
- const graphErrors = (0, validate_graph_1.collectGraphErrors)(index, {
299
+ const graphErrors = (0, validate_graph_1.collectGraphErrors)(validationIndex, {
288
300
  allowMissing: false,
289
301
  knownSkillSlugs: knownSkills,
290
302
  });
291
303
  errors.push(...graphErrors);
304
+ errors.push(...(0, visibility_1.visibilityViolationMessages)((0, visibility_1.collectVisibilityViolations)(validationIndex, config)).map((message) => `visibility: ${message}`));
292
305
  const skillsRoot = (0, skills_indexer_1.resolveSkillsRoot)(options.root, config);
293
306
  for (const dirPath of listDirectories(skillsRoot)) {
294
307
  const canonicalPath = path_1.default.join(dirPath, "SKILL.md");