mdkg 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +20 -6
  2. package/dist/cli.js +667 -11
  3. package/dist/commands/checkpoint.js +133 -0
  4. package/dist/commands/format.js +297 -0
  5. package/dist/commands/guide.js +22 -0
  6. package/dist/commands/index.js +17 -0
  7. package/dist/commands/init.js +111 -0
  8. package/dist/commands/list.js +52 -0
  9. package/dist/commands/new.js +279 -0
  10. package/dist/commands/next.js +75 -0
  11. package/dist/commands/node_card.js +17 -0
  12. package/dist/commands/pack.js +105 -0
  13. package/dist/commands/search.js +70 -0
  14. package/dist/commands/show.js +95 -0
  15. package/dist/commands/validate.js +229 -0
  16. package/dist/commands/workspace.js +101 -0
  17. package/dist/core/config.js +162 -0
  18. package/dist/core/migrate.js +30 -0
  19. package/dist/core/paths.js +14 -0
  20. package/dist/graph/edges.js +64 -0
  21. package/dist/graph/frontmatter.js +132 -0
  22. package/dist/graph/index_cache.js +50 -0
  23. package/dist/graph/indexer.js +144 -0
  24. package/dist/graph/node.js +225 -0
  25. package/dist/graph/staleness.js +31 -0
  26. package/dist/graph/template_schema.js +86 -0
  27. package/dist/graph/validate_graph.js +115 -0
  28. package/dist/graph/workspace_files.js +64 -0
  29. package/dist/init/AGENTS.md +43 -0
  30. package/dist/init/CLAUDE.md +37 -0
  31. package/dist/init/config.json +67 -0
  32. package/dist/init/core/core.md +12 -0
  33. package/dist/init/core/guide.md +99 -0
  34. package/dist/init/core/rule-1-mdkg-conventions.md +232 -0
  35. package/dist/init/core/rule-2-context-pack-rules.md +186 -0
  36. package/dist/init/core/rule-3-cli-contract.md +177 -0
  37. package/dist/init/core/rule-4-repo-safety-and-ignores.md +97 -0
  38. package/dist/init/core/rule-5-release-and-versioning.md +82 -0
  39. package/dist/init/core/rule-6-templates-and-schemas.md +186 -0
  40. package/dist/init/templates/default/bug.md +54 -0
  41. package/dist/init/templates/default/chk.md +55 -0
  42. package/dist/init/templates/default/dec.md +38 -0
  43. package/dist/init/templates/default/edd.md +50 -0
  44. package/dist/init/templates/default/epic.md +46 -0
  45. package/dist/init/templates/default/feat.md +35 -0
  46. package/dist/init/templates/default/prd.md +59 -0
  47. package/dist/init/templates/default/prop.md +45 -0
  48. package/dist/init/templates/default/rule.md +33 -0
  49. package/dist/init/templates/default/task.md +53 -0
  50. package/dist/init/templates/default/test.md +49 -0
  51. package/dist/pack/export_json.js +38 -0
  52. package/dist/pack/export_md.js +93 -0
  53. package/dist/pack/export_toon.js +7 -0
  54. package/dist/pack/export_xml.js +73 -0
  55. package/dist/pack/order.js +162 -0
  56. package/dist/pack/pack.js +181 -0
  57. package/dist/pack/types.js +2 -0
  58. package/dist/pack/verbose_core.js +23 -0
  59. package/dist/templates/loader.js +82 -0
  60. package/dist/util/argparse.js +154 -0
  61. package/dist/util/date.js +9 -0
  62. package/dist/util/errors.js +12 -0
  63. package/dist/util/filter.js +26 -0
  64. package/dist/util/output.js +50 -0
  65. package/dist/util/qid.js +54 -0
  66. package/dist/util/sort.js +40 -0
  67. package/package.json +18 -2
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportJson = exportJson;
4
+ function buildFrontmatter(node) {
5
+ const frontmatter = {};
6
+ if (node.links.length > 0) {
7
+ frontmatter.links = node.links;
8
+ }
9
+ if (node.artifacts.length > 0) {
10
+ frontmatter.artifacts = node.artifacts;
11
+ }
12
+ if (node.refs.length > 0) {
13
+ frontmatter.refs = node.refs;
14
+ }
15
+ if (node.aliases.length > 0) {
16
+ frontmatter.aliases = node.aliases;
17
+ }
18
+ return frontmatter;
19
+ }
20
+ function exportJson(pack) {
21
+ const nodes = pack.nodes.map((node) => ({
22
+ qid: node.qid,
23
+ id: node.id,
24
+ workspace: node.workspace,
25
+ type: node.type,
26
+ title: node.title,
27
+ status: node.status,
28
+ priority: node.priority,
29
+ path: node.path,
30
+ frontmatter: buildFrontmatter(node),
31
+ body: node.body,
32
+ }));
33
+ const payload = {
34
+ meta: pack.meta,
35
+ nodes,
36
+ };
37
+ return JSON.stringify(payload, null, 2);
38
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportMarkdown = exportMarkdown;
4
+ function formatList(label, values) {
5
+ if (values.length === 0) {
6
+ return `${label}: []`;
7
+ }
8
+ return `${label}: ${values.join(", ")}`;
9
+ }
10
+ function renderHeader(meta, nodes) {
11
+ const lines = [];
12
+ lines.push("# mdkg pack");
13
+ lines.push(`root: ${meta.root}`);
14
+ lines.push(`depth: ${meta.depth}`);
15
+ lines.push(`verbose: ${meta.verbose}`);
16
+ lines.push(`nodes: ${nodes.length}`);
17
+ lines.push(`truncated: max_nodes=${meta.truncated.max_nodes} max_bytes=${meta.truncated.max_bytes}`);
18
+ if (meta.truncated.dropped.length > 0) {
19
+ lines.push(`dropped: ${meta.truncated.dropped.join(", ")}`);
20
+ }
21
+ lines.push(`generated_at: ${meta.generated_at}`);
22
+ lines.push("");
23
+ lines.push("included_nodes:");
24
+ for (const node of nodes) {
25
+ lines.push(`- ${node.qid}`);
26
+ }
27
+ return lines;
28
+ }
29
+ function renderNode(node) {
30
+ const lines = [];
31
+ lines.push(`## ${node.qid}`);
32
+ lines.push(`qid: ${node.qid}`);
33
+ lines.push(`type: ${node.type}`);
34
+ lines.push(`title: ${node.title}`);
35
+ if (node.status) {
36
+ lines.push(`status: ${node.status}`);
37
+ }
38
+ if (node.priority !== undefined) {
39
+ lines.push(`priority: ${node.priority}`);
40
+ }
41
+ lines.push(`path: ${node.path}`);
42
+ lines.push(formatList("links", node.links));
43
+ lines.push(formatList("artifacts", node.artifacts));
44
+ if (node.refs.length > 0) {
45
+ lines.push(formatList("refs", node.refs));
46
+ }
47
+ if (node.body.trim().length > 0) {
48
+ lines.push("");
49
+ lines.push(node.body);
50
+ }
51
+ return lines;
52
+ }
53
+ function cloneTruncation(truncation) {
54
+ return {
55
+ max_nodes: truncation.max_nodes,
56
+ max_bytes: truncation.max_bytes,
57
+ dropped: [...truncation.dropped],
58
+ };
59
+ }
60
+ function buildMeta(meta, nodes) {
61
+ return {
62
+ ...meta,
63
+ node_count: nodes.length,
64
+ truncated: cloneTruncation(meta.truncated),
65
+ };
66
+ }
67
+ function renderMarkdown(meta, nodes) {
68
+ const lines = [];
69
+ lines.push(...renderHeader(meta, nodes));
70
+ for (const node of nodes) {
71
+ lines.push("");
72
+ lines.push("---");
73
+ lines.push("");
74
+ lines.push(...renderNode(node));
75
+ }
76
+ return lines.join("\n");
77
+ }
78
+ function exportMarkdown(pack, maxBytes) {
79
+ let nodes = pack.nodes;
80
+ let meta = buildMeta(pack.meta, nodes);
81
+ let content = renderMarkdown(meta, nodes);
82
+ if (maxBytes !== undefined && maxBytes > 0 && Buffer.byteLength(content) > maxBytes) {
83
+ meta.truncated.max_bytes = true;
84
+ while (nodes.length > 1 && Buffer.byteLength(content) > maxBytes) {
85
+ const dropped = nodes[nodes.length - 1];
86
+ nodes = nodes.slice(0, -1);
87
+ meta.truncated.dropped.push(dropped.qid);
88
+ meta = buildMeta(meta, nodes);
89
+ content = renderMarkdown(meta, nodes);
90
+ }
91
+ }
92
+ return { content, meta, nodes };
93
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportToon = exportToon;
4
+ const export_json_1 = require("./export_json");
5
+ function exportToon(pack) {
6
+ return (0, export_json_1.exportJson)(pack);
7
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportXml = exportXml;
4
+ function escapeXml(value) {
5
+ return value
6
+ .replace(/&/g, "&")
7
+ .replace(/</g, "&lt;")
8
+ .replace(/>/g, "&gt;")
9
+ .replace(/"/g, "&quot;")
10
+ .replace(/'/g, "&apos;");
11
+ }
12
+ function listItems(tag, itemTag, items, indent) {
13
+ if (items.length === 0) {
14
+ return [];
15
+ }
16
+ const lines = [];
17
+ lines.push(`${indent}<${tag}>`);
18
+ for (const item of items) {
19
+ lines.push(`${indent} <${itemTag}>${escapeXml(item)}</${itemTag}>`);
20
+ }
21
+ lines.push(`${indent}</${tag}>`);
22
+ return lines;
23
+ }
24
+ function exportXml(pack) {
25
+ const lines = [];
26
+ lines.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
27
+ lines.push("<pack>");
28
+ lines.push(" <meta>");
29
+ lines.push(` <root>${escapeXml(pack.meta.root)}</root>`);
30
+ lines.push(` <depth>${pack.meta.depth}</depth>`);
31
+ lines.push(` <verbose>${pack.meta.verbose}</verbose>`);
32
+ lines.push(` <generated_at>${escapeXml(pack.meta.generated_at)}</generated_at>`);
33
+ lines.push(` <node_count>${pack.meta.node_count}</node_count>`);
34
+ lines.push(" <truncated>");
35
+ lines.push(` <max_nodes>${pack.meta.truncated.max_nodes}</max_nodes>`);
36
+ lines.push(` <max_bytes>${pack.meta.truncated.max_bytes}</max_bytes>`);
37
+ if (pack.meta.truncated.dropped.length > 0) {
38
+ lines.push(" <dropped>");
39
+ for (const qid of pack.meta.truncated.dropped) {
40
+ lines.push(` <qid>${escapeXml(qid)}</qid>`);
41
+ }
42
+ lines.push(" </dropped>");
43
+ }
44
+ lines.push(" </truncated>");
45
+ lines.push(" </meta>");
46
+ lines.push(" <nodes>");
47
+ for (const node of pack.nodes) {
48
+ lines.push(" <node>");
49
+ lines.push(` <qid>${escapeXml(node.qid)}</qid>`);
50
+ lines.push(` <id>${escapeXml(node.id)}</id>`);
51
+ lines.push(` <workspace>${escapeXml(node.workspace)}</workspace>`);
52
+ lines.push(` <type>${escapeXml(node.type)}</type>`);
53
+ lines.push(` <title>${escapeXml(node.title)}</title>`);
54
+ if (node.status) {
55
+ lines.push(` <status>${escapeXml(node.status)}</status>`);
56
+ }
57
+ if (node.priority !== undefined) {
58
+ lines.push(` <priority>${node.priority}</priority>`);
59
+ }
60
+ lines.push(` <path>${escapeXml(node.path)}</path>`);
61
+ lines.push(" <frontmatter>");
62
+ lines.push(...listItems("links", "link", node.links, " "));
63
+ lines.push(...listItems("artifacts", "artifact", node.artifacts, " "));
64
+ lines.push(...listItems("refs", "ref", node.refs, " "));
65
+ lines.push(...listItems("aliases", "alias", node.aliases, " "));
66
+ lines.push(" </frontmatter>");
67
+ lines.push(` <body>${escapeXml(node.body)}</body>`);
68
+ lines.push(" </node>");
69
+ }
70
+ lines.push(" </nodes>");
71
+ lines.push("</pack>");
72
+ return lines.join("\n");
73
+ }
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.orderPackNodes = orderPackNodes;
4
+ const ARCH_TYPES = ["edd", "dec", "rule"];
5
+ const FALLBACK_TYPES = [
6
+ "edd",
7
+ "dec",
8
+ "rule",
9
+ "prd",
10
+ "prop",
11
+ "epic",
12
+ "feat",
13
+ "task",
14
+ "bug",
15
+ "checkpoint",
16
+ ];
17
+ const WORK_TYPES = ["epic", "feat", "task", "bug", "checkpoint"];
18
+ function idNumber(id) {
19
+ const match = id.match(/-(\d+)$/);
20
+ if (!match) {
21
+ return Number.POSITIVE_INFINITY;
22
+ }
23
+ const parsed = Number.parseInt(match[1], 10);
24
+ return Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed;
25
+ }
26
+ function typePriority(type, order) {
27
+ const idx = order.indexOf(type);
28
+ if (idx === -1) {
29
+ return order.length + 1;
30
+ }
31
+ return idx;
32
+ }
33
+ function rootRelationPriority(rootEdges, qid) {
34
+ if (rootEdges.blocked_by.includes(qid)) {
35
+ return 0;
36
+ }
37
+ if (rootEdges.blocks.includes(qid)) {
38
+ return 1;
39
+ }
40
+ if (rootEdges.prev === qid) {
41
+ return 2;
42
+ }
43
+ if (rootEdges.next === qid) {
44
+ return 3;
45
+ }
46
+ if (rootEdges.relates.includes(qid)) {
47
+ return 4;
48
+ }
49
+ return 5;
50
+ }
51
+ function immediateContextPriority(rootEdges, qid, nodeType) {
52
+ if (rootEdges.parent === qid) {
53
+ return 0;
54
+ }
55
+ if (rootEdges.epic === qid) {
56
+ return 1;
57
+ }
58
+ if (rootEdges.relates.includes(qid) && nodeType === "checkpoint") {
59
+ return 2;
60
+ }
61
+ if (rootEdges.blocked_by.includes(qid) || rootEdges.blocks.includes(qid)) {
62
+ return 3;
63
+ }
64
+ return undefined;
65
+ }
66
+ function buildOrderKey(index, rootQid, qid, depths) {
67
+ const node = index.nodes[qid];
68
+ const root = index.nodes[rootQid];
69
+ const depth = depths.get(qid);
70
+ const rootIsTask = root.type === "task" || root.type === "bug";
71
+ if (qid === rootQid) {
72
+ return {
73
+ group: 0,
74
+ subgroup: 0,
75
+ type_priority: 0,
76
+ id_number: idNumber(node.id),
77
+ title: node.title.toLowerCase(),
78
+ qid,
79
+ };
80
+ }
81
+ if (rootIsTask) {
82
+ const immediatePriority = depth === 1 ? immediateContextPriority(root.edges, qid, node.type) : undefined;
83
+ if (immediatePriority !== undefined) {
84
+ return {
85
+ group: 1,
86
+ subgroup: immediatePriority,
87
+ type_priority: 0,
88
+ id_number: idNumber(node.id),
89
+ title: node.title.toLowerCase(),
90
+ qid,
91
+ };
92
+ }
93
+ if (ARCH_TYPES.includes(node.type)) {
94
+ return {
95
+ group: 2,
96
+ subgroup: 0,
97
+ type_priority: typePriority(node.type, ARCH_TYPES),
98
+ id_number: idNumber(node.id),
99
+ title: node.title.toLowerCase(),
100
+ qid,
101
+ };
102
+ }
103
+ if (node.type === "prd") {
104
+ return {
105
+ group: 3,
106
+ subgroup: 0,
107
+ type_priority: 0,
108
+ id_number: idNumber(node.id),
109
+ title: node.title.toLowerCase(),
110
+ qid,
111
+ };
112
+ }
113
+ if (node.type === "prop") {
114
+ return {
115
+ group: 4,
116
+ subgroup: 0,
117
+ type_priority: 0,
118
+ id_number: idNumber(node.id),
119
+ title: node.title.toLowerCase(),
120
+ qid,
121
+ };
122
+ }
123
+ return {
124
+ group: 5,
125
+ subgroup: rootRelationPriority(root.edges, qid),
126
+ type_priority: typePriority(node.type, WORK_TYPES),
127
+ id_number: idNumber(node.id),
128
+ title: node.title.toLowerCase(),
129
+ qid,
130
+ };
131
+ }
132
+ return {
133
+ group: 1,
134
+ subgroup: typePriority(node.type, FALLBACK_TYPES),
135
+ type_priority: 0,
136
+ id_number: idNumber(node.id),
137
+ title: node.title.toLowerCase(),
138
+ qid,
139
+ };
140
+ }
141
+ function orderPackNodes(index, rootQid, qids, depths) {
142
+ return [...qids].sort((a, b) => {
143
+ const keyA = buildOrderKey(index, rootQid, a, depths);
144
+ const keyB = buildOrderKey(index, rootQid, b, depths);
145
+ if (keyA.group !== keyB.group) {
146
+ return keyA.group - keyB.group;
147
+ }
148
+ if (keyA.subgroup !== keyB.subgroup) {
149
+ return keyA.subgroup - keyB.subgroup;
150
+ }
151
+ if (keyA.type_priority !== keyB.type_priority) {
152
+ return keyA.type_priority - keyB.type_priority;
153
+ }
154
+ if (keyA.id_number !== keyB.id_number) {
155
+ return keyA.id_number - keyB.id_number;
156
+ }
157
+ if (keyA.title !== keyB.title) {
158
+ return keyA.title.localeCompare(keyB.title);
159
+ }
160
+ return keyA.qid.localeCompare(keyB.qid);
161
+ });
162
+ }
@@ -0,0 +1,181 @@
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.buildPack = buildPack;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const frontmatter_1 = require("../graph/frontmatter");
10
+ const qid_1 = require("../util/qid");
11
+ const order_1 = require("./order");
12
+ const verbose_core_1 = require("./verbose_core");
13
+ const EDGE_KEYS = ["parent", "epic", "relates", "blocked_by", "blocks", "prev", "next"];
14
+ function normalizeEdgeList(edges) {
15
+ const seen = new Set();
16
+ const result = [];
17
+ for (const edge of edges) {
18
+ const normalized = edge.trim().toLowerCase().replace(/-/g, "_");
19
+ if (!EDGE_KEYS.includes(normalized)) {
20
+ continue;
21
+ }
22
+ if (!seen.has(normalized)) {
23
+ seen.add(normalized);
24
+ result.push(normalized);
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ function getNeighbors(index, qid, edges) {
30
+ const node = index.nodes[qid];
31
+ if (!node) {
32
+ return [];
33
+ }
34
+ const neighbors = [];
35
+ for (const edge of edges) {
36
+ switch (edge) {
37
+ case "parent":
38
+ if (node.edges.parent) {
39
+ neighbors.push(node.edges.parent);
40
+ }
41
+ break;
42
+ case "epic":
43
+ if (node.edges.epic) {
44
+ neighbors.push(node.edges.epic);
45
+ }
46
+ break;
47
+ case "prev":
48
+ if (node.edges.prev) {
49
+ neighbors.push(node.edges.prev);
50
+ }
51
+ break;
52
+ case "next":
53
+ if (node.edges.next) {
54
+ neighbors.push(node.edges.next);
55
+ }
56
+ break;
57
+ case "relates":
58
+ neighbors.push(...node.edges.relates);
59
+ break;
60
+ case "blocked_by":
61
+ neighbors.push(...node.edges.blocked_by);
62
+ break;
63
+ case "blocks":
64
+ neighbors.push(...node.edges.blocks);
65
+ break;
66
+ default:
67
+ break;
68
+ }
69
+ }
70
+ return neighbors;
71
+ }
72
+ function collectNodes(index, rootQid, depth, edges) {
73
+ const selectedEdges = normalizeEdgeList(edges);
74
+ const visited = new Set();
75
+ const depths = new Map();
76
+ const queue = [];
77
+ queue.push({ qid: rootQid, depth: 0 });
78
+ visited.add(rootQid);
79
+ depths.set(rootQid, 0);
80
+ while (queue.length > 0) {
81
+ const current = queue.shift();
82
+ if (!current) {
83
+ break;
84
+ }
85
+ if (current.depth >= depth) {
86
+ continue;
87
+ }
88
+ const neighbors = getNeighbors(index, current.qid, selectedEdges);
89
+ for (const neighbor of neighbors) {
90
+ if (!index.nodes[neighbor]) {
91
+ continue;
92
+ }
93
+ if (visited.has(neighbor)) {
94
+ continue;
95
+ }
96
+ visited.add(neighbor);
97
+ depths.set(neighbor, current.depth + 1);
98
+ queue.push({ qid: neighbor, depth: current.depth + 1 });
99
+ }
100
+ }
101
+ return { qids: visited, depths };
102
+ }
103
+ function buildPackNode(root, index, qid) {
104
+ const node = index.nodes[qid];
105
+ if (!node) {
106
+ throw new Error(`node not found: ${qid}`);
107
+ }
108
+ const filePath = path_1.default.resolve(root, node.path);
109
+ if (!fs_1.default.existsSync(filePath)) {
110
+ throw new Error(`file not found for ${qid}: ${node.path}`);
111
+ }
112
+ const content = fs_1.default.readFileSync(filePath, "utf8");
113
+ const body = (0, frontmatter_1.parseFrontmatter)(content, filePath).body.trimEnd();
114
+ return {
115
+ qid: node.qid,
116
+ id: node.id,
117
+ workspace: node.ws,
118
+ type: node.type,
119
+ title: node.title,
120
+ status: node.status,
121
+ priority: node.priority,
122
+ path: node.path,
123
+ links: node.links,
124
+ artifacts: node.artifacts,
125
+ refs: node.refs,
126
+ aliases: node.aliases,
127
+ body,
128
+ };
129
+ }
130
+ function mergeWarnings(warnings, message) {
131
+ warnings.push(message);
132
+ }
133
+ function applyMaxNodes(orderedQids, maxNodes, truncation) {
134
+ if (maxNodes <= 0 || orderedQids.length <= maxNodes) {
135
+ return { included: orderedQids, dropped: [] };
136
+ }
137
+ const included = orderedQids.slice(0, maxNodes);
138
+ const dropped = orderedQids.slice(maxNodes);
139
+ truncation.max_nodes = true;
140
+ truncation.dropped.push(...dropped);
141
+ return { included, dropped };
142
+ }
143
+ function buildPack(options) {
144
+ const warnings = [];
145
+ const { qids, depths } = collectNodes(options.index, options.rootQid, options.depth, options.edges);
146
+ if (options.verbose) {
147
+ const coreIds = (0, verbose_core_1.readVerboseCoreList)(options.verboseCoreListPath);
148
+ for (const id of coreIds) {
149
+ const resolved = (0, qid_1.resolveQid)(options.index, id, options.wsHint);
150
+ if (resolved.status === "ok") {
151
+ qids.add(resolved.qid);
152
+ }
153
+ else if (resolved.status === "ambiguous") {
154
+ mergeWarnings(warnings, `verbose core id ambiguous: ${id}`);
155
+ }
156
+ else {
157
+ mergeWarnings(warnings, `verbose core id missing: ${id}`);
158
+ }
159
+ }
160
+ }
161
+ const ordered = (0, order_1.orderPackNodes)(options.index, options.rootQid, Array.from(qids), depths);
162
+ const truncation = {
163
+ max_nodes: false,
164
+ max_bytes: false,
165
+ dropped: [],
166
+ };
167
+ const { included } = applyMaxNodes(ordered, options.maxNodes, truncation);
168
+ const nodes = included.map((qid) => buildPackNode(options.root, options.index, qid));
169
+ const pack = {
170
+ meta: {
171
+ root: options.rootQid,
172
+ depth: options.depth,
173
+ verbose: options.verbose,
174
+ generated_at: new Date().toISOString(),
175
+ node_count: nodes.length,
176
+ truncated: truncation,
177
+ },
178
+ nodes,
179
+ };
180
+ return { pack, warnings };
181
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
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.readVerboseCoreList = readVerboseCoreList;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ function readVerboseCoreList(listPath) {
9
+ if (!fs_1.default.existsSync(listPath)) {
10
+ throw new Error(`verbose core list not found: ${listPath}`);
11
+ }
12
+ const raw = fs_1.default.readFileSync(listPath, "utf8");
13
+ const lines = raw.split(/\r?\n/);
14
+ const ids = [];
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed || trimmed.startsWith("#")) {
18
+ continue;
19
+ }
20
+ ids.push(trimmed.toLowerCase());
21
+ }
22
+ return ids;
23
+ }
@@ -0,0 +1,82 @@
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.loadTemplate = loadTemplate;
7
+ exports.renderTemplate = renderTemplate;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const frontmatter_1 = require("../graph/frontmatter");
11
+ const errors_1 = require("../util/errors");
12
+ function templateNameForType(type) {
13
+ const normalized = type.toLowerCase();
14
+ if (normalized === "checkpoint") {
15
+ return "chk";
16
+ }
17
+ return normalized;
18
+ }
19
+ function loadTemplate(root, config, type, templateSet) {
20
+ const setName = (templateSet ?? config.templates.default_set).toLowerCase();
21
+ const templateName = templateNameForType(type);
22
+ const templatePath = path_1.default.resolve(root, config.templates.root_path, setName, `${templateName}.md`);
23
+ if (!fs_1.default.existsSync(templatePath)) {
24
+ throw new errors_1.NotFoundError(`template not found: ${setName}/${templateName}.md`);
25
+ }
26
+ const content = fs_1.default.readFileSync(templatePath, "utf8");
27
+ const { frontmatter, body } = (0, frontmatter_1.parseFrontmatter)(content, templatePath);
28
+ return { templatePath, frontmatter, body };
29
+ }
30
+ function isTokenPlaceholder(value) {
31
+ return typeof value === "string" && /^\{\{[a-z0-9_]+\}\}$/.test(value);
32
+ }
33
+ function tokenKey(value) {
34
+ return value.slice(2, -2);
35
+ }
36
+ function renderTokenValue(value) {
37
+ if (value === undefined) {
38
+ return undefined;
39
+ }
40
+ if (Array.isArray(value)) {
41
+ return value;
42
+ }
43
+ if (typeof value === "boolean") {
44
+ return value;
45
+ }
46
+ if (typeof value === "number") {
47
+ return String(value);
48
+ }
49
+ return value;
50
+ }
51
+ function renderTemplate(template, context) {
52
+ const allowedKeys = new Set(Object.keys(template.frontmatter));
53
+ const rendered = {};
54
+ for (const [key, value] of Object.entries(template.frontmatter)) {
55
+ if (isTokenPlaceholder(value)) {
56
+ const replacement = renderTokenValue(context[tokenKey(value)]);
57
+ if (replacement !== undefined) {
58
+ rendered[key] = replacement;
59
+ }
60
+ continue;
61
+ }
62
+ rendered[key] = value;
63
+ }
64
+ for (const [key, value] of Object.entries(context)) {
65
+ if (!allowedKeys.has(key)) {
66
+ continue;
67
+ }
68
+ const replacement = renderTokenValue(value);
69
+ if (replacement !== undefined) {
70
+ rendered[key] = replacement;
71
+ }
72
+ }
73
+ const lines = [];
74
+ lines.push("---");
75
+ lines.push(...(0, frontmatter_1.formatFrontmatter)(rendered));
76
+ lines.push("---");
77
+ lines.push(template.body.trimStart());
78
+ if (!lines[lines.length - 1]?.endsWith("\n")) {
79
+ lines.push("");
80
+ }
81
+ return lines.join("\n");
82
+ }