mdkg 0.1.0 → 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.
- package/CHANGELOG.md +93 -0
- package/README.md +108 -15
- package/dist/cli.js +566 -15
- package/dist/commands/archive.js +474 -0
- package/dist/commands/bundle.js +743 -0
- package/dist/commands/bundle_import.js +243 -0
- package/dist/commands/capability.js +162 -0
- package/dist/commands/doctor.js +233 -2
- package/dist/commands/format.js +38 -9
- package/dist/commands/index.js +11 -0
- package/dist/commands/init.js +188 -63
- package/dist/commands/init_manifest.js +19 -6
- package/dist/commands/list.js +5 -2
- package/dist/commands/new.js +6 -0
- package/dist/commands/next.js +7 -0
- package/dist/commands/node_card.js +4 -1
- package/dist/commands/pack.js +62 -2
- package/dist/commands/query_output.js +1 -0
- package/dist/commands/search.js +5 -2
- package/dist/commands/show.js +7 -14
- package/dist/commands/skill_mirror.js +22 -0
- package/dist/commands/task.js +3 -0
- package/dist/commands/upgrade.js +151 -13
- package/dist/commands/validate.js +19 -2
- package/dist/commands/work.js +365 -0
- package/dist/commands/workspace.js +12 -2
- package/dist/core/config.js +100 -1
- package/dist/graph/agent_file_types.js +78 -5
- package/dist/graph/archive_file.js +125 -0
- package/dist/graph/archive_integrity.js +66 -0
- package/dist/graph/bundle_imports.js +418 -0
- package/dist/graph/capabilities_index_cache.js +103 -0
- package/dist/graph/capabilities_indexer.js +231 -0
- package/dist/graph/frontmatter.js +19 -0
- package/dist/graph/index_cache.js +21 -4
- package/dist/graph/indexer.js +4 -1
- package/dist/graph/node.js +23 -4
- package/dist/graph/node_body.js +37 -0
- package/dist/graph/skills_indexer.js +8 -3
- package/dist/graph/template_schema.js +33 -5
- package/dist/graph/validate_graph.js +83 -7
- package/dist/graph/visibility.js +214 -0
- package/dist/graph/workspace_files.js +22 -0
- package/dist/init/AGENT_START.md +21 -0
- package/dist/init/CLI_COMMAND_MATRIX.md +58 -3
- package/dist/init/README.md +60 -3
- package/dist/init/config.json +13 -1
- package/dist/init/core/guide.md +6 -2
- package/dist/init/core/rule-3-cli-contract.md +71 -4
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +20 -0
- package/dist/init/core/rule-6-templates-and-schemas.md +10 -1
- package/dist/init/init-manifest.json +19 -14
- package/dist/init/skills/default/build-pack-and-execute-task/SKILL.md +2 -1
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +26 -0
- package/dist/init/templates/default/archive.md +33 -0
- package/dist/init/templates/default/receipt.md +15 -1
- package/dist/init/templates/default/work.md +6 -1
- package/dist/init/templates/default/work_order.md +15 -1
- package/dist/pack/export_md.js +3 -0
- package/dist/pack/export_xml.js +3 -0
- package/dist/pack/order.js +1 -0
- package/dist/pack/pack.js +3 -13
- package/dist/templates/builtin.js +38 -0
- package/dist/templates/loader.js +9 -16
- package/dist/util/argparse.js +30 -0
- package/dist/util/refs.js +40 -0
- package/dist/util/zip.js +153 -0
- package/package.json +8 -2
package/dist/commands/pack.js
CHANGED
|
@@ -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
|
: {};
|
package/dist/commands/search.js
CHANGED
|
@@ -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,
|
package/dist/commands/show.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
}
|
package/dist/commands/task.js
CHANGED
|
@@ -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
|
}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runUpgradeCommand = runUpgradeCommand;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
9
10
|
const migrate_1 = require("../core/migrate");
|
|
10
11
|
const config_1 = require("../core/config");
|
|
11
12
|
const paths_1 = require("../core/paths");
|
|
@@ -17,6 +18,7 @@ const skill_mirror_1 = require("./skill_mirror");
|
|
|
17
18
|
const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
|
|
18
19
|
const PROTECTED_CORE_DOCS = new Set([".mdkg/core/SOUL.md", ".mdkg/core/HUMAN.md"]);
|
|
19
20
|
const CREATE_ONLY_PRESERVED = new Set([".mdkg/core/core.md"]);
|
|
21
|
+
const ARCHIVE_RAW_IGNORE_ENTRIES = [".mdkg/archive/**/source/"];
|
|
20
22
|
function seededInitEvent(nowIso) {
|
|
21
23
|
const event = {
|
|
22
24
|
ts: nowIso,
|
|
@@ -85,6 +87,9 @@ function record(summary, changes, change) {
|
|
|
85
87
|
summary.skipped += 1;
|
|
86
88
|
summary.conflicted += 1;
|
|
87
89
|
break;
|
|
90
|
+
case "skip":
|
|
91
|
+
summary.skipped += 1;
|
|
92
|
+
break;
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
function buildKnownHashes(manifests) {
|
|
@@ -103,7 +108,7 @@ function buildKnownHashes(manifests) {
|
|
|
103
108
|
return hashes;
|
|
104
109
|
}
|
|
105
110
|
function shouldIncludeFile(file, agentWorkspace) {
|
|
106
|
-
if (file.category === "default_skill") {
|
|
111
|
+
if (file.category === "agent_doc" || file.category === "startup_doc" || file.category === "default_skill") {
|
|
107
112
|
return agentWorkspace;
|
|
108
113
|
}
|
|
109
114
|
return file.category !== "config";
|
|
@@ -185,11 +190,59 @@ function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
|
185
190
|
writeFile(cfgPath, `${JSON.stringify(migrated.config, null, 2)}\n`);
|
|
186
191
|
}
|
|
187
192
|
}
|
|
193
|
+
function isIgnoredBySimpleGitignore(root, relativePath) {
|
|
194
|
+
const ignorePath = path_1.default.join(root, ".gitignore");
|
|
195
|
+
if (!fs_1.default.existsSync(ignorePath)) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
199
|
+
const lines = fs_1.default.readFileSync(ignorePath, "utf8").split(/\r?\n/);
|
|
200
|
+
let ignored = false;
|
|
201
|
+
for (const rawLine of lines) {
|
|
202
|
+
const line = rawLine.trim();
|
|
203
|
+
if (!line || line.startsWith("#")) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const negated = line.startsWith("!");
|
|
207
|
+
const pattern = negated ? line.slice(1) : line;
|
|
208
|
+
const normalizedPattern = pattern.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
209
|
+
const matches = normalizedPattern === normalized ||
|
|
210
|
+
(normalizedPattern.endsWith("/") && normalized.startsWith(normalizedPattern)) ||
|
|
211
|
+
(normalizedPattern.endsWith("/*") && normalized.startsWith(normalizedPattern.slice(0, -1)));
|
|
212
|
+
if (matches) {
|
|
213
|
+
ignored = !negated;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return ignored;
|
|
217
|
+
}
|
|
218
|
+
function isGitIgnored(root, relativePath) {
|
|
219
|
+
const result = (0, child_process_1.spawnSync)("git", ["check-ignore", "--quiet", "--", relativePath], {
|
|
220
|
+
cwd: root,
|
|
221
|
+
stdio: "ignore",
|
|
222
|
+
});
|
|
223
|
+
if (result.status === 0) {
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
if (result.status === 1) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return isIgnoredBySimpleGitignore(root, relativePath);
|
|
230
|
+
}
|
|
188
231
|
function ensureAgentRuntimeFiles(root, dryRun, summary, changes) {
|
|
189
232
|
const eventsPath = path_1.default.join(root, ".mdkg", "work", "events", "events.jsonl");
|
|
233
|
+
const relEventsPath = ".mdkg/work/events/events.jsonl";
|
|
190
234
|
if (!fs_1.default.existsSync(eventsPath)) {
|
|
235
|
+
if (isGitIgnored(root, relEventsPath)) {
|
|
236
|
+
record(summary, changes, {
|
|
237
|
+
path: relEventsPath,
|
|
238
|
+
category: "event_log",
|
|
239
|
+
action: "skip",
|
|
240
|
+
reason: "event log path is ignored; run `mdkg event enable` if local event provenance should be restored",
|
|
241
|
+
});
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
191
244
|
record(summary, changes, {
|
|
192
|
-
path:
|
|
245
|
+
path: relEventsPath,
|
|
193
246
|
category: "event_log",
|
|
194
247
|
action: "create",
|
|
195
248
|
reason: "agent workspace is missing event log",
|
|
@@ -202,9 +255,71 @@ function ensureAgentRuntimeFiles(root, dryRun, summary, changes) {
|
|
|
202
255
|
summary.unchanged += 1;
|
|
203
256
|
}
|
|
204
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
|
+
}
|
|
279
|
+
function isWritableChange(change) {
|
|
280
|
+
return change.action === "create" || change.action === "update" || change.action === "migrate" || change.action === "sync";
|
|
281
|
+
}
|
|
282
|
+
function buildApplySideEffects(options) {
|
|
283
|
+
const hasDirectWrites = options.changes.some(isWritableChange);
|
|
284
|
+
if (!hasDirectWrites && options.existingManifest) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
const effects = [
|
|
288
|
+
{
|
|
289
|
+
path: ".mdkg/init-manifest.json",
|
|
290
|
+
category: "init_manifest",
|
|
291
|
+
action: options.existingManifest ? "update" : "create",
|
|
292
|
+
reason: "records managed init asset fingerprints after apply",
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
if (options.agentWorkspace) {
|
|
296
|
+
effects.push({
|
|
297
|
+
path: ".mdkg/skills/registry.md",
|
|
298
|
+
category: "skill_registry",
|
|
299
|
+
action: "update",
|
|
300
|
+
reason: "refreshes canonical skill registry after apply",
|
|
301
|
+
}, {
|
|
302
|
+
path: ".agents/skills,.claude/skills",
|
|
303
|
+
category: "skill_mirror",
|
|
304
|
+
action: "sync",
|
|
305
|
+
reason: "syncs managed skill mirrors after apply",
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
return effects;
|
|
309
|
+
}
|
|
205
310
|
function emitHumanReceipt(receipt) {
|
|
206
311
|
const mode = receipt.dry_run ? "dry-run" : "apply";
|
|
207
312
|
console.log(`mdkg upgrade ${mode}: ${receipt.summary.created} create, ${receipt.summary.updated} update, ${receipt.summary.migrated} migrate, ${receipt.summary.synced} sync, ${receipt.summary.conflicted} conflict`);
|
|
313
|
+
console.log(`safe to apply: ${receipt.safe_to_apply ? "yes" : "no"}`);
|
|
314
|
+
if (receipt.will_write_paths.length > 0) {
|
|
315
|
+
console.log(`will write: ${receipt.will_write_paths.join(", ")}`);
|
|
316
|
+
}
|
|
317
|
+
if (receipt.preserved_customizations.length > 0) {
|
|
318
|
+
console.log(`preserved customizations: ${receipt.preserved_customizations.length}`);
|
|
319
|
+
}
|
|
320
|
+
if (receipt.blocking_conflicts.length > 0) {
|
|
321
|
+
console.log(`blocking conflicts: ${receipt.blocking_conflicts.length}`);
|
|
322
|
+
}
|
|
208
323
|
if (receipt.changes.length === 0) {
|
|
209
324
|
console.log("no upgrade changes pending");
|
|
210
325
|
}
|
|
@@ -213,8 +328,18 @@ function emitHumanReceipt(receipt) {
|
|
|
213
328
|
console.log(` ${change.action}: ${change.path} (${change.reason})`);
|
|
214
329
|
}
|
|
215
330
|
}
|
|
216
|
-
if (receipt.
|
|
217
|
-
|
|
331
|
+
if (receipt.apply_side_effects.length > 0) {
|
|
332
|
+
for (const effect of receipt.apply_side_effects) {
|
|
333
|
+
console.log(` apply-side-effect: ${effect.path} (${effect.reason})`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (receipt.dry_run && receipt.will_write_paths.length > 0) {
|
|
337
|
+
if (receipt.safe_to_apply) {
|
|
338
|
+
console.log("next: mdkg upgrade --apply (writes only safe managed paths; preserves customized files)");
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.log("next: resolve blocking conflicts before running mdkg upgrade --apply");
|
|
342
|
+
}
|
|
218
343
|
}
|
|
219
344
|
}
|
|
220
345
|
function runUpgradeCommand(options) {
|
|
@@ -250,30 +375,43 @@ function runUpgradeCommand(options) {
|
|
|
250
375
|
if (agentWorkspace) {
|
|
251
376
|
ensureAgentRuntimeFiles(root, dryRun, summary, changes);
|
|
252
377
|
}
|
|
378
|
+
ensureArchiveIgnorePolicy(root, dryRun, summary, changes);
|
|
379
|
+
const applySideEffects = buildApplySideEffects({
|
|
380
|
+
existingManifest,
|
|
381
|
+
agentWorkspace,
|
|
382
|
+
changes,
|
|
383
|
+
});
|
|
384
|
+
for (const effect of applySideEffects) {
|
|
385
|
+
record(summary, changes, effect);
|
|
386
|
+
}
|
|
253
387
|
if (!dryRun) {
|
|
254
388
|
const appliedManifest = {
|
|
255
389
|
...currentManifest,
|
|
256
390
|
files: managedCurrentFiles.sort((a, b) => a.path.localeCompare(b.path)),
|
|
257
391
|
};
|
|
258
|
-
|
|
259
|
-
|
|
392
|
+
if (applySideEffects.length > 0) {
|
|
393
|
+
(0, init_manifest_1.writeInitManifest)(path_1.default.join(root, ".mdkg", init_manifest_1.INIT_MANIFEST_FILE), appliedManifest);
|
|
394
|
+
}
|
|
395
|
+
if (agentWorkspace && applySideEffects.length > 0) {
|
|
260
396
|
const config = (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(JSON.parse(fs_1.default.readFileSync((0, paths_1.configPath)(root), "utf8"))).config);
|
|
261
397
|
(0, skill_support_1.refreshSkillsRegistry)(root, config);
|
|
262
398
|
(0, skill_mirror_1.scaffoldMirrorRoots)(root);
|
|
263
|
-
|
|
264
|
-
record(summary, changes, {
|
|
265
|
-
path: ".agents/skills,.claude/skills",
|
|
266
|
-
category: "skill_mirror",
|
|
267
|
-
action: "sync",
|
|
268
|
-
reason: `${result.synced} mirrored skill(s), ${result.pruned} stale mirror(s) pruned`,
|
|
269
|
-
});
|
|
399
|
+
(0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true });
|
|
270
400
|
}
|
|
271
401
|
}
|
|
402
|
+
const preservedCustomizations = changes.filter((change) => change.action === "conflict");
|
|
403
|
+
const blockingConflicts = [];
|
|
404
|
+
const willWritePaths = changes.filter(isWritableChange).map((change) => change.path);
|
|
272
405
|
const receipt = {
|
|
273
406
|
action: "upgrade",
|
|
274
407
|
dry_run: dryRun,
|
|
275
408
|
version,
|
|
409
|
+
safe_to_apply: blockingConflicts.length === 0,
|
|
276
410
|
summary,
|
|
411
|
+
will_write_paths: Array.from(new Set(willWritePaths)),
|
|
412
|
+
preserved_customizations: preservedCustomizations,
|
|
413
|
+
blocking_conflicts: blockingConflicts,
|
|
414
|
+
apply_side_effects: applySideEffects,
|
|
277
415
|
changes,
|
|
278
416
|
};
|
|
279
417
|
if (options.json) {
|
|
@@ -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 = {
|
|
@@ -200,10 +202,14 @@ function validateEventsJsonl(root, config, errors) {
|
|
|
200
202
|
}
|
|
201
203
|
function runValidateCommand(options) {
|
|
202
204
|
const config = (0, config_1.loadConfig)(options.root);
|
|
203
|
-
const
|
|
205
|
+
const templateSchemaInfo = (0, template_schema_1.loadTemplateSchemasWithInfo)(options.root, config, node_1.ALLOWED_TYPES);
|
|
206
|
+
const templateSchemas = templateSchemaInfo.schemas;
|
|
204
207
|
const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(options.root, config);
|
|
205
208
|
const errors = [];
|
|
206
209
|
const warnings = [];
|
|
210
|
+
if (templateSchemaInfo.fallbackTypes.length > 0) {
|
|
211
|
+
warnings.push(`using bundled template schema fallback for missing local type(s): ${templateSchemaInfo.fallbackTypes.join(", ")}; run \`mdkg upgrade --apply\` to vendor built-in templates`);
|
|
212
|
+
}
|
|
207
213
|
const nodes = {};
|
|
208
214
|
const idsByWorkspace = {};
|
|
209
215
|
for (const [alias, files] of Object.entries(filesByAlias)) {
|
|
@@ -264,6 +270,16 @@ function runValidateCommand(options) {
|
|
|
264
270
|
nodes,
|
|
265
271
|
reverse_edges: {},
|
|
266
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);
|
|
267
283
|
let knownSkills = new Set();
|
|
268
284
|
try {
|
|
269
285
|
const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
|
|
@@ -280,11 +296,12 @@ function runValidateCommand(options) {
|
|
|
280
296
|
const message = err instanceof Error ? err.message : "unknown skill validation error";
|
|
281
297
|
errors.push(message);
|
|
282
298
|
}
|
|
283
|
-
const graphErrors = (0, validate_graph_1.collectGraphErrors)(
|
|
299
|
+
const graphErrors = (0, validate_graph_1.collectGraphErrors)(validationIndex, {
|
|
284
300
|
allowMissing: false,
|
|
285
301
|
knownSkillSlugs: knownSkills,
|
|
286
302
|
});
|
|
287
303
|
errors.push(...graphErrors);
|
|
304
|
+
errors.push(...(0, visibility_1.visibilityViolationMessages)((0, visibility_1.collectVisibilityViolations)(validationIndex, config)).map((message) => `visibility: ${message}`));
|
|
288
305
|
const skillsRoot = (0, skills_indexer_1.resolveSkillsRoot)(options.root, config);
|
|
289
306
|
for (const dirPath of listDirectories(skillsRoot)) {
|
|
290
307
|
const canonicalPath = path_1.default.join(dirPath, "SKILL.md");
|