mdkg 0.0.9 → 0.1.1
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 +29 -0
- package/README.md +20 -2
- package/dist/cli.js +35 -0
- package/dist/commands/doctor.js +10 -2
- package/dist/commands/init.js +4 -0
- package/dist/commands/init_manifest.js +131 -0
- package/dist/commands/new.js +3 -0
- package/dist/commands/upgrade.js +401 -0
- package/dist/commands/validate.js +5 -1
- package/dist/core/version.js +31 -0
- package/dist/graph/template_schema.js +33 -5
- package/dist/init/AGENT_START.md +1 -0
- package/dist/init/CLI_COMMAND_MATRIX.md +8 -0
- package/dist/init/README.md +7 -0
- package/dist/init/core/rule-6-templates-and-schemas.md +3 -1
- package/dist/init/init-manifest.json +197 -0
- package/dist/init/legacy/v0.0.9-init-manifest.json +197 -0
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +11 -10
- package/dist/templates/builtin.js +38 -0
- package/dist/templates/loader.js +9 -16
- package/dist/util/argparse.js +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runUpgradeCommand = runUpgradeCommand;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const migrate_1 = require("../core/migrate");
|
|
11
|
+
const config_1 = require("../core/config");
|
|
12
|
+
const paths_1 = require("../core/paths");
|
|
13
|
+
const version_1 = require("../core/version");
|
|
14
|
+
const errors_1 = require("../util/errors");
|
|
15
|
+
const init_manifest_1 = require("./init_manifest");
|
|
16
|
+
const skill_support_1 = require("./skill_support");
|
|
17
|
+
const skill_mirror_1 = require("./skill_mirror");
|
|
18
|
+
const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
|
|
19
|
+
const PROTECTED_CORE_DOCS = new Set([".mdkg/core/SOUL.md", ".mdkg/core/HUMAN.md"]);
|
|
20
|
+
const CREATE_ONLY_PRESERVED = new Set([".mdkg/core/core.md"]);
|
|
21
|
+
function seededInitEvent(nowIso) {
|
|
22
|
+
const event = {
|
|
23
|
+
ts: nowIso,
|
|
24
|
+
run_id: `upgrade-${nowIso.replace(/[^0-9]/g, "").slice(0, 14)}`,
|
|
25
|
+
workspace: "root",
|
|
26
|
+
agent: "mdkg",
|
|
27
|
+
kind: "RUN_STARTED",
|
|
28
|
+
status: "ok",
|
|
29
|
+
refs: ["edd-4"],
|
|
30
|
+
artifacts: [],
|
|
31
|
+
notes: "upgrade ensured agent event log",
|
|
32
|
+
redacted: true,
|
|
33
|
+
};
|
|
34
|
+
return `${JSON.stringify(event)}\n`;
|
|
35
|
+
}
|
|
36
|
+
function requireSeedAssets(seedRoot) {
|
|
37
|
+
for (const required of ["config.json", "README.md", "core", "templates"]) {
|
|
38
|
+
if (!fs_1.default.existsSync(path_1.default.join(seedRoot, required))) {
|
|
39
|
+
throw new errors_1.NotFoundError(`upgrade assets missing ${required} at ${seedRoot} (try reinstalling mdkg)`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isAgentWorkspace(root) {
|
|
44
|
+
return [
|
|
45
|
+
path_1.default.join(root, ".mdkg", "skills"),
|
|
46
|
+
path_1.default.join(root, ".agents", "skills"),
|
|
47
|
+
path_1.default.join(root, ".claude", "skills"),
|
|
48
|
+
path_1.default.join(root, ".mdkg", "work", "events", "events.jsonl"),
|
|
49
|
+
].some((candidate) => fs_1.default.existsSync(candidate));
|
|
50
|
+
}
|
|
51
|
+
function copyFile(src, dest) {
|
|
52
|
+
fs_1.default.mkdirSync(path_1.default.dirname(dest), { recursive: true });
|
|
53
|
+
fs_1.default.copyFileSync(src, dest);
|
|
54
|
+
}
|
|
55
|
+
function writeFile(filePath, content) {
|
|
56
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
57
|
+
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
58
|
+
}
|
|
59
|
+
function createSummary() {
|
|
60
|
+
return {
|
|
61
|
+
created: 0,
|
|
62
|
+
updated: 0,
|
|
63
|
+
migrated: 0,
|
|
64
|
+
synced: 0,
|
|
65
|
+
skipped: 0,
|
|
66
|
+
conflicted: 0,
|
|
67
|
+
unchanged: 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function record(summary, changes, change) {
|
|
71
|
+
changes.push(change);
|
|
72
|
+
switch (change.action) {
|
|
73
|
+
case "create":
|
|
74
|
+
summary.created += 1;
|
|
75
|
+
break;
|
|
76
|
+
case "update":
|
|
77
|
+
summary.updated += 1;
|
|
78
|
+
break;
|
|
79
|
+
case "migrate":
|
|
80
|
+
summary.migrated += 1;
|
|
81
|
+
break;
|
|
82
|
+
case "sync":
|
|
83
|
+
summary.synced += 1;
|
|
84
|
+
break;
|
|
85
|
+
case "conflict":
|
|
86
|
+
summary.skipped += 1;
|
|
87
|
+
summary.conflicted += 1;
|
|
88
|
+
break;
|
|
89
|
+
case "skip":
|
|
90
|
+
summary.skipped += 1;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function buildKnownHashes(manifests) {
|
|
95
|
+
const hashes = new Map();
|
|
96
|
+
for (const manifest of manifests) {
|
|
97
|
+
if (!manifest) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
for (const file of manifest.files) {
|
|
101
|
+
if (!hashes.has(file.path)) {
|
|
102
|
+
hashes.set(file.path, new Set());
|
|
103
|
+
}
|
|
104
|
+
hashes.get(file.path)?.add(file.sha256);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return hashes;
|
|
108
|
+
}
|
|
109
|
+
function shouldIncludeFile(file, agentWorkspace) {
|
|
110
|
+
if (file.category === "default_skill") {
|
|
111
|
+
return agentWorkspace;
|
|
112
|
+
}
|
|
113
|
+
return file.category !== "config";
|
|
114
|
+
}
|
|
115
|
+
function planSeedFile(options) {
|
|
116
|
+
const destPath = path_1.default.join(options.root, options.file.path);
|
|
117
|
+
const srcPath = (0, init_manifest_1.seedSourcePath)(options.seedRoot, options.file);
|
|
118
|
+
const currentHash = fs_1.default.existsSync(destPath) && fs_1.default.statSync(destPath).isFile() ? (0, init_manifest_1.sha256File)(destPath) : undefined;
|
|
119
|
+
const nextHash = options.file.sha256;
|
|
120
|
+
if (!currentHash) {
|
|
121
|
+
record(options.summary, options.changes, {
|
|
122
|
+
path: options.file.path,
|
|
123
|
+
category: options.file.category,
|
|
124
|
+
action: "create",
|
|
125
|
+
reason: "missing managed init asset",
|
|
126
|
+
});
|
|
127
|
+
if (!options.dryRun) {
|
|
128
|
+
copyFile(srcPath, destPath);
|
|
129
|
+
}
|
|
130
|
+
options.managedCurrentFiles.push(options.file);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (currentHash === nextHash) {
|
|
134
|
+
options.summary.unchanged += 1;
|
|
135
|
+
options.managedCurrentFiles.push(options.file);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (CREATE_ONLY_PRESERVED.has(options.file.path)) {
|
|
139
|
+
options.summary.unchanged += 1;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
if (PROTECTED_CORE_DOCS.has(options.file.path)) {
|
|
143
|
+
record(options.summary, options.changes, {
|
|
144
|
+
path: options.file.path,
|
|
145
|
+
category: options.file.category,
|
|
146
|
+
action: "conflict",
|
|
147
|
+
reason: "protected core document exists; local content preserved",
|
|
148
|
+
});
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const known = options.knownHashes.get(options.file.path);
|
|
152
|
+
if (known?.has(currentHash)) {
|
|
153
|
+
record(options.summary, options.changes, {
|
|
154
|
+
path: options.file.path,
|
|
155
|
+
category: options.file.category,
|
|
156
|
+
action: "update",
|
|
157
|
+
reason: "matches a managed seed hash",
|
|
158
|
+
});
|
|
159
|
+
if (!options.dryRun) {
|
|
160
|
+
copyFile(srcPath, destPath);
|
|
161
|
+
}
|
|
162
|
+
options.managedCurrentFiles.push(options.file);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
record(options.summary, options.changes, {
|
|
166
|
+
path: options.file.path,
|
|
167
|
+
category: options.file.category,
|
|
168
|
+
action: "conflict",
|
|
169
|
+
reason: "local changes detected; content preserved",
|
|
170
|
+
});
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
174
|
+
const cfgPath = (0, paths_1.configPath)(root);
|
|
175
|
+
const raw = JSON.parse(fs_1.default.readFileSync(cfgPath, "utf8"));
|
|
176
|
+
const migrated = (0, migrate_1.migrateConfig)(raw);
|
|
177
|
+
(0, config_1.validateConfigSchema)(migrated.config);
|
|
178
|
+
if (migrated.from === migrated.to) {
|
|
179
|
+
summary.unchanged += 1;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
record(summary, changes, {
|
|
183
|
+
path: ".mdkg/config.json",
|
|
184
|
+
category: "config",
|
|
185
|
+
action: "migrate",
|
|
186
|
+
reason: `config schema_version ${migrated.from} -> ${migrated.to}`,
|
|
187
|
+
});
|
|
188
|
+
if (!dryRun) {
|
|
189
|
+
writeFile(cfgPath, `${JSON.stringify(migrated.config, null, 2)}\n`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function isIgnoredBySimpleGitignore(root, relativePath) {
|
|
193
|
+
const ignorePath = path_1.default.join(root, ".gitignore");
|
|
194
|
+
if (!fs_1.default.existsSync(ignorePath)) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
198
|
+
const lines = fs_1.default.readFileSync(ignorePath, "utf8").split(/\r?\n/);
|
|
199
|
+
let ignored = false;
|
|
200
|
+
for (const rawLine of lines) {
|
|
201
|
+
const line = rawLine.trim();
|
|
202
|
+
if (!line || line.startsWith("#")) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const negated = line.startsWith("!");
|
|
206
|
+
const pattern = negated ? line.slice(1) : line;
|
|
207
|
+
const normalizedPattern = pattern.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
208
|
+
const matches = normalizedPattern === normalized ||
|
|
209
|
+
(normalizedPattern.endsWith("/") && normalized.startsWith(normalizedPattern)) ||
|
|
210
|
+
(normalizedPattern.endsWith("/*") && normalized.startsWith(normalizedPattern.slice(0, -1)));
|
|
211
|
+
if (matches) {
|
|
212
|
+
ignored = !negated;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return ignored;
|
|
216
|
+
}
|
|
217
|
+
function isGitIgnored(root, relativePath) {
|
|
218
|
+
const result = (0, child_process_1.spawnSync)("git", ["check-ignore", "--quiet", "--", relativePath], {
|
|
219
|
+
cwd: root,
|
|
220
|
+
stdio: "ignore",
|
|
221
|
+
});
|
|
222
|
+
if (result.status === 0) {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
if (result.status === 1) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
return isIgnoredBySimpleGitignore(root, relativePath);
|
|
229
|
+
}
|
|
230
|
+
function ensureAgentRuntimeFiles(root, dryRun, summary, changes) {
|
|
231
|
+
const eventsPath = path_1.default.join(root, ".mdkg", "work", "events", "events.jsonl");
|
|
232
|
+
const relEventsPath = ".mdkg/work/events/events.jsonl";
|
|
233
|
+
if (!fs_1.default.existsSync(eventsPath)) {
|
|
234
|
+
if (isGitIgnored(root, relEventsPath)) {
|
|
235
|
+
record(summary, changes, {
|
|
236
|
+
path: relEventsPath,
|
|
237
|
+
category: "event_log",
|
|
238
|
+
action: "skip",
|
|
239
|
+
reason: "event log path is ignored; run `mdkg event enable` if local event provenance should be restored",
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
record(summary, changes, {
|
|
244
|
+
path: relEventsPath,
|
|
245
|
+
category: "event_log",
|
|
246
|
+
action: "create",
|
|
247
|
+
reason: "agent workspace is missing event log",
|
|
248
|
+
});
|
|
249
|
+
if (!dryRun) {
|
|
250
|
+
writeFile(eventsPath, seededInitEvent(new Date().toISOString()));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
summary.unchanged += 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function isWritableChange(change) {
|
|
258
|
+
return change.action === "create" || change.action === "update" || change.action === "migrate" || change.action === "sync";
|
|
259
|
+
}
|
|
260
|
+
function buildApplySideEffects(options) {
|
|
261
|
+
const hasDirectWrites = options.changes.some(isWritableChange);
|
|
262
|
+
if (!hasDirectWrites && options.existingManifest) {
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
265
|
+
const effects = [
|
|
266
|
+
{
|
|
267
|
+
path: ".mdkg/init-manifest.json",
|
|
268
|
+
category: "init_manifest",
|
|
269
|
+
action: options.existingManifest ? "update" : "create",
|
|
270
|
+
reason: "records managed init asset fingerprints after apply",
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
if (options.agentWorkspace) {
|
|
274
|
+
effects.push({
|
|
275
|
+
path: ".mdkg/skills/registry.md",
|
|
276
|
+
category: "skill_registry",
|
|
277
|
+
action: "update",
|
|
278
|
+
reason: "refreshes canonical skill registry after apply",
|
|
279
|
+
}, {
|
|
280
|
+
path: ".agents/skills,.claude/skills",
|
|
281
|
+
category: "skill_mirror",
|
|
282
|
+
action: "sync",
|
|
283
|
+
reason: "syncs managed skill mirrors after apply",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return effects;
|
|
287
|
+
}
|
|
288
|
+
function emitHumanReceipt(receipt) {
|
|
289
|
+
const mode = receipt.dry_run ? "dry-run" : "apply";
|
|
290
|
+
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`);
|
|
291
|
+
console.log(`safe to apply: ${receipt.safe_to_apply ? "yes" : "no"}`);
|
|
292
|
+
if (receipt.will_write_paths.length > 0) {
|
|
293
|
+
console.log(`will write: ${receipt.will_write_paths.join(", ")}`);
|
|
294
|
+
}
|
|
295
|
+
if (receipt.preserved_customizations.length > 0) {
|
|
296
|
+
console.log(`preserved customizations: ${receipt.preserved_customizations.length}`);
|
|
297
|
+
}
|
|
298
|
+
if (receipt.blocking_conflicts.length > 0) {
|
|
299
|
+
console.log(`blocking conflicts: ${receipt.blocking_conflicts.length}`);
|
|
300
|
+
}
|
|
301
|
+
if (receipt.changes.length === 0) {
|
|
302
|
+
console.log("no upgrade changes pending");
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
for (const change of receipt.changes) {
|
|
306
|
+
console.log(` ${change.action}: ${change.path} (${change.reason})`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (receipt.apply_side_effects.length > 0) {
|
|
310
|
+
for (const effect of receipt.apply_side_effects) {
|
|
311
|
+
console.log(` apply-side-effect: ${effect.path} (${effect.reason})`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (receipt.dry_run && receipt.will_write_paths.length > 0) {
|
|
315
|
+
if (receipt.safe_to_apply) {
|
|
316
|
+
console.log("next: mdkg upgrade --apply (writes only safe managed paths; preserves customized files)");
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
console.log("next: resolve blocking conflicts before running mdkg upgrade --apply");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function runUpgradeCommand(options) {
|
|
324
|
+
const root = path_1.default.resolve(options.root);
|
|
325
|
+
const seedRoot = options.seedRoot ? path_1.default.resolve(options.seedRoot) : DEFAULT_SEED_SUBDIR;
|
|
326
|
+
const dryRun = !options.apply;
|
|
327
|
+
const version = (0, version_1.readPackageVersion)();
|
|
328
|
+
requireSeedAssets(seedRoot);
|
|
329
|
+
const currentManifest = (0, init_manifest_1.createInitManifest)(seedRoot, version);
|
|
330
|
+
const existingManifest = (0, init_manifest_1.readInitManifest)(path_1.default.join(root, ".mdkg", init_manifest_1.INIT_MANIFEST_FILE));
|
|
331
|
+
const legacyManifests = (0, init_manifest_1.loadLegacyInitManifests)(seedRoot);
|
|
332
|
+
const knownHashes = buildKnownHashes([existingManifest, ...legacyManifests]);
|
|
333
|
+
const summary = createSummary();
|
|
334
|
+
const changes = [];
|
|
335
|
+
const agentWorkspace = isAgentWorkspace(root);
|
|
336
|
+
const managedCurrentFiles = [];
|
|
337
|
+
migrateConfigIfNeeded(root, dryRun, summary, changes);
|
|
338
|
+
for (const file of currentManifest.files) {
|
|
339
|
+
if (!shouldIncludeFile(file, agentWorkspace)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
planSeedFile({
|
|
343
|
+
root,
|
|
344
|
+
seedRoot,
|
|
345
|
+
file,
|
|
346
|
+
knownHashes,
|
|
347
|
+
dryRun,
|
|
348
|
+
summary,
|
|
349
|
+
changes,
|
|
350
|
+
managedCurrentFiles,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (agentWorkspace) {
|
|
354
|
+
ensureAgentRuntimeFiles(root, dryRun, summary, changes);
|
|
355
|
+
}
|
|
356
|
+
const applySideEffects = buildApplySideEffects({
|
|
357
|
+
existingManifest,
|
|
358
|
+
agentWorkspace,
|
|
359
|
+
changes,
|
|
360
|
+
});
|
|
361
|
+
for (const effect of applySideEffects) {
|
|
362
|
+
record(summary, changes, effect);
|
|
363
|
+
}
|
|
364
|
+
if (!dryRun) {
|
|
365
|
+
const appliedManifest = {
|
|
366
|
+
...currentManifest,
|
|
367
|
+
files: managedCurrentFiles.sort((a, b) => a.path.localeCompare(b.path)),
|
|
368
|
+
};
|
|
369
|
+
if (applySideEffects.length > 0) {
|
|
370
|
+
(0, init_manifest_1.writeInitManifest)(path_1.default.join(root, ".mdkg", init_manifest_1.INIT_MANIFEST_FILE), appliedManifest);
|
|
371
|
+
}
|
|
372
|
+
if (agentWorkspace && applySideEffects.length > 0) {
|
|
373
|
+
const config = (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(JSON.parse(fs_1.default.readFileSync((0, paths_1.configPath)(root), "utf8"))).config);
|
|
374
|
+
(0, skill_support_1.refreshSkillsRegistry)(root, config);
|
|
375
|
+
(0, skill_mirror_1.scaffoldMirrorRoots)(root);
|
|
376
|
+
(0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true });
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const preservedCustomizations = changes.filter((change) => change.action === "conflict");
|
|
380
|
+
const blockingConflicts = [];
|
|
381
|
+
const willWritePaths = changes.filter(isWritableChange).map((change) => change.path);
|
|
382
|
+
const receipt = {
|
|
383
|
+
action: "upgrade",
|
|
384
|
+
dry_run: dryRun,
|
|
385
|
+
version,
|
|
386
|
+
safe_to_apply: blockingConflicts.length === 0,
|
|
387
|
+
summary,
|
|
388
|
+
will_write_paths: Array.from(new Set(willWritePaths)),
|
|
389
|
+
preserved_customizations: preservedCustomizations,
|
|
390
|
+
blocking_conflicts: blockingConflicts,
|
|
391
|
+
apply_side_effects: applySideEffects,
|
|
392
|
+
changes,
|
|
393
|
+
};
|
|
394
|
+
if (options.json) {
|
|
395
|
+
console.log(`${JSON.stringify(receipt, null, 2)}`);
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
emitHumanReceipt(receipt);
|
|
399
|
+
}
|
|
400
|
+
return receipt;
|
|
401
|
+
}
|
|
@@ -200,10 +200,14 @@ function validateEventsJsonl(root, config, errors) {
|
|
|
200
200
|
}
|
|
201
201
|
function runValidateCommand(options) {
|
|
202
202
|
const config = (0, config_1.loadConfig)(options.root);
|
|
203
|
-
const
|
|
203
|
+
const templateSchemaInfo = (0, template_schema_1.loadTemplateSchemasWithInfo)(options.root, config, node_1.ALLOWED_TYPES);
|
|
204
|
+
const templateSchemas = templateSchemaInfo.schemas;
|
|
204
205
|
const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(options.root, config);
|
|
205
206
|
const errors = [];
|
|
206
207
|
const warnings = [];
|
|
208
|
+
if (templateSchemaInfo.fallbackTypes.length > 0) {
|
|
209
|
+
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
|
+
}
|
|
207
211
|
const nodes = {};
|
|
208
212
|
const idsByWorkspace = {};
|
|
209
213
|
for (const [alias, files] of Object.entries(filesByAlias)) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readPackageVersion = readPackageVersion;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function readPackageVersion(startDir = __dirname) {
|
|
10
|
+
let current = path_1.default.resolve(startDir);
|
|
11
|
+
for (let i = 0; i < 5; i += 1) {
|
|
12
|
+
const packagePath = path_1.default.join(current, "package.json");
|
|
13
|
+
if (fs_1.default.existsSync(packagePath)) {
|
|
14
|
+
try {
|
|
15
|
+
const raw = JSON.parse(fs_1.default.readFileSync(packagePath, "utf8"));
|
|
16
|
+
if (raw.name === "mdkg" && typeof raw.version === "string" && raw.version.trim().length > 0) {
|
|
17
|
+
return raw.version;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const parent = path_1.default.dirname(current);
|
|
25
|
+
if (parent === current) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
current = parent;
|
|
29
|
+
}
|
|
30
|
+
return "unknown";
|
|
31
|
+
}
|
|
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.loadTemplateSchemas = loadTemplateSchemas;
|
|
7
|
+
exports.loadTemplateSchemasWithInfo = loadTemplateSchemasWithInfo;
|
|
7
8
|
const fs_1 = __importDefault(require("fs"));
|
|
8
9
|
const path_1 = __importDefault(require("path"));
|
|
9
10
|
const frontmatter_1 = require("./frontmatter");
|
|
11
|
+
const builtin_1 = require("../templates/builtin");
|
|
10
12
|
function listMarkdownFiles(dir) {
|
|
11
13
|
if (!fs_1.default.existsSync(dir)) {
|
|
12
14
|
return [];
|
|
@@ -45,9 +47,12 @@ function addKeyToSchema(schema, key, kind, filePath) {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
function loadTemplateSchemas(root, config, requiredTypes) {
|
|
50
|
+
return loadTemplateSchemasWithInfo(root, config, requiredTypes).schemas;
|
|
51
|
+
}
|
|
52
|
+
function loadTemplateSchemasWithInfo(root, config, requiredTypes) {
|
|
48
53
|
const templateRoot = path_1.default.resolve(root, config.templates.root_path, config.templates.default_set);
|
|
49
54
|
const files = listMarkdownFiles(templateRoot);
|
|
50
|
-
if (files.length === 0) {
|
|
55
|
+
if (files.length === 0 && !requiredTypes) {
|
|
51
56
|
throw new Error(`no templates found at ${templateRoot}`);
|
|
52
57
|
}
|
|
53
58
|
const schemas = {};
|
|
@@ -75,12 +80,35 @@ function loadTemplateSchemas(root, config, requiredTypes) {
|
|
|
75
80
|
addKeyToSchema(schema, key, kind, filePath);
|
|
76
81
|
}
|
|
77
82
|
}
|
|
83
|
+
const fallbackTypes = [];
|
|
78
84
|
if (requiredTypes) {
|
|
79
85
|
const required = Array.from(requiredTypes, (value) => value.toLowerCase());
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
for (const missingType of required.filter((value) => !schemas[value])) {
|
|
87
|
+
const bundledPath = (0, builtin_1.requireBundledTemplatePath)(missingType);
|
|
88
|
+
const content = fs_1.default.readFileSync(bundledPath, "utf8");
|
|
89
|
+
const { frontmatter } = (0, frontmatter_1.parseFrontmatter)(content, bundledPath);
|
|
90
|
+
const typeValue = frontmatter.type;
|
|
91
|
+
if (typeValue !== missingType) {
|
|
92
|
+
throw new Error(`bundled template fallback type mismatch for ${missingType}: ${bundledPath}`);
|
|
93
|
+
}
|
|
94
|
+
const schema = {
|
|
95
|
+
type: missingType,
|
|
96
|
+
allowedKeys: new Set(),
|
|
97
|
+
keyKinds: {},
|
|
98
|
+
listKeys: new Set(),
|
|
99
|
+
};
|
|
100
|
+
schemas[missingType] = schema;
|
|
101
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
102
|
+
const kind = getValueKind(value);
|
|
103
|
+
addKeyToSchema(schema, key, kind, bundledPath);
|
|
104
|
+
}
|
|
105
|
+
fallbackTypes.push(missingType);
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
|
-
return
|
|
108
|
+
return {
|
|
109
|
+
schemas,
|
|
110
|
+
templateRoot,
|
|
111
|
+
bundledTemplateRoot: (0, builtin_1.resolveBundledTemplateRoot)(),
|
|
112
|
+
fallbackTypes,
|
|
113
|
+
};
|
|
86
114
|
}
|
package/dist/init/AGENT_START.md
CHANGED
|
@@ -23,6 +23,7 @@ Agent operating prompt:
|
|
|
23
23
|
- Use `mdkg search "..."` and `mdkg next` to discover current work.
|
|
24
24
|
- Use `mdkg skill list`, `mdkg skill search`, and `mdkg skill show <slug>` for skill discovery.
|
|
25
25
|
- Use `mdkg task start/update/done` for structured task, bug, and test lifecycle fields.
|
|
26
|
+
- Use `mdkg upgrade` to preview scaffold updates; only run `mdkg upgrade --apply` after reviewing the receipt.
|
|
26
27
|
- Keep nuanced summaries, body text, and manual parent closeout edits in markdown.
|
|
27
28
|
- Use `mdkg event enable` only if `events.jsonl` is missing and provenance should be restored.
|
|
28
29
|
- Use `CLI_COMMAND_MATRIX.md` for the canonical command and flag surface.
|
|
@@ -8,6 +8,7 @@ Verify live help with:
|
|
|
8
8
|
|
|
9
9
|
Primary commands:
|
|
10
10
|
- `mdkg init`
|
|
11
|
+
- `mdkg upgrade [--dry-run] [--apply] [--json]`
|
|
11
12
|
- `mdkg new`
|
|
12
13
|
- `mdkg show`
|
|
13
14
|
- `mdkg list`
|
|
@@ -64,6 +65,13 @@ Agent bootstrap:
|
|
|
64
65
|
- `mdkg init --llm --agent`
|
|
65
66
|
- published bootstrap config is root-only by default
|
|
66
67
|
|
|
68
|
+
Upgrade:
|
|
69
|
+
- `mdkg upgrade` previews safe scaffold updates and writes nothing by default
|
|
70
|
+
- `mdkg upgrade --apply` updates only managed or unchanged init assets
|
|
71
|
+
- JSON receipts include `safe_to_apply`, `will_write_paths`, `preserved_customizations`, `blocking_conflicts`, and `apply_side_effects`
|
|
72
|
+
- customized docs, templates, skills, and core files are preserved and reported
|
|
73
|
+
- ignored event logs are skipped with guidance to run `mdkg event enable`
|
|
74
|
+
|
|
67
75
|
Skill discovery:
|
|
68
76
|
- `mdkg skill list --tags stage:plan --json`
|
|
69
77
|
- `mdkg skill search "<query>" --json`
|
package/dist/init/README.md
CHANGED
|
@@ -15,6 +15,7 @@ This repository is initialized for mdkg.
|
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
mdkg init --llm --agent
|
|
18
|
+
mdkg upgrade
|
|
18
19
|
mdkg search "..."
|
|
19
20
|
mdkg show <id>
|
|
20
21
|
mdkg pack <id>
|
|
@@ -50,3 +51,9 @@ Recommended:
|
|
|
50
51
|
```bash
|
|
51
52
|
mdkg init --update-gitignore --update-npmignore
|
|
52
53
|
```
|
|
54
|
+
|
|
55
|
+
## Upgrade
|
|
56
|
+
|
|
57
|
+
`mdkg upgrade` previews safe scaffold updates for existing workspaces and writes nothing by default.
|
|
58
|
+
|
|
59
|
+
Use `mdkg upgrade --apply` only after reviewing `safe_to_apply`, `will_write_paths`, and `apply_side_effects` in the receipt. Local customizations are preserved and reported instead of overwritten. Missing built-in templates can be loaded from the installed package as a read-only fallback until you vendor them with upgrade.
|
|
@@ -187,4 +187,6 @@ Body headings are strongly recommended for agent usability but should not be har
|
|
|
187
187
|
- Node -> skill references in `skills: [...]` are validated against `.mdkg/skills/<slug>/SKILL.md`.
|
|
188
188
|
- `.mdkg/work/events/events.jsonl` is optional; when present, records are schema-validated by `mdkg validate`.
|
|
189
189
|
- If a template is missing:
|
|
190
|
-
-
|
|
190
|
+
- built-in mdkg node types may use the installed package's bundled default template as a read-only schema fallback.
|
|
191
|
+
- commands should warn when bundled fallback is used and recommend `mdkg upgrade --apply` to vendor missing templates.
|
|
192
|
+
- missing non-built-in templates or missing packaged fallback assets must fail with a helpful error.
|