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
@@ -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
  }
@@ -11,12 +11,15 @@ const path_1 = __importDefault(require("path"));
11
11
  const config_1 = require("../core/config");
12
12
  const indexer_1 = require("../graph/indexer");
13
13
  const index_cache_1 = require("../graph/index_cache");
14
+ const reindex_1 = require("../graph/reindex");
14
15
  const frontmatter_1 = require("../graph/frontmatter");
15
16
  const skills_indexer_1 = require("../graph/skills_indexer");
16
17
  const date_1 = require("../util/date");
17
18
  const errors_1 = require("../util/errors");
18
19
  const qid_1 = require("../util/qid");
19
20
  const id_1 = require("../util/id");
21
+ const atomic_1 = require("../util/atomic");
22
+ const lock_1 = require("../util/lock");
20
23
  const event_support_1 = require("./event_support");
21
24
  const checkpoint_1 = require("./checkpoint");
22
25
  const MUTABLE_TASK_TYPES = new Set(["task", "bug", "test"]);
@@ -93,8 +96,7 @@ function maybeReindex(root, config) {
93
96
  if (!config.index.auto_reindex) {
94
97
  return;
95
98
  }
96
- const outputPath = path_1.default.resolve(root, config.index.global_index_path);
97
- (0, index_cache_1.writeIndex)(outputPath, (0, indexer_1.buildIndex)(root, config, { tolerant: config.index.tolerant }));
99
+ (0, reindex_1.writeDerivedIndexes)(root, config, (0, indexer_1.buildIndex)(root, config, { tolerant: config.index.tolerant }));
98
100
  }
