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
|
@@ -11,8 +11,8 @@ const index_cache_1 = require("../graph/index_cache");
|
|
|
11
11
|
const loader_1 = require("../templates/loader");
|
|
12
12
|
const date_1 = require("../util/date");
|
|
13
13
|
const errors_1 = require("../util/errors");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
const id_1 = require("../util/id");
|
|
15
|
+
const event_support_1 = require("./event_support");
|
|
16
16
|
function parseCsvList(raw) {
|
|
17
17
|
if (!raw) {
|
|
18
18
|
return [];
|
|
@@ -24,14 +24,14 @@ function parseCsvList(raw) {
|
|
|
24
24
|
}
|
|
25
25
|
function normalizeId(value, key) {
|
|
26
26
|
const normalized = value.toLowerCase();
|
|
27
|
-
if (!
|
|
28
|
-
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number
|
|
27
|
+
if (!(0, id_1.isCanonicalId)(normalized)) {
|
|
28
|
+
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number> or reserved id: ${value}`);
|
|
29
29
|
}
|
|
30
30
|
return normalized;
|
|
31
31
|
}
|
|
32
32
|
function normalizeIdRef(value, key) {
|
|
33
33
|
const normalized = value.toLowerCase();
|
|
34
|
-
if (!
|
|
34
|
+
if (!(0, id_1.isCanonicalIdRef)(normalized)) {
|
|
35
35
|
throw new errors_1.UsageError(`${key} entries must match <id> or <ws>:<id>: ${value}`);
|
|
36
36
|
}
|
|
37
37
|
return normalized;
|
|
@@ -115,7 +115,8 @@ function runCheckpointNewCommand(options) {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
const scope = parseCsvList(options.scope).map((value) => normalizeId(value, "--scope"));
|
|
118
|
-
const
|
|
118
|
+
const now = options.now ?? new Date();
|
|
119
|
+
const today = (0, date_1.formatDate)(now);
|
|
119
120
|
const template = (0, loader_1.loadTemplate)(options.root, config, "checkpoint", options.template);
|
|
120
121
|
const content = (0, loader_1.renderTemplate)(template, {
|
|
121
122
|
id,
|
|
@@ -129,5 +130,15 @@ function runCheckpointNewCommand(options) {
|
|
|
129
130
|
});
|
|
130
131
|
fs_1.default.mkdirSync(workDir, { recursive: true });
|
|
131
132
|
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
133
|
+
(0, event_support_1.appendAutomaticEvent)({
|
|
134
|
+
root: options.root,
|
|
135
|
+
ws,
|
|
136
|
+
kind: "CHECKPOINT_CREATED",
|
|
137
|
+
status: "ok",
|
|
138
|
+
refs: [id],
|
|
139
|
+
notes: options.note ?? `checkpoint created via mdkg checkpoint new`,
|
|
140
|
+
runId: options.runId,
|
|
141
|
+
now,
|
|
142
|
+
});
|
|
132
143
|
console.log(`checkpoint created: ${ws}:${id} (${path_1.default.relative(options.root, filePath)})`);
|
|
133
144
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runEventEnableCommand = runEventEnableCommand;
|
|
4
|
+
exports.runEventAppendCommand = runEventAppendCommand;
|
|
5
|
+
const event_support_1 = require("./event_support");
|
|
6
|
+
const errors_1 = require("../util/errors");
|
|
7
|
+
function runEventEnableCommand(options) {
|
|
8
|
+
const result = (0, event_support_1.ensureEventsEnabled)(options);
|
|
9
|
+
const createdLabel = result.created ? "created" : "already present";
|
|
10
|
+
const ignoreLabel = result.gitignoreUpdated ? "updated .gitignore" : "left .gitignore unchanged";
|
|
11
|
+
console.log(`event logging enabled: ${result.ws} (${createdLabel}; ${ignoreLabel})`);
|
|
12
|
+
}
|
|
13
|
+
function normalizeEventStatus(value) {
|
|
14
|
+
const normalized = value.trim().toLowerCase();
|
|
15
|
+
if (normalized === "ok" ||
|
|
16
|
+
normalized === "error" ||
|
|
17
|
+
normalized === "retry" ||
|
|
18
|
+
normalized === "skipped") {
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
throw new errors_1.UsageError("--status must be one of ok, error, retry, skipped");
|
|
22
|
+
}
|
|
23
|
+
function runEventAppendCommand(options) {
|
|
24
|
+
const kind = options.kind.trim();
|
|
25
|
+
if (!kind) {
|
|
26
|
+
throw new errors_1.UsageError("--kind is required");
|
|
27
|
+
}
|
|
28
|
+
const refs = (0, event_support_1.normalizeEventRefList)(options.refs);
|
|
29
|
+
if (refs.length === 0) {
|
|
30
|
+
throw new errors_1.UsageError("--refs requires at least one id or qid");
|
|
31
|
+
}
|
|
32
|
+
const record = (0, event_support_1.appendEvent)({
|
|
33
|
+
root: options.root,
|
|
34
|
+
ws: options.ws,
|
|
35
|
+
kind,
|
|
36
|
+
status: normalizeEventStatus(options.status),
|
|
37
|
+
refs,
|
|
38
|
+
artifacts: (0, event_support_1.normalizeEventStringList)(options.artifacts),
|
|
39
|
+
notes: options.notes,
|
|
40
|
+
runId: options.runId,
|
|
41
|
+
agent: options.agent,
|
|
42
|
+
skill: options.skill,
|
|
43
|
+
tool: options.tool,
|
|
44
|
+
});
|
|
45
|
+
console.log(`event appended: ${record.workspace}:${record.kind} (${record.run_id})`);
|
|
46
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
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.normalizeWorkspaceForEvents = normalizeWorkspaceForEvents;
|
|
7
|
+
exports.resolveEventsPath = resolveEventsPath;
|
|
8
|
+
exports.createLocalRunId = createLocalRunId;
|
|
9
|
+
exports.isEventLoggingEnabled = isEventLoggingEnabled;
|
|
10
|
+
exports.ensureEventsEnabled = ensureEventsEnabled;
|
|
11
|
+
exports.normalizeEventRefList = normalizeEventRefList;
|
|
12
|
+
exports.normalizeEventStringList = normalizeEventStringList;
|
|
13
|
+
exports.appendEvent = appendEvent;
|
|
14
|
+
exports.appendAutomaticEvent = appendAutomaticEvent;
|
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const config_1 = require("../core/config");
|
|
18
|
+
const errors_1 = require("../util/errors");
|
|
19
|
+
function appendIgnoreEntries(filePath, entries) {
|
|
20
|
+
const normalizedEntries = entries.map((entry) => entry.trim()).filter(Boolean);
|
|
21
|
+
if (normalizedEntries.length === 0) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
let existing = "";
|
|
25
|
+
if (fs_1.default.existsSync(filePath)) {
|
|
26
|
+
existing = fs_1.default.readFileSync(filePath, "utf8");
|
|
27
|
+
}
|
|
28
|
+
const existingLines = new Set(existing
|
|
29
|
+
.split(/\r?\n/)
|
|
30
|
+
.map((line) => line.trim())
|
|
31
|
+
.filter(Boolean));
|
|
32
|
+
const additions = normalizedEntries.filter((entry) => !existingLines.has(entry));
|
|
33
|
+
if (additions.length === 0) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const next = existing.length === 0 ? `${additions.join("\n")}\n` : `${existing.replace(/\s*$/, "\n")}${additions.join("\n")}\n`;
|
|
37
|
+
fs_1.default.writeFileSync(filePath, next, "utf8");
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
function normalizeWorkspaceForEvents(config, raw) {
|
|
41
|
+
const normalized = (raw ?? "root").toLowerCase();
|
|
42
|
+
if (normalized === "all") {
|
|
43
|
+
throw new errors_1.UsageError("--ws all is not valid here");
|
|
44
|
+
}
|
|
45
|
+
if (!config.workspaces[normalized]) {
|
|
46
|
+
throw new errors_1.NotFoundError(`workspace not found: ${normalized}`);
|
|
47
|
+
}
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
function resolveEventsPath(root, config, ws = "root") {
|
|
51
|
+
const entry = config.workspaces[ws];
|
|
52
|
+
if (!entry) {
|
|
53
|
+
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
54
|
+
}
|
|
55
|
+
return path_1.default.resolve(root, entry.path, entry.mdkg_dir, "work", "events", "events.jsonl");
|
|
56
|
+
}
|
|
57
|
+
function formatRunIdTimestamp(now) {
|
|
58
|
+
const iso = now.toISOString().replace(/[-:]/g, "").replace(/\./g, "").replace("Z", "Z");
|
|
59
|
+
return iso;
|
|
60
|
+
}
|
|
61
|
+
function createLocalRunId(kind, now = new Date()) {
|
|
62
|
+
const normalizedKind = kind.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
63
|
+
return `run_mdkg_cli_${normalizedKind}_${formatRunIdTimestamp(now)}`;
|
|
64
|
+
}
|
|
65
|
+
function isEventLoggingEnabled(root, config, ws) {
|
|
66
|
+
const normalizedWs = normalizeWorkspaceForEvents(config, ws);
|
|
67
|
+
return fs_1.default.existsSync(resolveEventsPath(root, config, normalizedWs));
|
|
68
|
+
}
|
|
69
|
+
function ensureEventsEnabled(options) {
|
|
70
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
71
|
+
const ws = normalizeWorkspaceForEvents(config, options.ws);
|
|
72
|
+
const eventsPath = resolveEventsPath(options.root, config, ws);
|
|
73
|
+
const updateGitignore = options.updateGitignore !== false;
|
|
74
|
+
let created = false;
|
|
75
|
+
if (!fs_1.default.existsSync(eventsPath)) {
|
|
76
|
+
fs_1.default.mkdirSync(path_1.default.dirname(eventsPath), { recursive: true });
|
|
77
|
+
fs_1.default.writeFileSync(eventsPath, "", "utf8");
|
|
78
|
+
created = true;
|
|
79
|
+
}
|
|
80
|
+
let gitignoreUpdated = false;
|
|
81
|
+
if (updateGitignore) {
|
|
82
|
+
gitignoreUpdated = appendIgnoreEntries(path_1.default.join(options.root, ".gitignore"), [
|
|
83
|
+
".mdkg/work/events/*.jsonl",
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
return { ws, eventsPath, created, gitignoreUpdated };
|
|
87
|
+
}
|
|
88
|
+
function normalizeIdOrIdRef(value) {
|
|
89
|
+
return value.trim().toLowerCase();
|
|
90
|
+
}
|
|
91
|
+
function normalizeEventRefList(raw) {
|
|
92
|
+
if (!raw) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
return raw
|
|
96
|
+
.split(",")
|
|
97
|
+
.map((value) => normalizeIdOrIdRef(value))
|
|
98
|
+
.filter(Boolean);
|
|
99
|
+
}
|
|
100
|
+
function normalizeEventStringList(raw) {
|
|
101
|
+
if (!raw) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
return raw
|
|
105
|
+
.split(",")
|
|
106
|
+
.map((value) => value.trim())
|
|
107
|
+
.filter(Boolean);
|
|
108
|
+
}
|
|
109
|
+
function buildEventRecord(config, options) {
|
|
110
|
+
const now = options.now ?? new Date();
|
|
111
|
+
const ws = normalizeWorkspaceForEvents(config, options.ws);
|
|
112
|
+
return {
|
|
113
|
+
ts: now.toISOString(),
|
|
114
|
+
run_id: options.runId?.trim() || createLocalRunId(options.kind, now),
|
|
115
|
+
workspace: ws,
|
|
116
|
+
agent: options.agent?.trim() || "mdkg-cli",
|
|
117
|
+
kind: options.kind,
|
|
118
|
+
status: options.status,
|
|
119
|
+
refs: options.refs.map(normalizeIdOrIdRef).filter(Boolean),
|
|
120
|
+
artifacts: (options.artifacts ?? []).map((value) => value.trim()).filter(Boolean),
|
|
121
|
+
notes: options.notes?.trim() ?? "",
|
|
122
|
+
...(options.skill ? { skill: options.skill.trim().toLowerCase() } : {}),
|
|
123
|
+
...(options.tool ? { tool: options.tool.trim() } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function appendEvent(options) {
|
|
127
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
128
|
+
const record = buildEventRecord(config, options);
|
|
129
|
+
if (record.refs.length === 0) {
|
|
130
|
+
throw new errors_1.UsageError("--refs requires at least one id or qid");
|
|
131
|
+
}
|
|
132
|
+
const eventsPath = resolveEventsPath(options.root, config, record.workspace);
|
|
133
|
+
if (!fs_1.default.existsSync(eventsPath)) {
|
|
134
|
+
throw new errors_1.NotFoundError(`event logging is not enabled for workspace ${record.workspace}; run \`mdkg event enable --ws ${record.workspace}\``);
|
|
135
|
+
}
|
|
136
|
+
fs_1.default.appendFileSync(eventsPath, `${JSON.stringify(record)}\n`, "utf8");
|
|
137
|
+
return record;
|
|
138
|
+
}
|
|
139
|
+
function appendAutomaticEvent(options) {
|
|
140
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
141
|
+
const ws = normalizeWorkspaceForEvents(config, options.ws);
|
|
142
|
+
if (!isEventLoggingEnabled(options.root, config, ws)) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
return appendEvent({ ...options, ws });
|
|
146
|
+
}
|
package/dist/commands/format.js
CHANGED
|
@@ -13,8 +13,7 @@ const node_1 = require("../graph/node");
|
|
|
13
13
|
const workspace_files_1 = require("../graph/workspace_files");
|
|
14
14
|
const errors_1 = require("../util/errors");
|
|
15
15
|
const date_1 = require("../util/date");
|
|
16
|
-
const
|
|
17
|
-
const ID_REF_RE = /^([a-z][a-z0-9_]*:)?[a-z]+-[0-9]+$/;
|
|
16
|
+
const id_1 = require("../util/id");
|
|
18
17
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
19
18
|
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
20
19
|
const ID_LIST_KEYS = new Set(["refs", "scope"]);
|
|
@@ -22,7 +21,7 @@ const ID_REF_LIST_KEYS = new Set(["relates", "blocked_by", "blocks"]);
|
|
|
22
21
|
const ID_REF_SCALAR_KEYS = new Set(["epic", "parent", "prev", "next"]);
|
|
23
22
|
const PRESERVE_CASE_LIST_KEYS = new Set(["links", "artifacts"]);
|
|
24
23
|
function isValidId(value) {
|
|
25
|
-
return
|
|
24
|
+
return (0, id_1.isCanonicalId)(value);
|
|
26
25
|
}
|
|
27
26
|
function isCoreListFile(filePath) {
|
|
28
27
|
return path_1.default.basename(filePath) === "core.md" && path_1.default.basename(path_1.default.dirname(filePath)) === "core";
|
|
@@ -59,9 +58,9 @@ function normalizeList(values, key, errors, filePath) {
|
|
|
59
58
|
continue;
|
|
60
59
|
}
|
|
61
60
|
if (ID_LIST_KEYS.has(key) && !isValidId(entry)) {
|
|
62
|
-
errors.push(`${filePath}: ${key} entries must match <prefix>-<number
|
|
61
|
+
errors.push(`${filePath}: ${key} entries must match <prefix>-<number> or reserved id`);
|
|
63
62
|
}
|
|
64
|
-
if (ID_REF_LIST_KEYS.has(key) && !
|
|
63
|
+
if (ID_REF_LIST_KEYS.has(key) && !(0, id_1.isCanonicalIdRef)(entry)) {
|
|
65
64
|
errors.push(`${filePath}: ${key} entries must be valid id references`);
|
|
66
65
|
}
|
|
67
66
|
}
|
|
@@ -69,7 +68,7 @@ function normalizeList(values, key, errors, filePath) {
|
|
|
69
68
|
}
|
|
70
69
|
function normalizeIdRef(value, key, errors, filePath) {
|
|
71
70
|
const normalized = normalizeScalar(value).toLowerCase();
|
|
72
|
-
if (!
|
|
71
|
+
if (!(0, id_1.isCanonicalIdRef)(normalized)) {
|
|
73
72
|
errors.push(`${filePath}: ${key} must be a valid id reference`);
|
|
74
73
|
}
|
|
75
74
|
return normalized;
|
|
@@ -124,7 +123,7 @@ function normalizeFrontmatter(frontmatter, schema, type, workStatusEnum, priorit
|
|
|
124
123
|
else {
|
|
125
124
|
const normalizedId = idValue.toLowerCase();
|
|
126
125
|
if (!isValidId(normalizedId)) {
|
|
127
|
-
errors.push(`${filePath}: id must match <prefix>-<number
|
|
126
|
+
errors.push(`${filePath}: id must match <prefix>-<number> or reserved id`);
|
|
128
127
|
}
|
|
129
128
|
normalized.id = normalizedId;
|
|
130
129
|
}
|
package/dist/commands/index.js
CHANGED
|
@@ -8,10 +8,16 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const config_1 = require("../core/config");
|
|
9
9
|
const indexer_1 = require("../graph/indexer");
|
|
10
10
|
const index_cache_1 = require("../graph/index_cache");
|
|
11
|
+
const skills_index_cache_1 = require("../graph/skills_index_cache");
|
|
12
|
+
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
11
13
|
function runIndexCommand(options) {
|
|
12
14
|
const config = (0, config_1.loadConfig)(options.root);
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const nodeIndex = (0, indexer_1.buildIndex)(options.root, config, { tolerant: options.tolerant });
|
|
16
|
+
const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
|
|
17
|
+
const nodesOutputPath = path_1.default.resolve(options.root, config.index.global_index_path);
|
|
18
|
+
const skillsOutputPath = (0, skills_indexer_1.resolveSkillsIndexPath)(options.root);
|
|
19
|
+
(0, index_cache_1.writeIndex)(nodesOutputPath, nodeIndex);
|
|
20
|
+
(0, skills_index_cache_1.writeSkillsIndex)(skillsOutputPath, skillsIndex);
|
|
21
|
+
console.log(`index written: ${path_1.default.relative(options.root, nodesOutputPath)}`);
|
|
22
|
+
console.log(`skills index written: ${path_1.default.relative(options.root, skillsOutputPath)}`);
|
|
17
23
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -6,8 +6,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runInitCommand = runInitCommand;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const config_1 = require("../core/config");
|
|
9
10
|
const errors_1 = require("../util/errors");
|
|
11
|
+
const date_1 = require("../util/date");
|
|
12
|
+
const skill_support_1 = require("./skill_support");
|
|
13
|
+
const skill_mirror_1 = require("./skill_mirror");
|
|
10
14
|
const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
|
|
15
|
+
const SOUL_PIN_ID = "rule-soul";
|
|
16
|
+
const HUMAN_PIN_ID = "rule-human";
|
|
17
|
+
const DEFAULT_CORE_LIST_HEADER = [
|
|
18
|
+
"# mdkg verbose core list",
|
|
19
|
+
"",
|
|
20
|
+
"# One node ID per line. Lines starting with # are comments.",
|
|
21
|
+
"# This list is included by `mdkg pack --verbose`.",
|
|
22
|
+
];
|
|
11
23
|
function listFiles(dir) {
|
|
12
24
|
if (!fs_1.default.existsSync(dir)) {
|
|
13
25
|
return [];
|
|
@@ -59,16 +71,169 @@ function appendIgnoreEntries(filePath, entries) {
|
|
|
59
71
|
fs_1.default.writeFileSync(filePath, updated, "utf8");
|
|
60
72
|
return true;
|
|
61
73
|
}
|
|
74
|
+
function writeFileIfMissing(filePath, content, force, stats) {
|
|
75
|
+
if (fs_1.default.existsSync(filePath) && !force) {
|
|
76
|
+
stats.skipped += 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
80
|
+
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
81
|
+
stats.created += 1;
|
|
82
|
+
}
|
|
83
|
+
function soulTemplate(created) {
|
|
84
|
+
return [
|
|
85
|
+
"---",
|
|
86
|
+
`id: ${SOUL_PIN_ID}`,
|
|
87
|
+
"type: rule",
|
|
88
|
+
"title: agent soul and execution contract",
|
|
89
|
+
"tags: [agent, constraints]",
|
|
90
|
+
"owners: []",
|
|
91
|
+
"links: []",
|
|
92
|
+
"artifacts: []",
|
|
93
|
+
"relates: []",
|
|
94
|
+
"refs: []",
|
|
95
|
+
"aliases: [soul]",
|
|
96
|
+
`created: ${created}`,
|
|
97
|
+
`updated: ${created}`,
|
|
98
|
+
"---",
|
|
99
|
+
"",
|
|
100
|
+
"# Purpose",
|
|
101
|
+
"",
|
|
102
|
+
"Define the canonical agent execution boundaries and memory contract for this repository.",
|
|
103
|
+
"",
|
|
104
|
+
"# Scope",
|
|
105
|
+
"",
|
|
106
|
+
"Applies to all orchestrators and coding-agent executions using mdkg in this repo.",
|
|
107
|
+
"",
|
|
108
|
+
"# Requirements",
|
|
109
|
+
"",
|
|
110
|
+
"- Ask for approval before destructive operations or policy-sensitive actions.",
|
|
111
|
+
"- Prefer deterministic mdkg packs over ad-hoc context assembly.",
|
|
112
|
+
"- Follow single-writer commit discipline and event-driven batching.",
|
|
113
|
+
"- Never place secrets in mdkg docs or generated packs.",
|
|
114
|
+
"",
|
|
115
|
+
"# Notes",
|
|
116
|
+
"",
|
|
117
|
+
"Customize this file to encode repo-specific constraints, approval boundaries, and memory cadence.",
|
|
118
|
+
"",
|
|
119
|
+
].join("\n");
|
|
120
|
+
}
|
|
121
|
+
function humanTemplate(created) {
|
|
122
|
+
return [
|
|
123
|
+
"---",
|
|
124
|
+
`id: ${HUMAN_PIN_ID}`,
|
|
125
|
+
"type: rule",
|
|
126
|
+
"title: human working profile and collaboration preferences",
|
|
127
|
+
"tags: [human, collaboration, preferences]",
|
|
128
|
+
"owners: []",
|
|
129
|
+
"links: []",
|
|
130
|
+
"artifacts: []",
|
|
131
|
+
"relates: []",
|
|
132
|
+
"refs: []",
|
|
133
|
+
"aliases: [human]",
|
|
134
|
+
`created: ${created}`,
|
|
135
|
+
`updated: ${created}`,
|
|
136
|
+
"---",
|
|
137
|
+
"",
|
|
138
|
+
"# Purpose",
|
|
139
|
+
"",
|
|
140
|
+
"Capture stable collaboration preferences and boundaries so agents can work with less ambiguity.",
|
|
141
|
+
"",
|
|
142
|
+
"# Scope",
|
|
143
|
+
"",
|
|
144
|
+
"Applies to planning, implementation, and review interactions in this repository.",
|
|
145
|
+
"",
|
|
146
|
+
"# Requirements",
|
|
147
|
+
"",
|
|
148
|
+
"- Keep top goals, boundaries, and style preferences current.",
|
|
149
|
+
"- Include ask-before-doing constraints for risky or high-impact actions.",
|
|
150
|
+
"- Record preferred environment assumptions and validation commands.",
|
|
151
|
+
"",
|
|
152
|
+
"# Notes",
|
|
153
|
+
"",
|
|
154
|
+
"Suggested prompts:",
|
|
155
|
+
"- What are your top 3 goals in this repo right now?",
|
|
156
|
+
"- What should never happen without confirmation?",
|
|
157
|
+
"- What coding/review style should the agent prefer?",
|
|
158
|
+
"- What OS/runtime/test commands should be assumed?",
|
|
159
|
+
"",
|
|
160
|
+
].join("\n");
|
|
161
|
+
}
|
|
162
|
+
function seededInitEvent(nowIso) {
|
|
163
|
+
const event = {
|
|
164
|
+
ts: nowIso,
|
|
165
|
+
run_id: `init-${nowIso.replace(/[^0-9]/g, "").slice(0, 14)}`,
|
|
166
|
+
workspace: "root",
|
|
167
|
+
agent: "mdkg",
|
|
168
|
+
kind: "RUN_STARTED",
|
|
169
|
+
status: "ok",
|
|
170
|
+
refs: ["edd-4"],
|
|
171
|
+
artifacts: [],
|
|
172
|
+
notes: "init agent scaffold target initialized",
|
|
173
|
+
redacted: true,
|
|
174
|
+
};
|
|
175
|
+
return `${JSON.stringify(event)}\n`;
|
|
176
|
+
}
|
|
177
|
+
function parseCoreList(raw) {
|
|
178
|
+
const lines = raw.split(/\r?\n/);
|
|
179
|
+
const header = [];
|
|
180
|
+
const ids = [];
|
|
181
|
+
let seenFirstId = false;
|
|
182
|
+
for (const line of lines) {
|
|
183
|
+
const trimmed = line.trim();
|
|
184
|
+
const isComment = trimmed.startsWith("#");
|
|
185
|
+
if (!seenFirstId && (trimmed.length === 0 || isComment)) {
|
|
186
|
+
header.push(line);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (trimmed.length === 0 || isComment) {
|
|
190
|
+
seenFirstId = true;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
seenFirstId = true;
|
|
194
|
+
ids.push(trimmed.toLowerCase());
|
|
195
|
+
}
|
|
196
|
+
return { header, ids };
|
|
197
|
+
}
|
|
198
|
+
function ensureCorePins(coreListPath, requiredPins) {
|
|
199
|
+
const raw = fs_1.default.existsSync(coreListPath) ? fs_1.default.readFileSync(coreListPath, "utf8") : "";
|
|
200
|
+
const { header, ids } = parseCoreList(raw);
|
|
201
|
+
const seen = new Set();
|
|
202
|
+
const dedupedExisting = [];
|
|
203
|
+
for (const id of ids) {
|
|
204
|
+
if (seen.has(id)) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
seen.add(id);
|
|
208
|
+
dedupedExisting.push(id);
|
|
209
|
+
}
|
|
210
|
+
const required = requiredPins.map((value) => value.toLowerCase());
|
|
211
|
+
const filteredExisting = dedupedExisting.filter((value) => !required.includes(value));
|
|
212
|
+
const finalIds = [...required, ...filteredExisting];
|
|
213
|
+
const headerLines = header.length > 0 ? header : DEFAULT_CORE_LIST_HEADER;
|
|
214
|
+
const normalizedHeader = headerLines.slice();
|
|
215
|
+
while (normalizedHeader.length > 0 && normalizedHeader[normalizedHeader.length - 1].trim() === "") {
|
|
216
|
+
normalizedHeader.pop();
|
|
217
|
+
}
|
|
218
|
+
const output = [...normalizedHeader, "", ...finalIds, ""].join("\n");
|
|
219
|
+
fs_1.default.mkdirSync(path_1.default.dirname(coreListPath), { recursive: true });
|
|
220
|
+
fs_1.default.writeFileSync(coreListPath, output, "utf8");
|
|
221
|
+
}
|
|
62
222
|
function runInitCommand(options) {
|
|
63
223
|
const root = path_1.default.resolve(options.root);
|
|
64
224
|
const seedRoot = options.seedRoot ? path_1.default.resolve(options.seedRoot) : DEFAULT_SEED_SUBDIR;
|
|
65
225
|
const createAgents = Boolean(options.createAgents || options.createLlm);
|
|
66
226
|
const createClaude = Boolean(options.createClaude || options.createLlm);
|
|
227
|
+
const createStartupDocs = Boolean(options.createLlm || options.agent);
|
|
228
|
+
const force = Boolean(options.force);
|
|
67
229
|
const seedConfig = path_1.default.join(seedRoot, "config.json");
|
|
68
230
|
const seedCore = path_1.default.join(seedRoot, "core");
|
|
69
231
|
const seedTemplates = path_1.default.join(seedRoot, "templates");
|
|
70
232
|
const seedAgents = path_1.default.join(seedRoot, "AGENTS.md");
|
|
71
233
|
const seedClaude = path_1.default.join(seedRoot, "CLAUDE.md");
|
|
234
|
+
const seedLlms = path_1.default.join(seedRoot, "llms.txt");
|
|
235
|
+
const seedAgentStart = path_1.default.join(seedRoot, "AGENT_START.md");
|
|
236
|
+
const seedCliMatrix = path_1.default.join(seedRoot, "CLI_COMMAND_MATRIX.md");
|
|
72
237
|
const seedReadme = path_1.default.join(seedRoot, "README.md");
|
|
73
238
|
if (!fs_1.default.existsSync(seedConfig) || !fs_1.default.existsSync(seedCore) || !fs_1.default.existsSync(seedTemplates)) {
|
|
74
239
|
throw new errors_1.NotFoundError(`init assets not found at ${seedRoot} (try reinstalling mdkg)`);
|
|
@@ -79,6 +244,15 @@ function runInitCommand(options) {
|
|
|
79
244
|
if (createClaude && !fs_1.default.existsSync(seedClaude)) {
|
|
80
245
|
throw new errors_1.NotFoundError(`init assets missing CLAUDE.md at ${seedRoot}`);
|
|
81
246
|
}
|
|
247
|
+
if (createStartupDocs && !fs_1.default.existsSync(seedLlms)) {
|
|
248
|
+
throw new errors_1.NotFoundError(`init assets missing llms.txt at ${seedRoot}`);
|
|
249
|
+
}
|
|
250
|
+
if (createStartupDocs && !fs_1.default.existsSync(seedAgentStart)) {
|
|
251
|
+
throw new errors_1.NotFoundError(`init assets missing AGENT_START.md at ${seedRoot}`);
|
|
252
|
+
}
|
|
253
|
+
if (createStartupDocs && !fs_1.default.existsSync(seedCliMatrix)) {
|
|
254
|
+
throw new errors_1.NotFoundError(`init assets missing CLI_COMMAND_MATRIX.md at ${seedRoot}`);
|
|
255
|
+
}
|
|
82
256
|
if (!fs_1.default.existsSync(seedReadme)) {
|
|
83
257
|
throw new errors_1.NotFoundError(`init assets missing README.md at ${seedRoot}`);
|
|
84
258
|
}
|
|
@@ -87,34 +261,68 @@ function runInitCommand(options) {
|
|
|
87
261
|
fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "work"), { recursive: true });
|
|
88
262
|
fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "design"), { recursive: true });
|
|
89
263
|
const stats = { created: 0, skipped: 0 };
|
|
90
|
-
copySeedFile(seedConfig, path_1.default.join(mdkgDir, "config.json"),
|
|
91
|
-
copySeedFile(seedReadme, path_1.default.join(mdkgDir, "README.md"),
|
|
92
|
-
copySeedDir(seedCore, path_1.default.join(mdkgDir, "core"),
|
|
93
|
-
copySeedDir(seedTemplates, path_1.default.join(mdkgDir, "templates"),
|
|
264
|
+
copySeedFile(seedConfig, path_1.default.join(mdkgDir, "config.json"), force, stats);
|
|
265
|
+
copySeedFile(seedReadme, path_1.default.join(mdkgDir, "README.md"), force, stats);
|
|
266
|
+
copySeedDir(seedCore, path_1.default.join(mdkgDir, "core"), force, stats);
|
|
267
|
+
copySeedDir(seedTemplates, path_1.default.join(mdkgDir, "templates"), force, stats);
|
|
94
268
|
if (createAgents) {
|
|
95
|
-
copySeedFile(seedAgents, path_1.default.join(root, "AGENTS.md"),
|
|
269
|
+
copySeedFile(seedAgents, path_1.default.join(root, "AGENTS.md"), force, stats);
|
|
96
270
|
}
|
|
97
271
|
if (createClaude) {
|
|
98
|
-
copySeedFile(seedClaude, path_1.default.join(root, "CLAUDE.md"),
|
|
272
|
+
copySeedFile(seedClaude, path_1.default.join(root, "CLAUDE.md"), force, stats);
|
|
273
|
+
}
|
|
274
|
+
if (createStartupDocs) {
|
|
275
|
+
copySeedFile(seedLlms, path_1.default.join(root, "llms.txt"), force, stats);
|
|
276
|
+
copySeedFile(seedAgentStart, path_1.default.join(root, "AGENT_START.md"), force, stats);
|
|
277
|
+
copySeedFile(seedCliMatrix, path_1.default.join(root, "CLI_COMMAND_MATRIX.md"), force, stats);
|
|
278
|
+
}
|
|
279
|
+
if (options.agent) {
|
|
280
|
+
const today = (0, date_1.formatDate)(new Date());
|
|
281
|
+
const soulPath = path_1.default.join(mdkgDir, "core", "SOUL.md");
|
|
282
|
+
const humanPath = path_1.default.join(mdkgDir, "core", "HUMAN.md");
|
|
283
|
+
const skillsDir = path_1.default.join(mdkgDir, "skills");
|
|
284
|
+
const registryPath = path_1.default.join(skillsDir, "registry.md");
|
|
285
|
+
const eventsDir = path_1.default.join(mdkgDir, "work", "events");
|
|
286
|
+
const eventsPath = path_1.default.join(eventsDir, "events.jsonl");
|
|
287
|
+
fs_1.default.mkdirSync(skillsDir, { recursive: true });
|
|
288
|
+
fs_1.default.mkdirSync(eventsDir, { recursive: true });
|
|
289
|
+
writeFileIfMissing(soulPath, soulTemplate(today), force, stats);
|
|
290
|
+
writeFileIfMissing(humanPath, humanTemplate(today), force, stats);
|
|
291
|
+
writeFileIfMissing(registryPath, (0, skill_support_1.registryTemplate)(), force, stats);
|
|
292
|
+
if (!fs_1.default.existsSync(eventsPath) || force) {
|
|
293
|
+
writeFileIfMissing(eventsPath, seededInitEvent(new Date().toISOString()), force, stats);
|
|
294
|
+
}
|
|
295
|
+
const coreListPath = path_1.default.join(mdkgDir, "core", "core.md");
|
|
296
|
+
ensureCorePins(coreListPath, [SOUL_PIN_ID, HUMAN_PIN_ID]);
|
|
297
|
+
(0, skill_mirror_1.scaffoldMirrorRoots)(root);
|
|
298
|
+
const config = (0, config_1.loadConfig)(root);
|
|
299
|
+
(0, skill_mirror_1.syncSkillMirrors)({ root, config, createRoots: true, force });
|
|
99
300
|
}
|
|
100
|
-
|
|
101
|
-
|
|
301
|
+
const noUpdateIgnores = Boolean(options.noUpdateIgnores);
|
|
302
|
+
const shouldUpdateGitignore = Boolean(options.updateGitignore || !noUpdateIgnores);
|
|
303
|
+
const shouldUpdateNpmignore = Boolean(options.updateNpmignore || !noUpdateIgnores);
|
|
304
|
+
if (shouldUpdateGitignore) {
|
|
305
|
+
appendIgnoreEntries(path_1.default.join(root, ".gitignore"), [
|
|
306
|
+
".mdkg/index/",
|
|
307
|
+
".mdkg/pack/",
|
|
308
|
+
".mdkg/work/events/*.jsonl",
|
|
309
|
+
]);
|
|
102
310
|
}
|
|
103
|
-
if (
|
|
311
|
+
if (shouldUpdateNpmignore) {
|
|
104
312
|
appendIgnoreEntries(path_1.default.join(root, ".npmignore"), [".mdkg/", ".mdkg/index/", ".mdkg/pack/"]);
|
|
105
313
|
}
|
|
106
314
|
if (options.updateDockerignore) {
|
|
107
315
|
appendIgnoreEntries(path_1.default.join(root, ".dockerignore"), [".mdkg/"]);
|
|
108
316
|
}
|
|
109
|
-
if (!options.updateGitignore && !options.updateNpmignore && !options.updateDockerignore) {
|
|
110
|
-
console.error("warning: ignore files were not updated");
|
|
111
|
-
console.error("hint: rerun `mdkg init --update-gitignore --update-npmignore` to avoid committing cache/pack artifacts");
|
|
112
|
-
}
|
|
113
317
|
console.log(`mdkg init complete: ${stats.created} file(s) created, ${stats.skipped} skipped`);
|
|
114
318
|
console.log("next:");
|
|
115
|
-
|
|
319
|
+
if (createStartupDocs) {
|
|
320
|
+
console.log(" read AGENT_START.md");
|
|
321
|
+
}
|
|
116
322
|
console.log(' mdkg new task "..." --status todo --priority 1');
|
|
117
|
-
console.log(
|
|
118
|
-
console.log(" mdkg
|
|
323
|
+
console.log(' mdkg search "..."');
|
|
324
|
+
console.log(" mdkg show <id>");
|
|
325
|
+
console.log(" mdkg next");
|
|
326
|
+
console.log(" mdkg pack <id>");
|
|
119
327
|
console.log(" mdkg validate");
|
|
120
328
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -8,6 +8,7 @@ const errors_1 = require("../util/errors");
|
|
|
8
8
|
const qid_1 = require("../util/qid");
|
|
9
9
|
const sort_1 = require("../util/sort");
|
|
10
10
|
const node_card_1 = require("./node_card");
|
|
11
|
+
const query_output_1 = require("./query_output");
|
|
11
12
|
function normalizeWorkspace(value) {
|
|
12
13
|
if (!value || value === "all") {
|
|
13
14
|
return undefined;
|
|
@@ -20,6 +21,10 @@ function runListCommand(options) {
|
|
|
20
21
|
if (ws && !config.workspaces[ws]) {
|
|
21
22
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
22
23
|
}
|
|
24
|
+
const normalizedType = options.type?.toLowerCase();
|
|
25
|
+
if (normalizedType === "skill") {
|
|
26
|
+
throw new errors_1.UsageError("--type skill is no longer supported here; use `mdkg skill list`");
|
|
27
|
+
}
|
|
23
28
|
const { index, rebuilt, stale } = (0, index_cache_1.loadIndex)({
|
|
24
29
|
root: options.root,
|
|
25
30
|
config,
|
|
@@ -39,13 +44,25 @@ function runListCommand(options) {
|
|
|
39
44
|
}
|
|
40
45
|
const filtered = (0, filter_1.filterNodes)(Object.values(index.nodes), {
|
|
41
46
|
ws,
|
|
42
|
-
type:
|
|
47
|
+
type: normalizedType,
|
|
43
48
|
status: options.status,
|
|
44
49
|
epic: epicQid,
|
|
45
50
|
priority: options.priority,
|
|
46
51
|
blocked: options.blocked,
|
|
52
|
+
tags: options.tags,
|
|
53
|
+
tagsMode: options.tagsMode,
|
|
47
54
|
});
|
|
48
55
|
const sorted = (0, sort_1.sortNodesByQid)(filtered);
|
|
56
|
+
if (options.json) {
|
|
57
|
+
(0, query_output_1.writeJson)({
|
|
58
|
+
command: "list",
|
|
59
|
+
kind: "node",
|
|
60
|
+
count: sorted.length,
|
|
61
|
+
items: sorted.map(query_output_1.toNodeSummaryJson),
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
(0, query_output_1.writeCount)(sorted.length, sorted.length === 0 ? "no nodes matched current filters" : undefined);
|
|
49
66
|
for (const node of sorted) {
|
|
50
67
|
console.log((0, node_card_1.formatNodeCard)(node));
|
|
51
68
|
}
|