mdkg 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/README.md +108 -15
- package/dist/cli.js +566 -15
- package/dist/commands/archive.js +474 -0
- package/dist/commands/bundle.js +743 -0
- package/dist/commands/bundle_import.js +243 -0
- package/dist/commands/capability.js +162 -0
- package/dist/commands/doctor.js +233 -2
- package/dist/commands/format.js +38 -9
- package/dist/commands/index.js +11 -0
- package/dist/commands/init.js +188 -63
- package/dist/commands/init_manifest.js +19 -6
- package/dist/commands/list.js +5 -2
- package/dist/commands/new.js +6 -0
- package/dist/commands/next.js +7 -0
- package/dist/commands/node_card.js +4 -1
- package/dist/commands/pack.js +62 -2
- package/dist/commands/query_output.js +1 -0
- package/dist/commands/search.js +5 -2
- package/dist/commands/show.js +7 -14
- package/dist/commands/skill_mirror.js +22 -0
- package/dist/commands/task.js +3 -0
- package/dist/commands/upgrade.js +151 -13
- package/dist/commands/validate.js +19 -2
- package/dist/commands/work.js +365 -0
- package/dist/commands/workspace.js +12 -2
- package/dist/core/config.js +100 -1
- package/dist/graph/agent_file_types.js +78 -5
- package/dist/graph/archive_file.js +125 -0
- package/dist/graph/archive_integrity.js +66 -0
- package/dist/graph/bundle_imports.js +418 -0
- package/dist/graph/capabilities_index_cache.js +103 -0
- package/dist/graph/capabilities_indexer.js +231 -0
- package/dist/graph/frontmatter.js +19 -0
- package/dist/graph/index_cache.js +21 -4
- package/dist/graph/indexer.js +4 -1
- package/dist/graph/node.js +23 -4
- package/dist/graph/node_body.js +37 -0
- package/dist/graph/skills_indexer.js +8 -3
- package/dist/graph/template_schema.js +33 -5
- package/dist/graph/validate_graph.js +83 -7
- package/dist/graph/visibility.js +214 -0
- package/dist/graph/workspace_files.js +22 -0
- package/dist/init/AGENT_START.md +21 -0
- package/dist/init/CLI_COMMAND_MATRIX.md +58 -3
- package/dist/init/README.md +60 -3
- package/dist/init/config.json +13 -1
- package/dist/init/core/guide.md +6 -2
- package/dist/init/core/rule-3-cli-contract.md +71 -4
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +20 -0
- package/dist/init/core/rule-6-templates-and-schemas.md +10 -1
- package/dist/init/init-manifest.json +19 -14
- package/dist/init/skills/default/build-pack-and-execute-task/SKILL.md +2 -1
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +26 -0
- package/dist/init/templates/default/archive.md +33 -0
- package/dist/init/templates/default/receipt.md +15 -1
- package/dist/init/templates/default/work.md +6 -1
- package/dist/init/templates/default/work_order.md +15 -1
- package/dist/pack/export_md.js +3 -0
- package/dist/pack/export_xml.js +3 -0
- package/dist/pack/order.js +1 -0
- package/dist/pack/pack.js +3 -13
- package/dist/templates/builtin.js +38 -0
- package/dist/templates/loader.js +9 -16
- package/dist/util/argparse.js +30 -0
- package/dist/util/refs.js +40 -0
- package/dist/util/zip.js +153 -0
- package/package.json +8 -2
|
@@ -0,0 +1,365 @@
|
|
|
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.runWorkContractNewCommand = runWorkContractNewCommand;
|
|
7
|
+
exports.runWorkOrderNewCommand = runWorkOrderNewCommand;
|
|
8
|
+
exports.runWorkOrderUpdateCommand = runWorkOrderUpdateCommand;
|
|
9
|
+
exports.runWorkReceiptNewCommand = runWorkReceiptNewCommand;
|
|
10
|
+
exports.runWorkReceiptUpdateCommand = runWorkReceiptUpdateCommand;
|
|
11
|
+
exports.runWorkArtifactAddCommand = runWorkArtifactAddCommand;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const config_1 = require("../core/config");
|
|
15
|
+
const frontmatter_1 = require("../graph/frontmatter");
|
|
16
|
+
const indexer_1 = require("../graph/indexer");
|
|
17
|
+
const index_cache_1 = require("../graph/index_cache");
|
|
18
|
+
const agent_file_types_1 = require("../graph/agent_file_types");
|
|
19
|
+
const loader_1 = require("../templates/loader");
|
|
20
|
+
const date_1 = require("../util/date");
|
|
21
|
+
const errors_1 = require("../util/errors");
|
|
22
|
+
const id_1 = require("../util/id");
|
|
23
|
+
const qid_1 = require("../util/qid");
|
|
24
|
+
const event_support_1 = require("./event_support");
|
|
25
|
+
const archive_1 = require("./archive");
|
|
26
|
+
const PRICING_MODELS = new Set(["free", "included", "quoted", "fixed", "metered", "subscription"]);
|
|
27
|
+
const ORDER_STATUSES = new Set(["submitted", "accepted", "running", "completed", "cancelled", "failed"]);
|
|
28
|
+
const RECEIPT_STATUSES = new Set(["recorded", "verified", "rejected", "superseded"]);
|
|
29
|
+
const OUTCOMES = new Set(["success", "partial", "failure"]);
|
|
30
|
+
function parseCsvList(raw) {
|
|
31
|
+
if (!raw) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
return raw
|
|
35
|
+
.split(",")
|
|
36
|
+
.map((value) => value.trim())
|
|
37
|
+
.filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
function normalizeWorkspace(value) {
|
|
40
|
+
if (!value) {
|
|
41
|
+
return "root";
|
|
42
|
+
}
|
|
43
|
+
const normalized = value.toLowerCase();
|
|
44
|
+
if (normalized === "all") {
|
|
45
|
+
throw new errors_1.UsageError("--ws all is not valid for work commands");
|
|
46
|
+
}
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
function normalizePortableId(value, flag) {
|
|
50
|
+
const normalized = value.toLowerCase();
|
|
51
|
+
if (!(0, id_1.isPortableId)(normalized)) {
|
|
52
|
+
throw new errors_1.UsageError(`${flag} must be a lowercase portable id`);
|
|
53
|
+
}
|
|
54
|
+
return normalized;
|
|
55
|
+
}
|
|
56
|
+
function normalizeEnum(value, flag, allowed) {
|
|
57
|
+
const normalized = value.toLowerCase();
|
|
58
|
+
if (!allowed.has(normalized)) {
|
|
59
|
+
throw new errors_1.UsageError(`${flag} must be one of ${Array.from(allowed).join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
return normalized;
|
|
62
|
+
}
|
|
63
|
+
function slugifyTitle(title) {
|
|
64
|
+
const slug = title
|
|
65
|
+
.trim()
|
|
66
|
+
.toLowerCase()
|
|
67
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
68
|
+
.replace(/^-+|-+$/g, "")
|
|
69
|
+
.replace(/-+/g, "-");
|
|
70
|
+
return slug || "work";
|
|
71
|
+
}
|
|
72
|
+
function toPosixPath(value) {
|
|
73
|
+
return value.split(path_1.default.sep).join("/");
|
|
74
|
+
}
|
|
75
|
+
function appendUnique(existing, additions) {
|
|
76
|
+
const next = [...existing];
|
|
77
|
+
const seen = new Set(existing);
|
|
78
|
+
for (const addition of additions) {
|
|
79
|
+
if (!seen.has(addition)) {
|
|
80
|
+
next.push(addition);
|
|
81
|
+
seen.add(addition);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return next;
|
|
85
|
+
}
|
|
86
|
+
function toStringList(value) {
|
|
87
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
88
|
+
}
|
|
89
|
+
function maybeReindex(root, config) {
|
|
90
|
+
if (!config.index.auto_reindex) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const outputPath = path_1.default.resolve(root, config.index.global_index_path);
|
|
94
|
+
(0, index_cache_1.writeIndex)(outputPath, (0, indexer_1.buildIndex)(root, config, { tolerant: config.index.tolerant }));
|
|
95
|
+
}
|
|
96
|
+
function findNodeById(index, ws, id, type) {
|
|
97
|
+
const node = index.nodes[`${ws}:${id}`];
|
|
98
|
+
if (!node) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
if (type && node.type !== type) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
return node;
|
|
105
|
+
}
|
|
106
|
+
function requireNodeById(index, ws, id, type, label) {
|
|
107
|
+
const node = findNodeById(index, ws, id, type);
|
|
108
|
+
if (!node) {
|
|
109
|
+
throw new errors_1.NotFoundError(`${label} not found: ${id}`);
|
|
110
|
+
}
|
|
111
|
+
return node;
|
|
112
|
+
}
|
|
113
|
+
function nodeReceipt(root, node) {
|
|
114
|
+
return {
|
|
115
|
+
workspace: node.ws,
|
|
116
|
+
id: node.id,
|
|
117
|
+
qid: node.qid,
|
|
118
|
+
path: node.path,
|
|
119
|
+
type: node.type,
|
|
120
|
+
title: node.title,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function writeFrontmatterFile(filePath, frontmatter, body) {
|
|
124
|
+
const lines = (0, frontmatter_1.formatFrontmatter)(frontmatter, frontmatter_1.DEFAULT_FRONTMATTER_KEY_ORDER);
|
|
125
|
+
const content = ["---", ...lines, "---", body.trimStart()].join("\n");
|
|
126
|
+
fs_1.default.writeFileSync(filePath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
|
|
127
|
+
}
|
|
128
|
+
function createAgentWorkflowNode(options) {
|
|
129
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
130
|
+
const ws = normalizeWorkspace(options.ws);
|
|
131
|
+
const workspace = config.workspaces[ws];
|
|
132
|
+
if (!workspace) {
|
|
133
|
+
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
134
|
+
}
|
|
135
|
+
const id = normalizePortableId(options.id, "--id");
|
|
136
|
+
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
137
|
+
if (index.nodes[`${ws}:${id}`]) {
|
|
138
|
+
throw new errors_1.UsageError(`node already exists: ${ws}:${id}`);
|
|
139
|
+
}
|
|
140
|
+
const today = (0, date_1.formatDate)(options.now ?? new Date());
|
|
141
|
+
const slug = slugifyTitle(options.title);
|
|
142
|
+
const filePath = path_1.default.resolve(options.root, workspace.path, workspace.mdkg_dir, "work", `${id}-${slug}`, agent_file_types_1.AGENT_FILE_BASENAMES[options.type]);
|
|
143
|
+
const template = (0, loader_1.loadTemplate)(options.root, config, options.type);
|
|
144
|
+
const content = (0, loader_1.renderTemplate)(template, {
|
|
145
|
+
id,
|
|
146
|
+
type: options.type,
|
|
147
|
+
title: options.title,
|
|
148
|
+
created: today,
|
|
149
|
+
updated: today,
|
|
150
|
+
...options.overrides,
|
|
151
|
+
});
|
|
152
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
153
|
+
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
154
|
+
maybeReindex(options.root, config);
|
|
155
|
+
(0, event_support_1.appendAutomaticEvent)({
|
|
156
|
+
root: options.root,
|
|
157
|
+
ws,
|
|
158
|
+
kind: "WORK_NODE_CREATED",
|
|
159
|
+
status: "ok",
|
|
160
|
+
refs: [id],
|
|
161
|
+
notes: `${options.type} semantic mirror created via mdkg work`,
|
|
162
|
+
now: options.now,
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
workspace: ws,
|
|
166
|
+
id,
|
|
167
|
+
qid: `${ws}:${id}`,
|
|
168
|
+
path: toPosixPath(path_1.default.relative(options.root, filePath)),
|
|
169
|
+
type: options.type,
|
|
170
|
+
title: options.title,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function resolveWorkNode(index, idOrQid, ws, allowedTypes, label) {
|
|
174
|
+
const resolved = (0, qid_1.resolveQid)(index, idOrQid, ws);
|
|
175
|
+
if (resolved.status !== "ok") {
|
|
176
|
+
throw new errors_1.NotFoundError((0, qid_1.formatResolveError)(label, idOrQid, resolved, ws));
|
|
177
|
+
}
|
|
178
|
+
const node = index.nodes[resolved.qid];
|
|
179
|
+
if (!node || !allowedTypes.has(node.type)) {
|
|
180
|
+
throw new errors_1.NotFoundError(`${label} not found: ${idOrQid}`);
|
|
181
|
+
}
|
|
182
|
+
if (node.source?.imported) {
|
|
183
|
+
throw new errors_1.UsageError(`cannot mutate read-only imported node ${node.qid}; update the source workspace for bundle import ${node.source.import_alias}`);
|
|
184
|
+
}
|
|
185
|
+
return node;
|
|
186
|
+
}
|
|
187
|
+
function loadMutableAgentNode(root, idOrQid, wsRaw, type) {
|
|
188
|
+
const config = (0, config_1.loadConfig)(root);
|
|
189
|
+
const ws = normalizeWorkspace(wsRaw);
|
|
190
|
+
const { index } = (0, index_cache_1.loadIndex)({ root, config });
|
|
191
|
+
const node = resolveWorkNode(index, idOrQid, ws, new Set([type]), type);
|
|
192
|
+
const filePath = path_1.default.resolve(root, node.path);
|
|
193
|
+
const parsed = (0, frontmatter_1.parseFrontmatter)(fs_1.default.readFileSync(filePath, "utf8"), filePath);
|
|
194
|
+
return { config, node, filePath, frontmatter: { ...parsed.frontmatter }, body: parsed.body };
|
|
195
|
+
}
|
|
196
|
+
function printReceipt(action, receipt, json) {
|
|
197
|
+
if (json) {
|
|
198
|
+
console.log(JSON.stringify({ action, node: receipt }, null, 2));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log(`work ${action}: ${receipt.qid} (${receipt.path})`);
|
|
202
|
+
}
|
|
203
|
+
function runWorkContractNewCommand(options) {
|
|
204
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
205
|
+
const ws = normalizeWorkspace(options.ws);
|
|
206
|
+
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
207
|
+
const agentId = normalizePortableId(options.agentId, "--agent-id");
|
|
208
|
+
const relates = findNodeById(index, ws, agentId, "spec") ? [agentId] : [];
|
|
209
|
+
const receipt = createAgentWorkflowNode({
|
|
210
|
+
root: options.root,
|
|
211
|
+
ws,
|
|
212
|
+
type: "work",
|
|
213
|
+
title: options.title,
|
|
214
|
+
id: options.id,
|
|
215
|
+
now: options.now,
|
|
216
|
+
overrides: {
|
|
217
|
+
agent_id: agentId,
|
|
218
|
+
kind: options.kind.toLowerCase(),
|
|
219
|
+
pricing_model: normalizeEnum(options.pricingModel ?? "quoted", "--pricing-model", PRICING_MODELS),
|
|
220
|
+
required_capabilities: parseCsvList(options.requiredCapabilities),
|
|
221
|
+
inputs: parseCsvList(options.inputs),
|
|
222
|
+
outputs: parseCsvList(options.outputs),
|
|
223
|
+
receipt_required: true,
|
|
224
|
+
relates,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
printReceipt("contract created", receipt, options.json);
|
|
228
|
+
}
|
|
229
|
+
function runWorkOrderNewCommand(options) {
|
|
230
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
231
|
+
const ws = normalizeWorkspace(options.ws);
|
|
232
|
+
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
233
|
+
const workId = normalizePortableId(options.workId, "--work-id");
|
|
234
|
+
const workNode = requireNodeById(index, ws, workId, "work", "work contract");
|
|
235
|
+
const workVersion = String(workNode.attributes.version ?? "0.1.0");
|
|
236
|
+
const receipt = createAgentWorkflowNode({
|
|
237
|
+
root: options.root,
|
|
238
|
+
ws,
|
|
239
|
+
type: "work_order",
|
|
240
|
+
title: options.title,
|
|
241
|
+
id: options.id,
|
|
242
|
+
now: options.now,
|
|
243
|
+
overrides: {
|
|
244
|
+
work_id: workId,
|
|
245
|
+
work_version: workVersion,
|
|
246
|
+
requester: options.requester,
|
|
247
|
+
order_status: "submitted",
|
|
248
|
+
request_ref: options.requestRef ?? "request.redacted",
|
|
249
|
+
input_refs: parseCsvList(options.inputRefs),
|
|
250
|
+
requested_outputs: parseCsvList(options.requestedOutputs),
|
|
251
|
+
constraint_refs: parseCsvList(options.constraintRefs),
|
|
252
|
+
artifact_policy: "commit_sidecar_and_zip",
|
|
253
|
+
relates: [workId],
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
printReceipt("order created", receipt, options.json);
|
|
257
|
+
}
|
|
258
|
+
function runWorkOrderUpdateCommand(options) {
|
|
259
|
+
const loaded = loadMutableAgentNode(options.root, options.id, options.ws, "work_order");
|
|
260
|
+
if (options.status) {
|
|
261
|
+
loaded.frontmatter.order_status = normalizeEnum(options.status, "--status", ORDER_STATUSES);
|
|
262
|
+
}
|
|
263
|
+
loaded.frontmatter.input_refs = appendUnique(toStringList(loaded.frontmatter.input_refs), parseCsvList(options.addInputRefs));
|
|
264
|
+
loaded.frontmatter.artifacts = appendUnique(toStringList(loaded.frontmatter.artifacts), parseCsvList(options.addArtifacts));
|
|
265
|
+
loaded.frontmatter.updated = (0, date_1.formatDate)(options.now ?? new Date());
|
|
266
|
+
writeFrontmatterFile(loaded.filePath, loaded.frontmatter, loaded.body);
|
|
267
|
+
maybeReindex(options.root, loaded.config);
|
|
268
|
+
printReceipt("order updated", nodeReceipt(options.root, loaded.node), options.json);
|
|
269
|
+
}
|
|
270
|
+
function runWorkReceiptNewCommand(options) {
|
|
271
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
272
|
+
const ws = normalizeWorkspace(options.ws);
|
|
273
|
+
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
274
|
+
const workOrderId = normalizePortableId(options.workOrderId, "--work-order-id");
|
|
275
|
+
requireNodeById(index, ws, workOrderId, "work_order", "work order");
|
|
276
|
+
const receipt = createAgentWorkflowNode({
|
|
277
|
+
root: options.root,
|
|
278
|
+
ws,
|
|
279
|
+
type: "receipt",
|
|
280
|
+
title: options.title,
|
|
281
|
+
id: options.id,
|
|
282
|
+
now: options.now,
|
|
283
|
+
overrides: {
|
|
284
|
+
work_order_id: workOrderId,
|
|
285
|
+
receipt_status: normalizeEnum(options.receiptStatus ?? "recorded", "--receipt-status", RECEIPT_STATUSES),
|
|
286
|
+
outcome: normalizeEnum(options.outcome, "--outcome", OUTCOMES),
|
|
287
|
+
cost_ref: options.costRef ?? "cost.redacted",
|
|
288
|
+
artifacts: parseCsvList(options.artifacts),
|
|
289
|
+
proof_refs: parseCsvList(options.proofRefs),
|
|
290
|
+
attestation_refs: parseCsvList(options.attestationRefs),
|
|
291
|
+
input_hashes: parseCsvList(options.inputHashes),
|
|
292
|
+
output_hashes: parseCsvList(options.outputHashes),
|
|
293
|
+
relates: [workOrderId],
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
printReceipt("receipt created", receipt, options.json);
|
|
297
|
+
}
|
|
298
|
+
function runWorkReceiptUpdateCommand(options) {
|
|
299
|
+
const loaded = loadMutableAgentNode(options.root, options.id, options.ws, "receipt");
|
|
300
|
+
if (options.receiptStatus) {
|
|
301
|
+
loaded.frontmatter.receipt_status = normalizeEnum(options.receiptStatus, "--receipt-status", RECEIPT_STATUSES);
|
|
302
|
+
}
|
|
303
|
+
loaded.frontmatter.artifacts = appendUnique(toStringList(loaded.frontmatter.artifacts), parseCsvList(options.addArtifacts));
|
|
304
|
+
loaded.frontmatter.proof_refs = appendUnique(toStringList(loaded.frontmatter.proof_refs), parseCsvList(options.addProofRefs));
|
|
305
|
+
loaded.frontmatter.attestation_refs = appendUnique(toStringList(loaded.frontmatter.attestation_refs), parseCsvList(options.addAttestationRefs));
|
|
306
|
+
loaded.frontmatter.updated = (0, date_1.formatDate)(options.now ?? new Date());
|
|
307
|
+
writeFrontmatterFile(loaded.filePath, loaded.frontmatter, loaded.body);
|
|
308
|
+
maybeReindex(options.root, loaded.config);
|
|
309
|
+
printReceipt("receipt updated", nodeReceipt(options.root, loaded.node), options.json);
|
|
310
|
+
}
|
|
311
|
+
function runWorkArtifactAddCommand(options) {
|
|
312
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
313
|
+
const ws = normalizeWorkspace(options.ws);
|
|
314
|
+
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
315
|
+
const target = resolveWorkNode(index, options.targetId, ws, new Set(["work_order", "receipt"]), "work order or receipt");
|
|
316
|
+
const archiveLogs = [];
|
|
317
|
+
const originalLog = console.log;
|
|
318
|
+
console.log = (...args) => {
|
|
319
|
+
archiveLogs.push(args.map(String).join(" "));
|
|
320
|
+
};
|
|
321
|
+
let archivePayload = {};
|
|
322
|
+
try {
|
|
323
|
+
(0, archive_1.runArchiveAddCommand)({
|
|
324
|
+
root: options.root,
|
|
325
|
+
ws: target.ws,
|
|
326
|
+
file: options.file,
|
|
327
|
+
id: options.id,
|
|
328
|
+
kind: options.kind ?? (target.type === "work_order" ? "source" : "artifact"),
|
|
329
|
+
relates: target.id,
|
|
330
|
+
json: true,
|
|
331
|
+
now: options.now,
|
|
332
|
+
});
|
|
333
|
+
archivePayload = JSON.parse(archiveLogs.join("\n"));
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
console.log = originalLog;
|
|
337
|
+
}
|
|
338
|
+
const archiveUri = archivePayload.archive?.archive_uri;
|
|
339
|
+
if (!archiveUri) {
|
|
340
|
+
throw new Error("archive add did not return an archive URI");
|
|
341
|
+
}
|
|
342
|
+
const loaded = loadMutableAgentNode(options.root, target.qid, target.ws, target.type);
|
|
343
|
+
const archiveKind = (options.kind ?? (target.type === "work_order" ? "source" : "artifact")).toLowerCase();
|
|
344
|
+
if (target.type === "work_order" && archiveKind === "source") {
|
|
345
|
+
loaded.frontmatter.input_refs = appendUnique(toStringList(loaded.frontmatter.input_refs), [archiveUri]);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
loaded.frontmatter.artifacts = appendUnique(toStringList(loaded.frontmatter.artifacts), [archiveUri]);
|
|
349
|
+
}
|
|
350
|
+
if (archivePayload.archive?.id) {
|
|
351
|
+
loaded.frontmatter.relates = appendUnique(toStringList(loaded.frontmatter.relates), [archivePayload.archive.id]);
|
|
352
|
+
}
|
|
353
|
+
loaded.frontmatter.updated = (0, date_1.formatDate)(options.now ?? new Date());
|
|
354
|
+
writeFrontmatterFile(loaded.filePath, loaded.frontmatter, loaded.body);
|
|
355
|
+
maybeReindex(options.root, loaded.config);
|
|
356
|
+
if (options.json) {
|
|
357
|
+
console.log(JSON.stringify({
|
|
358
|
+
action: "artifact_registered",
|
|
359
|
+
target: nodeReceipt(options.root, target),
|
|
360
|
+
archive: archivePayload.archive,
|
|
361
|
+
}, null, 2));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
console.log(`work artifact registered: ${target.qid} -> ${archiveUri}`);
|
|
365
|
+
}
|
|
@@ -21,6 +21,7 @@ function workspaceReceipt(alias, workspace) {
|
|
|
21
21
|
path: workspace.path,
|
|
22
22
|
enabled: workspace.enabled,
|
|
23
23
|
mdkg_dir: workspace.mdkg_dir,
|
|
24
|
+
visibility: workspace.visibility ?? "private",
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
function printWorkspaceMutationReceipt(action, workspace, json) {
|
|
@@ -90,6 +91,7 @@ function runWorkspaceListCommand(options) {
|
|
|
90
91
|
path: ws.path,
|
|
91
92
|
enabled: ws.enabled,
|
|
92
93
|
mdkg_dir: ws.mdkg_dir,
|
|
94
|
+
visibility: ws.visibility,
|
|
93
95
|
};
|
|
94
96
|
}),
|
|
95
97
|
}, null, 2));
|
|
@@ -102,13 +104,21 @@ function runWorkspaceListCommand(options) {
|
|
|
102
104
|
for (const alias of aliases) {
|
|
103
105
|
const ws = config.workspaces[alias];
|
|
104
106
|
const status = ws.enabled ? "enabled" : "disabled";
|
|
105
|
-
console.log(`${alias} | ${status} | ${ws.path} | ${ws.mdkg_dir}`);
|
|
107
|
+
console.log(`${alias} | ${status} | ${ws.visibility} | ${ws.path} | ${ws.mdkg_dir}`);
|
|
106
108
|
}
|
|
107
109
|
}
|
|
110
|
+
function normalizeVisibility(value) {
|
|
111
|
+
const normalized = (value ?? "private").toLowerCase();
|
|
112
|
+
if (normalized === "private" || normalized === "internal" || normalized === "public") {
|
|
113
|
+
return normalized;
|
|
114
|
+
}
|
|
115
|
+
throw new errors_1.UsageError("--visibility must be private, internal, or public");
|
|
116
|
+
}
|
|
108
117
|
function runWorkspaceAddCommand(options) {
|
|
109
118
|
const alias = normalizeAlias(options.alias);
|
|
110
119
|
const workspacePath = normalizeCommandWorkspacePath(options.workspacePath, "workspace path");
|
|
111
120
|
const mdkgDir = normalizeCommandWorkspacePath(options.mdkgDir ?? ".mdkg", "workspace mdkg dir");
|
|
121
|
+
const visibility = normalizeVisibility(options.visibility);
|
|
112
122
|
if ((0, workspace_path_1.isRootWorkspacePath)(workspacePath)) {
|
|
113
123
|
throw new errors_1.UsageError('workspace path must not be "." for non-root workspaces');
|
|
114
124
|
}
|
|
@@ -133,7 +143,7 @@ function runWorkspaceAddCommand(options) {
|
|
|
133
143
|
throw new errors_1.UsageError(`workspace document root already registered by ${existingAlias}`);
|
|
134
144
|
}
|
|
135
145
|
}
|
|
136
|
-
const workspace = { path: workspacePath, enabled: true, mdkg_dir: mdkgDir };
|
|
146
|
+
const workspace = { path: workspacePath, enabled: true, mdkg_dir: mdkgDir, visibility };
|
|
137
147
|
workspaces[alias] = workspace;
|
|
138
148
|
raw.workspaces = workspaces;
|
|
139
149
|
writeRawConfig(configPath, raw);
|
package/dist/core/config.js
CHANGED
|
@@ -20,6 +20,9 @@ const PACK_EDGE_KEYS = new Set([
|
|
|
20
20
|
"next",
|
|
21
21
|
]);
|
|
22
22
|
const NEXT_WORK_STRATEGIES = new Set(["chain_then_priority"]);
|
|
23
|
+
const WORKSPACE_VISIBILITY_VALUES = new Set(["private", "internal", "public"]);
|
|
24
|
+
const BUNDLE_PROFILE_VALUES = new Set(["private", "public"]);
|
|
25
|
+
const DEFAULT_ARCHIVE_LARGE_CACHE_WARNING_BYTES = 26214400;
|
|
23
26
|
function isObject(value) {
|
|
24
27
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
28
|
}
|
|
@@ -166,6 +169,18 @@ function validateWorkspaceAlias(alias, errors) {
|
|
|
166
169
|
errors.push(`workspaces.${alias} alias must be lowercase and use [a-z0-9_]`);
|
|
167
170
|
}
|
|
168
171
|
}
|
|
172
|
+
function validateBundleImportAlias(alias, workspaces, errors) {
|
|
173
|
+
if (alias === "all") {
|
|
174
|
+
errors.push("bundle_imports.all alias is reserved");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (alias !== alias.toLowerCase() || !WORKSPACE_ALIAS_RE.test(alias)) {
|
|
178
|
+
errors.push(`bundle_imports.${alias} alias must be lowercase and use [a-z0-9_]`);
|
|
179
|
+
}
|
|
180
|
+
if (workspaces[alias]) {
|
|
181
|
+
errors.push(`bundle_imports.${alias} must not collide with workspaces.${alias}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
169
184
|
function requireContainedPath(value, path, errors) {
|
|
170
185
|
const raw = requireString(value, path, errors);
|
|
171
186
|
if (!raw) {
|
|
@@ -188,11 +203,30 @@ function validateConfigSchema(raw) {
|
|
|
188
203
|
const schema_version = requireNumber(raw.schema_version, "schema_version", errors);
|
|
189
204
|
const tool = requireString(raw.tool, "tool", errors);
|
|
190
205
|
const root_required = requireBoolean(raw.root_required, "root_required", errors);
|
|
206
|
+
const archiveRaw = raw.archive === undefined
|
|
207
|
+
? { large_cache_warning_bytes: DEFAULT_ARCHIVE_LARGE_CACHE_WARNING_BYTES }
|
|
208
|
+
: requireObject(raw.archive, "archive", errors);
|
|
191
209
|
const indexRaw = requireObject(raw.index, "index", errors);
|
|
210
|
+
const capabilitiesRaw = raw.capabilities === undefined
|
|
211
|
+
? { cache_path: ".mdkg/index/capabilities.json" }
|
|
212
|
+
: requireObject(raw.capabilities, "capabilities", errors);
|
|
213
|
+
const bundlesRaw = raw.bundles === undefined
|
|
214
|
+
? { output_dir: ".mdkg/bundles", default_profile: "private" }
|
|
215
|
+
: requireObject(raw.bundles, "bundles", errors);
|
|
216
|
+
const bundleImportsRaw = raw.bundle_imports === undefined
|
|
217
|
+
? {}
|
|
218
|
+
: requireObject(raw.bundle_imports, "bundle_imports", errors);
|
|
192
219
|
const packRaw = requireObject(raw.pack, "pack", errors);
|
|
193
220
|
const templatesRaw = requireObject(raw.templates, "templates", errors);
|
|
194
221
|
const workRaw = requireObject(raw.work, "work", errors);
|
|
195
222
|
const workspacesRaw = requireObject(raw.workspaces, "workspaces", errors);
|
|
223
|
+
const archive = archiveRaw
|
|
224
|
+
? {
|
|
225
|
+
large_cache_warning_bytes: archiveRaw.large_cache_warning_bytes === undefined
|
|
226
|
+
? DEFAULT_ARCHIVE_LARGE_CACHE_WARNING_BYTES
|
|
227
|
+
: requireNonNegativeInteger(archiveRaw.large_cache_warning_bytes, "archive.large_cache_warning_bytes", errors),
|
|
228
|
+
}
|
|
229
|
+
: undefined;
|
|
196
230
|
const index = indexRaw
|
|
197
231
|
? {
|
|
198
232
|
auto_reindex: requireBoolean(indexRaw.auto_reindex, "index.auto_reindex", errors),
|
|
@@ -200,6 +234,17 @@ function validateConfigSchema(raw) {
|
|
|
200
234
|
global_index_path: requireContainedPath(indexRaw.global_index_path, "index.global_index_path", errors),
|
|
201
235
|
}
|
|
202
236
|
: undefined;
|
|
237
|
+
const capabilities = capabilitiesRaw
|
|
238
|
+
? {
|
|
239
|
+
cache_path: requireContainedPath(capabilitiesRaw.cache_path, "capabilities.cache_path", errors),
|
|
240
|
+
}
|
|
241
|
+
: undefined;
|
|
242
|
+
const bundles = bundlesRaw
|
|
243
|
+
? {
|
|
244
|
+
output_dir: requireContainedPath(bundlesRaw.output_dir, "bundles.output_dir", errors),
|
|
245
|
+
default_profile: requireStringInSet(bundlesRaw.default_profile, "bundles.default_profile", BUNDLE_PROFILE_VALUES, errors),
|
|
246
|
+
}
|
|
247
|
+
: undefined;
|
|
203
248
|
const packLimitsRaw = packRaw ? requireObject(packRaw.limits, "pack.limits", errors) : undefined;
|
|
204
249
|
const pack = packRaw
|
|
205
250
|
? {
|
|
@@ -268,7 +313,10 @@ function validateConfigSchema(raw) {
|
|
|
268
313
|
const wsPath = requireString(ws.path, `workspaces.${alias}.path`, errors);
|
|
269
314
|
const wsEnabled = requireBoolean(ws.enabled, `workspaces.${alias}.enabled`, errors);
|
|
270
315
|
const wsMdkgDir = requireString(ws.mdkg_dir, `workspaces.${alias}.mdkg_dir`, errors);
|
|
271
|
-
|
|
316
|
+
const wsVisibility = ws.visibility === undefined
|
|
317
|
+
? "private"
|
|
318
|
+
: requireStringInSet(ws.visibility, `workspaces.${alias}.visibility`, WORKSPACE_VISIBILITY_VALUES, errors);
|
|
319
|
+
if (wsPath && wsEnabled !== undefined && wsMdkgDir && wsVisibility) {
|
|
272
320
|
let normalizedPath;
|
|
273
321
|
let normalizedMdkgDir;
|
|
274
322
|
try {
|
|
@@ -303,6 +351,7 @@ function validateConfigSchema(raw) {
|
|
|
303
351
|
path: normalizedPath,
|
|
304
352
|
enabled: wsEnabled,
|
|
305
353
|
mdkg_dir: normalizedMdkgDir,
|
|
354
|
+
visibility: wsVisibility,
|
|
306
355
|
};
|
|
307
356
|
}
|
|
308
357
|
}
|
|
@@ -325,6 +374,52 @@ function validateConfigSchema(raw) {
|
|
|
325
374
|
errors.push('workspaces.root.mdkg_dir must be ".mdkg"');
|
|
326
375
|
}
|
|
327
376
|
}
|
|
377
|
+
const bundle_imports = {};
|
|
378
|
+
if (bundleImportsRaw) {
|
|
379
|
+
for (const [alias, entry] of Object.entries(bundleImportsRaw)) {
|
|
380
|
+
validateBundleImportAlias(alias, workspaces, errors);
|
|
381
|
+
const rawImport = requireObject(entry, `bundle_imports.${alias}`, errors);
|
|
382
|
+
if (!rawImport) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const importPath = requireContainedPath(rawImport.path, `bundle_imports.${alias}.path`, errors);
|
|
386
|
+
const enabled = rawImport.enabled === undefined
|
|
387
|
+
? true
|
|
388
|
+
: requireBoolean(rawImport.enabled, `bundle_imports.${alias}.enabled`, errors);
|
|
389
|
+
const visibility = rawImport.visibility === undefined
|
|
390
|
+
? "private"
|
|
391
|
+
: requireStringInSet(rawImport.visibility, `bundle_imports.${alias}.visibility`, WORKSPACE_VISIBILITY_VALUES, errors);
|
|
392
|
+
const expectedProfile = rawImport.expected_profile === undefined
|
|
393
|
+
? "private"
|
|
394
|
+
: requireStringInSet(rawImport.expected_profile, `bundle_imports.${alias}.expected_profile`, BUNDLE_PROFILE_VALUES, errors);
|
|
395
|
+
const sourcePath = rawImport.source_path === undefined
|
|
396
|
+
? undefined
|
|
397
|
+
: requireContainedPath(rawImport.source_path, `bundle_imports.${alias}.source_path`, errors);
|
|
398
|
+
const sourceRepo = rawImport.source_repo === undefined
|
|
399
|
+
? undefined
|
|
400
|
+
: requireString(rawImport.source_repo, `bundle_imports.${alias}.source_repo`, errors);
|
|
401
|
+
const maxStaleSeconds = rawImport.max_stale_seconds === undefined
|
|
402
|
+
? undefined
|
|
403
|
+
: requirePositiveInteger(rawImport.max_stale_seconds, `bundle_imports.${alias}.max_stale_seconds`, errors);
|
|
404
|
+
if (visibility !== undefined &&
|
|
405
|
+
expectedProfile !== undefined &&
|
|
406
|
+
visibility !== "private" &&
|
|
407
|
+
expectedProfile !== "public") {
|
|
408
|
+
errors.push(`bundle_imports.${alias}.expected_profile must be public when visibility is ${visibility}`);
|
|
409
|
+
}
|
|
410
|
+
if (importPath && enabled !== undefined && visibility && expectedProfile) {
|
|
411
|
+
bundle_imports[alias] = {
|
|
412
|
+
path: importPath,
|
|
413
|
+
enabled,
|
|
414
|
+
visibility: visibility,
|
|
415
|
+
expected_profile: expectedProfile,
|
|
416
|
+
...(sourcePath ? { source_path: sourcePath } : {}),
|
|
417
|
+
...(sourceRepo ? { source_repo: sourceRepo } : {}),
|
|
418
|
+
...(maxStaleSeconds !== undefined ? { max_stale_seconds: maxStaleSeconds } : {}),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
328
423
|
if (errors.length > 0) {
|
|
329
424
|
throw new Error(`config validation failed:\n${errors.join("\n")}`);
|
|
330
425
|
}
|
|
@@ -332,7 +427,11 @@ function validateConfigSchema(raw) {
|
|
|
332
427
|
schema_version: schema_version,
|
|
333
428
|
tool: tool,
|
|
334
429
|
root_required: root_required,
|
|
430
|
+
archive: archive,
|
|
335
431
|
index: index,
|
|
432
|
+
capabilities: capabilities,
|
|
433
|
+
bundles: bundles,
|
|
434
|
+
bundle_imports,
|
|
336
435
|
pack: pack,
|
|
337
436
|
templates: templates,
|
|
338
437
|
work: work,
|