99
101
  function loadMutableTaskNode(root, idOrQid, wsHint) {
100
102
  const config = (0, config_1.loadConfig)(root);
@@ -107,6 +109,9 @@ function loadMutableTaskNode(root, idOrQid, wsHint) {
107
109
  if (!node) {
108
110
  throw new errors_1.NotFoundError(`task not found: ${idOrQid}`);
109
111
  }
112
+ if (node.source?.imported) {
113
+ throw new errors_1.UsageError(`cannot mutate read-only imported node ${node.qid}; update the source workspace for bundle import ${node.source.import_alias}`);
114
+ }
110
115
  if (!MUTABLE_TASK_TYPES.has(node.type)) {
111
116
  throw new errors_1.UsageError(`mdkg task only supports task, bug, and test nodes; use markdown editing for ${node.type}:${node.id}`);
112
117
  }
@@ -129,7 +134,7 @@ function writeNodeFile(root, filePath, frontmatter, body) {
129
134
  const lines = (0, frontmatter_1.formatFrontmatter)(frontmatter, frontmatter_1.DEFAULT_FRONTMATTER_KEY_ORDER);
130
135
  const frontmatterBlock = ["---", ...lines, "---"].join("\n");
131
136
  const content = body.length > 0 ? `${frontmatterBlock}\n${body}` : frontmatterBlock;
132
- fs_1.default.writeFileSync(filePath, content, "utf8");
137
+ (0, atomic_1.atomicWriteFile)(filePath, content);
133
138
  }
134
139
  function ensureStatusAllowed(config, statusRaw, flag = "--status") {
135
140
  const normalized = statusRaw.trim().toLowerCase();
@@ -199,7 +204,7 @@ function printTaskMutationReceipt(action, root, loaded, json, checkpoint) {
199
204
  }
200
205
  console.log(`task ${action}: ${loaded.qid}`);
201
206
  }
202
- function runTaskStartCommand(options) {
207
+ function runTaskStartCommandLocked(options) {
203
208
  const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
204
209
  const now = options.now ?? new Date();
205
210
  loaded.frontmatter.status = ensureStatusAllowed(loaded.config, "progress");
@@ -219,7 +224,7 @@ function runTaskStartCommand(options) {
219
224
  maybeWarnEventsDisabled(options.root, loaded.config, loaded.ws);
220
225
  printTaskMutationReceipt("started", options.root, loaded, options.json);
221
226
  }
222
- function runTaskUpdateCommand(options) {
227
+ function runTaskUpdateCommandLocked(options) {
223
228
  const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
224
229
  const now = options.now ?? new Date();
225
230
  if (options.status) {
@@ -261,7 +266,7 @@ function runTaskUpdateCommand(options) {
261
266
  });
262
267
  printTaskMutationReceipt("updated", options.root, loaded, options.json);
263
268
  }
264
- function runTaskDoneCommand(options) {
269
+ function runTaskDoneCommandLocked(options) {
265
270
  const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
266
271
  const now = options.now ?? new Date();
267
272
  const nextLinks = appendUnique(toStringList(loaded.frontmatter.links), parseCsvList(options.addLinks));
@@ -313,3 +318,15 @@ function runTaskDoneCommand(options) {
313
318
  maybeWarnEventsDisabled(options.root, loaded.config, loaded.ws);
314
319
  printTaskMutationReceipt("done", options.root, loaded, options.json, checkpoint);
315
320
  }
321
+ function runTaskStartCommand(options) {
322
+ const config = (0, config_1.loadConfig)(options.root);
323
+ return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runTaskStartCommandLocked(options));
324
+ }
325
+ function runTaskUpdateCommand(options) {
326
+ const config = (0, config_1.loadConfig)(options.root);
327
+ return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runTaskUpdateCommandLocked(options));
328
+ }
329
+ function runTaskDoneCommand(options) {
330
+ const config = (0, config_1.loadConfig)(options.root);
331
+ return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runTaskDoneCommandLocked(options));
332
+ }
@@ -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,9 @@ 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");
17
+ const sqlite_index_1 = require("../graph/sqlite_index");
15
18
  const errors_1 = require("../util/errors");
16
19
  const skill_mirror_1 = require("./skill_mirror");
17
20
  const RECOMMENDED_HEADINGS = {
@@ -205,6 +208,11 @@ function runValidateCommand(options) {
205
208
  const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(options.root, config);
206
209
  const errors = [];
207
210
  const warnings = [];
211
+ if ((0, sqlite_index_1.isSqliteBackend)(config)) {
212
+ const health = (0, sqlite_index_1.sqliteHealth)(options.root, config);
213
+ warnings.push(...health.warnings);
214
+ errors.push(...health.errors);
215
+ }
208
216
  if (templateSchemaInfo.fallbackTypes.length > 0) {
209
217
  warnings.push(`using bundled template schema fallback for missing local type(s): ${templateSchemaInfo.fallbackTypes.join(", ")}; run \`mdkg upgrade --apply\` to vendor built-in templates`);
210
218
  }
@@ -268,6 +276,16 @@ function runValidateCommand(options) {
268
276
  nodes,
269
277
  reverse_edges: {},
270
278
  };
279
+ const importProjection = (0, bundle_imports_1.buildBundleImportsIndex)(options.root, config);
280
+ for (const item of importProjection.index.imports) {
281
+ for (const warning of item.warnings) {
282
+ warnings.push(`bundle import ${item.alias}: ${warning}`);
283
+ }
284
+ for (const error of item.errors) {
285
+ errors.push(`bundle import ${item.alias}: ${error}`);
286
+ }
287
+ }
288
+ const validationIndex = (0, bundle_imports_1.mergeBundleImportsIntoIndex)(index, importProjection);
271
289
  let knownSkills = new Set();
272
290
  try {
273
291
  const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
@@ -284,11 +302,12 @@ function runValidateCommand(options) {
284
302
  const message = err instanceof Error ? err.message : "unknown skill validation error";
285
303
  errors.push(message);
286
304
  }
287
- const graphErrors = (0, validate_graph_1.collectGraphErrors)(index, {
305
+ const graphErrors = (0, validate_graph_1.collectGraphErrors)(validationIndex, {
288
306
  allowMissing: false,
289
307
  knownSkillSlugs: knownSkills,
290
308
  });
291
309
  errors.push(...graphErrors);
310
+ errors.push(...(0, visibility_1.visibilityViolationMessages)((0, visibility_1.collectVisibilityViolations)(validationIndex, config)).map((message) => `visibility: ${message}`));
292
311
  const skillsRoot = (0, skills_indexer_1.resolveSkillsRoot)(options.root, config);
293
312
  for (const dirPath of listDirectories(skillsRoot)) {
294
313
  const canonicalPath = path_1.default.join(dirPath, "SKILL.md");