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/init.js
CHANGED
|
@@ -7,7 +7,17 @@ exports.runInitCommand = runInitCommand;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const errors_1 = require("../util/errors");
|
|
10
|
+
const date_1 = require("../util/date");
|
|
11
|
+
const skill_support_1 = require("./skill_support");
|
|
10
12
|
const DEFAULT_SEED_SUBDIR = path_1.default.resolve(__dirname, "..", "init");
|
|
13
|
+
const SOUL_PIN_ID = "rule-soul";
|
|
14
|
+
const HUMAN_PIN_ID = "rule-human";
|
|
15
|
+
const DEFAULT_CORE_LIST_HEADER = [
|
|
16
|
+
"# mdkg verbose core list",
|
|
17
|
+
"",
|
|
18
|
+
"# One node ID per line. Lines starting with # are comments.",
|
|
19
|
+
"# This list is included by `mdkg pack --verbose`.",
|
|
20
|
+
];
|
|
11
21
|
function listFiles(dir) {
|
|
12
22
|
if (!fs_1.default.existsSync(dir)) {
|
|
13
23
|
return [];
|
|
@@ -59,16 +69,166 @@ function appendIgnoreEntries(filePath, entries) {
|
|
|
59
69
|
fs_1.default.writeFileSync(filePath, updated, "utf8");
|
|
60
70
|
return true;
|
|
61
71
|
}
|
|
72
|
+
function writeFileIfMissing(filePath, content, force, stats) {
|
|
73
|
+
if (fs_1.default.existsSync(filePath) && !force) {
|
|
74
|
+
stats.skipped += 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
78
|
+
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
79
|
+
stats.created += 1;
|
|
80
|
+
}
|
|
81
|
+
function soulTemplate(created) {
|
|
82
|
+
return [
|
|
83
|
+
"---",
|
|
84
|
+
`id: ${SOUL_PIN_ID}`,
|
|
85
|
+
"type: rule",
|
|
86
|
+
"title: agent soul and execution contract",
|
|
87
|
+
"tags: [omni, agent, constraints]",
|
|
88
|
+
"owners: []",
|
|
89
|
+
"links: []",
|
|
90
|
+
"artifacts: []",
|
|
91
|
+
"relates: []",
|
|
92
|
+
"refs: []",
|
|
93
|
+
"aliases: [soul]",
|
|
94
|
+
`created: ${created}`,
|
|
95
|
+
`updated: ${created}`,
|
|
96
|
+
"---",
|
|
97
|
+
"",
|
|
98
|
+
"# Purpose",
|
|
99
|
+
"",
|
|
100
|
+
"Define the canonical agent execution boundaries and memory contract for this repository.",
|
|
101
|
+
"",
|
|
102
|
+
"# Scope",
|
|
103
|
+
"",
|
|
104
|
+
"Applies to all orchestrators and coding-agent executions using mdkg in this repo.",
|
|
105
|
+
"",
|
|
106
|
+
"# Requirements",
|
|
107
|
+
"",
|
|
108
|
+
"- Ask for approval before destructive operations or policy-sensitive actions.",
|
|
109
|
+
"- Prefer deterministic mdkg packs over ad-hoc context assembly.",
|
|
110
|
+
"- Follow single-writer commit discipline and event-driven batching.",
|
|
111
|
+
"- Never place secrets in mdkg docs or generated packs.",
|
|
112
|
+
"",
|
|
113
|
+
"# Notes",
|
|
114
|
+
"",
|
|
115
|
+
"Customize this file to encode repo-specific constraints, approval boundaries, and memory cadence.",
|
|
116
|
+
"",
|
|
117
|
+
].join("\n");
|
|
118
|
+
}
|
|
119
|
+
function humanTemplate(created) {
|
|
120
|
+
return [
|
|
121
|
+
"---",
|
|
122
|
+
`id: ${HUMAN_PIN_ID}`,
|
|
123
|
+
"type: rule",
|
|
124
|
+
"title: human working profile and collaboration preferences",
|
|
125
|
+
"tags: [human, collaboration, preferences]",
|
|
126
|
+
"owners: []",
|
|
127
|
+
"links: []",
|
|
128
|
+
"artifacts: []",
|
|
129
|
+
"relates: []",
|
|
130
|
+
"refs: []",
|
|
131
|
+
"aliases: [human]",
|
|
132
|
+
`created: ${created}`,
|
|
133
|
+
`updated: ${created}`,
|
|
134
|
+
"---",
|
|
135
|
+
"",
|
|
136
|
+
"# Purpose",
|
|
137
|
+
"",
|
|
138
|
+
"Capture stable collaboration preferences and boundaries so agents can work with less ambiguity.",
|
|
139
|
+
"",
|
|
140
|
+
"# Scope",
|
|
141
|
+
"",
|
|
142
|
+
"Applies to planning, implementation, and review interactions in this repository.",
|
|
143
|
+
"",
|
|
144
|
+
"# Requirements",
|
|
145
|
+
"",
|
|
146
|
+
"- Keep top goals, boundaries, and style preferences current.",
|
|
147
|
+
"- Include ask-before-doing constraints for risky or high-impact actions.",
|
|
148
|
+
"- Record preferred environment assumptions and validation commands.",
|
|
149
|
+
"",
|
|
150
|
+
"# Notes",
|
|
151
|
+
"",
|
|
152
|
+
"Suggested prompts:",
|
|
153
|
+
"- What are your top 3 goals in this repo right now?",
|
|
154
|
+
"- What should never happen without confirmation?",
|
|
155
|
+
"- What coding/review style should the agent prefer?",
|
|
156
|
+
"- What OS/runtime/test commands should be assumed?",
|
|
157
|
+
"",
|
|
158
|
+
].join("\n");
|
|
159
|
+
}
|
|
160
|
+
function seededInitEvent(nowIso) {
|
|
161
|
+
const event = {
|
|
162
|
+
ts: nowIso,
|
|
163
|
+
run_id: `init-${nowIso.replace(/[^0-9]/g, "").slice(0, 14)}`,
|
|
164
|
+
workspace: "root",
|
|
165
|
+
agent: "mdkg",
|
|
166
|
+
kind: "RUN_STARTED",
|
|
167
|
+
status: "ok",
|
|
168
|
+
refs: ["edd-4"],
|
|
169
|
+
artifacts: [],
|
|
170
|
+
notes: "init omni scaffold target initialized",
|
|
171
|
+
redacted: true,
|
|
172
|
+
};
|
|
173
|
+
return `${JSON.stringify(event)}\n`;
|
|
174
|
+
}
|
|
175
|
+
function parseCoreList(raw) {
|
|
176
|
+
const lines = raw.split(/\r?\n/);
|
|
177
|
+
const header = [];
|
|
178
|
+
const ids = [];
|
|
179
|
+
let seenFirstId = false;
|
|
180
|
+
for (const line of lines) {
|
|
181
|
+
const trimmed = line.trim();
|
|
182
|
+
const isComment = trimmed.startsWith("#");
|
|
183
|
+
if (!seenFirstId && (trimmed.length === 0 || isComment)) {
|
|
184
|
+
header.push(line);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (trimmed.length === 0 || isComment) {
|
|
188
|
+
seenFirstId = true;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
seenFirstId = true;
|
|
192
|
+
ids.push(trimmed.toLowerCase());
|
|
193
|
+
}
|
|
194
|
+
return { header, ids };
|
|
195
|
+
}
|
|
196
|
+
function ensureCorePins(coreListPath, requiredPins) {
|
|
197
|
+
const raw = fs_1.default.existsSync(coreListPath) ? fs_1.default.readFileSync(coreListPath, "utf8") : "";
|
|
198
|
+
const { header, ids } = parseCoreList(raw);
|
|
199
|
+
const seen = new Set();
|
|
200
|
+
const dedupedExisting = [];
|
|
201
|
+
for (const id of ids) {
|
|
202
|
+
if (seen.has(id)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
seen.add(id);
|
|
206
|
+
dedupedExisting.push(id);
|
|
207
|
+
}
|
|
208
|
+
const required = requiredPins.map((value) => value.toLowerCase());
|
|
209
|
+
const filteredExisting = dedupedExisting.filter((value) => !required.includes(value));
|
|
210
|
+
const finalIds = [...required, ...filteredExisting];
|
|
211
|
+
const headerLines = header.length > 0 ? header : DEFAULT_CORE_LIST_HEADER;
|
|
212
|
+
const normalizedHeader = headerLines.slice();
|
|
213
|
+
while (normalizedHeader.length > 0 && normalizedHeader[normalizedHeader.length - 1].trim() === "") {
|
|
214
|
+
normalizedHeader.pop();
|
|
215
|
+
}
|
|
216
|
+
const output = [...normalizedHeader, "", ...finalIds, ""].join("\n");
|
|
217
|
+
fs_1.default.mkdirSync(path_1.default.dirname(coreListPath), { recursive: true });
|
|
218
|
+
fs_1.default.writeFileSync(coreListPath, output, "utf8");
|
|
219
|
+
}
|
|
62
220
|
function runInitCommand(options) {
|
|
63
221
|
const root = path_1.default.resolve(options.root);
|
|
64
222
|
const seedRoot = options.seedRoot ? path_1.default.resolve(options.seedRoot) : DEFAULT_SEED_SUBDIR;
|
|
65
223
|
const createAgents = Boolean(options.createAgents || options.createLlm);
|
|
66
224
|
const createClaude = Boolean(options.createClaude || options.createLlm);
|
|
225
|
+
const force = Boolean(options.force);
|
|
67
226
|
const seedConfig = path_1.default.join(seedRoot, "config.json");
|
|
68
227
|
const seedCore = path_1.default.join(seedRoot, "core");
|
|
69
228
|
const seedTemplates = path_1.default.join(seedRoot, "templates");
|
|
70
229
|
const seedAgents = path_1.default.join(seedRoot, "AGENTS.md");
|
|
71
230
|
const seedClaude = path_1.default.join(seedRoot, "CLAUDE.md");
|
|
231
|
+
const seedReadme = path_1.default.join(seedRoot, "README.md");
|
|
72
232
|
if (!fs_1.default.existsSync(seedConfig) || !fs_1.default.existsSync(seedCore) || !fs_1.default.existsSync(seedTemplates)) {
|
|
73
233
|
throw new errors_1.NotFoundError(`init assets not found at ${seedRoot} (try reinstalling mdkg)`);
|
|
74
234
|
}
|
|
@@ -78,24 +238,54 @@ function runInitCommand(options) {
|
|
|
78
238
|
if (createClaude && !fs_1.default.existsSync(seedClaude)) {
|
|
79
239
|
throw new errors_1.NotFoundError(`init assets missing CLAUDE.md at ${seedRoot}`);
|
|
80
240
|
}
|
|
241
|
+
if (!fs_1.default.existsSync(seedReadme)) {
|
|
242
|
+
throw new errors_1.NotFoundError(`init assets missing README.md at ${seedRoot}`);
|
|
243
|
+
}
|
|
81
244
|
const mdkgDir = path_1.default.join(root, ".mdkg");
|
|
82
245
|
fs_1.default.mkdirSync(mdkgDir, { recursive: true });
|
|
83
246
|
fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "work"), { recursive: true });
|
|
84
247
|
fs_1.default.mkdirSync(path_1.default.join(mdkgDir, "design"), { recursive: true });
|
|
85
248
|
const stats = { created: 0, skipped: 0 };
|
|
86
|
-
copySeedFile(seedConfig, path_1.default.join(mdkgDir, "config.json"),
|
|
87
|
-
|
|
88
|
-
copySeedDir(
|
|
249
|
+
copySeedFile(seedConfig, path_1.default.join(mdkgDir, "config.json"), force, stats);
|
|
250
|
+
copySeedFile(seedReadme, path_1.default.join(mdkgDir, "README.md"), force, stats);
|
|
251
|
+
copySeedDir(seedCore, path_1.default.join(mdkgDir, "core"), force, stats);
|
|
252
|
+
copySeedDir(seedTemplates, path_1.default.join(mdkgDir, "templates"), force, stats);
|
|
89
253
|
if (createAgents) {
|
|
90
|
-
copySeedFile(seedAgents, path_1.default.join(root, "AGENTS.md"),
|
|
254
|
+
copySeedFile(seedAgents, path_1.default.join(root, "AGENTS.md"), force, stats);
|
|
91
255
|
}
|
|
92
256
|
if (createClaude) {
|
|
93
|
-
copySeedFile(seedClaude, path_1.default.join(root, "CLAUDE.md"),
|
|
257
|
+
copySeedFile(seedClaude, path_1.default.join(root, "CLAUDE.md"), force, stats);
|
|
258
|
+
}
|
|
259
|
+
if (options.omni) {
|
|
260
|
+
const today = (0, date_1.formatDate)(new Date());
|
|
261
|
+
const soulPath = path_1.default.join(mdkgDir, "core", "SOUL.md");
|
|
262
|
+
const humanPath = path_1.default.join(mdkgDir, "core", "HUMAN.md");
|
|
263
|
+
const skillsDir = path_1.default.join(mdkgDir, "skills");
|
|
264
|
+
const registryPath = path_1.default.join(skillsDir, "registry.md");
|
|
265
|
+
const eventsDir = path_1.default.join(mdkgDir, "work", "events");
|
|
266
|
+
const eventsPath = path_1.default.join(eventsDir, "events.jsonl");
|
|
267
|
+
fs_1.default.mkdirSync(skillsDir, { recursive: true });
|
|
268
|
+
fs_1.default.mkdirSync(eventsDir, { recursive: true });
|
|
269
|
+
writeFileIfMissing(soulPath, soulTemplate(today), force, stats);
|
|
270
|
+
writeFileIfMissing(humanPath, humanTemplate(today), force, stats);
|
|
271
|
+
writeFileIfMissing(registryPath, (0, skill_support_1.registryTemplate)(), force, stats);
|
|
272
|
+
if (!fs_1.default.existsSync(eventsPath) || force) {
|
|
273
|
+
writeFileIfMissing(eventsPath, seededInitEvent(new Date().toISOString()), force, stats);
|
|
274
|
+
}
|
|
275
|
+
const coreListPath = path_1.default.join(mdkgDir, "core", "core.md");
|
|
276
|
+
ensureCorePins(coreListPath, [SOUL_PIN_ID, HUMAN_PIN_ID]);
|
|
94
277
|
}
|
|
95
|
-
|
|
96
|
-
|
|
278
|
+
const noUpdateIgnores = Boolean(options.noUpdateIgnores);
|
|
279
|
+
const shouldUpdateGitignore = Boolean(options.updateGitignore || !noUpdateIgnores);
|
|
280
|
+
const shouldUpdateNpmignore = Boolean(options.updateNpmignore || !noUpdateIgnores);
|
|
281
|
+
if (shouldUpdateGitignore) {
|
|
282
|
+
appendIgnoreEntries(path_1.default.join(root, ".gitignore"), [
|
|
283
|
+
".mdkg/index/",
|
|
284
|
+
".mdkg/pack/",
|
|
285
|
+
".mdkg/work/events/*.jsonl",
|
|
286
|
+
]);
|
|
97
287
|
}
|
|
98
|
-
if (
|
|
288
|
+
if (shouldUpdateNpmignore) {
|
|
99
289
|
appendIgnoreEntries(path_1.default.join(root, ".npmignore"), [".mdkg/", ".mdkg/index/", ".mdkg/pack/"]);
|
|
100
290
|
}
|
|
101
291
|
if (options.updateDockerignore) {
|
|
@@ -103,9 +293,10 @@ function runInitCommand(options) {
|
|
|
103
293
|
}
|
|
104
294
|
console.log(`mdkg init complete: ${stats.created} file(s) created, ${stats.skipped} skipped`);
|
|
105
295
|
console.log("next:");
|
|
106
|
-
console.log(" mdkg index");
|
|
107
296
|
console.log(' mdkg new task "..." --status todo --priority 1');
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(" mdkg
|
|
297
|
+
console.log(' mdkg search "..."');
|
|
298
|
+
console.log(" mdkg show <id>");
|
|
299
|
+
console.log(" mdkg next");
|
|
300
|
+
console.log(" mdkg pack <id>");
|
|
110
301
|
console.log(" mdkg validate");
|
|
111
302
|
}
|
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
|
}
|
package/dist/commands/new.js
CHANGED
|
@@ -14,10 +14,11 @@ const loader_1 = require("../templates/loader");
|
|
|
14
14
|
const date_1 = require("../util/date");
|
|
15
15
|
const errors_1 = require("../util/errors");
|
|
16
16
|
const qid_1 = require("../util/qid");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const id_1 = require("../util/id");
|
|
18
|
+
const event_support_1 = require("./event_support");
|
|
19
19
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
20
20
|
const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
21
|
+
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21
22
|
const CORE_TYPES = new Set(["rule"]);
|
|
22
23
|
const DESIGN_TYPES = new Set(["prd", "edd", "dec", "prop"]);
|
|
23
24
|
function parseCsvList(raw) {
|
|
@@ -31,14 +32,14 @@ function parseCsvList(raw) {
|
|
|
31
32
|
}
|
|
32
33
|
function normalizeId(value, key) {
|
|
33
34
|
const normalized = value.toLowerCase();
|
|
34
|
-
if (!
|
|
35
|
-
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number
|
|
35
|
+
if (!(0, id_1.isCanonicalId)(normalized)) {
|
|
36
|
+
throw new errors_1.UsageError(`${key} entries must match <prefix>-<number> or reserved id: ${value}`);
|
|
36
37
|
}
|
|
37
38
|
return normalized;
|
|
38
39
|
}
|
|
39
40
|
function normalizeIdRef(value, key) {
|
|
40
41
|
const normalized = value.toLowerCase();
|
|
41
|
-
if (!
|
|
42
|
+
if (!(0, id_1.isCanonicalIdRef)(normalized)) {
|
|
42
43
|
throw new errors_1.UsageError(`${key} entries must match <id> or <ws>:<id>: ${value}`);
|
|
43
44
|
}
|
|
44
45
|
return normalized;
|
|
@@ -55,6 +56,15 @@ function normalizeIdList(raw, key) {
|
|
|
55
56
|
function normalizeIdRefList(raw, key) {
|
|
56
57
|
return parseCsvList(raw).map((value) => normalizeIdRef(value, key));
|
|
57
58
|
}
|
|
59
|
+
function normalizeSkillList(raw) {
|
|
60
|
+
return parseCsvList(raw).map((value) => {
|
|
61
|
+
const normalized = value.toLowerCase();
|
|
62
|
+
if (!SKILL_SLUG_RE.test(normalized)) {
|
|
63
|
+
throw new errors_1.UsageError(`--skills entries must be kebab-case: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
return normalized;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
58
68
|
function normalizeWorkspace(value) {
|
|
59
69
|
if (!value) {
|
|
60
70
|
return "root";
|
|
@@ -206,8 +216,12 @@ function runNewCommand(options) {
|
|
|
206
216
|
const tags = normalizeLowercaseList(options.tags);
|
|
207
217
|
const owners = normalizeLowercaseList(options.owners);
|
|
208
218
|
const cases = normalizeLowercaseList(options.cases);
|
|
219
|
+
const skills = normalizeSkillList(options.skills);
|
|
209
220
|
const links = normalizeList(options.links);
|
|
210
221
|
const artifacts = normalizeList(options.artifacts);
|
|
222
|
+
if (skills.length > 0 && !node_1.WORK_TYPES.has(type)) {
|
|
223
|
+
throw new errors_1.UsageError("--skills is only valid for work items");
|
|
224
|
+
}
|
|
211
225
|
if (type === "dec" && options.supersedes) {
|
|
212
226
|
const supersedes = options.supersedes.toLowerCase();
|
|
213
227
|
if (!DEC_ID_RE.test(supersedes)) {
|
|
@@ -263,6 +277,7 @@ function runNewCommand(options) {
|
|
|
263
277
|
artifacts: artifacts.length > 0 ? artifacts : undefined,
|
|
264
278
|
refs: refs.length > 0 ? refs : undefined,
|
|
265
279
|
aliases: aliases.length > 0 ? aliases : undefined,
|
|
280
|
+
skills: skills.length > 0 ? skills : undefined,
|
|
266
281
|
cases: cases.length > 0 ? cases : undefined,
|
|
267
282
|
supersedes: options.supersedes ? options.supersedes.toLowerCase() : undefined,
|
|
268
283
|
created: today,
|
|
@@ -275,5 +290,15 @@ function runNewCommand(options) {
|
|
|
275
290
|
const outputPath = path_1.default.resolve(options.root, config.index.global_index_path);
|
|
276
291
|
(0, index_cache_1.writeIndex)(outputPath, updatedIndex);
|
|
277
292
|
}
|
|
293
|
+
(0, event_support_1.appendAutomaticEvent)({
|
|
294
|
+
root: options.root,
|
|
295
|
+
ws,
|
|
296
|
+
kind: "NODE_CREATED",
|
|
297
|
+
status: "ok",
|
|
298
|
+
refs: [id],
|
|
299
|
+
notes: `node created via mdkg new`,
|
|
300
|
+
runId: options.runId,
|
|
301
|
+
now: options.now,
|
|
302
|
+
});
|
|
278
303
|
console.log(`node created: ${ws}:${id} (${path_1.default.relative(options.root, filePath)})`);
|
|
279
304
|
}
|