mdkg 0.0.7 → 0.0.9
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/CHANGELOG.md +56 -0
- package/CONTRIBUTING.md +124 -0
- package/README.md +33 -10
- package/dist/cli.js +80 -32
- package/dist/commands/checkpoint.js +19 -2
- package/dist/commands/event.js +12 -0
- package/dist/commands/new.js +50 -4
- package/dist/commands/pack.js +14 -0
- package/dist/commands/query_output.js +2 -0
- package/dist/commands/search.js +8 -0
- package/dist/commands/show.js +7 -0
- package/dist/commands/skill.js +80 -12
- package/dist/commands/task.js +41 -4
- package/dist/commands/validate.js +31 -3
- package/dist/commands/workspace.js +105 -13
- package/dist/core/config.js +217 -22
- package/dist/core/migrate.js +39 -5
- package/dist/core/workspace_path.js +41 -0
- package/dist/graph/agent_file_types.js +392 -0
- package/dist/graph/edges.js +13 -10
- package/dist/graph/frontmatter.js +33 -0
- package/dist/graph/indexer.js +1 -0
- package/dist/graph/node.js +21 -5
- package/dist/graph/skills_indexer.js +14 -1
- package/dist/graph/validate_graph.js +302 -2
- package/dist/init/AGENT_START.md +13 -0
- package/dist/init/CLI_COMMAND_MATRIX.md +43 -1
- package/dist/init/README.md +7 -0
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +1 -1
- package/dist/init/templates/default/dispute.md +31 -0
- package/dist/init/templates/default/feedback.md +27 -0
- package/dist/init/templates/default/proposal.md +35 -0
- package/dist/init/templates/default/receipt.md +31 -0
- package/dist/init/templates/default/spec.md +43 -0
- package/dist/init/templates/default/work.md +44 -0
- package/dist/init/templates/default/work_order.md +32 -0
- package/dist/pack/export_json.js +3 -0
- package/dist/pack/export_md.js +9 -0
- package/dist/pack/export_xml.js +9 -0
- package/dist/pack/order.js +7 -0
- package/dist/pack/pack.js +1 -0
- package/dist/util/argparse.js +1 -0
- package/dist/util/id.js +19 -0
- package/package.json +9 -2
- package/scripts/postinstall.js +89 -0
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createCheckpoint = createCheckpoint;
|
|
6
7
|
exports.runCheckpointNewCommand = runCheckpointNewCommand;
|
|
7
8
|
const fs_1 = __importDefault(require("fs"));
|
|
8
9
|
const path_1 = __importDefault(require("path"));
|
|
@@ -76,7 +77,7 @@ function normalizeWorkspace(value) {
|
|
|
76
77
|
}
|
|
77
78
|
return normalized;
|
|
78
79
|
}
|
|
79
|
-
function
|
|
80
|
+
function createCheckpoint(options) {
|
|
80
81
|
const title = options.title.trim();
|
|
81
82
|
if (!title) {
|
|
82
83
|
throw new errors_1.UsageError("checkpoint title cannot be empty");
|
|
@@ -140,5 +141,21 @@ function runCheckpointNewCommand(options) {
|
|
|
140
141
|
runId: options.runId,
|
|
141
142
|
now,
|
|
142
143
|
});
|
|
143
|
-
|
|
144
|
+
return {
|
|
145
|
+
workspace: ws,
|
|
146
|
+
id,
|
|
147
|
+
qid: `${ws}:${id}`,
|
|
148
|
+
path: path_1.default.relative(options.root, filePath),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function runCheckpointNewCommand(options) {
|
|
152
|
+
const checkpoint = createCheckpoint(options);
|
|
153
|
+
if (options.json) {
|
|
154
|
+
console.log(JSON.stringify({
|
|
155
|
+
action: "created",
|
|
156
|
+
checkpoint,
|
|
157
|
+
}, null, 2));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
console.log(`checkpoint created: ${checkpoint.qid} (${checkpoint.path})`);
|
|
144
161
|
}
|
package/dist/commands/event.js
CHANGED
|
@@ -6,6 +6,14 @@ const event_support_1 = require("./event_support");
|
|
|
6
6
|
const errors_1 = require("../util/errors");
|
|
7
7
|
function runEventEnableCommand(options) {
|
|
8
8
|
const result = (0, event_support_1.ensureEventsEnabled)(options);
|
|
9
|
+
if (options.json) {
|
|
10
|
+
console.log(JSON.stringify({
|
|
11
|
+
action: "enabled",
|
|
12
|
+
workspace: result.ws,
|
|
13
|
+
created: result.created,
|
|
14
|
+
}, null, 2));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
9
17
|
const createdLabel = result.created ? "created" : "already present";
|
|
10
18
|
console.log(`event logging enabled: ${result.ws} (${createdLabel})`);
|
|
11
19
|
}
|
|
@@ -41,5 +49,9 @@ function runEventAppendCommand(options) {
|
|
|
41
49
|
skill: options.skill,
|
|
42
50
|
tool: options.tool,
|
|
43
51
|
});
|
|
52
|
+
if (options.json) {
|
|
53
|
+
console.log(JSON.stringify({ action: "appended", event: record }, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
44
56
|
console.log(`event appended: ${record.workspace}:${record.kind} (${record.run_id})`);
|
|
45
57
|
}
|
package/dist/commands/new.js
CHANGED
|
@@ -9,6 +9,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const config_1 = require("../core/config");
|
|
10
10
|
const index_cache_1 = require("../graph/index_cache");
|
|
11
11
|
const node_1 = require("../graph/node");
|
|
12
|
+
const agent_file_types_1 = require("../graph/agent_file_types");
|
|
12
13
|
const indexer_1 = require("../graph/indexer");
|
|
13
14
|
const loader_1 = require("../templates/loader");
|
|
14
15
|
const date_1 = require("../util/date");
|
|
@@ -44,6 +45,13 @@ function normalizeIdRef(value, key) {
|
|
|
44
45
|
}
|
|
45
46
|
return normalized;
|
|
46
47
|
}
|
|
48
|
+
function normalizeAgentFileId(value) {
|
|
49
|
+
const normalized = value.toLowerCase();
|
|
50
|
+
if (!(0, id_1.isPortableId)(normalized)) {
|
|
51
|
+
throw new errors_1.UsageError("--id must be a lowercase portable id for agent workflow file types");
|
|
52
|
+
}
|
|
53
|
+
return normalized;
|
|
54
|
+
}
|
|
47
55
|
function normalizeList(raw) {
|
|
48
56
|
return parseCsvList(raw);
|
|
49
57
|
}
|
|
@@ -110,6 +118,9 @@ function idPrefixForType(type) {
|
|
|
110
118
|
if (type === "checkpoint") {
|
|
111
119
|
return "chk";
|
|
112
120
|
}
|
|
121
|
+
if (type === "work_order") {
|
|
122
|
+
return "order";
|
|
123
|
+
}
|
|
113
124
|
return type;
|
|
114
125
|
}
|
|
115
126
|
function folderForType(type) {
|
|
@@ -122,8 +133,17 @@ function folderForType(type) {
|
|
|
122
133
|
if (node_1.WORK_TYPES.has(type)) {
|
|
123
134
|
return "work";
|
|
124
135
|
}
|
|
136
|
+
if ((0, agent_file_types_1.isAgentFileType)(type)) {
|
|
137
|
+
return "work";
|
|
138
|
+
}
|
|
125
139
|
throw new errors_1.UsageError(`unsupported type: ${type}`);
|
|
126
140
|
}
|
|
141
|
+
function fileNameForType(type, id, slug) {
|
|
142
|
+
if ((0, agent_file_types_1.isAgentFileType)(type)) {
|
|
143
|
+
return path_1.default.join(`${id}-${slug}`, agent_file_types_1.AGENT_FILE_BASENAMES[type]);
|
|
144
|
+
}
|
|
145
|
+
return `${id}-${slug}.md`;
|
|
146
|
+
}
|
|
127
147
|
function ensureExists(index, value, ws, label) {
|
|
128
148
|
const resolved = (0, qid_1.resolveQid)(index, value, ws);
|
|
129
149
|
if (resolved.status !== "ok") {
|
|
@@ -152,10 +172,18 @@ function runNewCommand(options) {
|
|
|
152
172
|
useCache: !noCache,
|
|
153
173
|
allowReindex: !noReindex,
|
|
154
174
|
});
|
|
175
|
+
if (options.id !== undefined && !(0, agent_file_types_1.isAgentFileType)(type)) {
|
|
176
|
+
throw new errors_1.UsageError("--id is only valid for agent workflow file types");
|
|
177
|
+
}
|
|
155
178
|
const prefix = idPrefixForType(type);
|
|
156
|
-
const id =
|
|
179
|
+
const id = options.id !== undefined
|
|
180
|
+
? normalizeAgentFileId(options.id)
|
|
181
|
+
: nextIdForPrefix(index.nodes, ws, prefix);
|
|
182
|
+
if (index.nodes[`${ws}:${id}`]) {
|
|
183
|
+
throw new errors_1.UsageError(`node already exists: ${ws}:${id}`);
|
|
184
|
+
}
|
|
157
185
|
const slug = slugifyTitle(title);
|
|
158
|
-
const fileName =
|
|
186
|
+
const fileName = fileNameForType(type, id, slug);
|
|
159
187
|
const wsEntry = config.workspaces[ws];
|
|
160
188
|
const folder = folderForType(type);
|
|
161
189
|
const targetDir = path_1.default.resolve(options.root, wsEntry.path, wsEntry.mdkg_dir, folder);
|
|
@@ -283,7 +311,7 @@ function runNewCommand(options) {
|
|
|
283
311
|
created: today,
|
|
284
312
|
updated: today,
|
|
285
313
|
});
|
|
286
|
-
fs_1.default.mkdirSync(
|
|
314
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
287
315
|
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
288
316
|
if (config.index.auto_reindex && !noReindex) {
|
|
289
317
|
const updatedIndex = (0, indexer_1.buildIndex)(options.root, config, { tolerant: config.index.tolerant });
|
|
@@ -300,5 +328,23 @@ function runNewCommand(options) {
|
|
|
300
328
|
runId: options.runId,
|
|
301
329
|
now: options.now,
|
|
302
330
|
});
|
|
303
|
-
|
|
331
|
+
const relativePath = path_1.default.relative(options.root, filePath);
|
|
332
|
+
const receipt = {
|
|
333
|
+
workspace: ws,
|
|
334
|
+
id,
|
|
335
|
+
qid: `${ws}:${id}`,
|
|
336
|
+
path: relativePath,
|
|
337
|
+
type,
|
|
338
|
+
title,
|
|
339
|
+
...(status ? { status } : {}),
|
|
340
|
+
...(priority !== undefined ? { priority } : {}),
|
|
341
|
+
};
|
|
342
|
+
if (options.json) {
|
|
343
|
+
console.log(JSON.stringify({
|
|
344
|
+
action: "created",
|
|
345
|
+
node: receipt,
|
|
346
|
+
}, null, 2));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
console.log(`node created: ${receipt.qid} (${receipt.path})`);
|
|
304
350
|
}
|
package/dist/commands/pack.js
CHANGED
|
@@ -106,6 +106,19 @@ function renderSkillMetaBody(skill) {
|
|
|
106
106
|
}
|
|
107
107
|
lines.push(`has_scripts: ${skill.has_scripts ? "true" : "false"}`);
|
|
108
108
|
lines.push(`has_references: ${skill.has_references ? "true" : "false"}`);
|
|
109
|
+
for (const [namespace, values] of Object.entries(skill.extensions).sort(([a], [b]) => a.localeCompare(b))) {
|
|
110
|
+
for (const [key, value] of Object.entries(values).sort(([a], [b]) => a.localeCompare(b))) {
|
|
111
|
+
if (Array.isArray(value)) {
|
|
112
|
+
lines.push(`extensions.${namespace}.${key}: ${value.join(", ")}`);
|
|
113
|
+
}
|
|
114
|
+
else if (typeof value === "boolean") {
|
|
115
|
+
lines.push(`extensions.${namespace}.${key}: ${value ? "true" : "false"}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
lines.push(`extensions.${namespace}.${key}: ${value}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
109
122
|
for (const [key, value] of Object.entries(skill.ochatr).sort(([a], [b]) => a.localeCompare(b))) {
|
|
110
123
|
if (Array.isArray(value)) {
|
|
111
124
|
lines.push(`${key}: ${value.join(", ")}`);
|
|
@@ -170,6 +183,7 @@ function appendSkillsToPack(pack, skillEntries, depth, root) {
|
|
|
170
183
|
artifacts: [],
|
|
171
184
|
refs: [],
|
|
172
185
|
aliases: [skill.slug, ...skill.tags],
|
|
186
|
+
attributes: {},
|
|
173
187
|
body: depth === "full" ? loadSkillFullBody(root, skill) : renderSkillMetaBody(skill),
|
|
174
188
|
}));
|
|
175
189
|
if (newNodes.length === 0) {
|
|
@@ -25,6 +25,7 @@ function toNodeSummaryJson(node) {
|
|
|
25
25
|
refs: [...node.refs],
|
|
26
26
|
aliases: [...node.aliases],
|
|
27
27
|
skills: [...node.skills],
|
|
28
|
+
attributes: { ...(node.attributes ?? {}) },
|
|
28
29
|
path: node.path,
|
|
29
30
|
edges: {
|
|
30
31
|
epic: node.edges.epic,
|
|
@@ -62,6 +63,7 @@ function toSkillSummaryJson(skill) {
|
|
|
62
63
|
path: skill.path,
|
|
63
64
|
has_scripts: skill.has_scripts,
|
|
64
65
|
has_references: skill.has_references,
|
|
66
|
+
extensions: JSON.parse(JSON.stringify(skill.extensions)),
|
|
65
67
|
ochatr: { ...skill.ochatr },
|
|
66
68
|
};
|
|
67
69
|
}
|
package/dist/commands/search.js
CHANGED
|
@@ -15,9 +15,16 @@ function normalizeWorkspace(value) {
|
|
|
15
15
|
return value;
|
|
16
16
|
}
|
|
17
17
|
function buildSearchText(node) {
|
|
18
|
+
const attributeTokens = Object.entries(node.attributes ?? {}).flatMap(([key, value]) => {
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
return [key, ...value];
|
|
21
|
+
}
|
|
22
|
+
return [key, String(value)];
|
|
23
|
+
});
|
|
18
24
|
const tokens = [
|
|
19
25
|
node.id,
|
|
20
26
|
node.qid,
|
|
27
|
+
node.type,
|
|
21
28
|
node.title,
|
|
22
29
|
node.path,
|
|
23
30
|
...node.tags,
|
|
@@ -27,6 +34,7 @@ function buildSearchText(node) {
|
|
|
27
34
|
...node.refs,
|
|
28
35
|
...node.aliases,
|
|
29
36
|
...node.skills,
|
|
37
|
+
...attributeTokens,
|
|
30
38
|
];
|
|
31
39
|
return tokens.join(" ").toLowerCase();
|
|
32
40
|
}
|
package/dist/commands/show.js
CHANGED
|
@@ -25,6 +25,12 @@ function maybeLine(label, values) {
|
|
|
25
25
|
}
|
|
26
26
|
return `${label}: ${values.join(", ")}`;
|
|
27
27
|
}
|
|
28
|
+
function formatAttributeLine(key, value) {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return `${key}: ${value.join(", ")}`;
|
|
31
|
+
}
|
|
32
|
+
return `${key}: ${String(value)}`;
|
|
33
|
+
}
|
|
28
34
|
function runShowCommand(options) {
|
|
29
35
|
const config = (0, config_1.loadConfig)(options.root);
|
|
30
36
|
const ws = normalizeWorkspace(options.ws);
|
|
@@ -79,6 +85,7 @@ function runShowCommand(options) {
|
|
|
79
85
|
maybeLine("skills", node.skills),
|
|
80
86
|
].filter((line) => Boolean(line));
|
|
81
87
|
lines.push(...metaLines);
|
|
88
|
+
lines.push(...Object.entries(node.attributes ?? {}).map(([key, value]) => formatAttributeLine(key, value)));
|
|
82
89
|
if (node.edges.epic) {
|
|
83
90
|
lines.push(`epic: ${node.edges.epic}`);
|
|
84
91
|
}
|
package/dist/commands/skill.js
CHANGED
|
@@ -99,6 +99,16 @@ function filterSkills(skills, tags, tagsMode = "any") {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
function buildSkillSearchText(skill) {
|
|
102
|
+
const extensionTokens = Object.entries(skill.extensions).flatMap(([namespace, values]) => Object.entries(values).flatMap(([key, value]) => {
|
|
103
|
+
const field = `extensions.${namespace}.${key}`;
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
return [field, ...value];
|
|
106
|
+
}
|
|
107
|
+
if (typeof value === "boolean") {
|
|
108
|
+
return [field, value ? "true" : "false"];
|
|
109
|
+
}
|
|
110
|
+
return [field, value];
|
|
111
|
+
}));
|
|
102
112
|
const ochatrTokens = Object.entries(skill.ochatr).flatMap(([key, value]) => {
|
|
103
113
|
if (Array.isArray(value)) {
|
|
104
114
|
return [key, ...value];
|
|
@@ -118,6 +128,7 @@ function buildSkillSearchText(skill) {
|
|
|
118
128
|
...skill.tags,
|
|
119
129
|
...skill.authors,
|
|
120
130
|
...skill.links,
|
|
131
|
+
...extensionTokens,
|
|
121
132
|
...ochatrTokens,
|
|
122
133
|
];
|
|
123
134
|
return tokens.join(" ").toLowerCase();
|
|
@@ -191,7 +202,23 @@ function runSkillNewCommand(options) {
|
|
|
191
202
|
skill: slug,
|
|
192
203
|
now: options.now,
|
|
193
204
|
});
|
|
194
|
-
|
|
205
|
+
const receipt = {
|
|
206
|
+
workspace: "root",
|
|
207
|
+
id: `skill:${slug}`,
|
|
208
|
+
qid: `root:skill:${slug}`,
|
|
209
|
+
slug,
|
|
210
|
+
name,
|
|
211
|
+
path: path_1.default.relative(root, canonicalPath),
|
|
212
|
+
with_scripts: Boolean(options.withScripts),
|
|
213
|
+
};
|
|
214
|
+
if (options.json) {
|
|
215
|
+
console.log(JSON.stringify({
|
|
216
|
+
action: "created",
|
|
217
|
+
skill: receipt,
|
|
218
|
+
}, null, 2));
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
console.log(`skill created: ${receipt.qid} (${receipt.path})`);
|
|
195
222
|
}
|
|
196
223
|
function runSkillListCommand(options) {
|
|
197
224
|
const config = (0, config_1.loadConfig)(options.root);
|
|
@@ -274,6 +301,19 @@ function runSkillShowCommand(options) {
|
|
|
274
301
|
}
|
|
275
302
|
lines.push(`has_scripts: ${skill.has_scripts ? "true" : "false"}`);
|
|
276
303
|
lines.push(`has_references: ${skill.has_references ? "true" : "false"}`);
|
|
304
|
+
for (const [namespace, values] of Object.entries(skill.extensions).sort(([a], [b]) => a.localeCompare(b))) {
|
|
305
|
+
for (const [key, value] of Object.entries(values).sort(([a], [b]) => a.localeCompare(b))) {
|
|
306
|
+
if (Array.isArray(value)) {
|
|
307
|
+
lines.push(`extensions.${namespace}.${key}: ${value.join(", ")}`);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (typeof value === "boolean") {
|
|
311
|
+
lines.push(`extensions.${namespace}.${key}: ${value ? "true" : "false"}`);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
lines.push(`extensions.${namespace}.${key}: ${value}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
277
317
|
for (const [key, value] of Object.entries(skill.ochatr).sort(([a], [b]) => a.localeCompare(b))) {
|
|
278
318
|
if (Array.isArray(value)) {
|
|
279
319
|
lines.push(`${key}: ${value.join(", ")}`);
|
|
@@ -329,8 +369,11 @@ function runSkillValidateCommand(options) {
|
|
|
329
369
|
const targetSlug = options.slug?.trim().toLowerCase();
|
|
330
370
|
const warnings = [];
|
|
331
371
|
const errors = [];
|
|
372
|
+
let checkedCount = 0;
|
|
332
373
|
if (targetSlug) {
|
|
333
|
-
const
|
|
374
|
+
const normalizedSlug = normalizeSlug(targetSlug);
|
|
375
|
+
const result = validateSingleSkill(options.root, normalizedSlug);
|
|
376
|
+
checkedCount = 1;
|
|
334
377
|
warnings.push(...result.warnings);
|
|
335
378
|
errors.push(...result.errors);
|
|
336
379
|
}
|
|
@@ -338,31 +381,49 @@ function runSkillValidateCommand(options) {
|
|
|
338
381
|
const skillsRoot = (0, skills_indexer_1.resolveSkillsRoot)(options.root, config);
|
|
339
382
|
if (fs_1.default.existsSync(skillsRoot)) {
|
|
340
383
|
const entries = fs_1.default.readdirSync(skillsRoot, { withFileTypes: true });
|
|
341
|
-
|
|
384
|
+
const skillDirs = entries
|
|
385
|
+
.filter((value) => value.isDirectory())
|
|
386
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
387
|
+
checkedCount = skillDirs.length;
|
|
388
|
+
for (const entry of skillDirs) {
|
|
342
389
|
const result = validateSingleSkill(options.root, entry.name.toLowerCase());
|
|
343
390
|
warnings.push(...result.warnings);
|
|
344
391
|
errors.push(...result.errors);
|
|
345
392
|
}
|
|
346
393
|
}
|
|
347
394
|
}
|
|
348
|
-
|
|
395
|
+
const uniqueWarnings = Array.from(new Set(warnings));
|
|
396
|
+
const uniqueErrors = Array.from(new Set(errors));
|
|
397
|
+
const receipt = {
|
|
398
|
+
action: "validated",
|
|
399
|
+
ok: uniqueErrors.length === 0,
|
|
400
|
+
checked_count: checkedCount,
|
|
401
|
+
warning_count: uniqueWarnings.length,
|
|
402
|
+
error_count: uniqueErrors.length,
|
|
403
|
+
warnings: uniqueWarnings,
|
|
404
|
+
errors: uniqueErrors,
|
|
405
|
+
...(targetSlug ? { target: normalizeSlug(targetSlug) } : {}),
|
|
406
|
+
};
|
|
407
|
+
if (options.json) {
|
|
408
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
409
|
+
if (uniqueErrors.length > 0) {
|
|
410
|
+
throw new errors_1.ValidationError(`skill validation failed with ${uniqueErrors.length} error(s)`);
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
for (const warning of uniqueWarnings) {
|
|
349
415
|
console.error(`warning: ${warning}`);
|
|
350
416
|
}
|
|
351
|
-
if (
|
|
352
|
-
for (const error of
|
|
417
|
+
if (uniqueErrors.length > 0) {
|
|
418
|
+
for (const error of uniqueErrors) {
|
|
353
419
|
console.error(error);
|
|
354
420
|
}
|
|
355
|
-
throw new errors_1.ValidationError(`skill validation failed with ${
|
|
421
|
+
throw new errors_1.ValidationError(`skill validation failed with ${uniqueErrors.length} error(s)`);
|
|
356
422
|
}
|
|
357
423
|
if (targetSlug) {
|
|
358
424
|
console.log(`skill validation ok: ${targetSlug} (1 skill checked)`);
|
|
359
425
|
return;
|
|
360
426
|
}
|
|
361
|
-
const checkedCount = fs_1.default.existsSync((0, skills_indexer_1.resolveSkillsRoot)(options.root, config))
|
|
362
|
-
? fs_1.default
|
|
363
|
-
.readdirSync((0, skills_indexer_1.resolveSkillsRoot)(options.root, config), { withFileTypes: true })
|
|
364
|
-
.filter((value) => value.isDirectory()).length
|
|
365
|
-
: 0;
|
|
366
427
|
console.log(`skill validation ok: ${checkedCount} skill${checkedCount === 1 ? "" : "s"} checked`);
|
|
367
428
|
}
|
|
368
429
|
function runSkillSyncCommand(options) {
|
|
@@ -373,5 +434,12 @@ function runSkillSyncCommand(options) {
|
|
|
373
434
|
createRoots: true,
|
|
374
435
|
force: options.force,
|
|
375
436
|
});
|
|
437
|
+
if (options.json) {
|
|
438
|
+
console.log(JSON.stringify({
|
|
439
|
+
action: "synced",
|
|
440
|
+
sync: result,
|
|
441
|
+
}, null, 2));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
376
444
|
console.log(`skill mirror sync ok: ${result.synced} synced, ${result.pruned} pruned across ${result.targets} target${result.targets === 1 ? "" : "s"}`);
|
|
377
445
|
}
|
package/dist/commands/task.js
CHANGED
|
@@ -175,6 +175,30 @@ function maybeWarnEventsDisabled(root, config, ws) {
|
|
|
175
175
|
}
|
|
176
176
|
console.error(`note: events.jsonl is missing for workspace ${ws}; run mdkg event enable --ws ${ws} to restore JSONL provenance`);
|
|
177
177
|
}
|
|
178
|
+
function taskReceipt(root, loaded) {
|
|
179
|
+
const rawPriority = loaded.frontmatter.priority;
|
|
180
|
+
const priority = rawPriority === undefined ? undefined : Number.parseInt(String(rawPriority), 10);
|
|
181
|
+
return {
|
|
182
|
+
workspace: loaded.ws,
|
|
183
|
+
id: loaded.id,
|
|
184
|
+
qid: loaded.qid,
|
|
185
|
+
path: path_1.default.relative(root, loaded.filePath),
|
|
186
|
+
type: loaded.type,
|
|
187
|
+
status: String(loaded.frontmatter.status ?? ""),
|
|
188
|
+
...(Number.isInteger(priority) ? { priority } : {}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function printTaskMutationReceipt(action, root, loaded, json, checkpoint) {
|
|
192
|
+
if (json) {
|
|
193
|
+
console.log(JSON.stringify({
|
|
194
|
+
action,
|
|
195
|
+
task: taskReceipt(root, loaded),
|
|
196
|
+
...(checkpoint ? { checkpoint } : {}),
|
|
197
|
+
}, null, 2));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
console.log(`task ${action}: ${loaded.qid}`);
|
|
201
|
+
}
|
|
178
202
|
function runTaskStartCommand(options) {
|
|
179
203
|
const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
|
|
180
204
|
const now = options.now ?? new Date();
|
|
@@ -193,7 +217,7 @@ function runTaskStartCommand(options) {
|
|
|
193
217
|
now,
|
|
194
218
|
});
|
|
195
219
|
maybeWarnEventsDisabled(options.root, loaded.config, loaded.ws);
|
|
196
|
-
|
|
220
|
+
printTaskMutationReceipt("started", options.root, loaded, options.json);
|
|
197
221
|
}
|
|
198
222
|
function runTaskUpdateCommand(options) {
|
|
199
223
|
const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
|
|
@@ -235,7 +259,7 @@ function runTaskUpdateCommand(options) {
|
|
|
235
259
|
runId: options.runId,
|
|
236
260
|
now,
|
|
237
261
|
});
|
|
238
|
-
|
|
262
|
+
printTaskMutationReceipt("updated", options.root, loaded, options.json);
|
|
239
263
|
}
|
|
240
264
|
function runTaskDoneCommand(options) {
|
|
241
265
|
const loaded = loadMutableTaskNode(options.root, options.id, options.ws);
|
|
@@ -260,7 +284,20 @@ function runTaskDoneCommand(options) {
|
|
|
260
284
|
runId: options.runId,
|
|
261
285
|
now,
|
|
262
286
|
});
|
|
263
|
-
|
|
287
|
+
let checkpoint;
|
|
288
|
+
if (options.checkpoint && options.json) {
|
|
289
|
+
checkpoint = (0, checkpoint_1.createCheckpoint)({
|
|
290
|
+
root: options.root,
|
|
291
|
+
title: options.checkpoint,
|
|
292
|
+
ws: loaded.ws,
|
|
293
|
+
relates: loaded.id,
|
|
294
|
+
scope: loaded.id,
|
|
295
|
+
runId: options.runId,
|
|
296
|
+
note: `checkpoint created from mdkg task done for ${loaded.id}`,
|
|
297
|
+
now,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
else if (options.checkpoint) {
|
|
264
301
|
(0, checkpoint_1.runCheckpointNewCommand)({
|
|
265
302
|
root: options.root,
|
|
266
303
|
title: options.checkpoint,
|
|
@@ -274,5 +311,5 @@ function runTaskDoneCommand(options) {
|
|
|
274
311
|
}
|
|
275
312
|
maybeReindex(options.root, loaded.config);
|
|
276
313
|
maybeWarnEventsDisabled(options.root, loaded.config, loaded.ws);
|
|
277
|
-
|
|
314
|
+
printTaskMutationReceipt("done", options.root, loaded, options.json, checkpoint);
|
|
278
315
|
}
|
|
@@ -65,6 +65,13 @@ const RECOMMENDED_HEADINGS = {
|
|
|
65
65
|
"Rollout plan",
|
|
66
66
|
],
|
|
67
67
|
dec: ["Context", "Decision", "Alternatives considered", "Consequences", "Links / references"],
|
|
68
|
+
spec: ["Purpose", "Runtime", "Work Contracts", "Capabilities"],
|
|
69
|
+
work: ["Capability", "Inputs", "Outputs", "Receipt"],
|
|
70
|
+
work_order: ["Request", "Inputs", "Constraints"],
|
|
71
|
+
receipt: ["Outcome", "Artifacts", "Notes"],
|
|
72
|
+
feedback: ["Feedback", "Evidence"],
|
|
73
|
+
dispute: ["Dispute", "Evidence", "Resolution"],
|
|
74
|
+
proposal: ["Summary", "Evidence", "Proposed Change", "Review"],
|
|
68
75
|
};
|
|
69
76
|
function normalizeHeading(value) {
|
|
70
77
|
return value.trim().toLowerCase();
|
|
@@ -119,6 +126,7 @@ function buildIndexNode(root, ws, filePath, node) {
|
|
|
119
126
|
refs: node.refs,
|
|
120
127
|
aliases: node.aliases,
|
|
121
128
|
skills: node.skills,
|
|
129
|
+
attributes: node.attributes,
|
|
122
130
|
path: path_1.default.relative(root, filePath),
|
|
123
131
|
edges: normalizeEdges(node.edges, ws),
|
|
124
132
|
};
|
|
@@ -256,11 +264,10 @@ function runValidateCommand(options) {
|
|
|
256
264
|
nodes,
|
|
257
265
|
reverse_edges: {},
|
|
258
266
|
};
|
|
259
|
-
|
|
260
|
-
errors.push(...graphErrors);
|
|
267
|
+
let knownSkills = new Set();
|
|
261
268
|
try {
|
|
262
269
|
const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
|
|
263
|
-
|
|
270
|
+
knownSkills = new Set(Object.keys(skillsIndex.skills));
|
|
264
271
|
for (const node of Object.values(nodes)) {
|
|
265
272
|
for (const slug of node.skills) {
|
|
266
273
|
if (!knownSkills.has(slug)) {
|
|
@@ -273,6 +280,11 @@ function runValidateCommand(options) {
|
|
|
273
280
|
const message = err instanceof Error ? err.message : "unknown skill validation error";
|
|
274
281
|
errors.push(message);
|
|
275
282
|
}
|
|
283
|
+
const graphErrors = (0, validate_graph_1.collectGraphErrors)(index, {
|
|
284
|
+
allowMissing: false,
|
|
285
|
+
knownSkillSlugs: knownSkills,
|
|
286
|
+
});
|
|
287
|
+
errors.push(...graphErrors);
|
|
276
288
|
const skillsRoot = (0, skills_indexer_1.resolveSkillsRoot)(options.root, config);
|
|
277
289
|
for (const dirPath of listDirectories(skillsRoot)) {
|
|
278
290
|
const canonicalPath = path_1.default.join(dirPath, "SKILL.md");
|
|
@@ -305,6 +317,22 @@ function runValidateCommand(options) {
|
|
|
305
317
|
fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
|
|
306
318
|
fs_1.default.writeFileSync(outPath, reportLines.join("\n"), "utf8");
|
|
307
319
|
}
|
|
320
|
+
const receipt = {
|
|
321
|
+
action: "validated",
|
|
322
|
+
ok: uniqueErrors.length === 0,
|
|
323
|
+
warning_count: uniqueWarnings.length,
|
|
324
|
+
error_count: uniqueErrors.length,
|
|
325
|
+
warnings: uniqueWarnings,
|
|
326
|
+
errors: uniqueErrors,
|
|
327
|
+
...(outPath ? { report_path: outPath } : {}),
|
|
328
|
+
};
|
|
329
|
+
if (options.json) {
|
|
330
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
331
|
+
if (uniqueErrors.length > 0) {
|
|
332
|
+
throw new errors_1.ValidationError(`validation failed with ${uniqueErrors.length} error(s)`);
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
308
336
|
if (!options.quiet) {
|
|
309
337
|
for (const warning of uniqueWarnings) {
|
|
310
338
|
console.error(`warning: ${warning}`);
|