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.
- package/README.md +20 -6
- package/dist/cli.js +667 -11
- package/dist/commands/checkpoint.js +133 -0
- package/dist/commands/format.js +297 -0
- package/dist/commands/guide.js +22 -0
- package/dist/commands/index.js +17 -0
- package/dist/commands/init.js +111 -0
- package/dist/commands/list.js +52 -0
- package/dist/commands/new.js +279 -0
- package/dist/commands/next.js +75 -0
- package/dist/commands/node_card.js +17 -0
- package/dist/commands/pack.js +105 -0
- package/dist/commands/search.js +70 -0
- package/dist/commands/show.js +95 -0
- package/dist/commands/validate.js +229 -0
- package/dist/commands/workspace.js +101 -0
- package/dist/core/config.js +162 -0
- package/dist/core/migrate.js +30 -0
- package/dist/core/paths.js +14 -0
- package/dist/graph/edges.js +64 -0
- package/dist/graph/frontmatter.js +132 -0
- package/dist/graph/index_cache.js +50 -0
- package/dist/graph/indexer.js +144 -0
- package/dist/graph/node.js +225 -0
- package/dist/graph/staleness.js +31 -0
- package/dist/graph/template_schema.js +86 -0
- package/dist/graph/validate_graph.js +115 -0
- package/dist/graph/workspace_files.js +64 -0
- package/dist/init/AGENTS.md +43 -0
- package/dist/init/CLAUDE.md +37 -0
- package/dist/init/config.json +67 -0
- package/dist/init/core/core.md +12 -0
- package/dist/init/core/guide.md +99 -0
- package/dist/init/core/rule-1-mdkg-conventions.md +232 -0
- package/dist/init/core/rule-2-context-pack-rules.md +186 -0
- package/dist/init/core/rule-3-cli-contract.md +177 -0
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +97 -0
- package/dist/init/core/rule-5-release-and-versioning.md +82 -0
- package/dist/init/core/rule-6-templates-and-schemas.md +186 -0
- package/dist/init/templates/default/bug.md +54 -0
- package/dist/init/templates/default/chk.md +55 -0
- package/dist/init/templates/default/dec.md +38 -0
- package/dist/init/templates/default/edd.md +50 -0
- package/dist/init/templates/default/epic.md +46 -0
- package/dist/init/templates/default/feat.md +35 -0
- package/dist/init/templates/default/prd.md +59 -0
- package/dist/init/templates/default/prop.md +45 -0
- package/dist/init/templates/default/rule.md +33 -0
- package/dist/init/templates/default/task.md +53 -0
- package/dist/init/templates/default/test.md +49 -0
- package/dist/pack/export_json.js +38 -0
- package/dist/pack/export_md.js +93 -0
- package/dist/pack/export_toon.js +7 -0
- package/dist/pack/export_xml.js +73 -0
- package/dist/pack/order.js +162 -0
- package/dist/pack/pack.js +181 -0
- package/dist/pack/types.js +2 -0
- package/dist/pack/verbose_core.js +23 -0
- package/dist/templates/loader.js +82 -0
- package/dist/util/argparse.js +154 -0
- package/dist/util/date.js +9 -0
- package/dist/util/errors.js +12 -0
- package/dist/util/filter.js +26 -0
- package/dist/util/output.js +50 -0
- package/dist/util/qid.js +54 -0
- package/dist/util/sort.js +40 -0
- package/package.json +18 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArgs = parseArgs;
|
|
4
|
+
const NORMALIZE_VALUE_FLAGS = new Set(["--ws", "--type", "--status", "--template", "--epic"]);
|
|
5
|
+
const VALUE_FLAGS = new Set([
|
|
6
|
+
"--root",
|
|
7
|
+
"--ws",
|
|
8
|
+
"--type",
|
|
9
|
+
"--status",
|
|
10
|
+
"--template",
|
|
11
|
+
"--epic",
|
|
12
|
+
"--priority",
|
|
13
|
+
"--depth",
|
|
14
|
+
"--edges",
|
|
15
|
+
"--format",
|
|
16
|
+
"--out",
|
|
17
|
+
"--relates",
|
|
18
|
+
"--scope",
|
|
19
|
+
"--blocked-by",
|
|
20
|
+
"--blocks",
|
|
21
|
+
"--prev",
|
|
22
|
+
"--next",
|
|
23
|
+
"--links",
|
|
24
|
+
"--artifacts",
|
|
25
|
+
"--refs",
|
|
26
|
+
"--aliases",
|
|
27
|
+
"--tags",
|
|
28
|
+
"--owners",
|
|
29
|
+
"--supersedes",
|
|
30
|
+
"--cases",
|
|
31
|
+
"--mdkg-dir",
|
|
32
|
+
]);
|
|
33
|
+
const BOOLEAN_FLAGS = new Set([
|
|
34
|
+
"--tolerant",
|
|
35
|
+
"--blocked",
|
|
36
|
+
"--body",
|
|
37
|
+
"--verbose",
|
|
38
|
+
"--quiet",
|
|
39
|
+
"--no-cache",
|
|
40
|
+
"--no-reindex",
|
|
41
|
+
"--force",
|
|
42
|
+
"--update-gitignore",
|
|
43
|
+
"--update-npmignore",
|
|
44
|
+
"--update-dockerignore",
|
|
45
|
+
"--agents",
|
|
46
|
+
"--claude",
|
|
47
|
+
"--llm",
|
|
48
|
+
]);
|
|
49
|
+
const FLAG_ALIASES = {
|
|
50
|
+
"--o": "--out",
|
|
51
|
+
"-o": "--out",
|
|
52
|
+
"--f": "--format",
|
|
53
|
+
"-f": "--format",
|
|
54
|
+
"--v": "--verbose",
|
|
55
|
+
"-v": "--verbose",
|
|
56
|
+
"--d": "--depth",
|
|
57
|
+
"-d": "--depth",
|
|
58
|
+
"--e": "--edges",
|
|
59
|
+
"-e": "--edges",
|
|
60
|
+
"--w": "--ws",
|
|
61
|
+
"-w": "--ws",
|
|
62
|
+
"--r": "--root",
|
|
63
|
+
"-r": "--root",
|
|
64
|
+
"--q": "--quiet",
|
|
65
|
+
"-q": "--quiet",
|
|
66
|
+
};
|
|
67
|
+
function normalizeFlag(flag) {
|
|
68
|
+
return FLAG_ALIASES[flag] ?? flag;
|
|
69
|
+
}
|
|
70
|
+
function normalizeFlagToken(token) {
|
|
71
|
+
if (!token.startsWith("-")) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
let normalized = token;
|
|
75
|
+
if (!normalized.startsWith("--") && normalized.length === 2) {
|
|
76
|
+
normalized = `--${normalized.slice(1)}`;
|
|
77
|
+
}
|
|
78
|
+
const eqIndex = normalized.indexOf("=");
|
|
79
|
+
const flag = eqIndex === -1 ? normalized : normalized.slice(0, eqIndex);
|
|
80
|
+
return normalizeFlag(flag);
|
|
81
|
+
}
|
|
82
|
+
function isFlagToken(token) {
|
|
83
|
+
const flag = normalizeFlagToken(token);
|
|
84
|
+
if (!flag) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return VALUE_FLAGS.has(flag) || BOOLEAN_FLAGS.has(flag) || flag === "--help";
|
|
88
|
+
}
|
|
89
|
+
function parseArgs(argv) {
|
|
90
|
+
const result = {
|
|
91
|
+
help: false,
|
|
92
|
+
positionals: [],
|
|
93
|
+
flags: {},
|
|
94
|
+
};
|
|
95
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
96
|
+
const arg = argv[i];
|
|
97
|
+
if (arg === "--help" || arg === "-h") {
|
|
98
|
+
result.help = true;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
let normalizedArg = arg;
|
|
102
|
+
if (normalizedArg.startsWith("-") && !normalizedArg.startsWith("--")) {
|
|
103
|
+
if (normalizedArg.length === 2) {
|
|
104
|
+
normalizedArg = `--${normalizedArg.slice(1)}`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (normalizedArg.startsWith("--")) {
|
|
108
|
+
const eqIndex = normalizedArg.indexOf("=");
|
|
109
|
+
const flagRaw = eqIndex === -1 ? normalizedArg : normalizedArg.slice(0, eqIndex);
|
|
110
|
+
const flag = normalizeFlag(flagRaw);
|
|
111
|
+
const inlineValue = eqIndex === -1 ? undefined : normalizedArg.slice(eqIndex + 1);
|
|
112
|
+
if (flag === "--root") {
|
|
113
|
+
const value = inlineValue ?? argv[i + 1];
|
|
114
|
+
if (!value || isFlagToken(value)) {
|
|
115
|
+
result.error = "--root requires a path";
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
if (inlineValue === undefined) {
|
|
119
|
+
i += 1;
|
|
120
|
+
}
|
|
121
|
+
result.root = value;
|
|
122
|
+
result.flags[flag] = value;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (BOOLEAN_FLAGS.has(flag)) {
|
|
126
|
+
result.flags[flag] = true;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const value = inlineValue ?? argv[i + 1];
|
|
130
|
+
if (VALUE_FLAGS.has(flag)) {
|
|
131
|
+
if (value === undefined || isFlagToken(value)) {
|
|
132
|
+
result.flags[flag] = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (inlineValue === undefined) {
|
|
136
|
+
i += 1;
|
|
137
|
+
}
|
|
138
|
+
result.flags[flag] = NORMALIZE_VALUE_FLAGS.has(flag) ? value.toLowerCase() : value;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (value === undefined || isFlagToken(value)) {
|
|
142
|
+
result.flags[flag] = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (inlineValue === undefined) {
|
|
146
|
+
i += 1;
|
|
147
|
+
}
|
|
148
|
+
result.flags[flag] = NORMALIZE_VALUE_FLAGS.has(flag) ? value.toLowerCase() : value;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
result.positionals.push(arg);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatDate = formatDate;
|
|
4
|
+
function formatDate(date) {
|
|
5
|
+
const year = date.getFullYear();
|
|
6
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
7
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
8
|
+
return `${year}-${month}-${day}`;
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotFoundError = exports.ValidationError = exports.UsageError = void 0;
|
|
4
|
+
class UsageError extends Error {
|
|
5
|
+
}
|
|
6
|
+
exports.UsageError = UsageError;
|
|
7
|
+
class ValidationError extends Error {
|
|
8
|
+
}
|
|
9
|
+
exports.ValidationError = ValidationError;
|
|
10
|
+
class NotFoundError extends Error {
|
|
11
|
+
}
|
|
12
|
+
exports.NotFoundError = NotFoundError;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterNodes = filterNodes;
|
|
4
|
+
function filterNodes(nodes, filters) {
|
|
5
|
+
return nodes.filter((node) => {
|
|
6
|
+
if (filters.ws && node.ws !== filters.ws) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (filters.type && node.type !== filters.type) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (filters.status && node.status !== filters.status) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (filters.epic && node.edges.epic !== filters.epic) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (filters.priority !== undefined && node.priority !== filters.priority) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (filters.blocked && node.status !== "blocked") {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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.PACK_WARN_BYTES = void 0;
|
|
7
|
+
exports.shouldWarnLargeOutput = shouldWarnLargeOutput;
|
|
8
|
+
exports.formatLargeOutputWarning = formatLargeOutputWarning;
|
|
9
|
+
exports.sanitizeFilename = sanitizeFilename;
|
|
10
|
+
exports.formatTimestampForFilename = formatTimestampForFilename;
|
|
11
|
+
exports.buildDefaultPackPath = buildDefaultPackPath;
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
exports.PACK_WARN_BYTES = 200000;
|
|
14
|
+
function shouldWarnLargeOutput(bytes, isTTY) {
|
|
15
|
+
return isTTY && bytes >= exports.PACK_WARN_BYTES;
|
|
16
|
+
}
|
|
17
|
+
function formatLargeOutputWarning(bytes) {
|
|
18
|
+
return `warning: pack output is large (${bytes} bytes); consider --out <path> to write to a file`;
|
|
19
|
+
}
|
|
20
|
+
function sanitizeFilename(value) {
|
|
21
|
+
return value.replace(/[^a-z0-9_-]/gi, "-");
|
|
22
|
+
}
|
|
23
|
+
function formatTimestampForFilename(date, useUtc = false) {
|
|
24
|
+
const pad = (value, size) => String(value).padStart(size, "0");
|
|
25
|
+
const year = useUtc ? date.getUTCFullYear() : date.getFullYear();
|
|
26
|
+
const month = useUtc ? date.getUTCMonth() + 1 : date.getMonth() + 1;
|
|
27
|
+
const day = useUtc ? date.getUTCDate() : date.getDate();
|
|
28
|
+
const hours = useUtc ? date.getUTCHours() : date.getHours();
|
|
29
|
+
const minutes = useUtc ? date.getUTCMinutes() : date.getMinutes();
|
|
30
|
+
const seconds = useUtc ? date.getUTCSeconds() : date.getSeconds();
|
|
31
|
+
const millis = useUtc ? date.getUTCMilliseconds() : date.getMilliseconds();
|
|
32
|
+
return [
|
|
33
|
+
year,
|
|
34
|
+
pad(month, 2),
|
|
35
|
+
pad(day, 2),
|
|
36
|
+
"-",
|
|
37
|
+
pad(hours, 2),
|
|
38
|
+
pad(minutes, 2),
|
|
39
|
+
pad(seconds, 2),
|
|
40
|
+
pad(millis, 3),
|
|
41
|
+
].join("");
|
|
42
|
+
}
|
|
43
|
+
function buildDefaultPackPath(root, rootId, format, verbose, now) {
|
|
44
|
+
const kind = verbose ? "verbose" : "standard";
|
|
45
|
+
const safeId = sanitizeFilename(rootId.toLowerCase());
|
|
46
|
+
const safeFormat = sanitizeFilename(format.toLowerCase());
|
|
47
|
+
const timestamp = formatTimestampForFilename(now);
|
|
48
|
+
const filename = `pack_${kind}_${safeId}_${timestamp}.${safeFormat}`;
|
|
49
|
+
return path_1.default.resolve(root, ".mdkg", "pack", filename);
|
|
50
|
+
}
|
package/dist/util/qid.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatResolveError = formatResolveError;
|
|
4
|
+
exports.resolveQid = resolveQid;
|
|
5
|
+
function formatResolveError(label, value, result, wsHint) {
|
|
6
|
+
switch (result.status) {
|
|
7
|
+
case "missing": {
|
|
8
|
+
if (wsHint) {
|
|
9
|
+
if (result.candidates.length > 0) {
|
|
10
|
+
return `${label} not found in workspace ${wsHint}: ${value} (did you mean ${result.candidates.join(", ")}?)`;
|
|
11
|
+
}
|
|
12
|
+
return `${label} not found in workspace ${wsHint}: ${value}`;
|
|
13
|
+
}
|
|
14
|
+
return `${label} not found: ${value}`;
|
|
15
|
+
}
|
|
16
|
+
case "ambiguous": {
|
|
17
|
+
const candidates = result.candidates.join(", ");
|
|
18
|
+
return `ambiguous ${label}: ${value} (use ${candidates})`;
|
|
19
|
+
}
|
|
20
|
+
case "ok": {
|
|
21
|
+
return `${label} resolved: ${result.qid}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function resolveQid(index, idOrQid, wsHint) {
|
|
26
|
+
const normalized = idOrQid.toLowerCase();
|
|
27
|
+
if (normalized.includes(":")) {
|
|
28
|
+
if (index.nodes[normalized]) {
|
|
29
|
+
return { status: "ok", qid: normalized };
|
|
30
|
+
}
|
|
31
|
+
return { status: "missing", candidates: [] };
|
|
32
|
+
}
|
|
33
|
+
const matches = Object.values(index.nodes)
|
|
34
|
+
.filter((node) => node.id === normalized)
|
|
35
|
+
.map((node) => node.qid)
|
|
36
|
+
.sort();
|
|
37
|
+
if (wsHint) {
|
|
38
|
+
const wsMatches = matches.filter((qid) => qid.startsWith(`${wsHint}:`));
|
|
39
|
+
if (wsMatches.length === 1) {
|
|
40
|
+
return { status: "ok", qid: wsMatches[0] };
|
|
41
|
+
}
|
|
42
|
+
if (wsMatches.length > 1) {
|
|
43
|
+
return { status: "ambiguous", candidates: wsMatches };
|
|
44
|
+
}
|
|
45
|
+
return { status: "missing", candidates: matches };
|
|
46
|
+
}
|
|
47
|
+
if (matches.length === 1) {
|
|
48
|
+
return { status: "ok", qid: matches[0] };
|
|
49
|
+
}
|
|
50
|
+
if (matches.length === 0) {
|
|
51
|
+
return { status: "missing", candidates: [] };
|
|
52
|
+
}
|
|
53
|
+
return { status: "ambiguous", candidates: matches };
|
|
54
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sortNodesByQid = sortNodesByQid;
|
|
4
|
+
exports.sortNodesForNext = sortNodesForNext;
|
|
5
|
+
exports.sortIndexNodes = sortIndexNodes;
|
|
6
|
+
function sortNodesByQid(nodes) {
|
|
7
|
+
return [...nodes].sort((a, b) => a.qid.localeCompare(b.qid));
|
|
8
|
+
}
|
|
9
|
+
function rankPriority(node, priorityMax) {
|
|
10
|
+
return node.priority === undefined ? priorityMax + 1 : node.priority;
|
|
11
|
+
}
|
|
12
|
+
function rankStatus(node, statusRanks) {
|
|
13
|
+
if (!node.status) {
|
|
14
|
+
return statusRanks.size;
|
|
15
|
+
}
|
|
16
|
+
return statusRanks.get(node.status) ?? statusRanks.size;
|
|
17
|
+
}
|
|
18
|
+
function sortNodesForNext(nodes, options) {
|
|
19
|
+
const statusRanks = new Map(options.statusPreference.map((status, index) => [status, index]));
|
|
20
|
+
return [...nodes].sort((a, b) => {
|
|
21
|
+
const priorityA = rankPriority(a, options.priorityMax);
|
|
22
|
+
const priorityB = rankPriority(b, options.priorityMax);
|
|
23
|
+
if (priorityA !== priorityB) {
|
|
24
|
+
return priorityA - priorityB;
|
|
25
|
+
}
|
|
26
|
+
const statusA = rankStatus(a, statusRanks);
|
|
27
|
+
const statusB = rankStatus(b, statusRanks);
|
|
28
|
+
if (statusA !== statusB) {
|
|
29
|
+
return statusA - statusB;
|
|
30
|
+
}
|
|
31
|
+
return a.qid.localeCompare(b.qid);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function sortIndexNodes(nodes) {
|
|
35
|
+
const sorted = {};
|
|
36
|
+
for (const qid of Object.keys(nodes).sort()) {
|
|
37
|
+
sorted[qid] = nodes[qid];
|
|
38
|
+
}
|
|
39
|
+
return sorted;
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdkg",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Markdown Knowledge Graph",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mdkg": "dist/cli.js"
|
|
8
8
|
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.build.json && node scripts/add-shebang.js && node scripts/copy-init-assets.js",
|
|
11
|
+
"build:test": "tsc -p tsconfig.test.json",
|
|
12
|
+
"test": "npm run build && npm run build:test && node --test dist/tests/**/*.test.js"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^18.19.0",
|
|
16
|
+
"typescript": "^5.4.0"
|
|
17
|
+
},
|
|
9
18
|
"files": [
|
|
10
|
-
"dist/",
|
|
19
|
+
"dist/cli.js",
|
|
20
|
+
"dist/commands/",
|
|
21
|
+
"dist/core/",
|
|
22
|
+
"dist/graph/",
|
|
23
|
+
"dist/init/",
|
|
24
|
+
"dist/pack/",
|
|
25
|
+
"dist/templates/",
|
|
26
|
+
"dist/util/",
|
|
11
27
|
"README.md",
|
|
12
28
|
"LICENSE"
|
|
13
29
|
],
|