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
|
@@ -0,0 +1,392 @@
|
|
|
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.AGENT_ATTRIBUTE_KEY_ORDER = exports.AGENT_FILE_BASENAMES = exports.AGENT_FILE_TYPES = void 0;
|
|
7
|
+
exports.isAgentFileType = isAgentFileType;
|
|
8
|
+
exports.validateAgentFileName = validateAgentFileName;
|
|
9
|
+
exports.validateAgentFrontmatter = validateAgentFrontmatter;
|
|
10
|
+
exports.extractAgentAttributes = extractAgentAttributes;
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const id_1 = require("../util/id");
|
|
13
|
+
exports.AGENT_FILE_TYPES = [
|
|
14
|
+
"spec",
|
|
15
|
+
"work",
|
|
16
|
+
"work_order",
|
|
17
|
+
"receipt",
|
|
18
|
+
"feedback",
|
|
19
|
+
"dispute",
|
|
20
|
+
"proposal",
|
|
21
|
+
];
|
|
22
|
+
exports.AGENT_FILE_BASENAMES = {
|
|
23
|
+
spec: "SPEC.md",
|
|
24
|
+
work: "WORK.md",
|
|
25
|
+
work_order: "WORK_ORDER.md",
|
|
26
|
+
receipt: "RECEIPT.md",
|
|
27
|
+
feedback: "FEEDBACK.md",
|
|
28
|
+
dispute: "DISPUTE.md",
|
|
29
|
+
proposal: "PROPOSAL.md",
|
|
30
|
+
};
|
|
31
|
+
exports.AGENT_ATTRIBUTE_KEY_ORDER = {
|
|
32
|
+
spec: [
|
|
33
|
+
"version",
|
|
34
|
+
"role",
|
|
35
|
+
"runtime_mode",
|
|
36
|
+
"work_contracts",
|
|
37
|
+
"requested_capabilities",
|
|
38
|
+
"skill_refs",
|
|
39
|
+
"tool_refs",
|
|
40
|
+
"model_refs",
|
|
41
|
+
"wasm_component_refs",
|
|
42
|
+
"runtime_image_refs",
|
|
43
|
+
"subagent_refs",
|
|
44
|
+
"resource_profile",
|
|
45
|
+
"update_policy",
|
|
46
|
+
],
|
|
47
|
+
work: [
|
|
48
|
+
"version",
|
|
49
|
+
"agent_id",
|
|
50
|
+
"kind",
|
|
51
|
+
"pricing_model",
|
|
52
|
+
"required_capabilities",
|
|
53
|
+
"skill_refs",
|
|
54
|
+
"tool_refs",
|
|
55
|
+
"model_refs",
|
|
56
|
+
"wasm_component_refs",
|
|
57
|
+
"runtime_image_refs",
|
|
58
|
+
"subagent_refs",
|
|
59
|
+
"inputs",
|
|
60
|
+
"outputs",
|
|
61
|
+
"receipt_required",
|
|
62
|
+
],
|
|
63
|
+
work_order: [
|
|
64
|
+
"version",
|
|
65
|
+
"work_id",
|
|
66
|
+
"work_version",
|
|
67
|
+
"requester",
|
|
68
|
+
"order_status",
|
|
69
|
+
"request_ref",
|
|
70
|
+
],
|
|
71
|
+
receipt: [
|
|
72
|
+
"version",
|
|
73
|
+
"work_order_id",
|
|
74
|
+
"receipt_status",
|
|
75
|
+
"outcome",
|
|
76
|
+
"cost_ref",
|
|
77
|
+
],
|
|
78
|
+
feedback: [
|
|
79
|
+
"version",
|
|
80
|
+
"target_id",
|
|
81
|
+
"sentiment",
|
|
82
|
+
"feedback_status",
|
|
83
|
+
"source_ref",
|
|
84
|
+
],
|
|
85
|
+
dispute: [
|
|
86
|
+
"version",
|
|
87
|
+
"work_order_id",
|
|
88
|
+
"receipt_id",
|
|
89
|
+
"dispute_status",
|
|
90
|
+
"severity",
|
|
91
|
+
],
|
|
92
|
+
proposal: [
|
|
93
|
+
"version",
|
|
94
|
+
"target_id",
|
|
95
|
+
"proposal_status",
|
|
96
|
+
"proposal_kind",
|
|
97
|
+
"evidence_refs",
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][a-z0-9.-]+)?$/;
|
|
101
|
+
const LOWER_TOKEN_RE = /^[a-z][a-z0-9_]*(?:-[a-z0-9_]+)*$/;
|
|
102
|
+
const FIELD_DESCRIPTOR_RE = /^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*(?::(?:required|optional))?$/;
|
|
103
|
+
const ROLE_VALUES = new Set([
|
|
104
|
+
"orchestrator",
|
|
105
|
+
"subagent",
|
|
106
|
+
"standalone_agent",
|
|
107
|
+
"tool_service",
|
|
108
|
+
"remote_agent",
|
|
109
|
+
]);
|
|
110
|
+
const RUNTIME_MODE_VALUES = new Set([
|
|
111
|
+
"room_orchestrated",
|
|
112
|
+
"standalone",
|
|
113
|
+
"tool_service",
|
|
114
|
+
"remote",
|
|
115
|
+
]);
|
|
116
|
+
const UPDATE_POLICY_VALUES = new Set([
|
|
117
|
+
"manual",
|
|
118
|
+
"proposal_required",
|
|
119
|
+
"automatic",
|
|
120
|
+
"disabled",
|
|
121
|
+
]);
|
|
122
|
+
const PRICING_MODEL_VALUES = new Set([
|
|
123
|
+
"free",
|
|
124
|
+
"included",
|
|
125
|
+
"quoted",
|
|
126
|
+
"fixed",
|
|
127
|
+
"metered",
|
|
128
|
+
"subscription",
|
|
129
|
+
]);
|
|
130
|
+
const ORDER_STATUS_VALUES = new Set([
|
|
131
|
+
"submitted",
|
|
132
|
+
"accepted",
|
|
133
|
+
"running",
|
|
134
|
+
"completed",
|
|
135
|
+
"cancelled",
|
|
136
|
+
"failed",
|
|
137
|
+
]);
|
|
138
|
+
const RECEIPT_STATUS_VALUES = new Set(["recorded", "verified", "rejected"]);
|
|
139
|
+
const OUTCOME_VALUES = new Set(["success", "partial", "failure"]);
|
|
140
|
+
const SENTIMENT_VALUES = new Set(["positive", "neutral", "negative", "mixed"]);
|
|
141
|
+
const FEEDBACK_STATUS_VALUES = new Set(["new", "triaged", "accepted", "rejected"]);
|
|
142
|
+
const DISPUTE_STATUS_VALUES = new Set(["open", "investigating", "resolved", "rejected"]);
|
|
143
|
+
const SEVERITY_VALUES = new Set(["low", "medium", "high", "critical"]);
|
|
144
|
+
const PROPOSAL_STATUS_VALUES = new Set([
|
|
145
|
+
"proposed",
|
|
146
|
+
"accepted",
|
|
147
|
+
"rejected",
|
|
148
|
+
"superseded",
|
|
149
|
+
"implemented",
|
|
150
|
+
]);
|
|
151
|
+
const PROPOSAL_KIND_VALUES = new Set([
|
|
152
|
+
"spec_update",
|
|
153
|
+
"work_update",
|
|
154
|
+
"skill_update",
|
|
155
|
+
"policy_update",
|
|
156
|
+
"documentation",
|
|
157
|
+
]);
|
|
158
|
+
function formatError(filePath, message) {
|
|
159
|
+
return new Error(`${filePath}: ${message}`);
|
|
160
|
+
}
|
|
161
|
+
function isAgentFileType(type) {
|
|
162
|
+
return exports.AGENT_FILE_TYPES.includes(type);
|
|
163
|
+
}
|
|
164
|
+
function validateAgentFileName(type, filePath) {
|
|
165
|
+
const expected = exports.AGENT_FILE_BASENAMES[type];
|
|
166
|
+
if (path_1.default.basename(filePath) !== expected) {
|
|
167
|
+
throw formatError(filePath, `${type} files must be named ${expected}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function expectString(frontmatter, key, filePath) {
|
|
171
|
+
const value = frontmatter[key];
|
|
172
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
173
|
+
throw formatError(filePath, `${key} is required and must be a non-empty string`);
|
|
174
|
+
}
|
|
175
|
+
if (value !== value.toLowerCase()) {
|
|
176
|
+
throw formatError(filePath, `${key} must be lowercase`);
|
|
177
|
+
}
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
function optionalString(frontmatter, key, filePath) {
|
|
181
|
+
const value = frontmatter[key];
|
|
182
|
+
if (value === undefined) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
186
|
+
throw formatError(filePath, `${key} must be a non-empty string`);
|
|
187
|
+
}
|
|
188
|
+
if (value !== value.toLowerCase()) {
|
|
189
|
+
throw formatError(filePath, `${key} must be lowercase`);
|
|
190
|
+
}
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
function expectBoolean(frontmatter, key, filePath) {
|
|
194
|
+
const value = frontmatter[key];
|
|
195
|
+
if (typeof value !== "boolean") {
|
|
196
|
+
throw formatError(filePath, `${key} is required and must be a boolean`);
|
|
197
|
+
}
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
function expectList(frontmatter, key, filePath) {
|
|
201
|
+
const value = frontmatter[key];
|
|
202
|
+
if (!Array.isArray(value)) {
|
|
203
|
+
throw formatError(filePath, `${key} is required and must be a list`);
|
|
204
|
+
}
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
function optionalList(frontmatter, key, filePath) {
|
|
208
|
+
const value = frontmatter[key];
|
|
209
|
+
if (value === undefined) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
if (!Array.isArray(value)) {
|
|
213
|
+
throw formatError(filePath, `${key} must be a list`);
|
|
214
|
+
}
|
|
215
|
+
return value;
|
|
216
|
+
}
|
|
217
|
+
function requirePortableId(value, key, filePath) {
|
|
218
|
+
if (!(0, id_1.isPortableId)(value)) {
|
|
219
|
+
throw formatError(filePath, `${key} must be a lowercase portable id`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function requireSemver(value, key, filePath) {
|
|
223
|
+
if (!SEMVER_RE.test(value)) {
|
|
224
|
+
throw formatError(filePath, `${key} must be a semantic version like 1.0.0`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function requireEnum(value, key, allowed, filePath) {
|
|
228
|
+
if (!allowed.has(value)) {
|
|
229
|
+
throw formatError(filePath, `${key} must be one of ${Array.from(allowed).join(", ")}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function requireLowerToken(value, key, filePath) {
|
|
233
|
+
if (!LOWER_TOKEN_RE.test(value)) {
|
|
234
|
+
throw formatError(filePath, `${key} must be lowercase snake/kebab style`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function validateCapabilities(values, key, filePath) {
|
|
238
|
+
for (const [index, value] of values.entries()) {
|
|
239
|
+
if (value !== value.toLowerCase()) {
|
|
240
|
+
throw formatError(filePath, `${key}[${index}] must be lowercase`);
|
|
241
|
+
}
|
|
242
|
+
if (!(0, id_1.isPortableId)(value)) {
|
|
243
|
+
throw formatError(filePath, `${key}[${index}] must be a portable capability id`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function validatePortableRefs(values, key, filePath) {
|
|
248
|
+
for (const [index, value] of values.entries()) {
|
|
249
|
+
if (value !== value.toLowerCase()) {
|
|
250
|
+
throw formatError(filePath, `${key}[${index}] must be lowercase`);
|
|
251
|
+
}
|
|
252
|
+
if (!(0, id_1.isPortableId)(value)) {
|
|
253
|
+
throw formatError(filePath, `${key}[${index}] must be a lowercase portable id`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function validateRelativeMarkdownPaths(values, key, basename, filePath) {
|
|
258
|
+
for (const [index, value] of values.entries()) {
|
|
259
|
+
if (path_1.default.isAbsolute(value) || value.split(/[\\/]/).includes("..")) {
|
|
260
|
+
throw formatError(filePath, `${key}[${index}] must be a relative path`);
|
|
261
|
+
}
|
|
262
|
+
if (path_1.default.basename(value) !== basename) {
|
|
263
|
+
throw formatError(filePath, `${key}[${index}] must point to ${basename}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function validateFieldDescriptors(values, key, filePath) {
|
|
268
|
+
if (values.length === 0) {
|
|
269
|
+
throw formatError(filePath, `${key} must not be empty`);
|
|
270
|
+
}
|
|
271
|
+
for (const [index, value] of values.entries()) {
|
|
272
|
+
if (value !== value.toLowerCase() || !FIELD_DESCRIPTOR_RE.test(value)) {
|
|
273
|
+
throw formatError(filePath, `${key}[${index}] must use name:type or name:type:required|optional`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function validateAgentFrontmatter(type, frontmatter, filePath) {
|
|
278
|
+
if (!isAgentFileType(type)) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
validateAgentFileName(type, filePath);
|
|
282
|
+
const version = expectString(frontmatter, "version", filePath);
|
|
283
|
+
requireSemver(version, "version", filePath);
|
|
284
|
+
switch (type) {
|
|
285
|
+
case "spec": {
|
|
286
|
+
const role = expectString(frontmatter, "role", filePath);
|
|
287
|
+
requireEnum(role, "role", ROLE_VALUES, filePath);
|
|
288
|
+
const runtimeMode = expectString(frontmatter, "runtime_mode", filePath);
|
|
289
|
+
requireEnum(runtimeMode, "runtime_mode", RUNTIME_MODE_VALUES, filePath);
|
|
290
|
+
const updatePolicy = expectString(frontmatter, "update_policy", filePath);
|
|
291
|
+
requireEnum(updatePolicy, "update_policy", UPDATE_POLICY_VALUES, filePath);
|
|
292
|
+
validateRelativeMarkdownPaths(optionalList(frontmatter, "work_contracts", filePath), "work_contracts", "WORK.md", filePath);
|
|
293
|
+
validateCapabilities(optionalList(frontmatter, "requested_capabilities", filePath), "requested_capabilities", filePath);
|
|
294
|
+
validatePortableRefs(optionalList(frontmatter, "skill_refs", filePath), "skill_refs", filePath);
|
|
295
|
+
validatePortableRefs(optionalList(frontmatter, "tool_refs", filePath), "tool_refs", filePath);
|
|
296
|
+
validatePortableRefs(optionalList(frontmatter, "model_refs", filePath), "model_refs", filePath);
|
|
297
|
+
validatePortableRefs(optionalList(frontmatter, "wasm_component_refs", filePath), "wasm_component_refs", filePath);
|
|
298
|
+
validatePortableRefs(optionalList(frontmatter, "runtime_image_refs", filePath), "runtime_image_refs", filePath);
|
|
299
|
+
validatePortableRefs(optionalList(frontmatter, "subagent_refs", filePath), "subagent_refs", filePath);
|
|
300
|
+
const resourceProfile = optionalString(frontmatter, "resource_profile", filePath);
|
|
301
|
+
if (resourceProfile) {
|
|
302
|
+
requireLowerToken(resourceProfile, "resource_profile", filePath);
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
case "work": {
|
|
307
|
+
const agentId = expectString(frontmatter, "agent_id", filePath);
|
|
308
|
+
requirePortableId(agentId, "agent_id", filePath);
|
|
309
|
+
const kind = expectString(frontmatter, "kind", filePath);
|
|
310
|
+
requireLowerToken(kind, "kind", filePath);
|
|
311
|
+
const pricingModel = expectString(frontmatter, "pricing_model", filePath);
|
|
312
|
+
requireEnum(pricingModel, "pricing_model", PRICING_MODEL_VALUES, filePath);
|
|
313
|
+
validateCapabilities(expectList(frontmatter, "required_capabilities", filePath), "required_capabilities", filePath);
|
|
314
|
+
validatePortableRefs(optionalList(frontmatter, "skill_refs", filePath), "skill_refs", filePath);
|
|
315
|
+
validatePortableRefs(optionalList(frontmatter, "tool_refs", filePath), "tool_refs", filePath);
|
|
316
|
+
validatePortableRefs(optionalList(frontmatter, "model_refs", filePath), "model_refs", filePath);
|
|
317
|
+
validatePortableRefs(optionalList(frontmatter, "wasm_component_refs", filePath), "wasm_component_refs", filePath);
|
|
318
|
+
validatePortableRefs(optionalList(frontmatter, "runtime_image_refs", filePath), "runtime_image_refs", filePath);
|
|
319
|
+
validatePortableRefs(optionalList(frontmatter, "subagent_refs", filePath), "subagent_refs", filePath);
|
|
320
|
+
validateFieldDescriptors(expectList(frontmatter, "inputs", filePath), "inputs", filePath);
|
|
321
|
+
validateFieldDescriptors(expectList(frontmatter, "outputs", filePath), "outputs", filePath);
|
|
322
|
+
expectBoolean(frontmatter, "receipt_required", filePath);
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
case "work_order": {
|
|
326
|
+
const workId = expectString(frontmatter, "work_id", filePath);
|
|
327
|
+
requirePortableId(workId, "work_id", filePath);
|
|
328
|
+
const workVersion = expectString(frontmatter, "work_version", filePath);
|
|
329
|
+
requireSemver(workVersion, "work_version", filePath);
|
|
330
|
+
const requester = expectString(frontmatter, "requester", filePath);
|
|
331
|
+
requirePortableId(requester, "requester", filePath);
|
|
332
|
+
const orderStatus = expectString(frontmatter, "order_status", filePath);
|
|
333
|
+
requireEnum(orderStatus, "order_status", ORDER_STATUS_VALUES, filePath);
|
|
334
|
+
optionalString(frontmatter, "request_ref", filePath);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
case "receipt": {
|
|
338
|
+
const workOrderId = expectString(frontmatter, "work_order_id", filePath);
|
|
339
|
+
requirePortableId(workOrderId, "work_order_id", filePath);
|
|
340
|
+
const receiptStatus = expectString(frontmatter, "receipt_status", filePath);
|
|
341
|
+
requireEnum(receiptStatus, "receipt_status", RECEIPT_STATUS_VALUES, filePath);
|
|
342
|
+
const outcome = expectString(frontmatter, "outcome", filePath);
|
|
343
|
+
requireEnum(outcome, "outcome", OUTCOME_VALUES, filePath);
|
|
344
|
+
optionalString(frontmatter, "cost_ref", filePath);
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
case "feedback": {
|
|
348
|
+
const targetId = expectString(frontmatter, "target_id", filePath);
|
|
349
|
+
requirePortableId(targetId, "target_id", filePath);
|
|
350
|
+
const sentiment = expectString(frontmatter, "sentiment", filePath);
|
|
351
|
+
requireEnum(sentiment, "sentiment", SENTIMENT_VALUES, filePath);
|
|
352
|
+
const feedbackStatus = expectString(frontmatter, "feedback_status", filePath);
|
|
353
|
+
requireEnum(feedbackStatus, "feedback_status", FEEDBACK_STATUS_VALUES, filePath);
|
|
354
|
+
optionalString(frontmatter, "source_ref", filePath);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case "dispute": {
|
|
358
|
+
const workOrderId = expectString(frontmatter, "work_order_id", filePath);
|
|
359
|
+
requirePortableId(workOrderId, "work_order_id", filePath);
|
|
360
|
+
const receiptId = expectString(frontmatter, "receipt_id", filePath);
|
|
361
|
+
requirePortableId(receiptId, "receipt_id", filePath);
|
|
362
|
+
const disputeStatus = expectString(frontmatter, "dispute_status", filePath);
|
|
363
|
+
requireEnum(disputeStatus, "dispute_status", DISPUTE_STATUS_VALUES, filePath);
|
|
364
|
+
const severity = expectString(frontmatter, "severity", filePath);
|
|
365
|
+
requireEnum(severity, "severity", SEVERITY_VALUES, filePath);
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
case "proposal": {
|
|
369
|
+
const targetId = expectString(frontmatter, "target_id", filePath);
|
|
370
|
+
requirePortableId(targetId, "target_id", filePath);
|
|
371
|
+
const proposalStatus = expectString(frontmatter, "proposal_status", filePath);
|
|
372
|
+
requireEnum(proposalStatus, "proposal_status", PROPOSAL_STATUS_VALUES, filePath);
|
|
373
|
+
const proposalKind = expectString(frontmatter, "proposal_kind", filePath);
|
|
374
|
+
requireEnum(proposalKind, "proposal_kind", PROPOSAL_KIND_VALUES, filePath);
|
|
375
|
+
validatePortableRefs(optionalList(frontmatter, "evidence_refs", filePath), "evidence_refs", filePath);
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function extractAgentAttributes(type, frontmatter) {
|
|
381
|
+
if (!isAgentFileType(type)) {
|
|
382
|
+
return {};
|
|
383
|
+
}
|
|
384
|
+
const attributes = {};
|
|
385
|
+
for (const key of exports.AGENT_ATTRIBUTE_KEY_ORDER[type]) {
|
|
386
|
+
const value = frontmatter[key];
|
|
387
|
+
if (value !== undefined) {
|
|
388
|
+
attributes[key] = value;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return attributes;
|
|
392
|
+
}
|
package/dist/graph/edges.js
CHANGED
|
@@ -5,12 +5,15 @@ const id_1 = require("../util/id");
|
|
|
5
5
|
function formatError(filePath, key, message) {
|
|
6
6
|
return new Error(`${filePath}: ${key} ${message}`);
|
|
7
7
|
}
|
|
8
|
-
function normalizeIdRef(value, filePath, key) {
|
|
8
|
+
function normalizeIdRef(value, filePath, key, options) {
|
|
9
9
|
const normalized = value.toLowerCase();
|
|
10
10
|
if (normalized !== value) {
|
|
11
11
|
throw formatError(filePath, key, "must be lowercase");
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
const valid = options.allowPortableRefs
|
|
14
|
+
? (0, id_1.isPortableIdRef)(normalized)
|
|
15
|
+
: (0, id_1.isCanonicalIdRef)(normalized);
|
|
16
|
+
if (!valid) {
|
|
14
17
|
throw formatError(filePath, key, `invalid id reference: ${value}`);
|
|
15
18
|
}
|
|
16
19
|
return normalized;
|
|
@@ -35,7 +38,7 @@ function readStringList(fm, key) {
|
|
|
35
38
|
}
|
|
36
39
|
return value;
|
|
37
40
|
}
|
|
38
|
-
function extractEdges(frontmatter, filePath) {
|
|
41
|
+
function extractEdges(frontmatter, filePath, options = {}) {
|
|
39
42
|
const epic = readString(frontmatter, "epic");
|
|
40
43
|
const parent = readString(frontmatter, "parent");
|
|
41
44
|
const prev = readString(frontmatter, "prev");
|
|
@@ -44,21 +47,21 @@ function extractEdges(frontmatter, filePath) {
|
|
|
44
47
|
const blocked_by = readStringList(frontmatter, "blocked_by") ?? [];
|
|
45
48
|
const blocks = readStringList(frontmatter, "blocks") ?? [];
|
|
46
49
|
const edges = {
|
|
47
|
-
relates: relates.map((value) => normalizeIdRef(value, filePath, "relates")),
|
|
48
|
-
blocked_by: blocked_by.map((value) => normalizeIdRef(value, filePath, "blocked_by")),
|
|
49
|
-
blocks: blocks.map((value) => normalizeIdRef(value, filePath, "blocks")),
|
|
50
|
+
relates: relates.map((value) => normalizeIdRef(value, filePath, "relates", options)),
|
|
51
|
+
blocked_by: blocked_by.map((value) => normalizeIdRef(value, filePath, "blocked_by", options)),
|
|
52
|
+
blocks: blocks.map((value) => normalizeIdRef(value, filePath, "blocks", options)),
|
|
50
53
|
};
|
|
51
54
|
if (epic) {
|
|
52
|
-
edges.epic = normalizeIdRef(epic, filePath, "epic");
|
|
55
|
+
edges.epic = normalizeIdRef(epic, filePath, "epic", options);
|
|
53
56
|
}
|
|
54
57
|
if (parent) {
|
|
55
|
-
edges.parent = normalizeIdRef(parent, filePath, "parent");
|
|
58
|
+
edges.parent = normalizeIdRef(parent, filePath, "parent", options);
|
|
56
59
|
}
|
|
57
60
|
if (prev) {
|
|
58
|
-
edges.prev = normalizeIdRef(prev, filePath, "prev");
|
|
61
|
+
edges.prev = normalizeIdRef(prev, filePath, "prev", options);
|
|
59
62
|
}
|
|
60
63
|
if (next) {
|
|
61
|
-
edges.next = normalizeIdRef(next, filePath, "next");
|
|
64
|
+
edges.next = normalizeIdRef(next, filePath, "next", options);
|
|
62
65
|
}
|
|
63
66
|
return edges;
|
|
64
67
|
}
|
|
@@ -15,6 +15,39 @@ exports.DEFAULT_FRONTMATTER_KEY_ORDER = [
|
|
|
15
15
|
"prev",
|
|
16
16
|
"next",
|
|
17
17
|
"supersedes",
|
|
18
|
+
"version",
|
|
19
|
+
"role",
|
|
20
|
+
"runtime_mode",
|
|
21
|
+
"work_contracts",
|
|
22
|
+
"requested_capabilities",
|
|
23
|
+
"resource_profile",
|
|
24
|
+
"update_policy",
|
|
25
|
+
"agent_id",
|
|
26
|
+
"kind",
|
|
27
|
+
"pricing_model",
|
|
28
|
+
"required_capabilities",
|
|
29
|
+
"inputs",
|
|
30
|
+
"outputs",
|
|
31
|
+
"receipt_required",
|
|
32
|
+
"work_id",
|
|
33
|
+
"work_version",
|
|
34
|
+
"requester",
|
|
35
|
+
"order_status",
|
|
36
|
+
"request_ref",
|
|
37
|
+
"work_order_id",
|
|
38
|
+
"receipt_status",
|
|
39
|
+
"outcome",
|
|
40
|
+
"cost_ref",
|
|
41
|
+
"target_id",
|
|
42
|
+
"sentiment",
|
|
43
|
+
"feedback_status",
|
|
44
|
+
"source_ref",
|
|
45
|
+
"receipt_id",
|
|
46
|
+
"dispute_status",
|
|
47
|
+
"severity",
|
|
48
|
+
"proposal_status",
|
|
49
|
+
"proposal_kind",
|
|
50
|
+
"evidence_refs",
|
|
18
51
|
"tags",
|
|
19
52
|
"owners",
|
|
20
53
|
"links",
|
package/dist/graph/indexer.js
CHANGED
package/dist/graph/node.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.ALLOWED_TYPES = exports.DEC_TYPES = exports.WORK_TYPES = void 0;
|
|
|
4
4
|
exports.parseNode = parseNode;
|
|
5
5
|
const frontmatter_1 = require("./frontmatter");
|
|
6
6
|
const edges_1 = require("./edges");
|
|
7
|
+
const agent_file_types_1 = require("./agent_file_types");
|
|
7
8
|
const id_1 = require("../util/id");
|
|
8
9
|
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
9
10
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
@@ -21,6 +22,7 @@ exports.ALLOWED_TYPES = new Set([
|
|
|
21
22
|
"bug",
|
|
22
23
|
"checkpoint",
|
|
23
24
|
"test",
|
|
25
|
+
...agent_file_types_1.AGENT_FILE_TYPES,
|
|
24
26
|
]);
|
|
25
27
|
const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
26
28
|
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -83,6 +85,12 @@ function requireIdFormat(value, key, filePath) {
|
|
|
83
85
|
}
|
|
84
86
|
return value;
|
|
85
87
|
}
|
|
88
|
+
function requirePortableIdFormat(value, key, filePath) {
|
|
89
|
+
if (!(0, id_1.isPortableId)(value)) {
|
|
90
|
+
throw formatError(filePath, `${key} must be a lowercase portable id`);
|
|
91
|
+
}
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
86
94
|
function requireDate(value, key, filePath) {
|
|
87
95
|
if (!DATE_RE.test(value)) {
|
|
88
96
|
throw formatError(filePath, `${key} must be YYYY-MM-DD`);
|
|
@@ -99,12 +107,13 @@ function parsePriority(value, filePath, min, max) {
|
|
|
99
107
|
}
|
|
100
108
|
return parsed;
|
|
101
109
|
}
|
|
102
|
-
function normalizeIdList(values, key, filePath) {
|
|
110
|
+
function normalizeIdList(values, key, filePath, allowPortableIds = false) {
|
|
103
111
|
return values.map((value) => {
|
|
104
112
|
if (value !== value.toLowerCase()) {
|
|
105
113
|
throw formatError(filePath, `${key} entries must be lowercase`);
|
|
106
114
|
}
|
|
107
|
-
|
|
115
|
+
const valid = allowPortableIds ? (0, id_1.isPortableId)(value) : isValidId(value);
|
|
116
|
+
if (!valid) {
|
|
108
117
|
throw formatError(filePath, `${key} entries must match <prefix>-<number> or reserved id`);
|
|
109
118
|
}
|
|
110
119
|
return value;
|
|
@@ -156,9 +165,14 @@ function parseNode(content, filePath, options) {
|
|
|
156
165
|
if (!exports.ALLOWED_TYPES.has(type)) {
|
|
157
166
|
throw formatError(filePath, `type must be one of ${Array.from(exports.ALLOWED_TYPES).join(", ")}`);
|
|
158
167
|
}
|
|
168
|
+
const isAgentType = (0, agent_file_types_1.isAgentFileType)(type);
|
|
159
169
|
const schema = requireTemplateSchema(type, options.templateSchemas, filePath);
|
|
160
170
|
validateTemplateKeys(frontmatter, schema, filePath);
|
|
161
|
-
|
|
171
|
+
(0, agent_file_types_1.validateAgentFrontmatter)(type, frontmatter, filePath);
|
|
172
|
+
const idValue = requireLowercase(expectString(frontmatter, "id", filePath), "id", filePath);
|
|
173
|
+
const id = isAgentType
|
|
174
|
+
? requirePortableIdFormat(idValue, "id", filePath)
|
|
175
|
+
: requireIdFormat(idValue, "id", filePath);
|
|
162
176
|
const title = expectString(frontmatter, "title", filePath);
|
|
163
177
|
const created = requireDate(expectString(frontmatter, "created", filePath), "created", filePath);
|
|
164
178
|
const updated = requireDate(expectString(frontmatter, "updated", filePath), "updated", filePath);
|
|
@@ -200,7 +214,7 @@ function parseNode(content, filePath, options) {
|
|
|
200
214
|
const owners = requireLowercaseList(optionalList(frontmatter, "owners", filePath), "owners", filePath);
|
|
201
215
|
const links = optionalList(frontmatter, "links", filePath);
|
|
202
216
|
const artifacts = optionalList(frontmatter, "artifacts", filePath);
|
|
203
|
-
const refs = normalizeIdList(optionalList(frontmatter, "refs", filePath), "refs", filePath);
|
|
217
|
+
const refs = normalizeIdList(optionalList(frontmatter, "refs", filePath), "refs", filePath, isAgentType);
|
|
204
218
|
const aliases = requireLowercaseList(optionalList(frontmatter, "aliases", filePath), "aliases", filePath);
|
|
205
219
|
const skillsRaw = optionalList(frontmatter, "skills", filePath);
|
|
206
220
|
const skills = normalizeSkillList(skillsRaw, filePath);
|
|
@@ -218,7 +232,8 @@ function parseNode(content, filePath, options) {
|
|
|
218
232
|
throw formatError(filePath, "supersedes must be a dec-# id");
|
|
219
233
|
}
|
|
220
234
|
}
|
|
221
|
-
const edges = (0, edges_1.extractEdges)(frontmatter, filePath);
|
|
235
|
+
const edges = (0, edges_1.extractEdges)(frontmatter, filePath, { allowPortableRefs: isAgentType });
|
|
236
|
+
const attributes = (0, agent_file_types_1.extractAgentAttributes)(type, frontmatter);
|
|
222
237
|
return {
|
|
223
238
|
id,
|
|
224
239
|
type,
|
|
@@ -235,6 +250,7 @@ function parseNode(content, filePath, options) {
|
|
|
235
250
|
aliases,
|
|
236
251
|
skills,
|
|
237
252
|
edges,
|
|
253
|
+
attributes,
|
|
238
254
|
body,
|
|
239
255
|
frontmatter,
|
|
240
256
|
};
|
|
@@ -81,6 +81,13 @@ function extractOchatr(frontmatter) {
|
|
|
81
81
|
}
|
|
82
82
|
return extracted;
|
|
83
83
|
}
|
|
84
|
+
function stripPrefix(values, prefix) {
|
|
85
|
+
const stripped = {};
|
|
86
|
+
for (const [key, value] of Object.entries(values)) {
|
|
87
|
+
stripped[key.slice(prefix.length)] = value;
|
|
88
|
+
}
|
|
89
|
+
return stripped;
|
|
90
|
+
}
|
|
84
91
|
function hasDirectory(dirPath) {
|
|
85
92
|
if (!fs_1.default.existsSync(dirPath)) {
|
|
86
93
|
return false;
|
|
@@ -113,6 +120,11 @@ function buildSkillIndexEntry(root, slug, filePath) {
|
|
|
113
120
|
const authors = toLowercaseList(optionalList(frontmatter, "authors", filePath));
|
|
114
121
|
const links = optionalList(frontmatter, "links", filePath);
|
|
115
122
|
const skillDir = path_1.default.dirname(filePath);
|
|
123
|
+
const ochatr = extractOchatr(frontmatter);
|
|
124
|
+
const extensions = {};
|
|
125
|
+
if (Object.keys(ochatr).length > 0) {
|
|
126
|
+
extensions.ochatr = stripPrefix(ochatr, "ochatr_");
|
|
127
|
+
}
|
|
116
128
|
return {
|
|
117
129
|
slug,
|
|
118
130
|
id: `skill:${slug}`,
|
|
@@ -128,7 +140,8 @@ function buildSkillIndexEntry(root, slug, filePath) {
|
|
|
128
140
|
path: path_1.default.relative(root, filePath),
|
|
129
141
|
has_scripts: hasDirectory(path_1.default.join(skillDir, "scripts")),
|
|
130
142
|
has_references: hasDirectory(path_1.default.join(skillDir, "references")),
|
|
131
|
-
|
|
143
|
+
extensions,
|
|
144
|
+
ochatr,
|
|
132
145
|
};
|
|
133
146
|
}
|
|
134
147
|
function buildSkillsIndex(root, config) {
|