mdkg 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +31 -15
- package/dist/cli.js +182 -85
- package/dist/commands/archive.js +20 -8
- package/dist/commands/bundle.js +7 -7
- package/dist/commands/capability.js +118 -4
- package/dist/commands/checkpoint.js +31 -5
- package/dist/commands/doctor.js +61 -24
- package/dist/commands/index.js +12 -23
- package/dist/commands/init.js +7 -1
- package/dist/commands/list.js +1 -1
- package/dist/commands/new.js +33 -7
- package/dist/commands/next.js +1 -1
- package/dist/commands/node_card.js +1 -1
- package/dist/commands/pack.js +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/show.js +1 -1
- package/dist/commands/subgraph.js +312 -0
- package/dist/commands/task.js +21 -7
- package/dist/commands/upgrade.js +51 -4
- package/dist/commands/validate.js +12 -6
- package/dist/commands/work.js +44 -12
- package/dist/core/config.js +110 -39
- package/dist/graph/capabilities_index_cache.js +2 -2
- package/dist/graph/index_cache.js +14 -14
- package/dist/graph/indexer.js +1 -1
- package/dist/graph/reindex.js +46 -0
- package/dist/graph/skills_index_cache.js +2 -2
- package/dist/graph/sqlite_index.js +293 -0
- package/dist/graph/{bundle_imports.js → subgraphs.js} +216 -142
- package/dist/graph/visibility.js +3 -3
- package/dist/init/AGENT_START.md +5 -1
- package/dist/init/CLI_COMMAND_MATRIX.md +21 -7
- package/dist/init/README.md +20 -10
- package/dist/init/config.json +6 -2
- package/dist/init/core/rule-1-mdkg-conventions.md +2 -1
- package/dist/init/core/rule-3-cli-contract.md +32 -24
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +28 -12
- package/dist/init/core/rule-5-release-and-versioning.md +4 -3
- package/dist/init/init-manifest.json +10 -10
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +1 -1
- package/dist/util/argparse.js +2 -0
- package/dist/util/atomic.js +44 -0
- package/dist/util/lock.js +72 -0
- package/package.json +13 -9
- package/dist/commands/bundle_import.js +0 -243
|
@@ -3,20 +3,21 @@ 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.
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
9
|
-
exports.
|
|
10
|
-
exports.
|
|
11
|
-
exports.
|
|
12
|
-
exports.
|
|
6
|
+
exports.resolveSubgraphsIndexPath = resolveSubgraphsIndexPath;
|
|
7
|
+
exports.buildSubgraphsIndex = buildSubgraphsIndex;
|
|
8
|
+
exports.writeSubgraphsIndex = writeSubgraphsIndex;
|
|
9
|
+
exports.isSubgraphsIndexStale = isSubgraphsIndexStale;
|
|
10
|
+
exports.mergeSubgraphsIntoIndex = mergeSubgraphsIntoIndex;
|
|
11
|
+
exports.subgraphWarnings = subgraphWarnings;
|
|
12
|
+
exports.buildSubgraphCapabilityRecords = buildSubgraphCapabilityRecords;
|
|
13
13
|
const crypto_1 = __importDefault(require("crypto"));
|
|
14
14
|
const fs_1 = __importDefault(require("fs"));
|
|
15
15
|
const path_1 = __importDefault(require("path"));
|
|
16
16
|
const child_process_1 = require("child_process");
|
|
17
17
|
const paths_1 = require("../core/paths");
|
|
18
|
+
const atomic_1 = require("../util/atomic");
|
|
18
19
|
const zip_1 = require("../util/zip");
|
|
19
|
-
const
|
|
20
|
+
const SUBGRAPHS_CACHE_VERSION = 1;
|
|
20
21
|
const MANIFEST_ENTRY = "manifest.json";
|
|
21
22
|
const GLOBAL_INDEX_ENTRY = ".mdkg/index/global.json";
|
|
22
23
|
const SKILLS_INDEX_ENTRY = ".mdkg/index/skills.json";
|
|
@@ -37,8 +38,8 @@ function readJsonEntry(entries, entryPath) {
|
|
|
37
38
|
function readBundleEntries(bundlePath) {
|
|
38
39
|
return new Map((0, zip_1.readZipEntries)(fs_1.default.readFileSync(bundlePath)).map((entry) => [entry.name, entry.data]));
|
|
39
40
|
}
|
|
40
|
-
function resolveBundlePath(root,
|
|
41
|
-
return path_1.default.resolve(root,
|
|
41
|
+
function resolveBundlePath(root, source) {
|
|
42
|
+
return path_1.default.resolve(root, source.path);
|
|
42
43
|
}
|
|
43
44
|
function gitOutput(cwd, args) {
|
|
44
45
|
const result = (0, child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
@@ -48,13 +49,13 @@ function gitOutput(cwd, args) {
|
|
|
48
49
|
const output = result.stdout.trim();
|
|
49
50
|
return output.length > 0 ? output : null;
|
|
50
51
|
}
|
|
51
|
-
function sourcePathState(root,
|
|
52
|
-
if (!
|
|
52
|
+
function sourcePathState(root, subgraph, manifest, warnings, errors) {
|
|
53
|
+
if (!subgraph.source_path) {
|
|
53
54
|
return false;
|
|
54
55
|
}
|
|
55
|
-
const sourceRoot = path_1.default.resolve(root,
|
|
56
|
+
const sourceRoot = path_1.default.resolve(root, subgraph.source_path);
|
|
56
57
|
if (!fs_1.default.existsSync(sourceRoot)) {
|
|
57
|
-
errors.push(`source_path does not exist: ${
|
|
58
|
+
errors.push(`source_path does not exist: ${subgraph.source_path}`);
|
|
58
59
|
return false;
|
|
59
60
|
}
|
|
60
61
|
const currentHead = gitOutput(sourceRoot, ["rev-parse", "HEAD"]);
|
|
@@ -65,20 +66,17 @@ function sourcePathState(root, entry, manifest, warnings, errors) {
|
|
|
65
66
|
stale = true;
|
|
66
67
|
}
|
|
67
68
|
if (currentStatus) {
|
|
68
|
-
warnings.push(`source_path has uncommitted changes: ${
|
|
69
|
+
warnings.push(`source_path has uncommitted changes: ${subgraph.source_path}`);
|
|
69
70
|
stale = true;
|
|
70
71
|
}
|
|
71
72
|
return stale;
|
|
72
73
|
}
|
|
73
|
-
function ageState(bundlePath,
|
|
74
|
-
if (entry.max_stale_seconds === undefined) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
74
|
+
function ageState(bundlePath, maxStaleSeconds, warnings) {
|
|
77
75
|
const ageSeconds = Math.floor((Date.now() - fs_1.default.statSync(bundlePath).mtimeMs) / 1000);
|
|
78
|
-
if (ageSeconds <=
|
|
76
|
+
if (ageSeconds <= maxStaleSeconds) {
|
|
79
77
|
return false;
|
|
80
78
|
}
|
|
81
|
-
warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${
|
|
79
|
+
warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${maxStaleSeconds}`);
|
|
82
80
|
return true;
|
|
83
81
|
}
|
|
84
82
|
function remapTarget(target, qidMap) {
|
|
@@ -130,72 +128,147 @@ function entryHashErrors(entries, manifest) {
|
|
|
130
128
|
}
|
|
131
129
|
return errors;
|
|
132
130
|
}
|
|
133
|
-
function
|
|
134
|
-
const bundlePath = resolveBundlePath(root,
|
|
131
|
+
function projectOneSource(root, subgraph, source) {
|
|
132
|
+
const bundlePath = resolveBundlePath(root, source);
|
|
135
133
|
const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
|
|
136
134
|
const warnings = [];
|
|
137
135
|
const errors = [];
|
|
138
|
-
const nodes = {};
|
|
139
|
-
const reverse_edges = {};
|
|
140
136
|
let manifest;
|
|
141
|
-
let
|
|
137
|
+
let index;
|
|
138
|
+
let entries;
|
|
142
139
|
let stale = false;
|
|
143
|
-
if (!
|
|
140
|
+
if (!source.enabled) {
|
|
144
141
|
return {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
source,
|
|
143
|
+
relativeBundlePath,
|
|
144
|
+
sourceHealth: {
|
|
145
|
+
label: source.label,
|
|
146
|
+
path: source.path,
|
|
148
147
|
enabled: false,
|
|
149
|
-
|
|
150
|
-
expected_profile: entry.expected_profile,
|
|
148
|
+
expected_profile: source.expected_profile,
|
|
151
149
|
stale: false,
|
|
152
150
|
warning_count: 0,
|
|
153
151
|
error_count: 0,
|
|
154
152
|
warnings: [],
|
|
155
153
|
errors: [],
|
|
156
154
|
},
|
|
157
|
-
nodes,
|
|
158
|
-
reverse_edges,
|
|
159
155
|
};
|
|
160
156
|
}
|
|
161
157
|
try {
|
|
162
158
|
if (!fs_1.default.existsSync(bundlePath)) {
|
|
163
|
-
throw new Error(`bundle not found: ${
|
|
159
|
+
throw new Error(`bundle not found: ${source.path}`);
|
|
164
160
|
}
|
|
165
|
-
|
|
161
|
+
entries = readBundleEntries(bundlePath);
|
|
166
162
|
manifest = readJsonEntry(entries, MANIFEST_ENTRY);
|
|
167
|
-
|
|
163
|
+
index = readJsonEntry(entries, GLOBAL_INDEX_ENTRY);
|
|
168
164
|
readJsonEntry(entries, SKILLS_INDEX_ENTRY);
|
|
169
165
|
readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
|
|
170
166
|
errors.push(...entryHashErrors(entries, manifest));
|
|
171
|
-
if (manifest.profile !==
|
|
172
|
-
errors.push(`expected ${
|
|
167
|
+
if (manifest.profile !== source.expected_profile) {
|
|
168
|
+
errors.push(`expected ${source.expected_profile} bundle but found ${manifest.profile}`);
|
|
173
169
|
}
|
|
174
|
-
stale = sourcePathState(root,
|
|
175
|
-
stale = ageState(bundlePath,
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
stale = sourcePathState(root, subgraph, manifest, warnings, errors) || stale;
|
|
171
|
+
stale = ageState(bundlePath, subgraph.max_stale_seconds, warnings) || stale;
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
errors.push(err instanceof Error ? err.message : String(err));
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
source,
|
|
178
|
+
relativeBundlePath,
|
|
179
|
+
manifest,
|
|
180
|
+
index,
|
|
181
|
+
entries,
|
|
182
|
+
sourceHealth: {
|
|
183
|
+
label: source.label,
|
|
184
|
+
path: source.path,
|
|
185
|
+
enabled: source.enabled,
|
|
186
|
+
expected_profile: source.expected_profile,
|
|
187
|
+
profile: manifest?.profile,
|
|
188
|
+
bundle_hash: manifest?.bundle_hash,
|
|
189
|
+
source_git_head: manifest?.source?.git_head ?? null,
|
|
190
|
+
stale,
|
|
191
|
+
warning_count: warnings.length,
|
|
192
|
+
error_count: errors.length,
|
|
193
|
+
warnings,
|
|
194
|
+
errors,
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function projectOneSubgraph(root, alias, subgraph) {
|
|
199
|
+
const nodes = {};
|
|
200
|
+
const reverse_edges = {};
|
|
201
|
+
if (!subgraph.enabled) {
|
|
202
|
+
return {
|
|
203
|
+
health: {
|
|
204
|
+
alias,
|
|
205
|
+
enabled: false,
|
|
206
|
+
visibility: subgraph.visibility,
|
|
207
|
+
permissions: subgraph.permissions,
|
|
208
|
+
source_path: subgraph.source_path,
|
|
209
|
+
source_repo: subgraph.source_repo,
|
|
210
|
+
stale: false,
|
|
211
|
+
warning_count: 0,
|
|
212
|
+
error_count: 0,
|
|
213
|
+
warnings: [],
|
|
214
|
+
errors: [],
|
|
215
|
+
sources: subgraph.sources.map((source) => ({
|
|
216
|
+
label: source.label,
|
|
217
|
+
path: source.path,
|
|
218
|
+
enabled: source.enabled,
|
|
219
|
+
expected_profile: source.expected_profile,
|
|
220
|
+
stale: false,
|
|
221
|
+
warning_count: 0,
|
|
222
|
+
error_count: 0,
|
|
223
|
+
warnings: [],
|
|
224
|
+
errors: [],
|
|
225
|
+
})),
|
|
226
|
+
},
|
|
227
|
+
nodes,
|
|
228
|
+
reverse_edges,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const loadedSources = subgraph.sources.map((source) => projectOneSource(root, subgraph, source));
|
|
232
|
+
const warnings = loadedSources.flatMap((item) => item.sourceHealth.warnings);
|
|
233
|
+
const errors = loadedSources.flatMap((item) => item.sourceHealth.errors);
|
|
234
|
+
const stale = loadedSources.some((item) => item.sourceHealth.stale);
|
|
235
|
+
const idOwners = new Map();
|
|
236
|
+
for (const loaded of loadedSources) {
|
|
237
|
+
if (!loaded.source.enabled || loaded.sourceHealth.error_count > 0 || !loaded.index) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
for (const node of Object.values(loaded.index.nodes)) {
|
|
178
241
|
const owners = idOwners.get(node.id) ?? [];
|
|
179
|
-
owners.push(node.qid);
|
|
242
|
+
owners.push(`${loaded.source.label ?? loaded.source.path}:${node.qid}`);
|
|
180
243
|
idOwners.set(node.id, owners);
|
|
181
244
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
245
|
+
}
|
|
246
|
+
for (const [id, owners] of idOwners.entries()) {
|
|
247
|
+
if (owners.length > 1) {
|
|
248
|
+
errors.push(`duplicate projected id ${id} from ${owners.join(", ")}; split sources into separate subgraphs or use portable unique ids`);
|
|
186
249
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
250
|
+
}
|
|
251
|
+
if (errors.length === 0) {
|
|
252
|
+
const qidMap = new Map();
|
|
253
|
+
for (const loaded of loadedSources) {
|
|
254
|
+
if (!loaded.source.enabled || !loaded.index) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
for (const node of Object.values(loaded.index.nodes)) {
|
|
190
258
|
qidMap.set(node.qid, `${alias}:${node.id}`);
|
|
191
259
|
}
|
|
192
|
-
|
|
260
|
+
}
|
|
261
|
+
for (const loaded of loadedSources) {
|
|
262
|
+
if (!loaded.source.enabled || !loaded.index) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
for (const node of Object.values(loaded.index.nodes)) {
|
|
193
266
|
const projectedQid = qidMap.get(node.qid);
|
|
194
267
|
const projected = {
|
|
195
268
|
...node,
|
|
196
269
|
ws: alias,
|
|
197
270
|
qid: projectedQid,
|
|
198
|
-
path: `${relativeBundlePath}#${toPosixPath(node.path)}`,
|
|
271
|
+
path: `${loaded.relativeBundlePath}#${toPosixPath(node.path)}`,
|
|
199
272
|
attributes: { ...(node.attributes ?? {}) },
|
|
200
273
|
edges: {
|
|
201
274
|
epic: remapTarget(node.edges.epic, qidMap),
|
|
@@ -209,18 +282,19 @@ function projectOneImport(root, alias, entry) {
|
|
|
209
282
|
source: {
|
|
210
283
|
imported: true,
|
|
211
284
|
read_only: true,
|
|
212
|
-
|
|
285
|
+
subgraph_alias: alias,
|
|
213
286
|
original_qid: node.qid,
|
|
214
287
|
original_ws: node.ws,
|
|
215
288
|
original_path: toPosixPath(node.path),
|
|
216
|
-
bundle_path: relativeBundlePath,
|
|
217
|
-
bundle_hash: manifest
|
|
218
|
-
profile: manifest
|
|
219
|
-
visibility:
|
|
289
|
+
bundle_path: loaded.relativeBundlePath,
|
|
290
|
+
bundle_hash: loaded.manifest?.bundle_hash,
|
|
291
|
+
profile: loaded.manifest?.profile,
|
|
292
|
+
visibility: subgraph.visibility,
|
|
293
|
+
permissions: subgraph.permissions,
|
|
220
294
|
stale,
|
|
221
295
|
warnings: [...warnings],
|
|
222
|
-
source_repo:
|
|
223
|
-
source_git_head: manifest
|
|
296
|
+
source_repo: subgraph.source_repo ?? loaded.manifest?.source?.repo,
|
|
297
|
+
source_git_head: loaded.manifest?.source?.git_head ?? null,
|
|
224
298
|
},
|
|
225
299
|
};
|
|
226
300
|
nodes[projected.qid] = projected;
|
|
@@ -228,46 +302,41 @@ function projectOneImport(root, alias, entry) {
|
|
|
228
302
|
}
|
|
229
303
|
}
|
|
230
304
|
}
|
|
231
|
-
catch (err) {
|
|
232
|
-
errors.push(err instanceof Error ? err.message : String(err));
|
|
233
|
-
}
|
|
234
305
|
return {
|
|
235
306
|
health: {
|
|
236
307
|
alias,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
bundle_hash: manifest?.bundle_hash,
|
|
243
|
-
source_git_head: manifest?.source?.git_head ?? null,
|
|
244
|
-
source_repo: entry.source_repo ?? manifest?.source?.repo,
|
|
308
|
+
enabled: subgraph.enabled,
|
|
309
|
+
visibility: subgraph.visibility,
|
|
310
|
+
permissions: subgraph.permissions,
|
|
311
|
+
source_path: subgraph.source_path,
|
|
312
|
+
source_repo: subgraph.source_repo,
|
|
245
313
|
stale,
|
|
246
314
|
warning_count: warnings.length,
|
|
247
315
|
error_count: errors.length,
|
|
248
316
|
warnings,
|
|
249
317
|
errors,
|
|
318
|
+
sources: loadedSources.map((item) => item.sourceHealth),
|
|
250
319
|
},
|
|
251
320
|
nodes,
|
|
252
321
|
reverse_edges,
|
|
253
322
|
};
|
|
254
323
|
}
|
|
255
|
-
function
|
|
256
|
-
return path_1.default.resolve(root, ".mdkg", "index", "
|
|
324
|
+
function resolveSubgraphsIndexPath(root) {
|
|
325
|
+
return path_1.default.resolve(root, ".mdkg", "index", "subgraphs.json");
|
|
257
326
|
}
|
|
258
|
-
function
|
|
259
|
-
const
|
|
327
|
+
function buildSubgraphsIndex(root, config) {
|
|
328
|
+
const subgraphs = [];
|
|
260
329
|
const nodes = {};
|
|
261
330
|
const reverse_edges = {};
|
|
262
331
|
const workspaces = {};
|
|
263
|
-
for (const alias of Object.keys(config.
|
|
264
|
-
const
|
|
265
|
-
const projected =
|
|
266
|
-
|
|
267
|
-
if (!
|
|
332
|
+
for (const alias of Object.keys(config.subgraphs).sort()) {
|
|
333
|
+
const subgraph = config.subgraphs[alias];
|
|
334
|
+
const projected = projectOneSubgraph(root, alias, subgraph);
|
|
335
|
+
subgraphs.push(projected.health);
|
|
336
|
+
if (!subgraph.enabled || projected.health.error_count > 0) {
|
|
268
337
|
continue;
|
|
269
338
|
}
|
|
270
|
-
workspaces[alias] = { path: `
|
|
339
|
+
workspaces[alias] = { path: `subgraph:${alias}`, enabled: true };
|
|
271
340
|
Object.assign(nodes, projected.nodes);
|
|
272
341
|
for (const [edgeKey, targets] of Object.entries(projected.reverse_edges)) {
|
|
273
342
|
reverse_edges[edgeKey] = reverse_edges[edgeKey] ?? {};
|
|
@@ -284,45 +353,46 @@ function buildBundleImportsIndex(root, config) {
|
|
|
284
353
|
meta: {
|
|
285
354
|
tool: config.tool,
|
|
286
355
|
schema_version: config.schema_version,
|
|
287
|
-
cache_version:
|
|
356
|
+
cache_version: SUBGRAPHS_CACHE_VERSION,
|
|
288
357
|
generated_at: new Date().toISOString(),
|
|
289
358
|
root,
|
|
290
|
-
|
|
359
|
+
subgraph_count: subgraphs.length,
|
|
291
360
|
node_count: Object.keys(nodes).length,
|
|
292
361
|
},
|
|
293
|
-
|
|
362
|
+
subgraphs,
|
|
294
363
|
nodes,
|
|
295
364
|
reverse_edges,
|
|
296
365
|
},
|
|
297
366
|
workspaces,
|
|
298
367
|
};
|
|
299
368
|
}
|
|
300
|
-
function
|
|
301
|
-
|
|
302
|
-
fs_1.default.writeFileSync(indexPath, JSON.stringify(index, null, 2), "utf8");
|
|
369
|
+
function writeSubgraphsIndex(indexPath, index) {
|
|
370
|
+
(0, atomic_1.atomicWriteFile)(indexPath, JSON.stringify(index, null, 2));
|
|
303
371
|
}
|
|
304
|
-
function
|
|
305
|
-
const indexPath =
|
|
372
|
+
function isSubgraphsIndexStale(root, config) {
|
|
373
|
+
const indexPath = resolveSubgraphsIndexPath(root);
|
|
306
374
|
if (!fs_1.default.existsSync(indexPath)) {
|
|
307
|
-
return Object.keys(config.
|
|
375
|
+
return Object.keys(config.subgraphs).length > 0;
|
|
308
376
|
}
|
|
309
377
|
const indexMtime = fs_1.default.statSync(indexPath).mtimeMs;
|
|
310
378
|
const cfgPath = (0, paths_1.configPath)(root);
|
|
311
379
|
if (fs_1.default.existsSync(cfgPath) && fs_1.default.statSync(cfgPath).mtimeMs > indexMtime) {
|
|
312
380
|
return true;
|
|
313
381
|
}
|
|
314
|
-
for (const
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
382
|
+
for (const subgraph of Object.values(config.subgraphs)) {
|
|
383
|
+
for (const source of subgraph.sources) {
|
|
384
|
+
const bundlePath = path_1.default.resolve(root, source.path);
|
|
385
|
+
if (!fs_1.default.existsSync(bundlePath)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
if (fs_1.default.statSync(bundlePath).mtimeMs > indexMtime) {
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
321
391
|
}
|
|
322
392
|
}
|
|
323
393
|
return false;
|
|
324
394
|
}
|
|
325
|
-
function
|
|
395
|
+
function mergeSubgraphsIntoIndex(base, projection) {
|
|
326
396
|
const nodes = { ...base.nodes, ...projection.index.nodes };
|
|
327
397
|
const reverse_edges = JSON.parse(JSON.stringify(base.reverse_edges));
|
|
328
398
|
for (const [edgeKey, targets] of Object.entries(projection.index.reverse_edges)) {
|
|
@@ -348,70 +418,74 @@ function mergeBundleImportsIntoIndex(base, projection) {
|
|
|
348
418
|
reverse_edges,
|
|
349
419
|
};
|
|
350
420
|
}
|
|
351
|
-
function
|
|
421
|
+
function subgraphWarnings(projection) {
|
|
352
422
|
const warnings = [];
|
|
353
|
-
for (const item of projection.index.
|
|
423
|
+
for (const item of projection.index.subgraphs) {
|
|
354
424
|
for (const warning of item.warnings) {
|
|
355
|
-
warnings.push(`
|
|
425
|
+
warnings.push(`subgraph ${item.alias}: ${warning}`);
|
|
356
426
|
}
|
|
357
427
|
for (const error of item.errors) {
|
|
358
|
-
warnings.push(`
|
|
428
|
+
warnings.push(`subgraph ${item.alias}: ${error}`);
|
|
359
429
|
}
|
|
360
430
|
}
|
|
361
431
|
return warnings;
|
|
362
432
|
}
|
|
363
|
-
function
|
|
433
|
+
function buildSubgraphCapabilityRecords(root, config) {
|
|
364
434
|
const records = [];
|
|
365
435
|
const warnings = [];
|
|
366
|
-
for (const alias of Object.keys(config.
|
|
367
|
-
const
|
|
368
|
-
if (!
|
|
436
|
+
for (const alias of Object.keys(config.subgraphs).sort()) {
|
|
437
|
+
const subgraph = config.subgraphs[alias];
|
|
438
|
+
if (!subgraph.enabled) {
|
|
369
439
|
continue;
|
|
370
440
|
}
|
|
371
|
-
const projection =
|
|
441
|
+
const projection = projectOneSubgraph(root, alias, subgraph);
|
|
372
442
|
for (const warning of projection.health.warnings) {
|
|
373
|
-
warnings.push(`
|
|
443
|
+
warnings.push(`subgraph ${alias}: ${warning}`);
|
|
374
444
|
}
|
|
375
445
|
for (const error of projection.health.errors) {
|
|
376
|
-
warnings.push(`
|
|
446
|
+
warnings.push(`subgraph ${alias}: ${error}`);
|
|
377
447
|
}
|
|
378
448
|
if (projection.health.error_count > 0) {
|
|
379
449
|
continue;
|
|
380
450
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
workspace
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
451
|
+
for (const source of subgraph.sources) {
|
|
452
|
+
if (!source.enabled) {
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const bundlePath = resolveBundlePath(root, source);
|
|
457
|
+
const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
|
|
458
|
+
const entries = readBundleEntries(bundlePath);
|
|
459
|
+
const capabilities = readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
|
|
460
|
+
for (const record of capabilities.records ?? []) {
|
|
461
|
+
const id = String(record.id ?? "");
|
|
462
|
+
const originalQid = String(record.qid ?? id);
|
|
463
|
+
const originalWorkspace = String(record.workspace ?? "");
|
|
464
|
+
const originalPath = String(record.path ?? "");
|
|
465
|
+
records.push({
|
|
466
|
+
...record,
|
|
467
|
+
workspace: alias,
|
|
468
|
+
visibility: subgraph.visibility,
|
|
469
|
+
qid: `${alias}:${id}`,
|
|
470
|
+
path: `${relativeBundlePath}#${originalPath}`,
|
|
471
|
+
source: {
|
|
472
|
+
imported: true,
|
|
473
|
+
read_only: true,
|
|
474
|
+
subgraph_alias: alias,
|
|
475
|
+
original_qid: originalQid,
|
|
476
|
+
original_workspace: originalWorkspace,
|
|
477
|
+
original_path: originalPath,
|
|
478
|
+
bundle_path: relativeBundlePath,
|
|
479
|
+
stale: projection.health.stale,
|
|
480
|
+
permissions: subgraph.permissions,
|
|
481
|
+
warnings: [...projection.health.warnings],
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
warnings.push(`subgraph ${alias}: ${err instanceof Error ? err.message : String(err)}`);
|
|
411
488
|
}
|
|
412
|
-
}
|
|
413
|
-
catch (err) {
|
|
414
|
-
warnings.push(`bundle import ${alias}: ${err instanceof Error ? err.message : String(err)}`);
|
|
415
489
|
}
|
|
416
490
|
}
|
|
417
491
|
return { records, warnings };
|
package/dist/graph/visibility.js
CHANGED
|
@@ -45,9 +45,9 @@ function effectiveNodeVisibility(node, config) {
|
|
|
45
45
|
if (isVisibility(workspaceVisibility)) {
|
|
46
46
|
return workspaceVisibility;
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
if (isVisibility(
|
|
50
|
-
return
|
|
48
|
+
const subgraphVisibility = config.subgraphs[node.ws]?.visibility;
|
|
49
|
+
if (isVisibility(subgraphVisibility)) {
|
|
50
|
+
return subgraphVisibility;
|
|
51
51
|
}
|
|
52
52
|
return "private";
|
|
53
53
|
}
|
package/dist/init/AGENT_START.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This repository uses mdkg for deterministic project memory.
|
|
4
4
|
|
|
5
|
+
mdkg is pre-v1 public alpha software. Treat generated graph, cache, bundle, and DAL contracts as usable but still stabilizing before v1.
|
|
6
|
+
|
|
5
7
|
Read these files in order:
|
|
6
8
|
1. `.mdkg/core/SOUL.md` if it exists
|
|
7
9
|
2. `.mdkg/core/HUMAN.md` if it exists
|
|
@@ -23,12 +25,14 @@ Agent operating prompt:
|
|
|
23
25
|
- Use `mdkg search "..."` and `mdkg next` to discover current work.
|
|
24
26
|
- Use `mdkg skill list`, `mdkg skill search`, and `mdkg skill show <slug>` for skill discovery.
|
|
25
27
|
- Use `mdkg capability list/search/show` for deterministic skills, `SPEC.md`, `WORK.md`, core-doc, and design-doc capability discovery.
|
|
28
|
+
- Use `mdkg index` to refresh JSON compatibility caches and `.mdkg/index/mdkg.sqlite` when SQLite mode is enabled.
|
|
26
29
|
- Use `mdkg archive add/list/show/verify/compress` for committed source and artifact sidecars under `.mdkg/archive`.
|
|
27
30
|
- Use `mdkg work ...` helpers for semantic mirror contracts, work orders, receipts, and artifact registration.
|
|
28
31
|
- Treat work contracts, orders, and receipts as committed semantic mirrors only; never store raw secrets, credentials, live payment state, ledger mutations, or canonical marketplace state in mdkg.
|
|
29
32
|
- Use `artifact://...` for external/runtime-managed artifacts and `archive://...` for committed mdkg archive sidecars.
|
|
30
33
|
- Use `mdkg bundle create/list/show/verify` for explicit full `.mdkg` graph snapshot bundles.
|
|
31
|
-
- Use `mdkg
|
|
34
|
+
- Use `mdkg subgraph add/list/verify` to register child bundle snapshots as read-only planning context.
|
|
35
|
+
- Use `mdkg capability resolve` to rank local and subgraph capabilities for orchestration planning.
|
|
32
36
|
- Use `mdkg pack <id> --visibility public|internal` only when you need a public-safe or internal-safe pack; no flag remains private-capable local behavior.
|
|
33
37
|
- Mark archive sidecars public only with explicit `mdkg archive add --visibility public` intent.
|
|
34
38
|
- Treat sidecar `.md` plus deterministic `.zip` caches as the commit-eligible archive record; validation and `mdkg archive verify` both check ZIP payload integrity.
|
|
@@ -22,6 +22,11 @@ Primary commands:
|
|
|
22
22
|
- `mdkg task`
|
|
23
23
|
- `mdkg validate`
|
|
24
24
|
|
|
25
|
+
Index backend:
|
|
26
|
+
- fresh mdkg workspaces default to `index.backend: sqlite`
|
|
27
|
+
- `.mdkg/index/mdkg.sqlite` is rebuildable and commit-eligible when intentionally tracked
|
|
28
|
+
- JSON compatibility caches remain generated and ignored by default
|
|
29
|
+
|
|
25
30
|
Validation commands:
|
|
26
31
|
- `mdkg validate [--out <path>] [--quiet] [--json]`
|
|
27
32
|
|
|
@@ -87,6 +92,7 @@ Capability discovery:
|
|
|
87
92
|
- `mdkg capability list [--kind <skill|spec|work|core|design>] [--visibility <private|internal|public>] [--json]`
|
|
88
93
|
- `mdkg capability search "<query>" [--kind <kind>] [--visibility <level>] [--json]`
|
|
89
94
|
- `mdkg capability show <id-or-qid-or-slug> [--json]`
|
|
95
|
+
- `mdkg capability resolve [query] [--requires <capability>] [--fresh-only] [--json]`
|
|
90
96
|
- capability records are deterministic cache projections from Markdown
|
|
91
97
|
- records include source hash, headings, refs, and `indexed_at`
|
|
92
98
|
- normal task, epic, feat, bug, test, and checkpoint nodes are intentionally excluded
|
|
@@ -109,16 +115,24 @@ Graph snapshot bundles:
|
|
|
109
115
|
- `mdkg bundle verify [bundle-path] [--json]`
|
|
110
116
|
- `mdkg bundle show <bundle-path> [--json]`
|
|
111
117
|
- `mdkg bundle list [--json]`
|
|
112
|
-
- `mdkg bundle import add/list/rm/enable/disable/verify ...`
|
|
113
|
-
- `mdkg bundle import add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--json]`
|
|
114
|
-
- `mdkg bundle import verify [alias|--all] [--json]`
|
|
115
118
|
- default output is `.mdkg/bundles/<profile>/<workspace-or-all>.mdkg.zip`
|
|
116
119
|
- private bundles are explicit local graph transport artifacts
|
|
117
|
-
- bundle imports are read-only planning views and use import-alias qids such as `child_repo:task-1`
|
|
118
120
|
- repos that track archive caches or bundles should run `mdkg archive compress --all`, `mdkg archive verify --json`, `mdkg bundle create --profile private`, and `mdkg bundle verify .mdkg/bundles/private/all.mdkg.zip` before commit
|
|
119
121
|
- public bundles include only public workspace content and public archive sidecars
|
|
120
|
-
- public bundle creation fails when public records reference private graph, archive, or
|
|
121
|
-
|
|
122
|
+
- public bundle creation fails when public records reference private graph, archive, or subgraph records
|
|
123
|
+
|
|
124
|
+
Subgraph orchestration:
|
|
125
|
+
- `mdkg subgraph add <alias> <bundle-path> [--visibility private|internal|public] [--profile private|public] [--source-path <path>] [--json]`
|
|
126
|
+
- `mdkg subgraph list [--json]`
|
|
127
|
+
- `mdkg subgraph show <alias> [--json]`
|
|
128
|
+
- `mdkg subgraph rm <alias> [--json]`
|
|
129
|
+
- `mdkg subgraph enable <alias> [--json]`
|
|
130
|
+
- `mdkg subgraph disable <alias> [--json]`
|
|
131
|
+
- `mdkg subgraph verify [alias|--all] [--json]`
|
|
132
|
+
- `mdkg subgraph refresh [alias|--all] [--json]`
|
|
133
|
+
- subgraphs are read-only planning views and use subgraph-alias qids such as `child_repo:task-1`
|
|
134
|
+
- subgraph refresh reloads configured bundle sources only and never mutates child repos
|
|
135
|
+
- public/internal subgraphs require public bundle profiles
|
|
122
136
|
|
|
123
137
|
Work semantic mirrors:
|
|
124
138
|
- `mdkg work contract new "<title>" --id <work.id> --agent-id <agent.id> --kind <kind> --inputs <...> --outputs <...> [--required-capabilities <...>] [--pricing-model <...>] [--json]`
|
|
@@ -130,7 +144,7 @@ Work semantic mirrors:
|
|
|
130
144
|
- work commands mutate mdkg semantic mirror files only; production order, receipt, feedback, dispute, payment, ledger, marketplace inventory, fulfillment, and execution state remains canonical outside mdkg
|
|
131
145
|
- do not store raw secrets, credentials, live payment state, ledger mutations, or canonical marketplace state in work mirrors
|
|
132
146
|
- `artifact://...` refs identify external/runtime-managed artifacts; `archive://...` refs identify committed mdkg archive sidecars
|
|
133
|
-
- work update and artifact commands accept local ids or local qids;
|
|
147
|
+
- work update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace
|
|
134
148
|
|
|
135
149
|
Discovery/show export flags:
|
|
136
150
|
- `--json`
|