mdkg 0.1.3 → 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 +27 -1
- package/README.md +11 -10
- package/dist/cli.js +180 -86
- package/dist/commands/bundle.js +7 -7
- package/dist/commands/capability.js +118 -4
- package/dist/commands/doctor.js +15 -15
- package/dist/commands/index.js +1 -1
- package/dist/commands/list.js +1 -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 +51 -4
- package/dist/commands/validate.js +6 -6
- package/dist/commands/work.js +1 -1
- package/dist/core/config.js +95 -39
- package/dist/graph/index_cache.js +12 -12
- package/dist/graph/indexer.js +1 -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/visibility.js +3 -3
- package/dist/init/AGENT_START.md +2 -1
- package/dist/init/CLI_COMMAND_MATRIX.md +16 -7
- package/dist/init/README.md +9 -8
- package/dist/init/config.json +1 -1
- package/dist/init/core/rule-3-cli-contract.md +30 -23
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +1 -1
- package/dist/init/init-manifest.json +8 -8
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +1 -1
- package/dist/util/argparse.js +2 -0
- package/package.json +7 -6
- package/dist/commands/bundle_import.js +0 -255
package/dist/commands/doctor.js
CHANGED
|
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const config_1 = require("../core/config");
|
|
10
10
|
const index_cache_1 = require("../graph/index_cache");
|
|
11
11
|
const capabilities_index_cache_1 = require("../graph/capabilities_index_cache");
|
|
12
|
-
const
|
|
12
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
13
13
|
const node_1 = require("../graph/node");
|
|
14
14
|
const template_schema_1 = require("../graph/template_schema");
|
|
15
15
|
const visibility_1 = require("../graph/visibility");
|
|
@@ -186,45 +186,45 @@ function runBundleStorageCheck(root, outputDir) {
|
|
|
186
186
|
detail: `${bundles.length} bundle(s) found; run \`mdkg bundle verify <path>\` to check freshness before handoff`,
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
-
function
|
|
190
|
-
const projection = (0,
|
|
191
|
-
if (projection.index.
|
|
189
|
+
function runSubgraphChecks(root, config) {
|
|
190
|
+
const projection = (0, subgraphs_1.buildSubgraphsIndex)(root, config);
|
|
191
|
+
if (projection.index.subgraphs.length === 0) {
|
|
192
192
|
return [
|
|
193
193
|
{
|
|
194
|
-
name: "
|
|
194
|
+
name: "subgraphs",
|
|
195
195
|
ok: true,
|
|
196
|
-
detail: "no
|
|
196
|
+
detail: "no subgraphs configured",
|
|
197
197
|
},
|
|
198
198
|
];
|
|
199
199
|
}
|
|
200
|
-
return projection.index.
|
|
200
|
+
return projection.index.subgraphs.map((item) => {
|
|
201
201
|
if (!item.enabled) {
|
|
202
202
|
return {
|
|
203
|
-
name: `
|
|
203
|
+
name: `subgraph:${item.alias}`,
|
|
204
204
|
ok: true,
|
|
205
205
|
level: "warn",
|
|
206
|
-
detail:
|
|
206
|
+
detail: "disabled subgraph",
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
209
|
if (item.error_count > 0) {
|
|
210
210
|
return {
|
|
211
|
-
name: `
|
|
211
|
+
name: `subgraph:${item.alias}`,
|
|
212
212
|
ok: false,
|
|
213
213
|
detail: item.errors.join("; "),
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
if (item.stale || item.warning_count > 0) {
|
|
217
217
|
return {
|
|
218
|
-
name: `
|
|
218
|
+
name: `subgraph:${item.alias}`,
|
|
219
219
|
ok: true,
|
|
220
220
|
level: "warn",
|
|
221
|
-
detail: `
|
|
221
|
+
detail: `subgraph is stale or has warnings; run \`mdkg subgraph verify ${item.alias}\` (${item.warnings.join("; ")})`,
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
224
|
return {
|
|
225
|
-
name: `
|
|
225
|
+
name: `subgraph:${item.alias}`,
|
|
226
226
|
ok: true,
|
|
227
|
-
detail: `
|
|
227
|
+
detail: `subgraph loaded from ${item.sources.map((source) => source.path).join(", ")}`,
|
|
228
228
|
};
|
|
229
229
|
});
|
|
230
230
|
}
|
|
@@ -299,7 +299,7 @@ function runDoctorCommand(options) {
|
|
|
299
299
|
results.push(runArchiveLargeCacheCheck(options.root, config.archive.large_cache_warning_bytes));
|
|
300
300
|
results.push(runBundleStorageCheck(options.root, config.bundles.output_dir));
|
|
301
301
|
results.push(runSqliteCheck(options.root, config));
|
|
302
|
-
results.push(...
|
|
302
|
+
results.push(...runSubgraphChecks(options.root, config));
|
|
303
303
|
results.push(runVisibilityPolicyCheck(options.root, config, options));
|
|
304
304
|
try {
|
|
305
305
|
const templateSchemaInfo = (0, template_schema_1.loadTemplateSchemasWithInfo)(options.root, config, node_1.ALLOWED_TYPES);
|
package/dist/commands/index.js
CHANGED
|
@@ -15,7 +15,7 @@ function runIndexCommand(options) {
|
|
|
15
15
|
console.log(`index written: ${path_1.default.relative(options.root, result.paths.nodes)}`);
|
|
16
16
|
console.log(`skills index written: ${path_1.default.relative(options.root, result.paths.skills)}`);
|
|
17
17
|
console.log(`capabilities index written: ${path_1.default.relative(options.root, result.paths.capabilities)}`);
|
|
18
|
-
console.log(`
|
|
18
|
+
console.log(`subgraphs index written: ${path_1.default.relative(options.root, result.paths.subgraphs)}`);
|
|
19
19
|
if (result.paths.sqlite) {
|
|
20
20
|
console.log(`sqlite index written: ${path_1.default.relative(options.root, result.paths.sqlite)}`);
|
|
21
21
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -18,7 +18,7 @@ function normalizeWorkspace(value) {
|
|
|
18
18
|
function runListCommand(options) {
|
|
19
19
|
const config = (0, config_1.loadConfig)(options.root);
|
|
20
20
|
const ws = normalizeWorkspace(options.ws);
|
|
21
|
-
if (ws && !config.workspaces[ws] && !config.
|
|
21
|
+
if (ws && !config.workspaces[ws] && !config.subgraphs[ws]) {
|
|
22
22
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
23
23
|
}
|
|
24
24
|
const normalizedType = options.type?.toLowerCase();
|
package/dist/commands/next.js
CHANGED
|
@@ -63,7 +63,7 @@ function runNextCommand(options) {
|
|
|
63
63
|
}
|
|
64
64
|
const node = index.nodes[resolved.qid];
|
|
65
65
|
if (node.source?.imported) {
|
|
66
|
-
console.error("no local next item:
|
|
66
|
+
console.error("no local next item: subgraph nodes are read-only planning context");
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
const nextQid = node.edges.next;
|
|
@@ -8,7 +8,7 @@ function formatStatusPriority(node) {
|
|
|
8
8
|
}
|
|
9
9
|
function formatNodeCard(node) {
|
|
10
10
|
const sourceLabel = node.source?.imported
|
|
11
|
-
? ` |
|
|
11
|
+
? ` | subgraph:${node.source.subgraph_alias}${node.source.stale ? ":stale" : ""} | read-only`
|
|
12
12
|
: "";
|
|
13
13
|
return [
|
|
14
14
|
node.qid,
|
package/dist/commands/pack.js
CHANGED
|
@@ -318,7 +318,7 @@ function printDryRunSummary(pack, stats, format) {
|
|
|
318
318
|
function runPackCommand(options) {
|
|
319
319
|
const config = (0, config_1.loadConfig)(options.root);
|
|
320
320
|
const ws = normalizeWorkspace(options.ws);
|
|
321
|
-
if (ws && !config.workspaces[ws] && !config.
|
|
321
|
+
if (ws && !config.workspaces[ws] && !config.subgraphs[ws]) {
|
|
322
322
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
323
323
|
}
|
|
324
324
|
const { index, rebuilt, stale, warnings } = (0, index_cache_1.loadIndex)({
|
package/dist/commands/search.js
CHANGED
|
@@ -54,7 +54,7 @@ function runSearchCommand(options) {
|
|
|
54
54
|
}
|
|
55
55
|
const config = (0, config_1.loadConfig)(options.root);
|
|
56
56
|
const ws = normalizeWorkspace(options.ws);
|
|
57
|
-
if (ws && !config.workspaces[ws] && !config.
|
|
57
|
+
if (ws && !config.workspaces[ws] && !config.subgraphs[ws]) {
|
|
58
58
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
59
59
|
}
|
|
60
60
|
const normalizedType = options.type?.toLowerCase();
|
package/dist/commands/show.js
CHANGED
|
@@ -29,7 +29,7 @@ function formatAttributeLine(key, value) {
|
|
|
29
29
|
function runShowCommand(options) {
|
|
30
30
|
const config = (0, config_1.loadConfig)(options.root);
|
|
31
31
|
const ws = normalizeWorkspace(options.ws);
|
|
32
|
-
if (ws && !config.workspaces[ws] && !config.
|
|
32
|
+
if (ws && !config.workspaces[ws] && !config.subgraphs[ws]) {
|
|
33
33
|
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
34
34
|
}
|
|
35
35
|
const normalizedId = options.id.toLowerCase();
|
|
@@ -0,0 +1,312 @@
|
|
|
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.runSubgraphAddCommand = runSubgraphAddCommand;
|
|
7
|
+
exports.runSubgraphListCommand = runSubgraphListCommand;
|
|
8
|
+
exports.runSubgraphShowCommand = runSubgraphShowCommand;
|
|
9
|
+
exports.runSubgraphRemoveCommand = runSubgraphRemoveCommand;
|
|
10
|
+
exports.runSubgraphEnableCommand = runSubgraphEnableCommand;
|
|
11
|
+
exports.runSubgraphDisableCommand = runSubgraphDisableCommand;
|
|
12
|
+
exports.runSubgraphVerifyCommand = runSubgraphVerifyCommand;
|
|
13
|
+
exports.runSubgraphRefreshCommand = runSubgraphRefreshCommand;
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const config_1 = require("../core/config");
|
|
17
|
+
const migrate_1 = require("../core/migrate");
|
|
18
|
+
const workspace_path_1 = require("../core/workspace_path");
|
|
19
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
20
|
+
const reindex_1 = require("../graph/reindex");
|
|
21
|
+
const errors_1 = require("../util/errors");
|
|
22
|
+
const atomic_1 = require("../util/atomic");
|
|
23
|
+
const lock_1 = require("../util/lock");
|
|
24
|
+
const ALIAS_RE = /^[a-z][a-z0-9_]*$/;
|
|
25
|
+
function writeJson(value) {
|
|
26
|
+
console.log(JSON.stringify(value, null, 2));
|
|
27
|
+
}
|
|
28
|
+
function normalizeAlias(alias) {
|
|
29
|
+
if (alias === "all") {
|
|
30
|
+
throw new errors_1.UsageError("subgraph alias cannot be 'all'");
|
|
31
|
+
}
|
|
32
|
+
if (alias !== alias.toLowerCase() || !ALIAS_RE.test(alias)) {
|
|
33
|
+
throw new errors_1.UsageError("subgraph alias must be lowercase and use [a-z0-9_]");
|
|
34
|
+
}
|
|
35
|
+
return alias;
|
|
36
|
+
}
|
|
37
|
+
function normalizeVisibility(value) {
|
|
38
|
+
const normalized = (value ?? "private").toLowerCase();
|
|
39
|
+
if (normalized === "private" || normalized === "internal" || normalized === "public") {
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
throw new errors_1.UsageError("--visibility must be private, internal, or public");
|
|
43
|
+
}
|
|
44
|
+
function normalizeProfile(value) {
|
|
45
|
+
const normalized = (value ?? "private").toLowerCase();
|
|
46
|
+
if (normalized === "private" || normalized === "public") {
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
throw new errors_1.UsageError("--profile must be private or public");
|
|
50
|
+
}
|
|
51
|
+
function normalizeContained(value, label) {
|
|
52
|
+
try {
|
|
53
|
+
return (0, workspace_path_1.normalizeContainedWorkspacePath)(value, label);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
throw new errors_1.UsageError(err instanceof Error ? err.message : String(err));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function readRawConfig(root) {
|
|
60
|
+
const configPath = path_1.default.join(root, ".mdkg", "config.json");
|
|
61
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
62
|
+
throw new errors_1.NotFoundError(`config not found at ${configPath}`);
|
|
63
|
+
}
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(fs_1.default.readFileSync(configPath, "utf8"));
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new errors_1.UsageError(`failed to read config: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
}
|
|
71
|
+
const migrated = (0, migrate_1.migrateConfig)(parsed).config;
|
|
72
|
+
(0, config_1.validateConfigSchema)(migrated);
|
|
73
|
+
if (typeof migrated !== "object" || migrated === null || Array.isArray(migrated)) {
|
|
74
|
+
throw new errors_1.UsageError("config must be a JSON object");
|
|
75
|
+
}
|
|
76
|
+
return { configPath, raw: migrated };
|
|
77
|
+
}
|
|
78
|
+
function writeRawConfig(configPath, raw) {
|
|
79
|
+
(0, atomic_1.atomicWriteFile)(configPath, `${JSON.stringify(raw, null, 2)}\n`);
|
|
80
|
+
}
|
|
81
|
+
function getSubgraphs(raw) {
|
|
82
|
+
if (raw.bundle_imports !== undefined) {
|
|
83
|
+
throw new errors_1.UsageError("config uses legacy bundle_imports; run `mdkg upgrade --apply` before editing subgraphs");
|
|
84
|
+
}
|
|
85
|
+
const subgraphs = raw.subgraphs;
|
|
86
|
+
if (subgraphs === undefined) {
|
|
87
|
+
raw.subgraphs = {};
|
|
88
|
+
return raw.subgraphs;
|
|
89
|
+
}
|
|
90
|
+
if (typeof subgraphs !== "object" || subgraphs === null || Array.isArray(subgraphs)) {
|
|
91
|
+
throw new errors_1.UsageError("config.subgraphs must be an object");
|
|
92
|
+
}
|
|
93
|
+
return subgraphs;
|
|
94
|
+
}
|
|
95
|
+
function receiptForHealth(action, health) {
|
|
96
|
+
return {
|
|
97
|
+
action,
|
|
98
|
+
subgraph: health,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function healthByAlias(root, alias) {
|
|
102
|
+
const config = (0, config_1.loadConfig)(root);
|
|
103
|
+
const health = (0, subgraphs_1.buildSubgraphsIndex)(root, config).index.subgraphs.find((item) => item.alias === alias);
|
|
104
|
+
if (!health) {
|
|
105
|
+
throw new errors_1.NotFoundError(`subgraph not found: ${alias}`);
|
|
106
|
+
}
|
|
107
|
+
return health;
|
|
108
|
+
}
|
|
109
|
+
function withSubgraphLock(root, fn) {
|
|
110
|
+
const config = (0, config_1.loadConfig)(root);
|
|
111
|
+
return (0, lock_1.withMutationLock)(root, config.index.lock_timeout_ms, fn);
|
|
112
|
+
}
|
|
113
|
+
function runSubgraphAddCommandLocked(options) {
|
|
114
|
+
const alias = normalizeAlias(options.alias);
|
|
115
|
+
const bundlePath = normalizeContained(options.bundlePath, "subgraph bundle path");
|
|
116
|
+
const visibility = normalizeVisibility(options.visibility);
|
|
117
|
+
const expected_profile = normalizeProfile(options.profile);
|
|
118
|
+
if (visibility !== "private" && expected_profile !== "public") {
|
|
119
|
+
throw new errors_1.UsageError("--profile public is required when --visibility is public or internal");
|
|
120
|
+
}
|
|
121
|
+
const source_path = options.sourcePath
|
|
122
|
+
? normalizeContained(options.sourcePath, "subgraph source path")
|
|
123
|
+
: undefined;
|
|
124
|
+
if (options.maxStaleSeconds !== undefined && (!Number.isInteger(options.maxStaleSeconds) || options.maxStaleSeconds <= 0)) {
|
|
125
|
+
throw new errors_1.UsageError("--max-stale-seconds must be a positive integer");
|
|
126
|
+
}
|
|
127
|
+
const { configPath, raw } = readRawConfig(options.root);
|
|
128
|
+
const subgraphs = getSubgraphs(raw);
|
|
129
|
+
if (subgraphs[alias]) {
|
|
130
|
+
throw new errors_1.UsageError(`subgraph already exists: ${alias}`);
|
|
131
|
+
}
|
|
132
|
+
const workspaces = raw.workspaces;
|
|
133
|
+
if (workspaces && workspaces[alias]) {
|
|
134
|
+
throw new errors_1.UsageError(`subgraph alias collides with workspace: ${alias}`);
|
|
135
|
+
}
|
|
136
|
+
subgraphs[alias] = {
|
|
137
|
+
enabled: true,
|
|
138
|
+
visibility,
|
|
139
|
+
permissions: ["read"],
|
|
140
|
+
max_stale_seconds: options.maxStaleSeconds ?? 3600,
|
|
141
|
+
...(source_path ? { source_path } : {}),
|
|
142
|
+
...(options.sourceRepo ? { source_repo: options.sourceRepo } : {}),
|
|
143
|
+
sources: [
|
|
144
|
+
{
|
|
145
|
+
path: bundlePath,
|
|
146
|
+
enabled: true,
|
|
147
|
+
expected_profile,
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
raw.subgraphs = subgraphs;
|
|
152
|
+
const validated = (0, config_1.validateConfigSchema)(raw);
|
|
153
|
+
const health = (0, subgraphs_1.buildSubgraphsIndex)(options.root, validated).index.subgraphs.find((item) => item.alias === alias);
|
|
154
|
+
if (!health) {
|
|
155
|
+
throw new errors_1.NotFoundError(`subgraph not found after validation: ${alias}`);
|
|
156
|
+
}
|
|
157
|
+
if (health.error_count > 0) {
|
|
158
|
+
throw new errors_1.ValidationError(`subgraph ${alias} is invalid:\n${health.errors.join("\n")}`);
|
|
159
|
+
}
|
|
160
|
+
writeRawConfig(configPath, raw);
|
|
161
|
+
const receipt = receiptForHealth("added", health);
|
|
162
|
+
if (options.json) {
|
|
163
|
+
writeJson(receipt);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
console.log(`subgraph added: ${alias} (${bundlePath})`);
|
|
167
|
+
if (health.warning_count > 0) {
|
|
168
|
+
console.log(`warnings: ${health.warning_count}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function runSubgraphAddCommand(options) {
|
|
172
|
+
return withSubgraphLock(options.root, () => runSubgraphAddCommandLocked(options));
|
|
173
|
+
}
|
|
174
|
+
function runSubgraphListCommand(options) {
|
|
175
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
176
|
+
const subgraphs = (0, subgraphs_1.buildSubgraphsIndex)(options.root, config).index.subgraphs;
|
|
177
|
+
if (options.json) {
|
|
178
|
+
writeJson({ action: "list", count: subgraphs.length, subgraphs });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (subgraphs.length === 0) {
|
|
182
|
+
console.log("no subgraphs configured");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
for (const item of subgraphs) {
|
|
186
|
+
const status = item.enabled ? item.error_count > 0 ? "invalid" : item.stale ? "stale" : "ok" : "disabled";
|
|
187
|
+
const sourcePaths = item.sources.map((source) => source.path).join(",");
|
|
188
|
+
console.log(`${item.alias} | ${status} | ${item.visibility} | ${sourcePaths}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function runSubgraphShowCommand(options) {
|
|
192
|
+
const alias = normalizeAlias(options.alias);
|
|
193
|
+
const health = healthByAlias(options.root, alias);
|
|
194
|
+
if (options.json) {
|
|
195
|
+
writeJson(receiptForHealth("show", health));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
console.log(`${health.alias} | ${health.enabled ? "enabled" : "disabled"} | ${health.visibility}`);
|
|
199
|
+
console.log(`permissions: ${health.permissions.join(",")}`);
|
|
200
|
+
console.log(`max source count: ${health.sources.length}`);
|
|
201
|
+
for (const source of health.sources) {
|
|
202
|
+
const status = source.enabled ? source.error_count > 0 ? "invalid" : source.stale ? "stale" : "ok" : "disabled";
|
|
203
|
+
console.log(`source: ${source.path} | ${status} | ${source.expected_profile}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function runSubgraphRemoveCommandLocked(options) {
|
|
207
|
+
const alias = normalizeAlias(options.alias);
|
|
208
|
+
const { configPath, raw } = readRawConfig(options.root);
|
|
209
|
+
const subgraphs = getSubgraphs(raw);
|
|
210
|
+
const existing = subgraphs[alias];
|
|
211
|
+
if (!existing) {
|
|
212
|
+
throw new errors_1.NotFoundError(`subgraph not found: ${alias}`);
|
|
213
|
+
}
|
|
214
|
+
delete subgraphs[alias];
|
|
215
|
+
raw.subgraphs = subgraphs;
|
|
216
|
+
(0, config_1.validateConfigSchema)(raw);
|
|
217
|
+
writeRawConfig(configPath, raw);
|
|
218
|
+
const receipt = { action: "removed", subgraph: { alias } };
|
|
219
|
+
if (options.json) {
|
|
220
|
+
writeJson(receipt);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
console.log(`subgraph removed: ${alias}`);
|
|
224
|
+
}
|
|
225
|
+
function runSubgraphRemoveCommand(options) {
|
|
226
|
+
return withSubgraphLock(options.root, () => runSubgraphRemoveCommandLocked(options));
|
|
227
|
+
}
|
|
228
|
+
function setSubgraphEnabledLocked(options, enabled) {
|
|
229
|
+
const alias = normalizeAlias(options.alias);
|
|
230
|
+
const { configPath, raw } = readRawConfig(options.root);
|
|
231
|
+
const subgraphs = getSubgraphs(raw);
|
|
232
|
+
const existing = subgraphs[alias];
|
|
233
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
234
|
+
throw new errors_1.NotFoundError(`subgraph not found: ${alias}`);
|
|
235
|
+
}
|
|
236
|
+
subgraphs[alias] = { ...existing, enabled };
|
|
237
|
+
raw.subgraphs = subgraphs;
|
|
238
|
+
(0, config_1.validateConfigSchema)(raw);
|
|
239
|
+
writeRawConfig(configPath, raw);
|
|
240
|
+
const health = healthByAlias(options.root, alias);
|
|
241
|
+
const receipt = receiptForHealth(enabled ? "enabled" : "disabled", health);
|
|
242
|
+
if (options.json) {
|
|
243
|
+
writeJson(receipt);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
console.log(`subgraph ${enabled ? "enabled" : "disabled"}: ${alias}`);
|
|
247
|
+
}
|
|
248
|
+
function runSubgraphEnableCommand(options) {
|
|
249
|
+
withSubgraphLock(options.root, () => setSubgraphEnabledLocked(options, true));
|
|
250
|
+
}
|
|
251
|
+
function runSubgraphDisableCommand(options) {
|
|
252
|
+
withSubgraphLock(options.root, () => setSubgraphEnabledLocked(options, false));
|
|
253
|
+
}
|
|
254
|
+
function selectHealth(items, alias, all) {
|
|
255
|
+
const includeAll = all || !alias;
|
|
256
|
+
const selected = items.filter((item) => includeAll ? true : item.alias === alias);
|
|
257
|
+
if (!includeAll && selected.length === 0) {
|
|
258
|
+
throw new errors_1.NotFoundError(`subgraph not found: ${alias}`);
|
|
259
|
+
}
|
|
260
|
+
return selected;
|
|
261
|
+
}
|
|
262
|
+
function runSubgraphVerifyCommand(options) {
|
|
263
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
264
|
+
const subgraphs = selectHealth((0, subgraphs_1.buildSubgraphsIndex)(options.root, config).index.subgraphs, options.alias, options.all);
|
|
265
|
+
const ok = subgraphs.every((item) => item.error_count === 0 && !item.stale);
|
|
266
|
+
const receipt = { action: "verified", ok, count: subgraphs.length, subgraphs };
|
|
267
|
+
if (options.json) {
|
|
268
|
+
writeJson(receipt);
|
|
269
|
+
}
|
|
270
|
+
else if (ok) {
|
|
271
|
+
console.log(`subgraphs verified: ${subgraphs.length}`);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
console.log(`subgraph verify failed: ${subgraphs.length}`);
|
|
275
|
+
for (const item of subgraphs) {
|
|
276
|
+
for (const warning of item.warnings) {
|
|
277
|
+
console.log(`warning: ${item.alias}: ${warning}`);
|
|
278
|
+
}
|
|
279
|
+
for (const error of item.errors) {
|
|
280
|
+
console.log(`error: ${item.alias}: ${error}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (!ok) {
|
|
285
|
+
throw new errors_1.ValidationError("subgraph verify failed");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function runSubgraphRefreshCommand(options) {
|
|
289
|
+
withSubgraphLock(options.root, () => {
|
|
290
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
291
|
+
const result = (0, reindex_1.writeDerivedIndexes)(options.root, config);
|
|
292
|
+
const subgraphs = selectHealth((0, subgraphs_1.buildSubgraphsIndex)(options.root, config).index.subgraphs, options.alias, options.all);
|
|
293
|
+
const ok = subgraphs.every((item) => item.error_count === 0);
|
|
294
|
+
const receipt = {
|
|
295
|
+
action: "refreshed",
|
|
296
|
+
ok,
|
|
297
|
+
count: subgraphs.length,
|
|
298
|
+
paths: result.paths,
|
|
299
|
+
subgraphs,
|
|
300
|
+
};
|
|
301
|
+
if (options.json) {
|
|
302
|
+
writeJson(receipt);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
console.log(`subgraphs refreshed: ${subgraphs.length}`);
|
|
306
|
+
console.log(`index: ${path_1.default.relative(options.root, result.paths.subgraphs)}`);
|
|
307
|
+
}
|
|
308
|
+
if (!ok) {
|
|
309
|
+
throw new errors_1.ValidationError("subgraph refresh failed");
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
package/dist/commands/task.js
CHANGED
|
@@ -110,7 +110,7 @@ function loadMutableTaskNode(root, idOrQid, wsHint) {
|
|
|
110
110
|
throw new errors_1.NotFoundError(`task not found: ${idOrQid}`);
|
|
111
111
|
}
|
|
112
112
|
if (node.source?.imported) {
|
|
113
|
-
throw new errors_1.UsageError(`cannot mutate read-only
|
|
113
|
+
throw new errors_1.UsageError(`cannot mutate read-only subgraph node ${node.qid}; update the source workspace for subgraph ${node.source.subgraph_alias}`);
|
|
114
114
|
}
|
|
115
115
|
if (!MUTABLE_TASK_TYPES.has(node.type)) {
|
|
116
116
|
throw new errors_1.UsageError(`mdkg task only supports task, bug, and test nodes; use markdown editing for ${node.type}:${node.id}`);
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -171,12 +171,57 @@ function planSeedFile(options) {
|
|
|
171
171
|
});
|
|
172
172
|
return false;
|
|
173
173
|
}
|
|
174
|
+
function migrateLegacyBundleImportsConfig(input) {
|
|
175
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
176
|
+
return { config: input, changed: false };
|
|
177
|
+
}
|
|
178
|
+
const raw = { ...input };
|
|
179
|
+
if (raw.bundle_imports === undefined) {
|
|
180
|
+
if (raw.subgraphs === undefined) {
|
|
181
|
+
raw.subgraphs = {};
|
|
182
|
+
return { config: raw, changed: true };
|
|
183
|
+
}
|
|
184
|
+
return { config: raw, changed: false };
|
|
185
|
+
}
|
|
186
|
+
if (raw.subgraphs !== undefined) {
|
|
187
|
+
return { config: raw, changed: false };
|
|
188
|
+
}
|
|
189
|
+
const subgraphs = {};
|
|
190
|
+
const legacy = raw.bundle_imports;
|
|
191
|
+
if (legacy && typeof legacy === "object" && !Array.isArray(legacy)) {
|
|
192
|
+
for (const [alias, value] of Object.entries(legacy)) {
|
|
193
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const entry = value;
|
|
197
|
+
subgraphs[alias] = {
|
|
198
|
+
enabled: entry.enabled ?? true,
|
|
199
|
+
visibility: entry.visibility ?? "private",
|
|
200
|
+
permissions: ["read"],
|
|
201
|
+
max_stale_seconds: entry.max_stale_seconds ?? 3600,
|
|
202
|
+
...(entry.source_path ? { source_path: entry.source_path } : {}),
|
|
203
|
+
...(entry.source_repo ? { source_repo: entry.source_repo } : {}),
|
|
204
|
+
sources: [
|
|
205
|
+
{
|
|
206
|
+
path: entry.path,
|
|
207
|
+
enabled: true,
|
|
208
|
+
expected_profile: entry.expected_profile ?? "private",
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
raw.subgraphs = subgraphs;
|
|
215
|
+
delete raw.bundle_imports;
|
|
216
|
+
return { config: raw, changed: true };
|
|
217
|
+
}
|
|
174
218
|
function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
175
219
|
const cfgPath = (0, paths_1.configPath)(root);
|
|
176
220
|
const raw = JSON.parse(fs_1.default.readFileSync(cfgPath, "utf8"));
|
|
177
221
|
const migrated = (0, migrate_1.migrateConfig)(raw);
|
|
178
|
-
|
|
179
|
-
|
|
222
|
+
const nextConfig = migrateLegacyBundleImportsConfig(migrated.config);
|
|
223
|
+
(0, config_1.validateConfigSchema)(nextConfig.config);
|
|
224
|
+
if (migrated.from === migrated.to && !nextConfig.changed) {
|
|
180
225
|
summary.unchanged += 1;
|
|
181
226
|
return;
|
|
182
227
|
}
|
|
@@ -184,10 +229,12 @@ function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
|
184
229
|
path: ".mdkg/config.json",
|
|
185
230
|
category: "config",
|
|
186
231
|
action: "migrate",
|
|
187
|
-
reason:
|
|
232
|
+
reason: nextConfig.changed
|
|
233
|
+
? `config subgraphs migration${migrated.from === migrated.to ? "" : ` and schema_version ${migrated.from} -> ${migrated.to}`}`
|
|
234
|
+
: `config schema_version ${migrated.from} -> ${migrated.to}`,
|
|
188
235
|
});
|
|
189
236
|
if (!dryRun) {
|
|
190
|
-
writeFile(cfgPath, `${JSON.stringify(
|
|
237
|
+
writeFile(cfgPath, `${JSON.stringify(nextConfig.config, null, 2)}\n`);
|
|
191
238
|
}
|
|
192
239
|
}
|
|
193
240
|
function isIgnoredBySimpleGitignore(root, relativePath) {
|
|
@@ -12,7 +12,7 @@ const node_1 = require("../graph/node");
|
|
|
12
12
|
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
13
13
|
const workspace_files_1 = require("../graph/workspace_files");
|
|
14
14
|
const validate_graph_1 = require("../graph/validate_graph");
|
|
15
|
-
const
|
|
15
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
16
16
|
const visibility_1 = require("../graph/visibility");
|
|
17
17
|
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
18
18
|
const errors_1 = require("../util/errors");
|
|
@@ -276,16 +276,16 @@ function runValidateCommand(options) {
|
|
|
276
276
|
nodes,
|
|
277
277
|
reverse_edges: {},
|
|
278
278
|
};
|
|
279
|
-
const
|
|
280
|
-
for (const item of
|
|
279
|
+
const subgraphProjection = (0, subgraphs_1.buildSubgraphsIndex)(options.root, config);
|
|
280
|
+
for (const item of subgraphProjection.index.subgraphs) {
|
|
281
281
|
for (const warning of item.warnings) {
|
|
282
|
-
warnings.push(`
|
|
282
|
+
warnings.push(`subgraph ${item.alias}: ${warning}`);
|
|
283
283
|
}
|
|
284
284
|
for (const error of item.errors) {
|
|
285
|
-
errors.push(`
|
|
285
|
+
errors.push(`subgraph ${item.alias}: ${error}`);
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
const validationIndex = (0,
|
|
288
|
+
const validationIndex = (0, subgraphs_1.mergeSubgraphsIntoIndex)(index, subgraphProjection);
|
|
289
289
|
let knownSkills = new Set();
|
|
290
290
|
try {
|
|
291
291
|
const skillsIndex = (0, skills_indexer_1.buildSkillsIndex)(options.root, config);
|
package/dist/commands/work.js
CHANGED
|
@@ -190,7 +190,7 @@ function resolveWorkNode(index, idOrQid, ws, allowedTypes, label) {
|
|
|
190
190
|
throw new errors_1.NotFoundError(`${label} not found: ${idOrQid}`);
|
|
191
191
|
}
|
|
192
192
|
if (node.source?.imported) {
|
|
193
|
-
throw new errors_1.UsageError(`cannot mutate read-only
|
|
193
|
+
throw new errors_1.UsageError(`cannot mutate read-only subgraph node ${node.qid}; update the source workspace for subgraph ${node.source.subgraph_alias}`);
|
|
194
194
|
}
|
|
195
195
|
return node;
|
|
196
196
|
}
|