mdkg 0.1.3 → 0.1.5
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 +45 -1
- package/README.md +34 -10
- package/dist/cli.js +354 -87
- package/dist/commands/bundle.js +7 -7
- package/dist/commands/capability.js +118 -4
- package/dist/commands/doctor.js +15 -15
- package/dist/commands/goal.js +548 -0
- package/dist/commands/index.js +1 -1
- package/dist/commands/init.js +1 -0
- package/dist/commands/list.js +1 -1
- package/dist/commands/new.js +7 -1
- 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 +1 -1
- package/dist/commands/upgrade.js +54 -7
- package/dist/commands/validate.js +39 -7
- package/dist/commands/work.js +1 -1
- package/dist/core/config.js +95 -39
- package/dist/graph/frontmatter.js +8 -0
- package/dist/graph/goal_scope.js +127 -0
- package/dist/graph/index_cache.js +12 -12
- package/dist/graph/indexer.js +1 -1
- package/dist/graph/node.js +80 -1
- package/dist/graph/reindex.js +6 -6
- package/dist/graph/sqlite_index.js +6 -6
- package/dist/graph/{bundle_imports.js → subgraphs.js} +214 -140
- package/dist/graph/validate_graph.js +41 -0
- package/dist/graph/visibility.js +3 -3
- package/dist/init/AGENT_START.md +17 -1
- package/dist/init/CLI_COMMAND_MATRIX.md +43 -7
- package/dist/init/README.md +9 -8
- package/dist/init/config.json +1 -1
- package/dist/init/core/rule-3-cli-contract.md +56 -23
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +7 -2
- package/dist/init/core/rule-6-templates-and-schemas.md +10 -1
- package/dist/init/init-manifest.json +20 -10
- package/dist/init/skills/default/pursue-mdkg-goal/SKILL.md +68 -0
- package/dist/init/skills/default/select-work-and-ground-context/SKILL.md +9 -7
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +11 -10
- package/dist/init/templates/default/goal.md +91 -0
- package/dist/pack/order.js +2 -1
- package/dist/pack/pack.js +17 -0
- package/dist/util/argparse.js +2 -0
- package/package.json +8 -6
- package/dist/commands/bundle_import.js +0 -255
|
@@ -3,13 +3,13 @@ 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"));
|
|
@@ -17,7 +17,7 @@ const child_process_1 = require("child_process");
|
|
|
17
17
|
const paths_1 = require("../core/paths");
|
|
18
18
|
const atomic_1 = require("../util/atomic");
|
|
19
19
|
const zip_1 = require("../util/zip");
|
|
20
|
-
const
|
|
20
|
+
const SUBGRAPHS_CACHE_VERSION = 1;
|
|
21
21
|
const MANIFEST_ENTRY = "manifest.json";
|
|
22
22
|
const GLOBAL_INDEX_ENTRY = ".mdkg/index/global.json";
|
|
23
23
|
const SKILLS_INDEX_ENTRY = ".mdkg/index/skills.json";
|
|
@@ -38,8 +38,8 @@ function readJsonEntry(entries, entryPath) {
|
|
|
38
38
|
function readBundleEntries(bundlePath) {
|
|
39
39
|
return new Map((0, zip_1.readZipEntries)(fs_1.default.readFileSync(bundlePath)).map((entry) => [entry.name, entry.data]));
|
|
40
40
|
}
|
|
41
|
-
function resolveBundlePath(root,
|
|
42
|
-
return path_1.default.resolve(root,
|
|
41
|
+
function resolveBundlePath(root, source) {
|
|
42
|
+
return path_1.default.resolve(root, source.path);
|
|
43
43
|
}
|
|
44
44
|
function gitOutput(cwd, args) {
|
|
45
45
|
const result = (0, child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
@@ -49,13 +49,13 @@ function gitOutput(cwd, args) {
|
|
|
49
49
|
const output = result.stdout.trim();
|
|
50
50
|
return output.length > 0 ? output : null;
|
|
51
51
|
}
|
|
52
|
-
function sourcePathState(root,
|
|
53
|
-
if (!
|
|
52
|
+
function sourcePathState(root, subgraph, manifest, warnings, errors) {
|
|
53
|
+
if (!subgraph.source_path) {
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
56
|
-
const sourceRoot = path_1.default.resolve(root,
|
|
56
|
+
const sourceRoot = path_1.default.resolve(root, subgraph.source_path);
|
|
57
57
|
if (!fs_1.default.existsSync(sourceRoot)) {
|
|
58
|
-
errors.push(`source_path does not exist: ${
|
|
58
|
+
errors.push(`source_path does not exist: ${subgraph.source_path}`);
|
|
59
59
|
return false;
|
|
60
60
|
}
|
|
61
61
|
const currentHead = gitOutput(sourceRoot, ["rev-parse", "HEAD"]);
|
|
@@ -66,20 +66,17 @@ function sourcePathState(root, entry, manifest, warnings, errors) {
|
|
|
66
66
|
stale = true;
|
|
67
67
|
}
|
|
68
68
|
if (currentStatus) {
|
|
69
|
-
warnings.push(`source_path has uncommitted changes: ${
|
|
69
|
+
warnings.push(`source_path has uncommitted changes: ${subgraph.source_path}`);
|
|
70
70
|
stale = true;
|
|
71
71
|
}
|
|
72
72
|
return stale;
|
|
73
73
|
}
|
|
74
|
-
function ageState(bundlePath,
|
|
75
|
-
if (entry.max_stale_seconds === undefined) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
74
|
+
function ageState(bundlePath, maxStaleSeconds, warnings) {
|
|
78
75
|
const ageSeconds = Math.floor((Date.now() - fs_1.default.statSync(bundlePath).mtimeMs) / 1000);
|
|
79
|
-
if (ageSeconds <=
|
|
76
|
+
if (ageSeconds <= maxStaleSeconds) {
|
|
80
77
|
return false;
|
|
81
78
|
}
|
|
82
|
-
warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${
|
|
79
|
+
warnings.push(`bundle age ${ageSeconds}s exceeds max_stale_seconds ${maxStaleSeconds}`);
|
|
83
80
|
return true;
|
|
84
81
|
}
|
|
85
82
|
function remapTarget(target, qidMap) {
|
|
@@ -131,72 +128,147 @@ function entryHashErrors(entries, manifest) {
|
|
|
131
128
|
}
|
|
132
129
|
return errors;
|
|
133
130
|
}
|
|
134
|
-
function
|
|
135
|
-
const bundlePath = resolveBundlePath(root,
|
|
131
|
+
function projectOneSource(root, subgraph, source) {
|
|
132
|
+
const bundlePath = resolveBundlePath(root, source);
|
|
136
133
|
const relativeBundlePath = toPosixPath(path_1.default.relative(root, bundlePath));
|
|
137
134
|
const warnings = [];
|
|
138
135
|
const errors = [];
|
|
139
|
-
const nodes = {};
|
|
140
|
-
const reverse_edges = {};
|
|
141
136
|
let manifest;
|
|
142
|
-
let
|
|
137
|
+
let index;
|
|
138
|
+
let entries;
|
|
143
139
|
let stale = false;
|
|
144
|
-
if (!
|
|
140
|
+
if (!source.enabled) {
|
|
145
141
|
return {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
source,
|
|
143
|
+
relativeBundlePath,
|
|
144
|
+
sourceHealth: {
|
|
145
|
+
label: source.label,
|
|
146
|
+
path: source.path,
|
|
149
147
|
enabled: false,
|
|
150
|
-
|
|
151
|
-
expected_profile: entry.expected_profile,
|
|
148
|
+
expected_profile: source.expected_profile,
|
|
152
149
|
stale: false,
|
|
153
150
|
warning_count: 0,
|
|
154
151
|
error_count: 0,
|
|
155
152
|
warnings: [],
|
|
156
153
|
errors: [],
|
|
157
154
|
},
|
|
158
|
-
nodes,
|
|
159
|
-
reverse_edges,
|
|
160
155
|
};
|
|
161
156
|
}
|
|
162
157
|
try {
|
|
163
158
|
if (!fs_1.default.existsSync(bundlePath)) {
|
|
164
|
-
throw new Error(`bundle not found: ${
|
|
159
|
+
throw new Error(`bundle not found: ${source.path}`);
|
|
165
160
|
}
|
|
166
|
-
|
|
161
|
+
entries = readBundleEntries(bundlePath);
|
|
167
162
|
manifest = readJsonEntry(entries, MANIFEST_ENTRY);
|
|
168
|
-
|
|
163
|
+
index = readJsonEntry(entries, GLOBAL_INDEX_ENTRY);
|
|
169
164
|
readJsonEntry(entries, SKILLS_INDEX_ENTRY);
|
|
170
165
|
readJsonEntry(entries, CAPABILITIES_INDEX_ENTRY);
|
|
171
166
|
errors.push(...entryHashErrors(entries, manifest));
|
|
172
|
-
if (manifest.profile !==
|
|
173
|
-
errors.push(`expected ${
|
|
167
|
+
if (manifest.profile !== source.expected_profile) {
|
|
168
|
+
errors.push(`expected ${source.expected_profile} bundle but found ${manifest.profile}`);
|
|
174
169
|
}
|
|
175
|
-
stale = sourcePathState(root,
|
|
176
|
-
stale = ageState(bundlePath,
|
|
177
|
-
|
|
178
|
-
|
|
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)) {
|
|
179
241
|
const owners = idOwners.get(node.id) ?? [];
|
|
180
|
-
owners.push(node.qid);
|
|
242
|
+
owners.push(`${loaded.source.label ?? loaded.source.path}:${node.qid}`);
|
|
181
243
|
idOwners.set(node.id, owners);
|
|
182
244
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
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`);
|
|
187
249
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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)) {
|
|
191
258
|
qidMap.set(node.qid, `${alias}:${node.id}`);
|
|
192
259
|
}
|
|
193
|
-
|
|
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)) {
|
|
194
266
|
const projectedQid = qidMap.get(node.qid);
|
|
195
267
|
const projected = {
|
|
196
268
|
...node,
|
|
197
269
|
ws: alias,
|
|
198
270
|
qid: projectedQid,
|
|
199
|
-
path: `${relativeBundlePath}#${toPosixPath(node.path)}`,
|
|
271
|
+
path: `${loaded.relativeBundlePath}#${toPosixPath(node.path)}`,
|
|
200
272
|
attributes: { ...(node.attributes ?? {}) },
|
|
201
273
|
edges: {
|
|
202
274
|
epic: remapTarget(node.edges.epic, qidMap),
|
|
@@ -210,18 +282,19 @@ function projectOneImport(root, alias, entry) {
|
|
|
210
282
|
source: {
|
|
211
283
|
imported: true,
|
|
212
284
|
read_only: true,
|
|
213
|
-
|
|
285
|
+
subgraph_alias: alias,
|
|
214
286
|
original_qid: node.qid,
|
|
215
287
|
original_ws: node.ws,
|
|
216
288
|
original_path: toPosixPath(node.path),
|
|
217
|
-
bundle_path: relativeBundlePath,
|
|
218
|
-
bundle_hash: manifest
|
|
219
|
-
profile: manifest
|
|
220
|
-
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,
|
|
221
294
|
stale,
|
|
222
295
|
warnings: [...warnings],
|
|
223
|
-
source_repo:
|
|
224
|
-
source_git_head: manifest
|
|
296
|
+
source_repo: subgraph.source_repo ?? loaded.manifest?.source?.repo,
|
|
297
|
+
source_git_head: loaded.manifest?.source?.git_head ?? null,
|
|
225
298
|
},
|
|
226
299
|
};
|
|
227
300
|
nodes[projected.qid] = projected;
|
|
@@ -229,46 +302,41 @@ function projectOneImport(root, alias, entry) {
|
|
|
229
302
|
}
|
|
230
303
|
}
|
|
231
304
|
}
|
|
232
|
-
catch (err) {
|
|
233
|
-
errors.push(err instanceof Error ? err.message : String(err));
|
|
234
|
-
}
|
|
235
305
|
return {
|
|
236
306
|
health: {
|
|
237
307
|
alias,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
bundle_hash: manifest?.bundle_hash,
|
|
244
|
-
source_git_head: manifest?.source?.git_head ?? null,
|
|
245
|
-
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,
|
|
246
313
|
stale,
|
|
247
314
|
warning_count: warnings.length,
|
|
248
315
|
error_count: errors.length,
|
|
249
316
|
warnings,
|
|
250
317
|
errors,
|
|
318
|
+
sources: loadedSources.map((item) => item.sourceHealth),
|
|
251
319
|
},
|
|
252
320
|
nodes,
|
|
253
321
|
reverse_edges,
|
|
254
322
|
};
|
|
255
323
|
}
|
|
256
|
-
function
|
|
257
|
-
return path_1.default.resolve(root, ".mdkg", "index", "
|
|
324
|
+
function resolveSubgraphsIndexPath(root) {
|
|
325
|
+
return path_1.default.resolve(root, ".mdkg", "index", "subgraphs.json");
|
|
258
326
|
}
|
|
259
|
-
function
|
|
260
|
-
const
|
|
327
|
+
function buildSubgraphsIndex(root, config) {
|
|
328
|
+
const subgraphs = [];
|
|
261
329
|
const nodes = {};
|
|
262
330
|
const reverse_edges = {};
|
|
263
331
|
const workspaces = {};
|
|
264
|
-
for (const alias of Object.keys(config.
|
|
265
|
-
const
|
|
266
|
-
const projected =
|
|
267
|
-
|
|
268
|
-
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) {
|
|
269
337
|
continue;
|
|
270
338
|
}
|
|
271
|
-
workspaces[alias] = { path: `
|
|
339
|
+
workspaces[alias] = { path: `subgraph:${alias}`, enabled: true };
|
|
272
340
|
Object.assign(nodes, projected.nodes);
|
|
273
341
|
for (const [edgeKey, targets] of Object.entries(projected.reverse_edges)) {
|
|
274
342
|
reverse_edges[edgeKey] = reverse_edges[edgeKey] ?? {};
|
|
@@ -285,44 +353,46 @@ function buildBundleImportsIndex(root, config) {
|
|
|
285
353
|
meta: {
|
|
286
354
|
tool: config.tool,
|
|
287
355
|
schema_version: config.schema_version,
|
|
288
|
-
cache_version:
|
|
356
|
+
cache_version: SUBGRAPHS_CACHE_VERSION,
|
|
289
357
|
generated_at: new Date().toISOString(),
|
|
290
358
|
root,
|
|
291
|
-
|
|
359
|
+
subgraph_count: subgraphs.length,
|
|
292
360
|
node_count: Object.keys(nodes).length,
|
|
293
361
|
},
|
|
294
|
-
|
|
362
|
+
subgraphs,
|
|
295
363
|
nodes,
|
|
296
364
|
reverse_edges,
|
|
297
365
|
},
|
|
298
366
|
workspaces,
|
|
299
367
|
};
|
|
300
368
|
}
|
|
301
|
-
function
|
|
369
|
+
function writeSubgraphsIndex(indexPath, index) {
|
|
302
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 };
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.collectGraphErrors = collectGraphErrors;
|
|
4
4
|
exports.validateGraph = validateGraph;
|
|
5
5
|
const refs_1 = require("../util/refs");
|
|
6
|
+
const goal_scope_1 = require("./goal_scope");
|
|
6
7
|
function pushError(errors, message) {
|
|
7
8
|
if (errors) {
|
|
8
9
|
errors.push(message);
|
|
@@ -433,6 +434,45 @@ function validateArchiveUriRefs(index, allowMissing, errors) {
|
|
|
433
434
|
}
|
|
434
435
|
}
|
|
435
436
|
}
|
|
437
|
+
function validateGoalRefs(index, allowMissing, errors) {
|
|
438
|
+
for (const [qid, node] of Object.entries(index.nodes)) {
|
|
439
|
+
if (node.type !== "goal") {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const scope = (0, goal_scope_1.collectGoalScope)(index, node, { includeCompatibilityRefs: false });
|
|
443
|
+
for (const ref of scope.missingRefs) {
|
|
444
|
+
if (allowMissing) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
pushError(errors, `${qid}: scope_refs references missing node ${ref}`);
|
|
448
|
+
}
|
|
449
|
+
for (const ref of scope.invalidRefs) {
|
|
450
|
+
const target = index.nodes[ref];
|
|
451
|
+
const typeLabel = target ? target.type : "missing";
|
|
452
|
+
pushError(errors, `${qid}: scope_refs references ${ref} with type ${typeLabel}, expected ${Array.from(goal_scope_1.GOAL_SCOPE_ALLOWED_TYPES).join(", ")}`);
|
|
453
|
+
}
|
|
454
|
+
const activeNode = node.attributes.active_node;
|
|
455
|
+
if (typeof activeNode !== "string") {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
const activeQid = activeNode.includes(":") ? activeNode : `${node.ws}:${activeNode}`;
|
|
459
|
+
const target = index.nodes[activeQid];
|
|
460
|
+
if (!target) {
|
|
461
|
+
if (allowMissing) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
pushError(errors, `${qid}: active_node references missing node ${activeNode}`);
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (!goal_scope_1.GOAL_SCOPE_ACTIONABLE_TYPES.has(target.type)) {
|
|
468
|
+
pushError(errors, `${qid}: active_node references ${activeQid} with type ${target.type}, expected ${Array.from(goal_scope_1.GOAL_SCOPE_ACTIONABLE_TYPES).join(", ")}`);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (scope.qids.size > 0 && !scope.actionableQids.has(activeQid)) {
|
|
472
|
+
pushError(errors, `${qid}: active_node ${activeQid} is not inside goal scope_refs`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
436
476
|
function detectPrevNextCycles(index, errors) {
|
|
437
477
|
const nodes = index.nodes;
|
|
438
478
|
const seen = new Set();
|
|
@@ -480,6 +520,7 @@ function collectGraphErrors(index, options = {}) {
|
|
|
480
520
|
validateAgentWorkflowDisputeRefs(index, allowMissing, errors);
|
|
481
521
|
validateAgentWorkflowFeedbackProposalRefs(index, allowMissing, knownSkillSlugs, externalWorkspaces, errors);
|
|
482
522
|
validateArchiveUriRefs(index, allowMissing, errors);
|
|
523
|
+
validateGoalRefs(index, allowMissing, errors);
|
|
483
524
|
detectPrevNextCycles(index, errors);
|
|
484
525
|
return errors;
|
|
485
526
|
}
|
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
|
@@ -23,6 +23,11 @@ Agent operating prompt:
|
|
|
23
23
|
- Treat mdkg rules, EDDs, DECs, PRDs, and work nodes as more authoritative than chat memory.
|
|
24
24
|
- Use `mdkg show <id>` for direct inspection and `mdkg show <id> --meta` for card-only inspection.
|
|
25
25
|
- Use `mdkg search "..."` and `mdkg next` to discover current work.
|
|
26
|
+
- Use `mdkg new goal "..."` for long-running recursive objectives that need an explicit end condition, active node, required skills, required checks, and completion evidence.
|
|
27
|
+
- Use `mdkg goal select <goal-id>` when a goal is active, then `mdkg goal next` to surface one scoped feature, task, bug, or test at a time; normal `mdkg next` remains for non-goal concrete work.
|
|
28
|
+
- Use `mdkg goal claim [goal-id] <work-id>` only after accepting the surfaced work item; `mdkg goal next` is read-only.
|
|
29
|
+
- Treat goal `required_checks` as report-only guidance from mdkg. Run commands yourself, then record evidence in the goal or active work item.
|
|
30
|
+
- Record skill improvement candidates during normal goal execution; edit `SKILL.md` only when the active node is explicit skill-maintenance work.
|
|
26
31
|
- Use `mdkg skill list`, `mdkg skill search`, and `mdkg skill show <slug>` for skill discovery.
|
|
27
32
|
- Use `mdkg capability list/search/show` for deterministic skills, `SPEC.md`, `WORK.md`, core-doc, and design-doc capability discovery.
|
|
28
33
|
- Use `mdkg index` to refresh JSON compatibility caches and `.mdkg/index/mdkg.sqlite` when SQLite mode is enabled.
|
|
@@ -31,7 +36,8 @@ Agent operating prompt:
|
|
|
31
36
|
- 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.
|
|
32
37
|
- Use `artifact://...` for external/runtime-managed artifacts and `archive://...` for committed mdkg archive sidecars.
|
|
33
38
|
- Use `mdkg bundle create/list/show/verify` for explicit full `.mdkg` graph snapshot bundles.
|
|
34
|
-
- Use `mdkg
|
|
39
|
+
- Use `mdkg subgraph add/list/verify` to register child bundle snapshots as read-only planning context.
|
|
40
|
+
- Use `mdkg capability resolve` to rank local and subgraph capabilities for orchestration planning.
|
|
35
41
|
- 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.
|
|
36
42
|
- Mark archive sidecars public only with explicit `mdkg archive add --visibility public` intent.
|
|
37
43
|
- Treat sidecar `.md` plus deterministic `.zip` caches as the commit-eligible archive record; validation and `mdkg archive verify` both check ZIP payload integrity.
|
|
@@ -50,6 +56,16 @@ If the active task is known:
|
|
|
50
56
|
- `mdkg task done <id>` when work is complete
|
|
51
57
|
- `mdkg validate`
|
|
52
58
|
|
|
59
|
+
If an active goal is known:
|
|
60
|
+
- `mdkg goal select <goal-id>`
|
|
61
|
+
- `mdkg goal current`
|
|
62
|
+
- `mdkg goal next`
|
|
63
|
+
- `mdkg goal claim <work-id>`
|
|
64
|
+
- work the selected concrete node to completion
|
|
65
|
+
- run required checks and record evidence
|
|
66
|
+
- `mdkg goal evaluate <goal-id>`
|
|
67
|
+
- repeat until the goal condition is achieved, blocked, paused, or budget-limited
|
|
68
|
+
|
|
53
69
|
If no task is known:
|
|
54
70
|
- `mdkg search "..."`
|
|
55
71
|
- `mdkg show <id>`
|