mdkg 0.0.3 → 0.0.5
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/README.md +181 -169
- package/dist/cli.js +1002 -624
- package/dist/commands/checkpoint.js +17 -6
- package/dist/commands/event.js +46 -0
- package/dist/commands/event_support.js +146 -0
- package/dist/commands/format.js +6 -7
- package/dist/commands/index.js +10 -4
- package/dist/commands/init.js +224 -16
- package/dist/commands/list.js +18 -1
- package/dist/commands/new.js +30 -5
- package/dist/commands/pack.js +194 -2
- package/dist/commands/query_output.js +84 -0
- package/dist/commands/search.js +22 -5
- package/dist/commands/show.js +26 -11
- package/dist/commands/skill.js +374 -0
- package/dist/commands/skill_mirror.js +290 -0
- package/dist/commands/skill_support.js +122 -0
- package/dist/commands/task.js +278 -0
- package/dist/commands/validate.js +106 -7
- package/dist/graph/edges.js +2 -2
- package/dist/graph/frontmatter.js +1 -0
- package/dist/graph/indexer.js +21 -0
- package/dist/graph/node.js +20 -4
- package/dist/graph/skills_index_cache.js +94 -0
- package/dist/graph/skills_indexer.js +160 -0
- package/dist/init/AGENTS.md +6 -41
- package/dist/init/AGENT_START.md +46 -0
- package/dist/init/CLAUDE.md +6 -35
- package/dist/init/CLI_COMMAND_MATRIX.md +29 -0
- package/dist/init/README.md +6 -4
- package/dist/init/core/HUMAN.md +36 -0
- package/dist/init/core/SOUL.md +257 -0
- package/dist/init/core/core.md +3 -1
- package/dist/init/core/rule-1-mdkg-conventions.md +9 -2
- package/dist/init/core/rule-3-cli-contract.md +81 -14
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +9 -3
- package/dist/init/core/rule-6-templates-and-schemas.md +6 -2
- package/dist/init/llms.txt +17 -0
- package/dist/init/skills/SKILL.md.example +41 -0
- package/dist/init/templates/default/bug.md +1 -0
- package/dist/init/templates/default/chk.md +1 -0
- package/dist/init/templates/default/epic.md +1 -0
- package/dist/init/templates/default/feat.md +1 -0
- package/dist/init/templates/default/task.md +1 -0
- package/dist/init/templates/default/test.md +1 -0
- package/dist/pack/export_md.js +6 -0
- package/dist/pack/export_xml.js +6 -0
- package/dist/pack/pack.js +35 -0
- package/dist/util/argparse.js +36 -5
- package/dist/util/filter.js +18 -0
- package/dist/util/id.js +23 -0
- package/package.json +5 -2
package/dist/commands/new.js
CHANGED
|
@@ -14,10 +14,11 @@ const loader_1 = require("../templates/loader");
|
|
|
14
14
|
const date_1 = require("../util/date");
|
|
15
15
|
const errors_1 = require("../util/errors");
|
|
16
16
|
const qid_1 = require("../util/qid");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const id_1 = require("../util/id");
|
|
18
|
+
const event_support_1 = require("./event_support");
|
|
19
19
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
20
20
|
const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
21
|
+
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21
22
|
const CORE_TYPES = new Set(["rule"]);
|
|
22
23
|
const DESIGN_TYPES = new Set(["prd", "edd", "dec", "prop"]);
|
|
23
24
|
function parseCsvList(raw) {
|
|
@@ -31,14 +32,14 @@ function parseCsvList(raw) {
|
|
|
31
32
|
}
|
|
32
33
|
function normalizeId(value, key) {
|
|
33
34
|
const normalized = value.toLowerCase();
|
|
34
|
-
if (!
|
|
35
|
-
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number
|
|
35
|
+
if (!(0, id_1.isCanonicalId)(normalized)) {
|
|
36
|
+
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number> or reserved id: ${value}`);
|
|
36
37
|
}
|
|
37
38
|
return normalized;
|
|
38
39
|
}
|
|
39
40
|
function normalizeIdRef(value, key) {
|
|
40
41
|
const normalized = value.toLowerCase();
|
|
41
|
-
if (!
|
|
42
|
+
if (!(0, id_1.isCanonicalIdRef)(normalized)) {
|
|
42
43
|
throw new errors_1.UsageError(`${key} entries must match <id> or <ws>:<id>: ${value}`);
|
|
43
44
|
}
|
|
44
45
|
return normalized;
|
|
@@ -55,6 +56,15 @@ function normalizeIdList(raw, key) {
|
|
|
55
56
|
function normalizeIdRefList(raw, key) {
|
|
56
57
|
return parseCsvList(raw).map((value) => normalizeIdRef(value, key));
|
|
57
58
|
}
|
|
59
|
+
function normalizeSkillList(raw) {
|
|
60
|
+
return parseCsvList(raw).map((value) => {
|
|
61
|
+
const normalized = value.toLowerCase();
|
|
62
|
+
if (!SKILL_SLUG_RE.test(normalized)) {
|
|
63
|
+
throw new errors_1.UsageError(`--skills entries must be kebab-case: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
return normalized;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
58
68
|
function normalizeWorkspace(value) {
|
|
59
69
|
if (!value) {
|
|
60
70
|
return "root";
|
|
@@ -206,8 +216,12 @@ function runNewCommand(options) {
|
|
|
206
216
|
const tags = normalizeLowercaseList(options.tags);
|
|
207
217
|
const owners = normalizeLowercaseList(options.owners);
|
|
208
218
|
const cases = normalizeLowercaseList(options.cases);
|
|
219
|
+
const skills = normalizeSkillList(options.skills);
|
|
209
220
|
const links = normalizeList(options.links);
|
|
210
221
|
const artifacts = normalizeList(options.artifacts);
|
|
222
|
+
if (skills.length > 0 && !node_1.WORK_TYPES.has(type)) {
|
|
223
|
+
throw new errors_1.UsageError("--skills is only valid for work items");
|
|
224
|
+
}
|
|
211
225
|
if (type === "dec" && options.supersedes) {
|
|
212
226
|
const supersedes = options.supersedes.toLowerCase();
|
|
213
227
|
if (!DEC_ID_RE.test(supersedes)) {
|
|
@@ -263,6 +277,7 @@ function runNewCommand(options) {
|
|
|
263
277
|
artifacts: artifacts.length > 0 ? artifacts : undefined,
|
|
264
278
|
refs: refs.length > 0 ? refs : undefined,
|
|
265
279
|
aliases: aliases.length > 0 ? aliases : undefined,
|
|
280
|
+
skills: skills.length > 0 ? skills : undefined,
|
|
266
281
|
cases: cases.length > 0 ? cases : undefined,
|
|
267
282
|
supersedes: options.supersedes ? options.supersedes.toLowerCase() : undefined,
|
|
268
283
|
created: today,
|
|
@@ -275,5 +290,15 @@ function runNewCommand(options) {
|
|
|
275
290
|
const outputPath = path_1.default.resolve(options.root, config.index.global_index_path);
|
|
276
291
|
(0, index_cache_1.writeIndex)(outputPath, updatedIndex);
|
|
277
292
|
}
|
|
293
|
+
(0, event_support_1.appendAutomaticEvent)({
|
|
294
|
+
root: options.root,
|
|
295
|
+
ws,
|
|
296
|
+
kind: "NODE_CREATED",
|
|
297
|
+
status: "ok",
|
|
298
|
+
refs: [id],
|
|
299
|
+
notes: `node created via mdkg new`,
|
|
300
|
+
runId: options.runId,
|
|
301
|
+
now: options.now,
|
|
302
|
+
});
|
|
278
303
|
console.log(`node created: ${ws}:${id} (${path_1.default.relative(options.root, filePath)})`);
|
|
279
304
|
}
|
package/dist/commands/pack.js
CHANGED
|
@@ -8,6 +8,8 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const config_1 = require("../core/config");
|
|
10
10
|
const index_cache_1 = require("../graph/index_cache");
|
|
11
|
+
const frontmatter_1 = require("../graph/frontmatter");
|
|
12
|
+
const skills_index_cache_1 = require("../graph/skills_index_cache");
|
|
11
13
|
const node_1 = require("../graph/node");
|
|
12
14
|
const budget_1 = require("../pack/budget");
|
|
13
15
|
const export_json_1 = require("../pack/export_json");
|
|
@@ -24,6 +26,7 @@ const output_1 = require("../util/output");
|
|
|
24
26
|
const qid_1 = require("../util/qid");
|
|
25
27
|
const EDGE_KEYS = new Set(["parent", "epic", "relates", "blocked_by", "blocks", "prev", "next"]);
|
|
26
28
|
const FORMAT_KEYS = new Set(["md", "json", "toon", "xml"]);
|
|
29
|
+
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
27
30
|
function normalizeWorkspace(value) {
|
|
28
31
|
if (!value || value === "all") {
|
|
29
32
|
return undefined;
|
|
@@ -48,6 +51,158 @@ function normalizeFormat(format) {
|
|
|
48
51
|
}
|
|
49
52
|
return normalized;
|
|
50
53
|
}
|
|
54
|
+
function normalizeSkillSlug(slug) {
|
|
55
|
+
const normalized = slug.toLowerCase().trim();
|
|
56
|
+
if (!SKILL_SLUG_RE.test(normalized)) {
|
|
57
|
+
throw new errors_1.UsageError(`invalid skill slug: ${slug}`);
|
|
58
|
+
}
|
|
59
|
+
return normalized;
|
|
60
|
+
}
|
|
61
|
+
function resolveSkillsPolicy(raw) {
|
|
62
|
+
if (!raw) {
|
|
63
|
+
return { mode: "auto" };
|
|
64
|
+
}
|
|
65
|
+
const normalized = raw.toLowerCase().trim();
|
|
66
|
+
if (!normalized || normalized === "auto") {
|
|
67
|
+
return { mode: "auto" };
|
|
68
|
+
}
|
|
69
|
+
if (normalized === "none") {
|
|
70
|
+
return { mode: "none" };
|
|
71
|
+
}
|
|
72
|
+
const slugs = normalized
|
|
73
|
+
.split(",")
|
|
74
|
+
.map((value) => value.trim())
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.map((value) => normalizeSkillSlug(value));
|
|
77
|
+
if (slugs.length === 0) {
|
|
78
|
+
return { mode: "none" };
|
|
79
|
+
}
|
|
80
|
+
return { mode: "list", slugs: Array.from(new Set(slugs)) };
|
|
81
|
+
}
|
|
82
|
+
function resolveSkillsDepth(raw) {
|
|
83
|
+
if (!raw) {
|
|
84
|
+
return "meta";
|
|
85
|
+
}
|
|
86
|
+
const normalized = raw.toLowerCase().trim();
|
|
87
|
+
if (normalized === "meta" || normalized === "full") {
|
|
88
|
+
return normalized;
|
|
89
|
+
}
|
|
90
|
+
throw new errors_1.UsageError("--skills-depth must be meta or full");
|
|
91
|
+
}
|
|
92
|
+
function renderSkillMetaBody(skill) {
|
|
93
|
+
const lines = [];
|
|
94
|
+
lines.push(`description: ${skill.description}`);
|
|
95
|
+
if (skill.tags.length > 0) {
|
|
96
|
+
lines.push(`tags: ${skill.tags.join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
if (skill.version) {
|
|
99
|
+
lines.push(`version: ${skill.version}`);
|
|
100
|
+
}
|
|
101
|
+
if (skill.authors.length > 0) {
|
|
102
|
+
lines.push(`authors: ${skill.authors.join(", ")}`);
|
|
103
|
+
}
|
|
104
|
+
if (skill.links.length > 0) {
|
|
105
|
+
lines.push(`links: ${skill.links.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
lines.push(`has_scripts: ${skill.has_scripts ? "true" : "false"}`);
|
|
108
|
+
lines.push(`has_references: ${skill.has_references ? "true" : "false"}`);
|
|
109
|
+
for (const [key, value] of Object.entries(skill.ochatr).sort(([a], [b]) => a.localeCompare(b))) {
|
|
110
|
+
if (Array.isArray(value)) {
|
|
111
|
+
lines.push(`${key}: ${value.join(", ")}`);
|
|
112
|
+
}
|
|
113
|
+
else if (typeof value === "boolean") {
|
|
114
|
+
lines.push(`${key}: ${value ? "true" : "false"}`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
lines.push(`${key}: ${value}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return lines.join("\n").trimEnd();
|
|
121
|
+
}
|
|
122
|
+
function loadSkillFullBody(root, skill) {
|
|
123
|
+
const skillPath = path_1.default.resolve(root, skill.path);
|
|
124
|
+
if (!fs_1.default.existsSync(skillPath)) {
|
|
125
|
+
return renderSkillMetaBody(skill);
|
|
126
|
+
}
|
|
127
|
+
const content = fs_1.default.readFileSync(skillPath, "utf8");
|
|
128
|
+
return (0, frontmatter_1.parseFrontmatter)(content, skillPath).body.trimEnd();
|
|
129
|
+
}
|
|
130
|
+
function uniqueSkillOrder(slugs) {
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
const ordered = [];
|
|
133
|
+
for (const slug of slugs) {
|
|
134
|
+
if (seen.has(slug)) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
seen.add(slug);
|
|
138
|
+
ordered.push(slug);
|
|
139
|
+
}
|
|
140
|
+
return ordered;
|
|
141
|
+
}
|
|
142
|
+
function collectReferencedSkills(indexQids, indexNodes) {
|
|
143
|
+
const slugs = [];
|
|
144
|
+
for (const qid of indexQids) {
|
|
145
|
+
const node = indexNodes[qid];
|
|
146
|
+
if (!node) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (node.type === "skill") {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
slugs.push(...node.skills);
|
|
153
|
+
}
|
|
154
|
+
return uniqueSkillOrder(slugs);
|
|
155
|
+
}
|
|
156
|
+
function appendSkillsToPack(pack, skillEntries, depth, root) {
|
|
157
|
+
const existing = new Set(pack.nodes.map((node) => node.qid));
|
|
158
|
+
const newNodes = skillEntries
|
|
159
|
+
.filter((skill) => !existing.has(skill.qid))
|
|
160
|
+
.map((skill) => ({
|
|
161
|
+
qid: skill.qid,
|
|
162
|
+
id: skill.id,
|
|
163
|
+
workspace: skill.ws,
|
|
164
|
+
type: "skill",
|
|
165
|
+
title: skill.name,
|
|
166
|
+
status: undefined,
|
|
167
|
+
priority: undefined,
|
|
168
|
+
path: skill.path,
|
|
169
|
+
links: skill.links,
|
|
170
|
+
artifacts: [],
|
|
171
|
+
refs: [],
|
|
172
|
+
aliases: [skill.slug, ...skill.tags],
|
|
173
|
+
body: depth === "full" ? loadSkillFullBody(root, skill) : renderSkillMetaBody(skill),
|
|
174
|
+
}));
|
|
175
|
+
if (newNodes.length === 0) {
|
|
176
|
+
return pack;
|
|
177
|
+
}
|
|
178
|
+
const mergedNodes = [...pack.nodes, ...newNodes];
|
|
179
|
+
return {
|
|
180
|
+
meta: {
|
|
181
|
+
...pack.meta,
|
|
182
|
+
node_count: mergedNodes.length,
|
|
183
|
+
},
|
|
184
|
+
nodes: mergedNodes,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function applyNodeCountLimit(pack, maxNodes) {
|
|
188
|
+
if (maxNodes <= 0 || pack.nodes.length <= maxNodes) {
|
|
189
|
+
return pack;
|
|
190
|
+
}
|
|
191
|
+
const included = pack.nodes.slice(0, maxNodes);
|
|
192
|
+
const dropped = pack.nodes.slice(maxNodes).map((node) => node.qid);
|
|
193
|
+
return {
|
|
194
|
+
meta: {
|
|
195
|
+
...pack.meta,
|
|
196
|
+
node_count: included.length,
|
|
197
|
+
truncated: {
|
|
198
|
+
...pack.meta.truncated,
|
|
199
|
+
max_nodes: true,
|
|
200
|
+
dropped: [...pack.meta.truncated.dropped, ...dropped],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
nodes: included,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
51
206
|
function writeJsonFile(outPath, payload) {
|
|
52
207
|
fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
|
|
53
208
|
fs_1.default.writeFileSync(outPath, JSON.stringify(payload, null, 2), "utf8");
|
|
@@ -76,6 +231,12 @@ function printDryRunSummary(pack, stats, format) {
|
|
|
76
231
|
console.log(`body_mode: ${pack.meta.body_mode ?? "full"}`);
|
|
77
232
|
console.log(`format: ${format}`);
|
|
78
233
|
console.log(`nodes: ${pack.nodes.length}`);
|
|
234
|
+
if (pack.meta.latest_checkpoint_qid) {
|
|
235
|
+
console.log(`latest_checkpoint_qid: ${pack.meta.latest_checkpoint_qid}`);
|
|
236
|
+
}
|
|
237
|
+
if (pack.meta.latest_checkpoint_qid_hint) {
|
|
238
|
+
console.log(`latest_checkpoint_qid_hint: ${pack.meta.latest_checkpoint_qid_hint}`);
|
|
239
|
+
}
|
|
79
240
|
if (pack.meta.truncated.dropped.length > 0) {
|
|
80
241
|
console.log(`dropped: ${pack.meta.truncated.dropped.join(", ")}`);
|
|
81
242
|
}
|
|
@@ -114,6 +275,8 @@ function runPackCommand(options) {
|
|
|
114
275
|
}
|
|
115
276
|
const extraEdges = options.edges ? normalizeEdges(options.edges) : [];
|
|
116
277
|
const edges = normalizeEdges([...config.pack.default_edges, ...extraEdges]);
|
|
278
|
+
const skillsPolicy = resolveSkillsPolicy(options.skills);
|
|
279
|
+
const skillsDepth = resolveSkillsDepth(options.skillsDepth);
|
|
117
280
|
let resolvedProfile;
|
|
118
281
|
try {
|
|
119
282
|
resolvedProfile = (0, profile_1.resolvePackProfile)({
|
|
@@ -128,7 +291,7 @@ function runPackCommand(options) {
|
|
|
128
291
|
throw new errors_1.UsageError(message);
|
|
129
292
|
}
|
|
130
293
|
if (options.verbose && resolvedProfile.profile !== "standard") {
|
|
131
|
-
throw new errors_1.UsageError("--verbose is only supported with --
|
|
294
|
+
throw new errors_1.UsageError("--verbose is only supported with --profile standard");
|
|
132
295
|
}
|
|
133
296
|
const buildResult = (0, pack_1.buildPack)({
|
|
134
297
|
root: options.root,
|
|
@@ -140,14 +303,43 @@ function runPackCommand(options) {
|
|
|
140
303
|
maxNodes: config.pack.limits.max_nodes,
|
|
141
304
|
verboseCoreListPath: path_1.default.resolve(options.root, config.pack.verbose_core_list_path),
|
|
142
305
|
wsHint: ws,
|
|
306
|
+
includeLatestCheckpoint: true,
|
|
143
307
|
});
|
|
144
308
|
for (const warning of buildResult.warnings) {
|
|
145
309
|
console.error(`warning: ${warning}`);
|
|
146
310
|
}
|
|
311
|
+
let packWithSkills = buildResult.pack;
|
|
312
|
+
if (skillsPolicy.mode !== "none") {
|
|
313
|
+
const skillsLoad = (0, skills_index_cache_1.loadSkillsIndex)({
|
|
314
|
+
root: options.root,
|
|
315
|
+
config,
|
|
316
|
+
useCache: !options.noCache,
|
|
317
|
+
allowReindex: !options.noReindex,
|
|
318
|
+
});
|
|
319
|
+
if (skillsLoad.stale && !skillsLoad.rebuilt && !options.noCache) {
|
|
320
|
+
console.error("warning: skills index is stale; run mdkg index to refresh");
|
|
321
|
+
}
|
|
322
|
+
const indexQids = buildResult.pack.nodes.map((node) => node.qid);
|
|
323
|
+
const autoSlugs = collectReferencedSkills(indexQids, index.nodes);
|
|
324
|
+
const selectedSlugs = skillsPolicy.mode === "list"
|
|
325
|
+
? skillsPolicy.slugs
|
|
326
|
+
: autoSlugs;
|
|
327
|
+
const selectedEntries = [];
|
|
328
|
+
for (const slug of selectedSlugs) {
|
|
329
|
+
const entry = skillsLoad.index.skills[slug];
|
|
330
|
+
if (!entry) {
|
|
331
|
+
console.error(`warning: requested skill missing: ${slug}`);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
selectedEntries.push(entry);
|
|
335
|
+
}
|
|
336
|
+
packWithSkills = appendSkillsToPack(packWithSkills, selectedEntries, skillsDepth, options.root);
|
|
337
|
+
packWithSkills = applyNodeCountLimit(packWithSkills, config.pack.limits.max_nodes);
|
|
338
|
+
}
|
|
147
339
|
const templateHeadingMap = resolvedProfile.bodyMode === "summary"
|
|
148
340
|
? (0, headings_1.loadTemplateHeadingMap)(options.root, config, Array.from(node_1.ALLOWED_TYPES))
|
|
149
341
|
: {};
|
|
150
|
-
const shaped = (0, profile_1.shapePackBodies)(
|
|
342
|
+
const shaped = (0, profile_1.shapePackBodies)(packWithSkills, {
|
|
151
343
|
resolved: resolvedProfile,
|
|
152
344
|
templateHeadingMap,
|
|
153
345
|
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toNodeSummaryJson = toNodeSummaryJson;
|
|
4
|
+
exports.toNodeDetailJson = toNodeDetailJson;
|
|
5
|
+
exports.toSkillSummaryJson = toSkillSummaryJson;
|
|
6
|
+
exports.toSkillDetailJson = toSkillDetailJson;
|
|
7
|
+
exports.writeJson = writeJson;
|
|
8
|
+
exports.writeCount = writeCount;
|
|
9
|
+
function toNodeSummaryJson(node) {
|
|
10
|
+
return {
|
|
11
|
+
id: node.id,
|
|
12
|
+
qid: node.qid,
|
|
13
|
+
ws: node.ws,
|
|
14
|
+
type: node.type,
|
|
15
|
+
title: node.title,
|
|
16
|
+
status: node.status,
|
|
17
|
+
priority: node.priority,
|
|
18
|
+
created: node.created,
|
|
19
|
+
updated: node.updated,
|
|
20
|
+
tags: [...node.tags],
|
|
21
|
+
owners: [...node.owners],
|
|
22
|
+
links: [...node.links],
|
|
23
|
+
artifacts: [...node.artifacts],
|
|
24
|
+
refs: [...node.refs],
|
|
25
|
+
aliases: [...node.aliases],
|
|
26
|
+
skills: [...node.skills],
|
|
27
|
+
path: node.path,
|
|
28
|
+
edges: {
|
|
29
|
+
epic: node.edges.epic,
|
|
30
|
+
parent: node.edges.parent,
|
|
31
|
+
prev: node.edges.prev,
|
|
32
|
+
next: node.edges.next,
|
|
33
|
+
relates: [...node.edges.relates],
|
|
34
|
+
blocked_by: [...node.edges.blocked_by],
|
|
35
|
+
blocks: [...node.edges.blocks],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function toNodeDetailJson(node, body) {
|
|
40
|
+
const item = {
|
|
41
|
+
...toNodeSummaryJson(node),
|
|
42
|
+
};
|
|
43
|
+
if (body !== undefined) {
|
|
44
|
+
item.body = body;
|
|
45
|
+
}
|
|
46
|
+
return item;
|
|
47
|
+
}
|
|
48
|
+
function toSkillSummaryJson(skill) {
|
|
49
|
+
return {
|
|
50
|
+
slug: skill.slug,
|
|
51
|
+
id: skill.id,
|
|
52
|
+
qid: skill.qid,
|
|
53
|
+
ws: skill.ws,
|
|
54
|
+
type: skill.type,
|
|
55
|
+
name: skill.name,
|
|
56
|
+
description: skill.description,
|
|
57
|
+
tags: [...skill.tags],
|
|
58
|
+
version: skill.version,
|
|
59
|
+
authors: [...skill.authors],
|
|
60
|
+
links: [...skill.links],
|
|
61
|
+
path: skill.path,
|
|
62
|
+
has_scripts: skill.has_scripts,
|
|
63
|
+
has_references: skill.has_references,
|
|
64
|
+
ochatr: { ...skill.ochatr },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function toSkillDetailJson(skill, body) {
|
|
68
|
+
const item = {
|
|
69
|
+
...toSkillSummaryJson(skill),
|
|
70
|
+
};
|
|
71
|
+
if (body !== undefined) {
|
|
72
|
+
item.body = body;
|
|
73
|
+
}
|
|
74
|
+
return item;
|
|
75
|
+
}
|
|
76
|
+
function writeJson(payload) {
|
|
77
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
78
|
+
}
|
|
79
|
+
function writeCount(count, note) {
|
|
80
|
+
console.error(`count: ${count}`);
|
|
81
|
+
if (note) {
|
|
82
|
+
console.error(`note: ${note}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
package/dist/commands/search.js
CHANGED
|
@@ -7,6 +7,7 @@ const filter_1 = require("../util/filter");
|
|
|
7
7
|
const errors_1 = require("../util/errors");
|
|
8
8
|
const sort_1 = require("../util/sort");
|
|
9
9
|
const node_card_1 = require("./node_card");
|
|
10
|
+
const query_output_1 = require("./query_output");
|
|
10
11
|
function normalizeWorkspace(value) {
|
|
11
12
|
if (!value || value === "all") {
|
|
12
13
|
return undefined;
|
|
@@ -25,6 +26,7 @@ function buildSearchText(node) {
|
|
|
25
26
|
...node.artifacts,
|
|
26
27
|
...node.refs,
|
|
27
28
|
...node.aliases,
|
|
29
|
+
...node.skills,
|
|
28
30
|
];
|
|
29
31
|
return tokens.join(" ").toLowerCase();
|
|
30
32
|
}
|
|
@@ -47,6 +49,10 @@ function runSearchCommand(options) {
|
|
|
47
49
|
if (ws && !config.workspaces[ws]) {
|
|
48
50
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
49
51
|
}
|
|
52
|
+
const normalizedType = options.type?.toLowerCase();
|
|
53
|
+
if (normalizedType === "skill") {
|
|
54
|
+
throw new errors_1.UsageError("--type skill is no longer supported here; use `mdkg skill search`");
|
|
55
|
+
}
|
|
50
56
|
const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
|
|
51
57
|
root: options.root,
|
|
52
58
|
config,
|
|
@@ -57,13 +63,24 @@ function runSearchCommand(options) {
|
|
|
57
63
|
console.error("warning: index is stale; run mdkg index to refresh");
|
|
58
64
|
}
|
|
59
65
|
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
60
|
-
const
|
|
66
|
+
const nodeResults = (0, filter_1.filterNodes)(Object.values(index.nodes), {
|
|
61
67
|
ws,
|
|
62
|
-
type:
|
|
68
|
+
type: normalizedType,
|
|
63
69
|
status: options.status,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
tags: options.tags,
|
|
71
|
+
tagsMode: options.tagsMode,
|
|
72
|
+
}).filter((node) => matchesQuery(node, terms));
|
|
73
|
+
const sorted = (0, sort_1.sortNodesByQid)(nodeResults);
|
|
74
|
+
if (options.json) {
|
|
75
|
+
(0, query_output_1.writeJson)({
|
|
76
|
+
command: "search",
|
|
77
|
+
kind: "node",
|
|
78
|
+
count: sorted.length,
|
|
79
|
+
items: sorted.map(query_output_1.toNodeSummaryJson),
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
(0, query_output_1.writeCount)(sorted.length, sorted.length === 0 ? `no nodes matched query "${query}"` : undefined);
|
|
67
84
|
for (const node of sorted) {
|
|
68
85
|
console.log((0, node_card_1.formatNodeCard)(node));
|
|
69
86
|
}
|
package/dist/commands/show.js
CHANGED
|
@@ -12,6 +12,7 @@ const frontmatter_1 = require("../graph/frontmatter");
|
|
|
12
12
|
const errors_1 = require("../util/errors");
|
|
13
13
|
const qid_1 = require("../util/qid");
|
|
14
14
|
const node_card_1 = require("./node_card");
|
|
15
|
+
const query_output_1 = require("./query_output");
|
|
15
16
|
function normalizeWorkspace(value) {
|
|
16
17
|
if (!value || value === "all") {
|
|
17
18
|
return undefined;
|
|
@@ -30,6 +31,10 @@ function runShowCommand(options) {
|
|
|
30
31
|
if (ws && !config.workspaces[ws]) {
|
|
31
32
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
32
33
|
}
|
|
34
|
+
const normalizedId = options.id.toLowerCase();
|
|
35
|
+
if (normalizedId.startsWith("skill:") || normalizedId.startsWith("root:skill:")) {
|
|
36
|
+
throw new errors_1.UsageError(`generic skill show is no longer supported; use \`mdkg skill show ${options.id.replace(/^root:skill:|^skill:/i, "")}\``);
|
|
37
|
+
}
|
|
33
38
|
const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
|
|
34
39
|
root: options.root,
|
|
35
40
|
config,
|
|
@@ -44,6 +49,23 @@ function runShowCommand(options) {
|
|
|
44
49
|
throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("id", options.id, resolved, ws));
|
|
45
50
|
}
|
|
46
51
|
const node = index.nodes[resolved.qid];
|
|
52
|
+
const filePath = path_1.default.resolve(options.root, node.path);
|
|
53
|
+
let body = "";
|
|
54
|
+
if (!options.metaOnly) {
|
|
55
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
56
|
+
throw new errors_1.NotFoundError(`file not found for ${node.qid}: ${node.path}`);
|
|
57
|
+
}
|
|
58
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
59
|
+
body = (0, frontmatter_1.parseFrontmatter)(content, filePath).body.trimEnd();
|
|
60
|
+
}
|
|
61
|
+
if (options.json) {
|
|
62
|
+
(0, query_output_1.writeJson)({
|
|
63
|
+
command: "show",
|
|
64
|
+
kind: "node",
|
|
65
|
+
item: (0, query_output_1.toNodeDetailJson)(node, options.metaOnly ? undefined : body),
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
47
69
|
const lines = [];
|
|
48
70
|
lines.push((0, node_card_1.formatNodeCard)(node));
|
|
49
71
|
const metaLines = [
|
|
@@ -53,6 +75,7 @@ function runShowCommand(options) {
|
|
|
53
75
|
maybeLine("artifacts", node.artifacts),
|
|
54
76
|
maybeLine("refs", node.refs),
|
|
55
77
|
maybeLine("aliases", node.aliases),
|
|
78
|
+
maybeLine("skills", node.skills),
|
|
56
79
|
].filter((line) => Boolean(line));
|
|
57
80
|
lines.push(...metaLines);
|
|
58
81
|
if (node.edges.epic) {
|
|
@@ -79,17 +102,9 @@ function runShowCommand(options) {
|
|
|
79
102
|
if (blocksLine) {
|
|
80
103
|
lines.push(blocksLine);
|
|
81
104
|
}
|
|
82
|
-
if (options.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
throw new errors_1.NotFoundError(`file not found for ${node.qid}: ${node.path}`);
|
|
86
|
-
}
|
|
87
|
-
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
88
|
-
const body = (0, frontmatter_1.parseFrontmatter)(content, filePath).body.trimEnd();
|
|
89
|
-
if (body.length > 0) {
|
|
90
|
-
lines.push("");
|
|
91
|
-
lines.push(body);
|
|
92
|
-
}
|
|
105
|
+
if (!options.metaOnly && body.length > 0) {
|
|
106
|
+
lines.push("");
|
|
107
|
+
lines.push(body);
|
|
93
108
|
}
|
|
94
109
|
console.log(lines.join("\n"));
|
|
95
110
|
}
|