mdkg 0.0.2 → 0.0.4
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 +171 -151
- package/dist/cli.js +920 -422
- package/dist/commands/checkpoint.js +17 -6
- package/dist/commands/doctor.js +156 -0
- 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 +202 -11
- package/dist/commands/list.js +18 -1
- package/dist/commands/new.js +30 -5
- package/dist/commands/pack.js +332 -10
- 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 +359 -0
- package/dist/commands/skill_support.js +121 -0
- package/dist/commands/task.js +270 -0
- package/dist/commands/validate.js +104 -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/README.md +43 -0
- package/dist/init/core/rule-1-mdkg-conventions.md +9 -2
- package/dist/init/core/rule-3-cli-contract.md +73 -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/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/budget.js +186 -0
- package/dist/pack/export_md.js +17 -1
- package/dist/pack/export_xml.js +15 -0
- package/dist/pack/metrics.js +66 -0
- package/dist/pack/pack.js +35 -0
- package/dist/pack/profile.js +222 -0
- package/dist/pack/stats.js +37 -0
- package/dist/templates/headings.js +34 -0
- package/dist/util/argparse.js +47 -1
- package/dist/util/filter.js +18 -0
- package/dist/util/id.js +23 -0
- package/dist/util/output.js +2 -2
- package/package.json +6 -2
package/dist/commands/pack.js
CHANGED
|
@@ -8,16 +8,25 @@ 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
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const export_md_1 = require("../pack/export_md");
|
|
11
|
+
const frontmatter_1 = require("../graph/frontmatter");
|
|
12
|
+
const skills_index_cache_1 = require("../graph/skills_index_cache");
|
|
13
|
+
const node_1 = require("../graph/node");
|
|
14
|
+
const budget_1 = require("../pack/budget");
|
|
16
15
|
const export_json_1 = require("../pack/export_json");
|
|
16
|
+
const export_md_1 = require("../pack/export_md");
|
|
17
17
|
const export_toon_1 = require("../pack/export_toon");
|
|
18
18
|
const export_xml_1 = require("../pack/export_xml");
|
|
19
|
+
const metrics_1 = require("../pack/metrics");
|
|
20
|
+
const pack_1 = require("../pack/pack");
|
|
21
|
+
const profile_1 = require("../pack/profile");
|
|
22
|
+
const stats_1 = require("../pack/stats");
|
|
23
|
+
const headings_1 = require("../templates/headings");
|
|
24
|
+
const errors_1 = require("../util/errors");
|
|
25
|
+
const output_1 = require("../util/output");
|
|
26
|
+
const qid_1 = require("../util/qid");
|
|
19
27
|
const EDGE_KEYS = new Set(["parent", "epic", "relates", "blocked_by", "blocks", "prev", "next"]);
|
|
20
28
|
const FORMAT_KEYS = new Set(["md", "json", "toon", "xml"]);
|
|
29
|
+
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21
30
|
function normalizeWorkspace(value) {
|
|
22
31
|
if (!value || value === "all") {
|
|
23
32
|
return undefined;
|
|
@@ -42,6 +51,205 @@ function normalizeFormat(format) {
|
|
|
42
51
|
}
|
|
43
52
|
return normalized;
|
|
44
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
|
+
}
|
|
206
|
+
function writeJsonFile(outPath, payload) {
|
|
207
|
+
fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
|
|
208
|
+
fs_1.default.writeFileSync(outPath, JSON.stringify(payload, null, 2), "utf8");
|
|
209
|
+
}
|
|
210
|
+
function resolveStatsPath(root, outPath, statsOut) {
|
|
211
|
+
if (statsOut) {
|
|
212
|
+
return path_1.default.resolve(root, statsOut);
|
|
213
|
+
}
|
|
214
|
+
return `${outPath}.stats.json`;
|
|
215
|
+
}
|
|
216
|
+
function shouldWriteTruncationReport(pack, options) {
|
|
217
|
+
if (options.truncationReport) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
if (!options.maxChars && !options.maxLines && !options.maxTokens) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
const hasDrops = pack.meta.truncated.dropped.length > 0;
|
|
224
|
+
const hasBodyTruncation = (pack.meta.truncated.body_truncated ?? []).length > 0;
|
|
225
|
+
return hasDrops || hasBodyTruncation;
|
|
226
|
+
}
|
|
227
|
+
function printDryRunSummary(pack, stats, format) {
|
|
228
|
+
console.log("dry-run: no files written");
|
|
229
|
+
console.log(`root: ${pack.meta.root}`);
|
|
230
|
+
console.log(`profile: ${pack.meta.profile ?? "standard"}`);
|
|
231
|
+
console.log(`body_mode: ${pack.meta.body_mode ?? "full"}`);
|
|
232
|
+
console.log(`format: ${format}`);
|
|
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
|
+
}
|
|
240
|
+
if (pack.meta.truncated.dropped.length > 0) {
|
|
241
|
+
console.log(`dropped: ${pack.meta.truncated.dropped.join(", ")}`);
|
|
242
|
+
}
|
|
243
|
+
if ((pack.meta.truncated.body_truncated ?? []).length > 0) {
|
|
244
|
+
console.log(`body_truncated: ${(pack.meta.truncated.body_truncated ?? []).join(", ")}`);
|
|
245
|
+
}
|
|
246
|
+
console.log("included_nodes:");
|
|
247
|
+
for (const node of pack.nodes) {
|
|
248
|
+
console.log(`- ${node.qid}`);
|
|
249
|
+
}
|
|
250
|
+
console.log("");
|
|
251
|
+
console.log((0, stats_1.renderPackStats)(stats));
|
|
252
|
+
}
|
|
45
253
|
function runPackCommand(options) {
|
|
46
254
|
const config = (0, config_1.loadConfig)(options.root);
|
|
47
255
|
const ws = normalizeWorkspace(options.ws);
|
|
@@ -67,6 +275,24 @@ function runPackCommand(options) {
|
|
|
67
275
|
}
|
|
68
276
|
const extraEdges = options.edges ? normalizeEdges(options.edges) : [];
|
|
69
277
|
const edges = normalizeEdges([...config.pack.default_edges, ...extraEdges]);
|
|
278
|
+
const skillsPolicy = resolveSkillsPolicy(options.skills);
|
|
279
|
+
const skillsDepth = resolveSkillsDepth(options.skillsDepth);
|
|
280
|
+
let resolvedProfile;
|
|
281
|
+
try {
|
|
282
|
+
resolvedProfile = (0, profile_1.resolvePackProfile)({
|
|
283
|
+
profile: options.packProfile,
|
|
284
|
+
concise: options.concise,
|
|
285
|
+
stripCode: options.stripCode,
|
|
286
|
+
maxCodeLines: options.maxCodeLines,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
291
|
+
throw new errors_1.UsageError(message);
|
|
292
|
+
}
|
|
293
|
+
if (options.verbose && resolvedProfile.profile !== "standard") {
|
|
294
|
+
throw new errors_1.UsageError("--verbose is only supported with --profile standard");
|
|
295
|
+
}
|
|
70
296
|
const buildResult = (0, pack_1.buildPack)({
|
|
71
297
|
root: options.root,
|
|
72
298
|
index,
|
|
@@ -77,29 +303,125 @@ function runPackCommand(options) {
|
|
|
77
303
|
maxNodes: config.pack.limits.max_nodes,
|
|
78
304
|
verboseCoreListPath: path_1.default.resolve(options.root, config.pack.verbose_core_list_path),
|
|
79
305
|
wsHint: ws,
|
|
306
|
+
includeLatestCheckpoint: true,
|
|
80
307
|
});
|
|
81
308
|
for (const warning of buildResult.warnings) {
|
|
82
309
|
console.error(`warning: ${warning}`);
|
|
83
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
|
+
}
|
|
339
|
+
const templateHeadingMap = resolvedProfile.bodyMode === "summary"
|
|
340
|
+
? (0, headings_1.loadTemplateHeadingMap)(options.root, config, Array.from(node_1.ALLOWED_TYPES))
|
|
341
|
+
: {};
|
|
342
|
+
const shaped = (0, profile_1.shapePackBodies)(packWithSkills, {
|
|
343
|
+
resolved: resolvedProfile,
|
|
344
|
+
templateHeadingMap,
|
|
345
|
+
});
|
|
346
|
+
let budgeted;
|
|
347
|
+
try {
|
|
348
|
+
budgeted = (0, budget_1.applyPackBudgets)(shaped, {
|
|
349
|
+
maxChars: options.maxChars,
|
|
350
|
+
maxLines: options.maxLines,
|
|
351
|
+
maxTokens: options.maxTokens,
|
|
352
|
+
}, resolvedProfile.profile);
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
356
|
+
throw new errors_1.UsageError(message);
|
|
357
|
+
}
|
|
358
|
+
let finalPack = budgeted.pack;
|
|
84
359
|
const format = normalizeFormat(options.format);
|
|
85
360
|
let output = "";
|
|
86
361
|
if (format === "md") {
|
|
87
|
-
|
|
362
|
+
const markdown = (0, export_md_1.exportMarkdown)(finalPack, config.pack.limits.max_bytes);
|
|
363
|
+
output = markdown.content;
|
|
364
|
+
finalPack = {
|
|
365
|
+
meta: markdown.meta,
|
|
366
|
+
nodes: markdown.nodes,
|
|
367
|
+
};
|
|
88
368
|
}
|
|
89
369
|
else if (format === "json") {
|
|
90
|
-
output = (0, export_json_1.exportJson)(
|
|
370
|
+
output = (0, export_json_1.exportJson)(finalPack);
|
|
91
371
|
}
|
|
92
372
|
else if (format === "toon") {
|
|
93
|
-
output = (0, export_toon_1.exportToon)(
|
|
373
|
+
output = (0, export_toon_1.exportToon)(finalPack);
|
|
94
374
|
}
|
|
95
375
|
else if (format === "xml") {
|
|
96
|
-
output = (0, export_xml_1.exportXml)(
|
|
376
|
+
output = (0, export_xml_1.exportXml)(finalPack);
|
|
377
|
+
}
|
|
378
|
+
const finalStats = (0, metrics_1.measurePack)(finalPack);
|
|
379
|
+
if (options.dryRun) {
|
|
380
|
+
if (options.out || options.statsOut || options.truncationReport) {
|
|
381
|
+
console.error("warning: --out/--stats-out/--truncation-report are ignored with --dry-run");
|
|
382
|
+
}
|
|
383
|
+
printDryRunSummary(finalPack, finalStats, format);
|
|
384
|
+
return;
|
|
97
385
|
}
|
|
98
386
|
const rootId = resolved.qid.split(":")[1] ?? resolved.qid;
|
|
99
387
|
const outPath = options.out
|
|
100
388
|
? path_1.default.resolve(options.root, options.out)
|
|
101
|
-
: (0, output_1.buildDefaultPackPath)(options.root, rootId, format, Boolean(options.verbose), new Date());
|
|
389
|
+
: (0, output_1.buildDefaultPackPath)(options.root, rootId, format, Boolean(options.verbose), new Date(), resolvedProfile.profile);
|
|
102
390
|
fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
|
|
103
391
|
fs_1.default.writeFileSync(outPath, output, "utf8");
|
|
104
392
|
console.log(`pack written: ${outPath}`);
|
|
393
|
+
const statsEnabled = Boolean(options.stats || options.statsOut);
|
|
394
|
+
if (statsEnabled) {
|
|
395
|
+
const statsPayload = {
|
|
396
|
+
root: finalPack.meta.root,
|
|
397
|
+
profile: finalPack.meta.profile ?? resolvedProfile.profile,
|
|
398
|
+
body_mode: finalPack.meta.body_mode ?? resolvedProfile.bodyMode,
|
|
399
|
+
...finalStats,
|
|
400
|
+
};
|
|
401
|
+
const statsPath = resolveStatsPath(options.root, outPath, options.statsOut);
|
|
402
|
+
writeJsonFile(statsPath, statsPayload);
|
|
403
|
+
console.log(`pack stats written: ${statsPath}`);
|
|
404
|
+
if (options.stats) {
|
|
405
|
+
console.log((0, stats_1.renderPackStats)(finalStats));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const truncationReport = {
|
|
409
|
+
...budgeted.report,
|
|
410
|
+
after: {
|
|
411
|
+
node_count: finalPack.nodes.length,
|
|
412
|
+
chars: finalStats.totals.chars,
|
|
413
|
+
lines: finalStats.totals.lines,
|
|
414
|
+
bytes: finalStats.totals.bytes,
|
|
415
|
+
tokens_estimate: finalStats.totals.tokens_estimate,
|
|
416
|
+
},
|
|
417
|
+
dropped_nodes: [...finalPack.meta.truncated.dropped],
|
|
418
|
+
body_truncated_nodes: [...(finalPack.meta.truncated.body_truncated ?? [])],
|
|
419
|
+
};
|
|
420
|
+
if (shouldWriteTruncationReport(finalPack, options)) {
|
|
421
|
+
const reportPath = options.truncationReport
|
|
422
|
+
? path_1.default.resolve(options.root, options.truncationReport)
|
|
423
|
+
: `${outPath}.truncation.json`;
|
|
424
|
+
writeJsonFile(reportPath, truncationReport);
|
|
425
|
+
console.log(`pack truncation report written: ${reportPath}`);
|
|
426
|
+
}
|
|
105
427
|
}
|
|
@@ -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
|
}
|