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,231 @@
|
|
|
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.CAPABILITY_VISIBILITIES = exports.CAPABILITY_KINDS = exports.CAPABILITIES_INDEX_RELATIVE_PATH = void 0;
|
|
7
|
+
exports.resolveCapabilitiesIndexPath = resolveCapabilitiesIndexPath;
|
|
8
|
+
exports.buildCapabilitiesIndex = buildCapabilitiesIndex;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const indexer_1 = require("./indexer");
|
|
13
|
+
const skills_indexer_1 = require("./skills_indexer");
|
|
14
|
+
exports.CAPABILITIES_INDEX_RELATIVE_PATH = ".mdkg/index/capabilities.json";
|
|
15
|
+
exports.CAPABILITY_KINDS = ["skill", "spec", "work", "core", "design"];
|
|
16
|
+
exports.CAPABILITY_VISIBILITIES = ["private", "internal", "public"];
|
|
17
|
+
const CAPABILITY_CACHE_VERSION = 1;
|
|
18
|
+
function toPosixPath(value) {
|
|
19
|
+
return value.split(path_1.default.sep).join("/");
|
|
20
|
+
}
|
|
21
|
+
function sourceHash(content) {
|
|
22
|
+
return `sha256:${crypto_1.default.createHash("sha256").update(content).digest("hex")}`;
|
|
23
|
+
}
|
|
24
|
+
function extractHeadings(content) {
|
|
25
|
+
const headings = [];
|
|
26
|
+
for (const line of content.split(/\r?\n/)) {
|
|
27
|
+
const match = /^(#{1,6})\s+(.+?)\s*#*\s*$/.exec(line);
|
|
28
|
+
if (!match) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
headings.push({ level: match[1].length, text: match[2].trim() });
|
|
32
|
+
}
|
|
33
|
+
return headings;
|
|
34
|
+
}
|
|
35
|
+
function workspaceVisibility(config, alias) {
|
|
36
|
+
return config.workspaces[alias]?.visibility ?? "private";
|
|
37
|
+
}
|
|
38
|
+
function workspaceMdkgPrefix(entry) {
|
|
39
|
+
const wsPath = entry.path === "." ? "" : `${toPosixPath(entry.path).replace(/\/+$/, "")}/`;
|
|
40
|
+
const mdkgDir = toPosixPath(entry.mdkg_dir).replace(/^\/+|\/+$/g, "");
|
|
41
|
+
return `${wsPath}${mdkgDir}/`;
|
|
42
|
+
}
|
|
43
|
+
function classifyNodeCapability(node, config) {
|
|
44
|
+
if (node.type === "spec") {
|
|
45
|
+
return "spec";
|
|
46
|
+
}
|
|
47
|
+
if (node.type === "work") {
|
|
48
|
+
return "work";
|
|
49
|
+
}
|
|
50
|
+
const workspace = config.workspaces[node.ws];
|
|
51
|
+
if (!workspace) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const nodePath = toPosixPath(node.path);
|
|
55
|
+
const prefix = workspaceMdkgPrefix(workspace);
|
|
56
|
+
if (!nodePath.startsWith(prefix)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const relativeToMdkg = nodePath.slice(prefix.length);
|
|
60
|
+
if (relativeToMdkg.startsWith("core/")) {
|
|
61
|
+
return "core";
|
|
62
|
+
}
|
|
63
|
+
if (relativeToMdkg.startsWith("design/")) {
|
|
64
|
+
return "design";
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
function pickAttributes(attributes, keys) {
|
|
69
|
+
const picked = {};
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
if (attributes[key] !== undefined) {
|
|
72
|
+
picked[key] = attributes[key];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return picked;
|
|
76
|
+
}
|
|
77
|
+
function nodeCapabilityRecord(root, config, node, kind, indexedAt) {
|
|
78
|
+
const absolutePath = path_1.default.resolve(root, node.path);
|
|
79
|
+
const content = fs_1.default.readFileSync(absolutePath, "utf8");
|
|
80
|
+
const record = {
|
|
81
|
+
kind,
|
|
82
|
+
workspace: node.ws,
|
|
83
|
+
visibility: workspaceVisibility(config, node.ws),
|
|
84
|
+
id: node.id,
|
|
85
|
+
qid: node.qid,
|
|
86
|
+
path: toPosixPath(node.path),
|
|
87
|
+
title: node.title,
|
|
88
|
+
tags: [...node.tags],
|
|
89
|
+
refs: [...node.refs],
|
|
90
|
+
aliases: [...node.aliases],
|
|
91
|
+
links: [...node.links],
|
|
92
|
+
artifacts: [...node.artifacts],
|
|
93
|
+
updated: node.updated,
|
|
94
|
+
indexed_at: indexedAt,
|
|
95
|
+
source_hash: sourceHash(content),
|
|
96
|
+
headings: extractHeadings(content),
|
|
97
|
+
node_type: node.type,
|
|
98
|
+
};
|
|
99
|
+
if (kind === "spec") {
|
|
100
|
+
record.spec = pickAttributes(node.attributes, [
|
|
101
|
+
"version",
|
|
102
|
+
"role",
|
|
103
|
+
"runtime_mode",
|
|
104
|
+
"work_contracts",
|
|
105
|
+
"requested_capabilities",
|
|
106
|
+
"skill_refs",
|
|
107
|
+
"tool_refs",
|
|
108
|
+
"model_refs",
|
|
109
|
+
"wasm_component_refs",
|
|
110
|
+
"runtime_image_refs",
|
|
111
|
+
"subagent_refs",
|
|
112
|
+
"resource_profile",
|
|
113
|
+
"update_policy",
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
if (kind === "work") {
|
|
117
|
+
record.work = pickAttributes(node.attributes, [
|
|
118
|
+
"version",
|
|
119
|
+
"agent_id",
|
|
120
|
+
"kind",
|
|
121
|
+
"pricing_model",
|
|
122
|
+
"required_capabilities",
|
|
123
|
+
"skill_refs",
|
|
124
|
+
"tool_refs",
|
|
125
|
+
"model_refs",
|
|
126
|
+
"wasm_component_refs",
|
|
127
|
+
"runtime_image_refs",
|
|
128
|
+
"subagent_refs",
|
|
129
|
+
"inputs",
|
|
130
|
+
"outputs",
|
|
131
|
+
"receipt_required",
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
return record;
|
|
135
|
+
}
|
|
136
|
+
function skillCapabilityRecord(root, config, skill, indexedAt) {
|
|
137
|
+
const absolutePath = path_1.default.resolve(root, skill.path);
|
|
138
|
+
const content = fs_1.default.readFileSync(absolutePath, "utf8");
|
|
139
|
+
return {
|
|
140
|
+
kind: "skill",
|
|
141
|
+
workspace: skill.ws,
|
|
142
|
+
visibility: workspaceVisibility(config, skill.ws),
|
|
143
|
+
id: skill.id,
|
|
144
|
+
qid: skill.qid,
|
|
145
|
+
path: toPosixPath(skill.path),
|
|
146
|
+
title: skill.name,
|
|
147
|
+
name: skill.name,
|
|
148
|
+
description: skill.description,
|
|
149
|
+
slug: skill.slug,
|
|
150
|
+
tags: [...skill.tags],
|
|
151
|
+
refs: [],
|
|
152
|
+
aliases: [skill.slug, ...skill.tags],
|
|
153
|
+
links: [...skill.links],
|
|
154
|
+
artifacts: [],
|
|
155
|
+
indexed_at: indexedAt,
|
|
156
|
+
source_hash: sourceHash(content),
|
|
157
|
+
headings: extractHeadings(content),
|
|
158
|
+
skill: {
|
|
159
|
+
version: skill.version,
|
|
160
|
+
authors: [...skill.authors],
|
|
161
|
+
has_scripts: skill.has_scripts,
|
|
162
|
+
has_references: skill.has_references,
|
|
163
|
+
extensions: skill.extensions,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function workspaceSkillsRoot(root, entry) {
|
|
168
|
+
return path_1.default.resolve(root, entry.path, entry.mdkg_dir, "skills");
|
|
169
|
+
}
|
|
170
|
+
function buildWorkspaceSkillCapabilities(root, config, indexedAt) {
|
|
171
|
+
const records = [];
|
|
172
|
+
for (const alias of Object.keys(config.workspaces).sort()) {
|
|
173
|
+
const workspace = config.workspaces[alias];
|
|
174
|
+
if (!workspace.enabled) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const skillsRoot = workspaceSkillsRoot(root, workspace);
|
|
178
|
+
for (const candidate of (0, skills_indexer_1.listSkillMarkdownFiles)(skillsRoot)) {
|
|
179
|
+
const skill = (0, skills_indexer_1.buildSkillIndexEntryForWorkspace)(root, alias, candidate.slug, candidate.filePath);
|
|
180
|
+
records.push(skillCapabilityRecord(root, config, skill, indexedAt));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return records;
|
|
184
|
+
}
|
|
185
|
+
function sortRecords(records) {
|
|
186
|
+
return [...records].sort((a, b) => {
|
|
187
|
+
for (const [left, right] of [
|
|
188
|
+
[a.workspace, b.workspace],
|
|
189
|
+
[a.kind, b.kind],
|
|
190
|
+
[a.id, b.id],
|
|
191
|
+
[a.path, b.path],
|
|
192
|
+
]) {
|
|
193
|
+
const compared = left.localeCompare(right);
|
|
194
|
+
if (compared !== 0) {
|
|
195
|
+
return compared;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return 0;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function resolveCapabilitiesIndexPath(root, config) {
|
|
202
|
+
return path_1.default.resolve(root, config.capabilities.cache_path);
|
|
203
|
+
}
|
|
204
|
+
function buildCapabilitiesIndex(root, config, nodeIndex) {
|
|
205
|
+
const index = nodeIndex ?? (0, indexer_1.buildIndex)(root, config);
|
|
206
|
+
const records = [];
|
|
207
|
+
const generatedAt = new Date().toISOString();
|
|
208
|
+
for (const node of Object.values(index.nodes)) {
|
|
209
|
+
const kind = classifyNodeCapability(node, config);
|
|
210
|
+
if (!kind) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
records.push(nodeCapabilityRecord(root, config, node, kind, generatedAt));
|
|
214
|
+
}
|
|
215
|
+
records.push(...buildWorkspaceSkillCapabilities(root, config, generatedAt));
|
|
216
|
+
const sortedRecords = sortRecords(records);
|
|
217
|
+
return {
|
|
218
|
+
meta: {
|
|
219
|
+
tool: config.tool,
|
|
220
|
+
schema_version: config.schema_version,
|
|
221
|
+
cache_version: CAPABILITY_CACHE_VERSION,
|
|
222
|
+
generated_at: generatedAt,
|
|
223
|
+
root,
|
|
224
|
+
workspaces: Object.keys(config.workspaces)
|
|
225
|
+
.filter((alias) => config.workspaces[alias].enabled)
|
|
226
|
+
.sort(),
|
|
227
|
+
record_count: sortedRecords.length,
|
|
228
|
+
},
|
|
229
|
+
records: sortedRecords,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -48,6 +48,25 @@ exports.DEFAULT_FRONTMATTER_KEY_ORDER = [
|
|
|
48
48
|
"proposal_status",
|
|
49
49
|
"proposal_kind",
|
|
50
50
|
"evidence_refs",
|
|
51
|
+
"archive_kind",
|
|
52
|
+
"source_path",
|
|
53
|
+
"stored_path",
|
|
54
|
+
"compressed_path",
|
|
55
|
+
"mime_type",
|
|
56
|
+
"byte_size",
|
|
57
|
+
"sha256",
|
|
58
|
+
"compressed_sha256",
|
|
59
|
+
"visibility",
|
|
60
|
+
"provenance",
|
|
61
|
+
"ingest_status",
|
|
62
|
+
"input_refs",
|
|
63
|
+
"requested_outputs",
|
|
64
|
+
"constraint_refs",
|
|
65
|
+
"artifact_policy",
|
|
66
|
+
"proof_refs",
|
|
67
|
+
"attestation_refs",
|
|
68
|
+
"input_hashes",
|
|
69
|
+
"output_hashes",
|
|
51
70
|
"tags",
|
|
52
71
|
"owners",
|
|
53
72
|
"links",
|
|
@@ -10,6 +10,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
const sort_1 = require("../util/sort");
|
|
11
11
|
const indexer_1 = require("./indexer");
|
|
12
12
|
const staleness_1 = require("./staleness");
|
|
13
|
+
const bundle_imports_1 = require("./bundle_imports");
|
|
13
14
|
function readIndex(indexPath) {
|
|
14
15
|
try {
|
|
15
16
|
const raw = fs_1.default.readFileSync(indexPath, "utf8");
|
|
@@ -29,22 +30,38 @@ function loadIndex(options) {
|
|
|
29
30
|
const useCache = options.useCache ?? true;
|
|
30
31
|
const allowReindex = options.allowReindex ?? options.config.index.auto_reindex;
|
|
31
32
|
const tolerant = options.tolerant ?? options.config.index.tolerant;
|
|
33
|
+
const includeImports = options.includeImports ?? true;
|
|
32
34
|
const indexPath = path_1.default.resolve(options.root, options.config.index.global_index_path);
|
|
35
|
+
const withImports = (index, rebuilt, stale) => {
|
|
36
|
+
if (!includeImports || Object.keys(options.config.bundle_imports).length === 0) {
|
|
37
|
+
return { index, rebuilt, stale, warnings: [] };
|
|
38
|
+
}
|
|
39
|
+
const imports = (0, bundle_imports_1.buildBundleImportsIndex)(options.root, options.config);
|
|
40
|
+
if (allowReindex) {
|
|
41
|
+
(0, bundle_imports_1.writeBundleImportsIndex)((0, bundle_imports_1.resolveBundleImportsIndexPath)(options.root), imports.index);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
index: (0, bundle_imports_1.mergeBundleImportsIntoIndex)(index, imports),
|
|
45
|
+
rebuilt,
|
|
46
|
+
stale: stale || (0, bundle_imports_1.isBundleImportsIndexStale)(options.root, options.config),
|
|
47
|
+
warnings: (0, bundle_imports_1.importWarnings)(imports),
|
|
48
|
+
};
|
|
49
|
+
};
|
|
33
50
|
if (!useCache) {
|
|
34
51
|
const index = (0, indexer_1.buildIndex)(options.root, options.config, { tolerant });
|
|
35
|
-
return
|
|
52
|
+
return withImports(index, true, false);
|
|
36
53
|
}
|
|
37
54
|
const stale = (0, staleness_1.isIndexStale)(options.root, options.config);
|
|
38
55
|
if (fs_1.default.existsSync(indexPath) && !stale) {
|
|
39
|
-
return
|
|
56
|
+
return withImports(readIndex(indexPath), false, false);
|
|
40
57
|
}
|
|
41
58
|
if (allowReindex) {
|
|
42
59
|
const index = (0, indexer_1.buildIndex)(options.root, options.config, { tolerant });
|
|
43
60
|
writeIndex(indexPath, index);
|
|
44
|
-
return
|
|
61
|
+
return withImports(index, true, stale);
|
|
45
62
|
}
|
|
46
63
|
if (fs_1.default.existsSync(indexPath)) {
|
|
47
|
-
return
|
|
64
|
+
return withImports(readIndex(indexPath), false, true);
|
|
48
65
|
}
|
|
49
66
|
throw new Error("index missing and auto-reindex is disabled");
|
|
50
67
|
}
|
package/dist/graph/indexer.js
CHANGED
|
@@ -141,7 +141,10 @@ function buildIndex(root, config, options = {}) {
|
|
|
141
141
|
nodes,
|
|
142
142
|
reverse_edges,
|
|
143
143
|
};
|
|
144
|
-
(0, validate_graph_1.validateGraph)(index, {
|
|
144
|
+
(0, validate_graph_1.validateGraph)(index, {
|
|
145
|
+
allowMissing: tolerant,
|
|
146
|
+
externalWorkspaces: new Set(Object.keys(config.bundle_imports ?? {})),
|
|
147
|
+
});
|
|
145
148
|
const latestCheckpointByWorkspace = {};
|
|
146
149
|
for (const alias of workspaceAliases) {
|
|
147
150
|
const candidates = Object.values(nodes)
|
package/dist/graph/node.js
CHANGED
|
@@ -5,7 +5,9 @@ exports.parseNode = parseNode;
|
|
|
5
5
|
const frontmatter_1 = require("./frontmatter");
|
|
6
6
|
const edges_1 = require("./edges");
|
|
7
7
|
const agent_file_types_1 = require("./agent_file_types");
|
|
8
|
+
const archive_file_1 = require("./archive_file");
|
|
8
9
|
const id_1 = require("../util/id");
|
|
10
|
+
const refs_1 = require("../util/refs");
|
|
9
11
|
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
10
12
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
11
13
|
exports.WORK_TYPES = new Set(["epic", "feat", "task", "bug", "checkpoint", "test"]);
|
|
@@ -22,6 +24,7 @@ exports.ALLOWED_TYPES = new Set([
|
|
|
22
24
|
"bug",
|
|
23
25
|
"checkpoint",
|
|
24
26
|
"test",
|
|
27
|
+
"archive",
|
|
25
28
|
...agent_file_types_1.AGENT_FILE_TYPES,
|
|
26
29
|
]);
|
|
27
30
|
const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
@@ -119,6 +122,17 @@ function normalizeIdList(values, key, filePath, allowPortableIds = false) {
|
|
|
119
122
|
return value;
|
|
120
123
|
});
|
|
121
124
|
}
|
|
125
|
+
function normalizeRefsList(values, key, filePath, allowPortableOrUriRefs = false) {
|
|
126
|
+
if (!allowPortableOrUriRefs) {
|
|
127
|
+
return normalizeIdList(values, key, filePath);
|
|
128
|
+
}
|
|
129
|
+
return values.map((value) => {
|
|
130
|
+
if (!(0, refs_1.validatePortableOrUriRef)(value)) {
|
|
131
|
+
throw formatError(filePath, `${key} entries must be portable ids or URI refs`);
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
122
136
|
function normalizeSkillList(values, filePath) {
|
|
123
137
|
return values.map((value, index) => {
|
|
124
138
|
const normalized = value.toLowerCase();
|
|
@@ -166,11 +180,13 @@ function parseNode(content, filePath, options) {
|
|
|
166
180
|
throw formatError(filePath, `type must be one of ${Array.from(exports.ALLOWED_TYPES).join(", ")}`);
|
|
167
181
|
}
|
|
168
182
|
const isAgentType = (0, agent_file_types_1.isAgentFileType)(type);
|
|
183
|
+
const isPortableType = isAgentType || (0, archive_file_1.isArchiveType)(type);
|
|
169
184
|
const schema = requireTemplateSchema(type, options.templateSchemas, filePath);
|
|
170
185
|
validateTemplateKeys(frontmatter, schema, filePath);
|
|
171
186
|
(0, agent_file_types_1.validateAgentFrontmatter)(type, frontmatter, filePath);
|
|
187
|
+
(0, archive_file_1.validateArchiveFrontmatter)(type, frontmatter, filePath);
|
|
172
188
|
const idValue = requireLowercase(expectString(frontmatter, "id", filePath), "id", filePath);
|
|
173
|
-
const id =
|
|
189
|
+
const id = isPortableType
|
|
174
190
|
? requirePortableIdFormat(idValue, "id", filePath)
|
|
175
191
|
: requireIdFormat(idValue, "id", filePath);
|
|
176
192
|
const title = expectString(frontmatter, "title", filePath);
|
|
@@ -214,7 +230,7 @@ function parseNode(content, filePath, options) {
|
|
|
214
230
|
const owners = requireLowercaseList(optionalList(frontmatter, "owners", filePath), "owners", filePath);
|
|
215
231
|
const links = optionalList(frontmatter, "links", filePath);
|
|
216
232
|
const artifacts = optionalList(frontmatter, "artifacts", filePath);
|
|
217
|
-
const refs =
|
|
233
|
+
const refs = normalizeRefsList(optionalList(frontmatter, "refs", filePath), "refs", filePath, isPortableType);
|
|
218
234
|
const aliases = requireLowercaseList(optionalList(frontmatter, "aliases", filePath), "aliases", filePath);
|
|
219
235
|
const skillsRaw = optionalList(frontmatter, "skills", filePath);
|
|
220
236
|
const skills = normalizeSkillList(skillsRaw, filePath);
|
|
@@ -232,8 +248,11 @@ function parseNode(content, filePath, options) {
|
|
|
232
248
|
throw formatError(filePath, "supersedes must be a dec-# id");
|
|
233
249
|
}
|
|
234
250
|
}
|
|
235
|
-
const edges = (0, edges_1.extractEdges)(frontmatter, filePath, { allowPortableRefs:
|
|
236
|
-
const attributes =
|
|
251
|
+
const edges = (0, edges_1.extractEdges)(frontmatter, filePath, { allowPortableRefs: isPortableType });
|
|
252
|
+
const attributes = {
|
|
253
|
+
...(0, agent_file_types_1.extractAgentAttributes)(type, frontmatter),
|
|
254
|
+
...(0, archive_file_1.extractArchiveAttributes)(type, frontmatter),
|
|
255
|
+
};
|
|
237
256
|
return {
|
|
238
257
|
id,
|
|
239
258
|
type,
|
|
@@ -0,0 +1,37 @@
|
|
|
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.readNodeBody = readNodeBody;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const frontmatter_1 = require("./frontmatter");
|
|
10
|
+
const zip_1 = require("../util/zip");
|
|
11
|
+
const errors_1 = require("../util/errors");
|
|
12
|
+
function readImportedBody(root, node) {
|
|
13
|
+
const source = node.source;
|
|
14
|
+
if (!source?.imported) {
|
|
15
|
+
throw new Error("node is not imported");
|
|
16
|
+
}
|
|
17
|
+
const bundlePath = path_1.default.resolve(root, source.bundle_path);
|
|
18
|
+
if (!fs_1.default.existsSync(bundlePath)) {
|
|
19
|
+
throw new errors_1.NotFoundError(`bundle not found for ${node.qid}: ${source.bundle_path}`);
|
|
20
|
+
}
|
|
21
|
+
const entry = (0, zip_1.readZipEntries)(fs_1.default.readFileSync(bundlePath)).find((candidate) => candidate.name === source.original_path);
|
|
22
|
+
if (!entry) {
|
|
23
|
+
throw new errors_1.NotFoundError(`bundle entry not found for ${node.qid}: ${source.original_path}`);
|
|
24
|
+
}
|
|
25
|
+
return (0, frontmatter_1.parseFrontmatter)(entry.data.toString("utf8"), source.original_path).body.trimEnd();
|
|
26
|
+
}
|
|
27
|
+
function readNodeBody(root, node) {
|
|
28
|
+
if (node.source?.imported) {
|
|
29
|
+
return readImportedBody(root, node);
|
|
30
|
+
}
|
|
31
|
+
const filePath = path_1.default.resolve(root, node.path);
|
|
32
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
33
|
+
throw new errors_1.NotFoundError(`file not found for ${node.qid}: ${node.path}`);
|
|
34
|
+
}
|
|
35
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
36
|
+
return (0, frontmatter_1.parseFrontmatter)(content, filePath).body.trimEnd();
|
|
37
|
+
}
|
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SKILL_SLUG_RE = exports.SKILLS_INDEX_RELATIVE_PATH = void 0;
|
|
7
|
+
exports.listSkillMarkdownFiles = listSkillMarkdownFiles;
|
|
7
8
|
exports.resolveSkillsRoot = resolveSkillsRoot;
|
|
8
9
|
exports.resolveSkillsIndexPath = resolveSkillsIndexPath;
|
|
10
|
+
exports.buildSkillIndexEntryForWorkspace = buildSkillIndexEntryForWorkspace;
|
|
9
11
|
exports.buildSkillIndexEntry = buildSkillIndexEntry;
|
|
10
12
|
exports.buildSkillsIndex = buildSkillsIndex;
|
|
11
13
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -107,7 +109,7 @@ function resolveSkillsRoot(root, config) {
|
|
|
107
109
|
function resolveSkillsIndexPath(root) {
|
|
108
110
|
return path_1.default.resolve(root, exports.SKILLS_INDEX_RELATIVE_PATH);
|
|
109
111
|
}
|
|
110
|
-
function
|
|
112
|
+
function buildSkillIndexEntryForWorkspace(root, workspace, slug, filePath) {
|
|
111
113
|
if (!exports.SKILL_SLUG_RE.test(slug)) {
|
|
112
114
|
throw new Error(`${filePath}: skill slug must be kebab-case`);
|
|
113
115
|
}
|
|
@@ -128,8 +130,8 @@ function buildSkillIndexEntry(root, slug, filePath) {
|
|
|
128
130
|
return {
|
|
129
131
|
slug,
|
|
130
132
|
id: `skill:${slug}`,
|
|
131
|
-
qid:
|
|
132
|
-
ws:
|
|
133
|
+
qid: `${workspace}:skill:${slug}`,
|
|
134
|
+
ws: workspace,
|
|
133
135
|
type: "skill",
|
|
134
136
|
name,
|
|
135
137
|
description,
|
|
@@ -144,6 +146,9 @@ function buildSkillIndexEntry(root, slug, filePath) {
|
|
|
144
146
|
ochatr,
|
|
145
147
|
};
|
|
146
148
|
}
|
|
149
|
+
function buildSkillIndexEntry(root, slug, filePath) {
|
|
150
|
+
return buildSkillIndexEntryForWorkspace(root, "root", slug, filePath);
|
|
151
|
+
}
|
|
147
152
|
function buildSkillsIndex(root, config) {
|
|
148
153
|
const skillsRoot = resolveSkillsRoot(root, config);
|
|
149
154
|
const files = listSkillMarkdownFiles(skillsRoot);
|
|
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.loadTemplateSchemas = loadTemplateSchemas;
|
|
7
|
+
exports.loadTemplateSchemasWithInfo = loadTemplateSchemasWithInfo;
|
|
7
8
|
const fs_1 = __importDefault(require("fs"));
|
|
8
9
|
const path_1 = __importDefault(require("path"));
|
|
9
10
|
const frontmatter_1 = require("./frontmatter");
|
|
11
|
+
const builtin_1 = require("../templates/builtin");
|
|
10
12
|
function listMarkdownFiles(dir) {
|
|
11
13
|
if (!fs_1.default.existsSync(dir)) {
|
|
12
14
|
return [];
|
|
@@ -45,9 +47,12 @@ function addKeyToSchema(schema, key, kind, filePath) {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
function loadTemplateSchemas(root, config, requiredTypes) {
|
|
50
|
+
return loadTemplateSchemasWithInfo(root, config, requiredTypes).schemas;
|
|
51
|
+
}
|
|
52
|
+
function loadTemplateSchemasWithInfo(root, config, requiredTypes) {
|
|
48
53
|
const templateRoot = path_1.default.resolve(root, config.templates.root_path, config.templates.default_set);
|
|
49
54
|
const files = listMarkdownFiles(templateRoot);
|
|
50
|
-
if (files.length === 0) {
|
|
55
|
+
if (files.length === 0 && !requiredTypes) {
|
|
51
56
|
throw new Error(`no templates found at ${templateRoot}`);
|
|
52
57
|
}
|
|
53
58
|
const schemas = {};
|
|
@@ -75,12 +80,35 @@ function loadTemplateSchemas(root, config, requiredTypes) {
|
|
|
75
80
|
addKeyToSchema(schema, key, kind, filePath);
|
|
76
81
|
}
|
|
77
82
|
}
|
|
83
|
+
const fallbackTypes = [];
|
|
78
84
|
if (requiredTypes) {
|
|
79
85
|
const required = Array.from(requiredTypes, (value) => value.toLowerCase());
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
for (const missingType of required.filter((value) => !schemas[value])) {
|
|
87
|
+
const bundledPath = (0, builtin_1.requireBundledTemplatePath)(missingType);
|
|
88
|
+
const content = fs_1.default.readFileSync(bundledPath, "utf8");
|
|
89
|
+
const { frontmatter } = (0, frontmatter_1.parseFrontmatter)(content, bundledPath);
|
|
90
|
+
const typeValue = frontmatter.type;
|
|
91
|
+
if (typeValue !== missingType) {
|
|
92
|
+
throw new Error(`bundled template fallback type mismatch for ${missingType}: ${bundledPath}`);
|
|
93
|
+
}
|
|
94
|
+
const schema = {
|
|
95
|
+
type: missingType,
|
|
96
|
+
allowedKeys: new Set(),
|
|
97
|
+
keyKinds: {},
|
|
98
|
+
listKeys: new Set(),
|
|
99
|
+
};
|
|
100
|
+
schemas[missingType] = schema;
|
|
101
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
102
|
+
const kind = getValueKind(value);
|
|
103
|
+
addKeyToSchema(schema, key, kind, bundledPath);
|
|
104
|
+
}
|
|
105
|
+
fallbackTypes.push(missingType);
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
|
-
return
|
|
108
|
+
return {
|
|
109
|
+
schemas,
|
|
110
|
+
templateRoot,
|
|
111
|
+
bundledTemplateRoot: (0, builtin_1.resolveBundledTemplateRoot)(),
|
|
112
|
+
fallbackTypes,
|
|
113
|
+
};
|
|
86
114
|
}
|