mdkg 0.3.7 → 0.3.9
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 +50 -0
- package/CLI_COMMAND_MATRIX.md +85 -24
- package/README.md +51 -26
- package/dist/cli.js +72 -35
- package/dist/command-contract.json +354 -9
- package/dist/commands/capability.js +1 -0
- package/dist/commands/doctor.js +7 -7
- package/dist/commands/format.js +40 -1
- package/dist/commands/handoff.js +6 -0
- package/dist/commands/init.js +84 -3
- package/dist/commands/new.js +12 -3
- package/dist/commands/skill.js +1 -1
- package/dist/commands/skill_mirror.js +22 -17
- package/dist/commands/skill_support.js +1 -1
- package/dist/commands/spec.js +76 -17
- package/dist/commands/subgraph.js +7 -4
- package/dist/commands/upgrade.js +137 -30
- package/dist/commands/validate.js +106 -3
- package/dist/commands/work.js +12 -5
- package/dist/core/config.js +132 -0
- package/dist/graph/agent_file_types.js +59 -20
- package/dist/graph/capabilities_indexer.js +45 -3
- package/dist/graph/indexer.js +5 -0
- package/dist/graph/template_schema.js +37 -17
- package/dist/graph/validate_graph.js +11 -5
- package/dist/init/AGENT_START.md +10 -9
- package/dist/init/CLI_COMMAND_MATRIX.md +30 -17
- package/dist/init/README.md +11 -9
- package/dist/init/config.json +15 -0
- package/dist/init/core/COLLABORATION.md +45 -0
- package/dist/init/core/HUMAN.md +7 -1
- package/dist/init/core/core.md +1 -0
- package/dist/init/core/rule-1-mdkg-conventions.md +3 -0
- package/dist/init/core/rule-3-cli-contract.md +5 -5
- package/dist/init/init-manifest.json +78 -13
- package/dist/init/llms.txt +2 -1
- package/dist/init/skills/default/author-mdkg-skill/SKILL.md +211 -0
- package/dist/init/skills/default/pursue-mdkg-goal/SKILL.md +10 -0
- package/dist/init/skills/default/select-work-and-ground-context/SKILL.md +8 -0
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +73 -9
- package/dist/init/templates/default/manifest.md +45 -0
- package/dist/init/templates/specs/agent.MANIFEST.md +80 -0
- package/dist/init/templates/specs/api.MANIFEST.md +33 -0
- package/dist/init/templates/specs/base.MANIFEST.md +120 -0
- package/dist/init/templates/specs/capability.MANIFEST.md +45 -0
- package/dist/init/templates/specs/integration.MANIFEST.md +25 -0
- package/dist/init/templates/specs/model.MANIFEST.md +21 -0
- package/dist/init/templates/specs/project.MANIFEST.md +39 -0
- package/dist/init/templates/specs/runtime-agent.MANIFEST.md +49 -0
- package/dist/init/templates/specs/runtime-image.MANIFEST.md +21 -0
- package/dist/init/templates/specs/tool.MANIFEST.md +25 -0
- package/dist/util/argparse.js +3 -0
- package/package.json +19 -3
package/dist/commands/init.js
CHANGED
|
@@ -17,6 +17,7 @@ const skill_support_1 = require("./skill_support");
|
|
|
17
17
|
const skill_mirror_1 = require("./skill_mirror");
|
|
18
18
|
const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
|
|
19
19
|
const SOUL_PIN_ID = "rule-soul";
|
|
20
|
+
const COLLABORATION_PIN_ID = "rule-7";
|
|
20
21
|
const HUMAN_PIN_ID = "rule-human";
|
|
21
22
|
const DEFAULT_CORE_LIST_HEADER = [
|
|
22
23
|
"# mdkg verbose core list",
|
|
@@ -175,6 +176,52 @@ function humanTemplate(created) {
|
|
|
175
176
|
"",
|
|
176
177
|
].join("\n");
|
|
177
178
|
}
|
|
179
|
+
function collaborationTemplate(created) {
|
|
180
|
+
return [
|
|
181
|
+
"---",
|
|
182
|
+
`id: ${COLLABORATION_PIN_ID}`,
|
|
183
|
+
"type: rule",
|
|
184
|
+
"title: collaboration profile and operator preferences",
|
|
185
|
+
"tags: [collaboration, preferences, operator]",
|
|
186
|
+
"owners: []",
|
|
187
|
+
"links: []",
|
|
188
|
+
"artifacts: []",
|
|
189
|
+
"relates: [rule-human]",
|
|
190
|
+
"refs: [dec-53]",
|
|
191
|
+
"aliases: [collaboration, operator-profile]",
|
|
192
|
+
`created: ${created}`,
|
|
193
|
+
`updated: ${created}`,
|
|
194
|
+
"---",
|
|
195
|
+
"",
|
|
196
|
+
"# Purpose",
|
|
197
|
+
"",
|
|
198
|
+
"Capture stable collaboration preferences, operating boundaries, and repo-specific human expectations so agents can work with less ambiguity.",
|
|
199
|
+
"",
|
|
200
|
+
"# Scope",
|
|
201
|
+
"",
|
|
202
|
+
"Applies to planning, implementation, review, release, and handoff interactions in this repository.",
|
|
203
|
+
"",
|
|
204
|
+
"# Compatibility",
|
|
205
|
+
"",
|
|
206
|
+
"`COLLABORATION.md` is canonical. `HUMAN.md` remains a one-release legacy alias for repos and agent prompts that still reference it; read `COLLABORATION.md` first and then use `HUMAN.md` only for compatibility notes not yet migrated.",
|
|
207
|
+
"",
|
|
208
|
+
"# Requirements",
|
|
209
|
+
"",
|
|
210
|
+
"- Keep top goals, boundaries, and style preferences current.",
|
|
211
|
+
"- Include ask-before-doing constraints for risky or high-impact actions.",
|
|
212
|
+
"- Record preferred environment assumptions and validation commands.",
|
|
213
|
+
"- Preserve local operator customizations during `mdkg upgrade --apply`.",
|
|
214
|
+
"",
|
|
215
|
+
"# Notes",
|
|
216
|
+
"",
|
|
217
|
+
"Suggested prompts:",
|
|
218
|
+
"- What are your top 3 goals in this repo right now?",
|
|
219
|
+
"- What should never happen without confirmation?",
|
|
220
|
+
"- What coding/review style should the agent prefer?",
|
|
221
|
+
"- What OS/runtime/test commands should be assumed?",
|
|
222
|
+
"",
|
|
223
|
+
].join("\n");
|
|
224
|
+
}
|
|
178
225
|
function seededInitEvent(nowIso) {
|
|
179
226
|
const event = {
|
|
180
227
|
ts: nowIso,
|
|
@@ -277,6 +324,31 @@ function ensureCorePins(coreListPath, requiredPins) {
|
|
|
277
324
|
fs_1.default.mkdirSync(path_1.default.dirname(coreListPath), { recursive: true });
|
|
278
325
|
fs_1.default.writeFileSync(coreListPath, output, "utf8");
|
|
279
326
|
}
|
|
327
|
+
function refreshManifestHash(root, manifest, relPath) {
|
|
328
|
+
const entry = manifest.files.find((file) => file.path === relPath);
|
|
329
|
+
if (!entry) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const targetPath = path_1.default.join(root, relPath);
|
|
333
|
+
if (fs_1.default.existsSync(targetPath) && fs_1.default.statSync(targetPath).isFile()) {
|
|
334
|
+
entry.sha256 = (0, init_manifest_1.sha256File)(targetPath);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function ensureCreatedCoreManifestEntry(root, manifest, relPath, stats) {
|
|
338
|
+
if (manifest.files.some((file) => file.path === relPath) || !stats.createdPaths.includes(relPath)) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const targetPath = path_1.default.join(root, relPath);
|
|
342
|
+
if (!fs_1.default.existsSync(targetPath) || !fs_1.default.statSync(targetPath).isFile()) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
manifest.files.push({
|
|
346
|
+
path: relPath,
|
|
347
|
+
category: "core",
|
|
348
|
+
sha256: (0, init_manifest_1.sha256File)(targetPath),
|
|
349
|
+
});
|
|
350
|
+
manifest.files.sort((a, b) => a.path.localeCompare(b.path));
|
|
351
|
+
}
|
|
280
352
|
function runInitCommand(options) {
|
|
281
353
|
const root = path_1.default.resolve(options.root);
|
|
282
354
|
const seedRoot = options.seedRoot ? path_1.default.resolve(options.seedRoot) : DEFAULT_SEED_SUBDIR;
|
|
@@ -295,6 +367,7 @@ function runInitCommand(options) {
|
|
|
295
367
|
const seedReadme = path_1.default.join(seedRoot, "README.md");
|
|
296
368
|
const seedDefaultSkills = path_1.default.join(seedRoot, "skills", "default");
|
|
297
369
|
const seedSoul = path_1.default.join(seedCore, "SOUL.md");
|
|
370
|
+
const seedCollaboration = path_1.default.join(seedCore, "COLLABORATION.md");
|
|
298
371
|
const seedHuman = path_1.default.join(seedCore, "HUMAN.md");
|
|
299
372
|
const seedManifest = (0, init_manifest_1.createInitManifest)(seedRoot, (0, version_1.readPackageVersion)(), {
|
|
300
373
|
includeAgentDocs: Boolean(options.agent),
|
|
@@ -367,6 +440,7 @@ function runInitCommand(options) {
|
|
|
367
440
|
if (options.agent) {
|
|
368
441
|
const today = (0, date_1.formatDate)(new Date());
|
|
369
442
|
const soulPath = path_1.default.join(mdkgDir, "core", "SOUL.md");
|
|
443
|
+
const collaborationPath = path_1.default.join(mdkgDir, "core", "COLLABORATION.md");
|
|
370
444
|
const humanPath = path_1.default.join(mdkgDir, "core", "HUMAN.md");
|
|
371
445
|
const skillsDir = path_1.default.join(mdkgDir, "skills");
|
|
372
446
|
const registryPath = path_1.default.join(skillsDir, "registry.md");
|
|
@@ -378,6 +452,9 @@ function runInitCommand(options) {
|
|
|
378
452
|
if (!fs_1.default.existsSync(seedSoul)) {
|
|
379
453
|
writeFileIfMissing(root, soulPath, soulTemplate(today), force, stats);
|
|
380
454
|
}
|
|
455
|
+
if (!fs_1.default.existsSync(seedCollaboration)) {
|
|
456
|
+
writeFileIfMissing(root, collaborationPath, collaborationTemplate(today), force, stats);
|
|
457
|
+
}
|
|
381
458
|
if (!fs_1.default.existsSync(seedHuman)) {
|
|
382
459
|
writeFileIfMissing(root, humanPath, humanTemplate(today), force, stats);
|
|
383
460
|
}
|
|
@@ -386,9 +463,13 @@ function runInitCommand(options) {
|
|
|
386
463
|
writeFileIfMissing(root, eventsPath, seededInitEvent(new Date().toISOString()), force, stats);
|
|
387
464
|
}
|
|
388
465
|
const coreListPath = path_1.default.join(mdkgDir, "core", "core.md");
|
|
389
|
-
ensureCorePins(coreListPath, [SOUL_PIN_ID, HUMAN_PIN_ID]);
|
|
390
|
-
(
|
|
466
|
+
ensureCorePins(coreListPath, [SOUL_PIN_ID, COLLABORATION_PIN_ID, HUMAN_PIN_ID]);
|
|
467
|
+
refreshManifestHash(root, seedManifest, ".mdkg/core/core.md");
|
|
468
|
+
ensureCreatedCoreManifestEntry(root, seedManifest, ".mdkg/core/SOUL.md", stats);
|
|
469
|
+
ensureCreatedCoreManifestEntry(root, seedManifest, ".mdkg/core/COLLABORATION.md", stats);
|
|
470
|
+
ensureCreatedCoreManifestEntry(root, seedManifest, ".mdkg/core/HUMAN.md", stats);
|
|
391
471
|
const config = (0, config_1.loadConfig)(root);
|
|
472
|
+
(0, skill_mirror_1.scaffoldMirrorRoots)(root, config);
|
|
392
473
|
(0, skill_support_1.refreshSkillsRegistry)(root, config);
|
|
393
474
|
stats.registryRefreshed = true;
|
|
394
475
|
const mirrorResult = (0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true, force });
|
|
@@ -452,7 +533,7 @@ function runInitCommand(options) {
|
|
|
452
533
|
}
|
|
453
534
|
if (options.agent) {
|
|
454
535
|
console.log("agent bootstrap: AGENT_START.md, AGENTS.md, CLAUDE.md, llms.txt, CLI_COMMAND_MATRIX.md");
|
|
455
|
-
console.log("agent core pins: rule-soul, rule-human");
|
|
536
|
+
console.log("agent core pins: rule-soul, rule-7, rule-human");
|
|
456
537
|
console.log("agent event log: .mdkg/work/events/events.jsonl");
|
|
457
538
|
console.log(`skill mirrors: ${stats.mirroredSkills} sync operation(s) across ${stats.mirrorTargets} target(s)`);
|
|
458
539
|
if (stats.registryRefreshed) {
|
package/dist/commands/new.js
CHANGED
|
@@ -27,6 +27,7 @@ const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
|
27
27
|
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
28
28
|
const CORE_TYPES = new Set(["rule"]);
|
|
29
29
|
const DESIGN_TYPES = new Set(["prd", "edd", "dec", "prop"]);
|
|
30
|
+
const LEGACY_NEW_SPEC_WARNING = "warning: mdkg new spec is legacy; use mdkg new manifest. This alias creates MANIFEST.md with type: manifest during the compatibility release.";
|
|
30
31
|
function parseCsvList(raw) {
|
|
31
32
|
if (!raw) {
|
|
32
33
|
return [];
|
|
@@ -162,6 +163,9 @@ function fileNameForType(type, id, slug) {
|
|
|
162
163
|
}
|
|
163
164
|
return `${id}-${slug}.md`;
|
|
164
165
|
}
|
|
166
|
+
function canonicalCreationType(requestedType) {
|
|
167
|
+
return requestedType === "spec" ? "manifest" : requestedType;
|
|
168
|
+
}
|
|
165
169
|
function ensureExists(index, value, ws, label) {
|
|
166
170
|
const resolved = (0, qid_1.resolveQid)(index, value, ws);
|
|
167
171
|
if (resolved.status !== "ok") {
|
|
@@ -177,13 +181,15 @@ function runNewCommandLocked(options) {
|
|
|
177
181
|
if (!title) {
|
|
178
182
|
throw new errors_1.UsageError("title cannot be empty");
|
|
179
183
|
}
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
184
|
+
const requestedType = options.type.toLowerCase();
|
|
185
|
+
if (requestedType === "archive") {
|
|
182
186
|
throw new errors_1.UsageError("use `mdkg archive add <file>` to create archive sidecars");
|
|
183
187
|
}
|
|
184
|
-
if (!node_1.ALLOWED_TYPES.has(
|
|
188
|
+
if (!node_1.ALLOWED_TYPES.has(requestedType)) {
|
|
185
189
|
throw new errors_1.UsageError(`type must be one of ${Array.from(node_1.ALLOWED_TYPES).join(", ")}`);
|
|
186
190
|
}
|
|
191
|
+
const type = canonicalCreationType(requestedType);
|
|
192
|
+
const legacySpecAlias = requestedType === "spec";
|
|
187
193
|
const config = (0, config_1.loadConfig)(options.root);
|
|
188
194
|
const ws = normalizeWorkspace(options.ws);
|
|
189
195
|
if (!config.workspaces[ws]) {
|
|
@@ -389,6 +395,9 @@ function runNewCommandLocked(options) {
|
|
|
389
395
|
...(status ? { status } : {}),
|
|
390
396
|
...(priority !== undefined ? { priority } : {}),
|
|
391
397
|
};
|
|
398
|
+
if (legacySpecAlias) {
|
|
399
|
+
console.error(LEGACY_NEW_SPEC_WARNING);
|
|
400
|
+
}
|
|
392
401
|
if (options.json) {
|
|
393
402
|
console.log(JSON.stringify({
|
|
394
403
|
action: "created",
|
package/dist/commands/skill.js
CHANGED
|
@@ -186,7 +186,7 @@ function runSkillNewCommandLocked(options) {
|
|
|
186
186
|
(0, atomic_1.atomicWriteFile)(canonicalPath, content);
|
|
187
187
|
(0, skill_support_1.ensureSkillsRegistry)(root, config);
|
|
188
188
|
(0, skill_support_1.refreshSkillsRegistry)(root, config);
|
|
189
|
-
if ((0, skill_mirror_1.shouldMaintainSkillMirrors)(root)) {
|
|
189
|
+
if ((0, skill_mirror_1.shouldMaintainSkillMirrors)(root, config)) {
|
|
190
190
|
(0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true, force });
|
|
191
191
|
}
|
|
192
192
|
if (config.index.auto_reindex) {
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.configuredSkillMirrorTargets = configuredSkillMirrorTargets;
|
|
6
7
|
exports.syncSkillMirrors = syncSkillMirrors;
|
|
7
8
|
exports.preflightSkillMirrorTargets = preflightSkillMirrorTargets;
|
|
8
9
|
exports.shouldMaintainSkillMirrors = shouldMaintainSkillMirrors;
|
|
@@ -10,22 +11,26 @@ exports.auditSkillMirrors = auditSkillMirrors;
|
|
|
10
11
|
exports.scaffoldMirrorRoots = scaffoldMirrorRoots;
|
|
11
12
|
const fs_1 = __importDefault(require("fs"));
|
|
12
13
|
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const config_1 = require("../core/config");
|
|
13
15
|
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
14
16
|
const errors_1 = require("../util/errors");
|
|
15
|
-
const MIRROR_PRODUCTS = ["agents", "claude"];
|
|
16
17
|
const MANIFEST_FILE = ".mdkg-managed.json";
|
|
17
18
|
const MANAGED_ROOT_MARKERS = [
|
|
18
19
|
path_1.default.join(".mdkg", "core", "SOUL.md"),
|
|
20
|
+
path_1.default.join(".mdkg", "core", "COLLABORATION.md"),
|
|
19
21
|
path_1.default.join(".mdkg", "core", "HUMAN.md"),
|
|
20
22
|
];
|
|
21
23
|
const ALLOWED_ROOT_ENTRIES = ["SKILL.md", "references", "assets", "scripts"];
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
function configuredSkillMirrorTargets(config) {
|
|
25
|
+
const configured = config?.customization.skill_mirrors.targets ?? (0, config_1.defaultCustomizationConfig)().skill_mirrors.targets;
|
|
26
|
+
return Array.from(new Set(configured.map((value) => value.trim()).filter(Boolean)));
|
|
27
|
+
}
|
|
28
|
+
function resolveMirrorTargets(root, config) {
|
|
29
|
+
return configuredSkillMirrorTargets(config).map((configuredPath) => {
|
|
30
|
+
const skillsRoot = path_1.default.join(root, configuredPath);
|
|
26
31
|
return {
|
|
27
|
-
|
|
28
|
-
rootDir,
|
|
32
|
+
configuredPath,
|
|
33
|
+
rootDir: path_1.default.dirname(skillsRoot),
|
|
29
34
|
skillsRoot,
|
|
30
35
|
manifestPath: path_1.default.join(skillsRoot, MANIFEST_FILE),
|
|
31
36
|
};
|
|
@@ -55,11 +60,11 @@ function writeManifest(target, managed) {
|
|
|
55
60
|
fs_1.default.mkdirSync(target.skillsRoot, { recursive: true });
|
|
56
61
|
fs_1.default.writeFileSync(target.manifestPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
57
62
|
}
|
|
58
|
-
function shouldCreateMirrorRoots(root) {
|
|
63
|
+
function shouldCreateMirrorRoots(root, config) {
|
|
59
64
|
if (MANAGED_ROOT_MARKERS.some((relPath) => fs_1.default.existsSync(path_1.default.join(root, relPath)))) {
|
|
60
65
|
return true;
|
|
61
66
|
}
|
|
62
|
-
return resolveMirrorTargets(root).some((target) => fs_1.default.existsSync(target.rootDir) || fs_1.default.existsSync(target.skillsRoot));
|
|
67
|
+
return resolveMirrorTargets(root, config).some((target) => fs_1.default.existsSync(target.rootDir) || fs_1.default.existsSync(target.skillsRoot));
|
|
63
68
|
}
|
|
64
69
|
function listAllowedEntries(dirPath) {
|
|
65
70
|
if (!fs_1.default.existsSync(dirPath)) {
|
|
@@ -235,7 +240,7 @@ function syncSkillMirrors(options) {
|
|
|
235
240
|
const sources = loadCanonicalSources(options.root, options.config);
|
|
236
241
|
const createRoots = Boolean(options.createRoots);
|
|
237
242
|
const force = Boolean(options.force);
|
|
238
|
-
const targets = resolveMirrorTargets(options.root);
|
|
243
|
+
const targets = resolveMirrorTargets(options.root, options.config);
|
|
239
244
|
let synced = 0;
|
|
240
245
|
let pruned = 0;
|
|
241
246
|
let touchedTargets = 0;
|
|
@@ -280,7 +285,7 @@ function preflightSkillMirrorTargets(options) {
|
|
|
280
285
|
if (slugs.length === 0) {
|
|
281
286
|
return;
|
|
282
287
|
}
|
|
283
|
-
for (const target of resolveMirrorTargets(options.root)) {
|
|
288
|
+
for (const target of resolveMirrorTargets(options.root, options.config)) {
|
|
284
289
|
if (!fs_1.default.existsSync(target.rootDir) && !fs_1.default.existsSync(target.skillsRoot)) {
|
|
285
290
|
continue;
|
|
286
291
|
}
|
|
@@ -293,18 +298,18 @@ function preflightSkillMirrorTargets(options) {
|
|
|
293
298
|
}
|
|
294
299
|
}
|
|
295
300
|
}
|
|
296
|
-
function shouldMaintainSkillMirrors(root) {
|
|
297
|
-
return shouldCreateMirrorRoots(root);
|
|
301
|
+
function shouldMaintainSkillMirrors(root, config) {
|
|
302
|
+
return shouldCreateMirrorRoots(root, config);
|
|
298
303
|
}
|
|
299
304
|
function auditSkillMirrors(root, config) {
|
|
300
|
-
const shouldAudit = shouldCreateMirrorRoots(root);
|
|
305
|
+
const shouldAudit = shouldCreateMirrorRoots(root, config);
|
|
301
306
|
if (!shouldAudit) {
|
|
302
307
|
return [];
|
|
303
308
|
}
|
|
304
309
|
const warnings = [];
|
|
305
310
|
const sources = loadCanonicalSources(root, config);
|
|
306
311
|
const sourceBySlug = new Map(sources.map((source) => [source.slug, source]));
|
|
307
|
-
for (const target of resolveMirrorTargets(root)) {
|
|
312
|
+
for (const target of resolveMirrorTargets(root, config)) {
|
|
308
313
|
if (!fs_1.default.existsSync(target.skillsRoot)) {
|
|
309
314
|
warnings.push(`${path_1.default.relative(root, target.skillsRoot)}: mirror root missing; run \`mdkg skill sync\``);
|
|
310
315
|
continue;
|
|
@@ -335,8 +340,8 @@ function auditSkillMirrors(root, config) {
|
|
|
335
340
|
}
|
|
336
341
|
return warnings;
|
|
337
342
|
}
|
|
338
|
-
function scaffoldMirrorRoots(root) {
|
|
339
|
-
for (const target of resolveMirrorTargets(root)) {
|
|
343
|
+
function scaffoldMirrorRoots(root, config) {
|
|
344
|
+
for (const target of resolveMirrorTargets(root, config)) {
|
|
340
345
|
fs_1.default.mkdirSync(target.skillsRoot, { recursive: true });
|
|
341
346
|
if (!fs_1.default.existsSync(target.manifestPath)) {
|
|
342
347
|
writeManifest(target, []);
|
|
@@ -52,7 +52,7 @@ function registryTemplate() {
|
|
|
52
52
|
"This directory stores Agent Skills packages used by mdkg tooling and orchestrators.",
|
|
53
53
|
"",
|
|
54
54
|
"Use `mdkg skill new <slug> \"<name>\" --description \"...\"` to scaffold a new skill from the built-in Anthropic-aligned template.",
|
|
55
|
-
"Use `mdkg skill sync` to mirror canonical skills into `.agents/skills/` and `.claude/skills
|
|
55
|
+
"Use `mdkg skill sync` to mirror canonical skills into configured `.mdkg/config.json` targets; defaults are `.agents/skills/` and `.claude/skills/`.",
|
|
56
56
|
"Use `CLI_COMMAND_MATRIX.md` as the canonical command and flag reference when updating skill procedures.",
|
|
57
57
|
"",
|
|
58
58
|
"## Conventions",
|
package/dist/commands/spec.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runSpecListCommand = runSpecListCommand;
|
|
4
4
|
exports.runSpecShowCommand = runSpecShowCommand;
|
|
5
5
|
exports.runSpecValidateCommand = runSpecValidateCommand;
|
|
6
|
+
exports.runManifestListCommand = runManifestListCommand;
|
|
7
|
+
exports.runManifestShowCommand = runManifestShowCommand;
|
|
8
|
+
exports.runManifestValidateCommand = runManifestValidateCommand;
|
|
6
9
|
const capability_1 = require("./capability");
|
|
7
10
|
const validate_1 = require("./validate");
|
|
8
11
|
const errors_1 = require("../util/errors");
|
|
@@ -24,6 +27,9 @@ function loadSpecRecords(options) {
|
|
|
24
27
|
};
|
|
25
28
|
return sortSpecRecords((0, capability_1.filterCapabilityRecords)((0, capability_1.loadCapabilityRecords)(listOptions), listOptions));
|
|
26
29
|
}
|
|
30
|
+
function commandSurface(options) {
|
|
31
|
+
return options.surface ?? "spec";
|
|
32
|
+
}
|
|
27
33
|
function matchesSpecRef(record, id) {
|
|
28
34
|
const normalized = id.toLowerCase();
|
|
29
35
|
return (record.id === id ||
|
|
@@ -34,15 +40,15 @@ function matchesSpecRef(record, id) {
|
|
|
34
40
|
record.path.toLowerCase() === normalized ||
|
|
35
41
|
record.aliases.some((alias) => alias.toLowerCase() === normalized));
|
|
36
42
|
}
|
|
37
|
-
function resolveSpecRecord(records, id) {
|
|
43
|
+
function resolveSpecRecord(records, id, surface) {
|
|
38
44
|
const matches = records.filter((record) => matchesSpecRef(record, id));
|
|
39
45
|
if (matches.length === 1) {
|
|
40
46
|
return matches[0];
|
|
41
47
|
}
|
|
42
48
|
if (matches.length > 1) {
|
|
43
|
-
throw new errors_1.UsageError(
|
|
49
|
+
throw new errors_1.UsageError(`${surface === "manifest" ? "manifest capability" : "SPEC"} reference is ambiguous: ${id}`);
|
|
44
50
|
}
|
|
45
|
-
throw new errors_1.NotFoundError(
|
|
51
|
+
throw new errors_1.NotFoundError(`${surface === "manifest" ? "manifest capability" : "SPEC"} not found: ${id}`);
|
|
46
52
|
}
|
|
47
53
|
function stringValue(value) {
|
|
48
54
|
return typeof value === "string" ? value : undefined;
|
|
@@ -50,33 +56,74 @@ function stringValue(value) {
|
|
|
50
56
|
function stringArrayValue(value) {
|
|
51
57
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
52
58
|
}
|
|
53
|
-
function
|
|
59
|
+
function compatibilityLabel(record) {
|
|
60
|
+
const mode = record.manifest?.compatibility_mode;
|
|
61
|
+
if (mode === "legacy") {
|
|
62
|
+
return "legacy SPEC.md";
|
|
63
|
+
}
|
|
64
|
+
if (mode === "transitional") {
|
|
65
|
+
return "transitional MANIFEST.md type: spec";
|
|
66
|
+
}
|
|
67
|
+
return "MANIFEST.md";
|
|
68
|
+
}
|
|
69
|
+
function legacySpecDeprecation() {
|
|
70
|
+
return "mdkg spec is a legacy alias for mdkg manifest during the one-compatibility-release bridge.";
|
|
71
|
+
}
|
|
72
|
+
function printSpecList(records, json, surface = "spec") {
|
|
54
73
|
if (json) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
const receipt = surface === "manifest"
|
|
75
|
+
? {
|
|
76
|
+
kind: "manifest",
|
|
77
|
+
compatibility_kind: "spec",
|
|
78
|
+
count: records.length,
|
|
79
|
+
items: records,
|
|
80
|
+
}
|
|
81
|
+
: {
|
|
82
|
+
kind: "spec",
|
|
83
|
+
canonical_kind: "manifest",
|
|
84
|
+
legacy_alias: true,
|
|
85
|
+
deprecation: legacySpecDeprecation(),
|
|
86
|
+
count: records.length,
|
|
87
|
+
items: records,
|
|
88
|
+
};
|
|
89
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
60
90
|
return;
|
|
61
91
|
}
|
|
92
|
+
if (surface === "spec") {
|
|
93
|
+
console.log(legacySpecDeprecation());
|
|
94
|
+
}
|
|
62
95
|
if (records.length === 0) {
|
|
63
|
-
console.log("no SPEC.md capabilities found");
|
|
96
|
+
console.log("no MANIFEST.md/SPEC.md capabilities found");
|
|
64
97
|
return;
|
|
65
98
|
}
|
|
66
|
-
console.log(
|
|
99
|
+
console.log(`${surface === "manifest" ? "MANIFEST.md" : "MANIFEST.md/SPEC.md"} capabilities: ${records.length}`);
|
|
67
100
|
for (const record of records) {
|
|
68
101
|
const kind = stringValue(record.spec?.spec_kind);
|
|
69
102
|
const kindLabel = kind ? ` | ${kind}` : "";
|
|
70
|
-
console.log(`${record.qid} | ${record.visibility}${kindLabel} | ${record.title}`);
|
|
103
|
+
console.log(`${record.qid} | ${record.visibility}${kindLabel} | ${compatibilityLabel(record)} | ${record.title}`);
|
|
71
104
|
}
|
|
72
105
|
}
|
|
73
|
-
function printSpec(record, json) {
|
|
106
|
+
function printSpec(record, json, surface = "spec") {
|
|
74
107
|
if (json) {
|
|
75
|
-
|
|
108
|
+
const receipt = surface === "manifest"
|
|
109
|
+
? { kind: "manifest", compatibility_kind: "spec", item: record }
|
|
110
|
+
: {
|
|
111
|
+
kind: "spec",
|
|
112
|
+
canonical_kind: "manifest",
|
|
113
|
+
legacy_alias: true,
|
|
114
|
+
deprecation: legacySpecDeprecation(),
|
|
115
|
+
item: record,
|
|
116
|
+
};
|
|
117
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
76
118
|
return;
|
|
77
119
|
}
|
|
120
|
+
if (surface === "spec") {
|
|
121
|
+
console.log(legacySpecDeprecation());
|
|
122
|
+
}
|
|
78
123
|
console.log(`${record.qid} | ${record.visibility}`);
|
|
79
124
|
console.log(`title: ${record.title}`);
|
|
125
|
+
console.log(`semantic_kind: ${record.manifest?.semantic_kind ?? "manifest"}`);
|
|
126
|
+
console.log(`compatibility: ${compatibilityLabel(record)}`);
|
|
80
127
|
const specKind = stringValue(record.spec?.spec_kind);
|
|
81
128
|
if (specKind) {
|
|
82
129
|
console.log(`spec_kind: ${specKind}`);
|
|
@@ -88,14 +135,26 @@ function printSpec(record, json) {
|
|
|
88
135
|
}
|
|
89
136
|
}
|
|
90
137
|
function runSpecListCommand(options) {
|
|
91
|
-
|
|
138
|
+
const surface = commandSurface(options);
|
|
139
|
+
printSpecList(loadSpecRecords(options), options.json, surface);
|
|
92
140
|
}
|
|
93
141
|
function runSpecShowCommand(options) {
|
|
94
|
-
|
|
142
|
+
const surface = commandSurface(options);
|
|
143
|
+
printSpec(resolveSpecRecord(loadSpecRecords(options), options.id, surface), options.json, surface);
|
|
95
144
|
}
|
|
96
145
|
function runSpecValidateCommand(options) {
|
|
146
|
+
const surface = commandSurface(options);
|
|
97
147
|
if (options.id) {
|
|
98
|
-
resolveSpecRecord(loadSpecRecords(options), options.id);
|
|
148
|
+
resolveSpecRecord(loadSpecRecords(options), options.id, surface);
|
|
99
149
|
}
|
|
100
150
|
(0, validate_1.runValidateCommand)({ root: options.root, json: options.json });
|
|
101
151
|
}
|
|
152
|
+
function runManifestListCommand(options) {
|
|
153
|
+
runSpecListCommand({ ...options, surface: "manifest" });
|
|
154
|
+
}
|
|
155
|
+
function runManifestShowCommand(options) {
|
|
156
|
+
runSpecShowCommand({ ...options, surface: "manifest" });
|
|
157
|
+
}
|
|
158
|
+
function runManifestValidateCommand(options) {
|
|
159
|
+
runSpecValidateCommand({ ...options, surface: "manifest" });
|
|
160
|
+
}
|
|
@@ -323,6 +323,9 @@ function runSubgraphVerifyCommand(options) {
|
|
|
323
323
|
throw new errors_1.ValidationError("subgraph verify failed");
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
+
function dirtySourceGuidance(paths) {
|
|
327
|
+
return `source_path has dirty tracked changes: ${paths.join(", ")}; commit or stash the child repo first, then refresh the root-owned subgraph bundle from the clean accepted child commit`;
|
|
328
|
+
}
|
|
326
329
|
function pushAuditCheck(receipt, check) {
|
|
327
330
|
receipt.checks.push(check);
|
|
328
331
|
if (!check.ok && check.severity === "error") {
|
|
@@ -349,7 +352,7 @@ function auditOneAlias(options) {
|
|
|
349
352
|
source_repo: options.health.source_repo,
|
|
350
353
|
capability_summary: {
|
|
351
354
|
node_count: options.nodeTypes.length,
|
|
352
|
-
spec_count: options.nodeTypes.filter((type) => type === "spec").length,
|
|
355
|
+
spec_count: options.nodeTypes.filter((type) => type === "manifest" || type === "spec").length,
|
|
353
356
|
work_count: options.nodeTypes.filter((type) => type === "work").length,
|
|
354
357
|
skill_count: options.nodeTypes.filter((type) => type === "skill").length,
|
|
355
358
|
},
|
|
@@ -392,7 +395,7 @@ function auditOneAlias(options) {
|
|
|
392
395
|
ok: !gitState.dirtyTracked,
|
|
393
396
|
severity: "warning",
|
|
394
397
|
message: gitState.dirtyTracked
|
|
395
|
-
?
|
|
398
|
+
? dirtySourceGuidance(gitState.dirtyTrackedPaths)
|
|
396
399
|
: "source_path has no dirty tracked changes",
|
|
397
400
|
path: options.subgraph.source_path,
|
|
398
401
|
details: { dirty_tracked_paths: gitState.dirtyTrackedPaths },
|
|
@@ -539,7 +542,7 @@ function upgradePlanForAlias(options) {
|
|
|
539
542
|
blockers.push(sourceGitError.message);
|
|
540
543
|
}
|
|
541
544
|
if (options.audit.dirty_tracked) {
|
|
542
|
-
blockers.push(
|
|
545
|
+
blockers.push(dirtySourceGuidance(options.audit.dirty_tracked_paths ?? []));
|
|
543
546
|
}
|
|
544
547
|
const rootOwnedErrors = options.audit.checks.filter((check) => check.id === "subgraph.bundle.root_owned" && !check.ok);
|
|
545
548
|
blockers.push(...rootOwnedErrors.map((check) => check.message));
|
|
@@ -705,7 +708,7 @@ function inspectSourcePath(root, alias, subgraph, allowDirty) {
|
|
|
705
708
|
? status.stdout.split(/\r?\n/).map((line) => line.slice(3)).filter(Boolean).sort()
|
|
706
709
|
: [];
|
|
707
710
|
if (dirtyTrackedPaths.length > 0 && !allowDirty) {
|
|
708
|
-
throw new errors_1.UsageError(`subgraph ${alias}
|
|
711
|
+
throw new errors_1.UsageError(`subgraph ${alias} ${dirtySourceGuidance(dirtyTrackedPaths)}`);
|
|
709
712
|
}
|
|
710
713
|
return {
|
|
711
714
|
sourceRoot,
|