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
package/dist/commands/bundle.js
CHANGED
|
@@ -13,7 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
13
|
const child_process_1 = require("child_process");
|
|
14
14
|
const config_1 = require("../core/config");
|
|
15
15
|
const capabilities_indexer_1 = require("../graph/capabilities_indexer");
|
|
16
|
-
const
|
|
16
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
17
17
|
const indexer_1 = require("../graph/indexer");
|
|
18
18
|
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
19
19
|
const zip_1 = require("../util/zip");
|
|
@@ -386,11 +386,11 @@ function collectStringValues(value, out) {
|
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
-
function
|
|
390
|
-
const
|
|
389
|
+
function publicSubgraphReferenceErrors(config, index, includedQids) {
|
|
390
|
+
const privateSubgraphAliases = new Set(Object.entries(config.subgraphs)
|
|
391
391
|
.filter(([, entry]) => entry.enabled && entry.visibility !== "public")
|
|
392
392
|
.map(([alias]) => alias));
|
|
393
|
-
if (
|
|
393
|
+
if (privateSubgraphAliases.size === 0) {
|
|
394
394
|
return [];
|
|
395
395
|
}
|
|
396
396
|
const errors = [];
|
|
@@ -404,8 +404,8 @@ function publicImportReferenceErrors(config, index, includedQids) {
|
|
|
404
404
|
values.push(...node.links, ...node.artifacts, ...node.refs, ...node.aliases);
|
|
405
405
|
for (const value of values) {
|
|
406
406
|
const [alias] = value.split(":");
|
|
407
|
-
if (alias &&
|
|
408
|
-
errors.push(`${node.qid} references private
|
|
407
|
+
if (alias && privateSubgraphAliases.has(alias)) {
|
|
408
|
+
errors.push(`${node.qid} references private subgraph ${value}`);
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
}
|
|
@@ -465,7 +465,7 @@ function buildBundle(options) {
|
|
|
465
465
|
const filteredIndex = filterIndex(index, config, selectedSet, profile);
|
|
466
466
|
if (profile === "public") {
|
|
467
467
|
const includedQids = new Set(Object.keys(filteredIndex.nodes));
|
|
468
|
-
const mergedIndex = (0,
|
|
468
|
+
const mergedIndex = (0, subgraphs_1.mergeSubgraphsIntoIndex)(index, (0, subgraphs_1.buildSubgraphsIndex)(options.root, config));
|
|
469
469
|
const errors = (0, visibility_1.visibilityViolationMessages)((0, visibility_1.collectVisibilityViolations)(mergedIndex, config, {
|
|
470
470
|
includedQids,
|
|
471
471
|
scope: "public",
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runCapabilityListCommand = runCapabilityListCommand;
|
|
4
4
|
exports.runCapabilitySearchCommand = runCapabilitySearchCommand;
|
|
5
5
|
exports.runCapabilityShowCommand = runCapabilityShowCommand;
|
|
6
|
+
exports.runCapabilityResolveCommand = runCapabilityResolveCommand;
|
|
6
7
|
const config_1 = require("../core/config");
|
|
7
8
|
const capabilities_indexer_1 = require("../graph/capabilities_indexer");
|
|
8
9
|
const capabilities_index_cache_1 = require("../graph/capabilities_index_cache");
|
|
9
|
-
const
|
|
10
|
+
const subgraphs_1 = require("../graph/subgraphs");
|
|
10
11
|
const errors_1 = require("../util/errors");
|
|
11
12
|
function normalizeKind(value) {
|
|
12
13
|
if (value === undefined) {
|
|
@@ -39,11 +40,11 @@ function loadRecords(options) {
|
|
|
39
40
|
if (stale && !rebuilt && !options.noCache) {
|
|
40
41
|
console.error("warning: capabilities index is stale; run mdkg index to refresh");
|
|
41
42
|
}
|
|
42
|
-
const
|
|
43
|
-
for (const warning of
|
|
43
|
+
const subgraph = (0, subgraphs_1.buildSubgraphCapabilityRecords)(options.root, config);
|
|
44
|
+
for (const warning of subgraph.warnings) {
|
|
44
45
|
console.error(`warning: ${warning}`);
|
|
45
46
|
}
|
|
46
|
-
return [...index.records, ...
|
|
47
|
+
return [...index.records, ...subgraph.records];
|
|
47
48
|
}
|
|
48
49
|
function applyFilters(records, options) {
|
|
49
50
|
const kind = normalizeKind(options.kind);
|
|
@@ -95,6 +96,89 @@ function matchesQuery(record, query) {
|
|
|
95
96
|
const text = capabilitySearchText(record);
|
|
96
97
|
return terms.every((term) => text.includes(term));
|
|
97
98
|
}
|
|
99
|
+
function recordSource(record) {
|
|
100
|
+
const source = record.source;
|
|
101
|
+
return source ?? {};
|
|
102
|
+
}
|
|
103
|
+
function isStale(record) {
|
|
104
|
+
return recordSource(record).stale === true;
|
|
105
|
+
}
|
|
106
|
+
function hasReadPermission(record) {
|
|
107
|
+
const permissions = recordSource(record).permissions;
|
|
108
|
+
return !Array.isArray(permissions) || permissions.includes("read");
|
|
109
|
+
}
|
|
110
|
+
function requirementMatch(record, required) {
|
|
111
|
+
if (!required) {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
const normalized = required.toLowerCase();
|
|
115
|
+
const haystack = [
|
|
116
|
+
...record.refs,
|
|
117
|
+
...record.tags,
|
|
118
|
+
JSON.stringify(record.spec ?? {}),
|
|
119
|
+
JSON.stringify(record.work ?? {}),
|
|
120
|
+
JSON.stringify(record.skill ?? {}),
|
|
121
|
+
]
|
|
122
|
+
.join(" ")
|
|
123
|
+
.toLowerCase();
|
|
124
|
+
return haystack.includes(normalized) ? 1 : 0;
|
|
125
|
+
}
|
|
126
|
+
function linkageScore(record) {
|
|
127
|
+
let score = 0;
|
|
128
|
+
if (record.kind === "work") {
|
|
129
|
+
score += 2;
|
|
130
|
+
}
|
|
131
|
+
if (record.kind === "spec") {
|
|
132
|
+
score += 1;
|
|
133
|
+
}
|
|
134
|
+
if (record.work || record.spec) {
|
|
135
|
+
score += 1;
|
|
136
|
+
}
|
|
137
|
+
return score;
|
|
138
|
+
}
|
|
139
|
+
function resolveScore(record, options) {
|
|
140
|
+
let score = 0;
|
|
141
|
+
if (record.workspace === "root") {
|
|
142
|
+
score += 1000;
|
|
143
|
+
}
|
|
144
|
+
if (!isStale(record)) {
|
|
145
|
+
score += 500;
|
|
146
|
+
}
|
|
147
|
+
if (hasReadPermission(record)) {
|
|
148
|
+
score += 100;
|
|
149
|
+
}
|
|
150
|
+
if (options.query && matchesQuery(record, options.query)) {
|
|
151
|
+
score += 50;
|
|
152
|
+
}
|
|
153
|
+
score += requirementMatch(record, options.requires) * 25;
|
|
154
|
+
score += linkageScore(record);
|
|
155
|
+
return score;
|
|
156
|
+
}
|
|
157
|
+
function resolveCapabilities(records, options) {
|
|
158
|
+
const filtered = records.filter((record) => {
|
|
159
|
+
if (options.freshOnly && isStale(record)) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (options.query && !matchesQuery(record, options.query)) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (options.requires && requirementMatch(record, options.requires) === 0) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
});
|
|
170
|
+
return filtered.sort((a, b) => {
|
|
171
|
+
const scoreDelta = resolveScore(b, options) - resolveScore(a, options);
|
|
172
|
+
if (scoreDelta !== 0) {
|
|
173
|
+
return scoreDelta;
|
|
174
|
+
}
|
|
175
|
+
const qidDelta = a.qid.localeCompare(b.qid);
|
|
176
|
+
if (qidDelta !== 0) {
|
|
177
|
+
return qidDelta;
|
|
178
|
+
}
|
|
179
|
+
return a.path.localeCompare(b.path);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
98
182
|
function printCapabilityList(records, json, query) {
|
|
99
183
|
if (json) {
|
|
100
184
|
console.log(JSON.stringify({
|
|
@@ -160,3 +244,33 @@ function runCapabilityShowCommand(options) {
|
|
|
160
244
|
const records = loadRecords(options);
|
|
161
245
|
printCapability(resolveCapability(records, options.id), options.json);
|
|
162
246
|
}
|
|
247
|
+
function runCapabilityResolveCommand(options) {
|
|
248
|
+
const records = applyFilters(loadRecords(options), options);
|
|
249
|
+
const items = resolveCapabilities(records, options).map((record, rank) => ({
|
|
250
|
+
rank: rank + 1,
|
|
251
|
+
score: resolveScore(record, options),
|
|
252
|
+
stale: isStale(record),
|
|
253
|
+
item: record,
|
|
254
|
+
}));
|
|
255
|
+
if (options.json) {
|
|
256
|
+
console.log(JSON.stringify({
|
|
257
|
+
kind: "capability.resolve",
|
|
258
|
+
query: options.query,
|
|
259
|
+
requires: options.requires,
|
|
260
|
+
fresh_only: options.freshOnly === true,
|
|
261
|
+
count: items.length,
|
|
262
|
+
items,
|
|
263
|
+
}, null, 2));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (items.length === 0) {
|
|
267
|
+
console.log("no capabilities resolved");
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
console.log(`resolved capabilities: ${items.length}`);
|
|
271
|
+
for (const result of items) {
|
|
272
|
+
const record = result.item;
|
|
273
|
+
const stale = result.stale ? " stale" : "";
|
|
274
|
+
console.log(`${result.rank}. ${record.qid} | score ${result.score}${stale} | ${record.kind} | ${record.title}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -13,6 +13,9 @@ const loader_1 = require("../templates/loader");
|
|
|
13
13
|
const date_1 = require("../util/date");
|
|
14
14
|
const errors_1 = require("../util/errors");
|
|
15
15
|
const id_1 = require("../util/id");
|
|
16
|
+
const atomic_1 = require("../util/atomic");
|
|
17
|
+
const lock_1 = require("../util/lock");
|
|
18
|
+
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
16
19
|
const event_support_1 = require("./event_support");
|
|
17
20
|
function parseCsvList(raw) {
|
|
18
21
|
if (!raw) {
|
|
@@ -38,6 +41,9 @@ function normalizeIdRef(value, key) {
|
|
|
38
41
|
return normalized;
|
|
39
42
|
}
|
|
40
43
|
function nextCheckpointId(index, ws) {
|
|
44
|
+
return `chk-${maxCheckpointId(index, ws) + 1}`;
|
|
45
|
+
}
|
|
46
|
+
function maxCheckpointId(index, ws) {
|
|
41
47
|
let max = 0;
|
|
42
48
|
for (const node of Object.values(index.nodes)) {
|
|
43
49
|
if (node.ws !== ws) {
|
|
@@ -52,7 +58,7 @@ function nextCheckpointId(index, ws) {
|
|
|
52
58
|
max = parsed;
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
|
-
return
|
|
61
|
+
return max;
|
|
56
62
|
}
|
|
57
63
|
function slugifyTitle(title) {
|
|
58
64
|
const slug = title
|
|
@@ -77,7 +83,7 @@ function normalizeWorkspace(value) {
|
|
|
77
83
|
}
|
|
78
84
|
return normalized;
|
|
79
85
|
}
|
|
80
|
-
function
|
|
86
|
+
function createCheckpointLocked(options) {
|
|
81
87
|
const title = options.title.trim();
|
|
82
88
|
if (!title) {
|
|
83
89
|
throw new errors_1.UsageError("checkpoint title cannot be empty");
|
|
@@ -99,7 +105,15 @@ function createCheckpoint(options) {
|
|
|
99
105
|
throw new errors_1.UsageError(`--priority must be between ${priorityMin} and ${priorityMax}`);
|
|
100
106
|
}
|
|
101
107
|
const { index } = (0, index_cache_1.loadIndex)({ root: options.root, config });
|
|
102
|
-
const id =
|
|
108
|
+
const id = (0, sqlite_index_1.isSqliteBackend)(config)
|
|
109
|
+
? (0, sqlite_index_1.reserveSqliteNumericId)({
|
|
110
|
+
root: options.root,
|
|
111
|
+
config,
|
|
112
|
+
ws,
|
|
113
|
+
prefix: "chk",
|
|
114
|
+
currentMax: maxCheckpointId(index, ws),
|
|
115
|
+
}) ?? nextCheckpointId(index, ws)
|
|
116
|
+
: nextCheckpointId(index, ws);
|
|
103
117
|
const slug = slugifyTitle(title);
|
|
104
118
|
const fileName = `${id}-${slug}.md`;
|
|
105
119
|
const wsEntry = config.workspaces[ws];
|
|
@@ -129,8 +143,16 @@ function createCheckpoint(options) {
|
|
|
129
143
|
relates,
|
|
130
144
|
scope,
|
|
131
145
|
});
|
|
132
|
-
|
|
133
|
-
|
|
146
|
+
try {
|
|
147
|
+
(0, atomic_1.writeFileExclusive)(filePath, content);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "";
|
|
151
|
+
if (code === "EEXIST") {
|
|
152
|
+
throw new errors_1.UsageError(`checkpoint file already exists: ${path_1.default.relative(options.root, filePath)}`);
|
|
153
|
+
}
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
134
156
|
(0, event_support_1.appendAutomaticEvent)({
|
|
135
157
|
root: options.root,
|
|
136
158
|
ws,
|
|
@@ -148,6 +170,10 @@ function createCheckpoint(options) {
|
|
|
148
170
|
path: path_1.default.relative(options.root, filePath),
|
|
149
171
|
};
|
|
150
172
|
}
|
|
173
|
+
function createCheckpoint(options) {
|
|
174
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
175
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => createCheckpointLocked(options));
|
|
176
|
+
}
|
|
151
177
|
function runCheckpointNewCommand(options) {
|
|
152
178
|
const checkpoint = createCheckpoint(options);
|
|
153
179
|
if (options.json) {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -9,35 +9,41 @@ 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");
|
|
16
|
+
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
16
17
|
const errors_1 = require("../util/errors");
|
|
17
|
-
const REQUIRED_NODE_MAJOR =
|
|
18
|
+
const REQUIRED_NODE_MAJOR = 24;
|
|
19
|
+
const REQUIRED_NODE_MINOR = 15;
|
|
18
20
|
const ARCHIVE_RAW_ALLOWED_DIRS = new Set(["source"]);
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
|
|
21
|
+
function parseNodeVersion(version) {
|
|
22
|
+
const [majorRaw, minorRaw, patchRaw] = version.split(".");
|
|
23
|
+
const major = Number.parseInt(majorRaw ?? "", 10);
|
|
24
|
+
const minor = Number.parseInt(minorRaw ?? "", 10);
|
|
25
|
+
const patch = Number.parseInt(patchRaw ?? "", 10);
|
|
26
|
+
if (!Number.isInteger(major) || !Number.isInteger(minor) || !Number.isInteger(patch)) {
|
|
22
27
|
return null;
|
|
23
28
|
}
|
|
24
|
-
return major;
|
|
29
|
+
return { major, minor, patch };
|
|
25
30
|
}
|
|
26
31
|
function runNodeVersionCheck() {
|
|
27
32
|
const nodeVersion = process.versions.node;
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
33
|
+
const parsed = parseNodeVersion(nodeVersion);
|
|
34
|
+
if (parsed === null) {
|
|
30
35
|
return {
|
|
31
36
|
name: "node-version",
|
|
32
37
|
ok: false,
|
|
33
38
|
detail: `unable to parse Node.js version: ${nodeVersion}`,
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
|
-
if (major < REQUIRED_NODE_MAJOR
|
|
41
|
+
if (parsed.major < REQUIRED_NODE_MAJOR ||
|
|
42
|
+
(parsed.major === REQUIRED_NODE_MAJOR && parsed.minor < REQUIRED_NODE_MINOR)) {
|
|
37
43
|
return {
|
|
38
44
|
name: "node-version",
|
|
39
45
|
ok: false,
|
|
40
|
-
detail: `Node.js ${nodeVersion} is unsupported (requires >=${REQUIRED_NODE_MAJOR})`,
|
|
46
|
+
detail: `Node.js ${nodeVersion} is unsupported (requires >=${REQUIRED_NODE_MAJOR}.${REQUIRED_NODE_MINOR}.0)`,
|
|
41
47
|
};
|
|
42
48
|
}
|
|
43
49
|
return {
|
|
@@ -46,6 +52,36 @@ function runNodeVersionCheck() {
|
|
|
46
52
|
detail: `Node.js ${nodeVersion} (ok)`,
|
|
47
53
|
};
|
|
48
54
|
}
|
|
55
|
+
function runSqliteCheck(root, config) {
|
|
56
|
+
if (!(0, sqlite_index_1.isSqliteBackend)(config)) {
|
|
57
|
+
return {
|
|
58
|
+
name: "sqlite-cache",
|
|
59
|
+
ok: true,
|
|
60
|
+
detail: "SQLite backend disabled; JSON cache backend active",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const health = (0, sqlite_index_1.sqliteHealth)(root, config);
|
|
64
|
+
if (health.errors.length > 0) {
|
|
65
|
+
return {
|
|
66
|
+
name: "sqlite-cache",
|
|
67
|
+
ok: false,
|
|
68
|
+
detail: health.errors.join("; "),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (health.warnings.length > 0) {
|
|
72
|
+
return {
|
|
73
|
+
name: "sqlite-cache",
|
|
74
|
+
ok: true,
|
|
75
|
+
level: "warn",
|
|
76
|
+
detail: health.warnings.join("; "),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
name: "sqlite-cache",
|
|
81
|
+
ok: true,
|
|
82
|
+
detail: `.mdkg SQLite cache ok (${health.size} bytes)`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
49
85
|
function walkFiles(root) {
|
|
50
86
|
if (!fs_1.default.existsSync(root)) {
|
|
51
87
|
return [];
|
|
@@ -150,45 +186,45 @@ function runBundleStorageCheck(root, outputDir) {
|
|
|
150
186
|
detail: `${bundles.length} bundle(s) found; run \`mdkg bundle verify <path>\` to check freshness before handoff`,
|
|
151
187
|
};
|
|
152
188
|
}
|
|
153
|
-
function
|
|
154
|
-
const projection = (0,
|
|
155
|
-
if (projection.index.
|
|
189
|
+
function runSubgraphChecks(root, config) {
|
|
190
|
+
const projection = (0, subgraphs_1.buildSubgraphsIndex)(root, config);
|
|
191
|
+
if (projection.index.subgraphs.length === 0) {
|
|
156
192
|
return [
|
|
157
193
|
{
|
|
158
|
-
name: "
|
|
194
|
+
name: "subgraphs",
|
|
159
195
|
ok: true,
|
|
160
|
-
detail: "no
|
|
196
|
+
detail: "no subgraphs configured",
|
|
161
197
|
},
|
|
162
198
|
];
|
|
163
199
|
}
|
|
164
|
-
return projection.index.
|
|
200
|
+
return projection.index.subgraphs.map((item) => {
|
|
165
201
|
if (!item.enabled) {
|
|
166
202
|
return {
|
|
167
|
-
name: `
|
|
203
|
+
name: `subgraph:${item.alias}`,
|
|
168
204
|
ok: true,
|
|
169
205
|
level: "warn",
|
|
170
|
-
detail:
|
|
206
|
+
detail: "disabled subgraph",
|
|
171
207
|
};
|
|
172
208
|
}
|
|
173
209
|
if (item.error_count > 0) {
|
|
174
210
|
return {
|
|
175
|
-
name: `
|
|
211
|
+
name: `subgraph:${item.alias}`,
|
|
176
212
|
ok: false,
|
|
177
213
|
detail: item.errors.join("; "),
|
|
178
214
|
};
|
|
179
215
|
}
|
|
180
216
|
if (item.stale || item.warning_count > 0) {
|
|
181
217
|
return {
|
|
182
|
-
name: `
|
|
218
|
+
name: `subgraph:${item.alias}`,
|
|
183
219
|
ok: true,
|
|
184
220
|
level: "warn",
|
|
185
|
-
detail: `
|
|
221
|
+
detail: `subgraph is stale or has warnings; run \`mdkg subgraph verify ${item.alias}\` (${item.warnings.join("; ")})`,
|
|
186
222
|
};
|
|
187
223
|
}
|
|
188
224
|
return {
|
|
189
|
-
name: `
|
|
225
|
+
name: `subgraph:${item.alias}`,
|
|
190
226
|
ok: true,
|
|
191
|
-
detail: `
|
|
227
|
+
detail: `subgraph loaded from ${item.sources.map((source) => source.path).join(", ")}`,
|
|
192
228
|
};
|
|
193
229
|
});
|
|
194
230
|
}
|
|
@@ -262,7 +298,8 @@ function runDoctorCommand(options) {
|
|
|
262
298
|
results.push(runArchiveStorageCheck(options.root));
|
|
263
299
|
results.push(runArchiveLargeCacheCheck(options.root, config.archive.large_cache_warning_bytes));
|
|
264
300
|
results.push(runBundleStorageCheck(options.root, config.bundles.output_dir));
|
|
265
|
-
results.push(
|
|
301
|
+
results.push(runSqliteCheck(options.root, config));
|
|
302
|
+
results.push(...runSubgraphChecks(options.root, config));
|
|
266
303
|
results.push(runVisibilityPolicyCheck(options.root, config, options));
|
|
267
304
|
try {
|
|
268
305
|
const templateSchemaInfo = (0, template_schema_1.loadTemplateSchemasWithInfo)(options.root, config, node_1.ALLOWED_TYPES);
|
package/dist/commands/index.js
CHANGED
|
@@ -6,29 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runIndexCommand = runIndexCommand;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const config_1 = require("../core/config");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const skills_index_cache_1 = require("../graph/skills_index_cache");
|
|
12
|
-
const skills_indexer_1 = require("../graph/skills_indexer");
|
|
13
|
-
const capabilities_indexer_1 = require("../graph/capabilities_indexer");
|
|
14
|
-
const capabilities_index_cache_1 = require("../graph/capabilities_index_cache");
|
|
15
|
-
const bundle_imports_1 = require("../graph/bundle_imports");
|
|
9
|
+
const reindex_1 = require("../graph/reindex");
|
|
10
|
+
const lock_1 = require("../util/lock");
|
|
16
11
|
function runIndexCommand(options) {
|
|
17
12
|
const config = (0, config_1.loadConfig)(options.root);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
(0, capabilities_index_cache_1.writeCapabilitiesIndex)(capabilitiesOutputPath, capabilitiesIndex);
|
|
29
|
-
(0, bundle_imports_1.writeBundleImportsIndex)(importsOutputPath, importsIndex.index);
|
|
30
|
-
console.log(`index written: ${path_1.default.relative(options.root, nodesOutputPath)}`);
|
|
31
|
-
console.log(`skills index written: ${path_1.default.relative(options.root, skillsOutputPath)}`);
|
|
32
|
-
console.log(`capabilities index written: ${path_1.default.relative(options.root, capabilitiesOutputPath)}`);
|
|
33
|
-
console.log(`bundle imports index written: ${path_1.default.relative(options.root, importsOutputPath)}`);
|
|
13
|
+
(0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => {
|
|
14
|
+
const result = (0, reindex_1.writeDerivedIndexes)(options.root, config, undefined, { tolerant: options.tolerant });
|
|
15
|
+
console.log(`index written: ${path_1.default.relative(options.root, result.paths.nodes)}`);
|
|
16
|
+
console.log(`skills index written: ${path_1.default.relative(options.root, result.paths.skills)}`);
|
|
17
|
+
console.log(`capabilities index written: ${path_1.default.relative(options.root, result.paths.capabilities)}`);
|
|
18
|
+
console.log(`subgraphs index written: ${path_1.default.relative(options.root, result.paths.subgraphs)}`);
|
|
19
|
+
if (result.paths.sqlite) {
|
|
20
|
+
console.log(`sqlite index written: ${path_1.default.relative(options.root, result.paths.sqlite)}`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
34
23
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -409,7 +409,13 @@ function runInitCommand(options) {
|
|
|
409
409
|
try {
|
|
410
410
|
if (shouldUpdateGitignore) {
|
|
411
411
|
if (appendIgnoreEntries(path_1.default.join(root, ".gitignore"), [
|
|
412
|
-
".mdkg/index
|
|
412
|
+
".mdkg/index/*.json",
|
|
413
|
+
".mdkg/index/*.tmp",
|
|
414
|
+
".mdkg/index/*.lock",
|
|
415
|
+
".mdkg/index/write.lock/",
|
|
416
|
+
".mdkg/index/*.sqlite-wal",
|
|
417
|
+
".mdkg/index/*.sqlite-shm",
|
|
418
|
+
".mdkg/index/*.sqlite-journal",
|
|
413
419
|
".mdkg/pack/",
|
|
414
420
|
".mdkg/archive/**/source/",
|
|
415
421
|
])) {
|
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/new.js
CHANGED
|
@@ -16,6 +16,10 @@ const date_1 = require("../util/date");
|
|
|
16
16
|
const errors_1 = require("../util/errors");
|
|
17
17
|
const qid_1 = require("../util/qid");
|
|
18
18
|
const id_1 = require("../util/id");
|
|
19
|
+
const atomic_1 = require("../util/atomic");
|
|
20
|
+
const lock_1 = require("../util/lock");
|
|
21
|
+
const sqlite_index_1 = require("../graph/sqlite_index");
|
|
22
|
+
const reindex_1 = require("../graph/reindex");
|
|
19
23
|
const event_support_1 = require("./event_support");
|
|
20
24
|
const DEC_ID_RE = /^dec-[0-9]+$/;
|
|
21
25
|
const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
|
|
@@ -97,6 +101,9 @@ function slugifyTitle(title) {
|
|
|
97
101
|
return slug.length > maxLen ? slug.slice(0, maxLen).replace(/-+$/g, "") : slug;
|
|
98
102
|
}
|
|
99
103
|
function nextIdForPrefix(index, ws, prefix) {
|
|
104
|
+
return `${prefix}-${maxIdForPrefix(index, ws, prefix) + 1}`;
|
|
105
|
+
}
|
|
106
|
+
function maxIdForPrefix(index, ws, prefix) {
|
|
100
107
|
let max = 0;
|
|
101
108
|
const pattern = new RegExp(`^${prefix}-(\\d+)$`);
|
|
102
109
|
for (const node of Object.values(index)) {
|
|
@@ -112,7 +119,7 @@ function nextIdForPrefix(index, ws, prefix) {
|
|
|
112
119
|
max = parsed;
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
|
-
return
|
|
122
|
+
return max;
|
|
116
123
|
}
|
|
117
124
|
function idPrefixForType(type) {
|
|
118
125
|
if (type === "checkpoint") {
|
|
@@ -150,7 +157,7 @@ function ensureExists(index, value, ws, label) {
|
|
|
150
157
|
throw new errors_1.NotFoundError((0, qid_1.formatResolveError)(label, value, resolved, ws));
|
|
151
158
|
}
|
|
152
159
|
}
|
|
153
|
-
function
|
|
160
|
+
function runNewCommandLocked(options) {
|
|
154
161
|
const title = options.title.trim();
|
|
155
162
|
if (!title) {
|
|
156
163
|
throw new errors_1.UsageError("title cannot be empty");
|
|
@@ -181,7 +188,15 @@ function runNewCommand(options) {
|
|
|
181
188
|
const prefix = idPrefixForType(type);
|
|
182
189
|
const id = options.id !== undefined
|
|
183
190
|
? normalizeAgentFileId(options.id)
|
|
184
|
-
:
|
|
191
|
+
: (0, sqlite_index_1.isSqliteBackend)(config)
|
|
192
|
+
? (0, sqlite_index_1.reserveSqliteNumericId)({
|
|
193
|
+
root: options.root,
|
|
194
|
+
config,
|
|
195
|
+
ws,
|
|
196
|
+
prefix,
|
|
197
|
+
currentMax: maxIdForPrefix(index.nodes, ws, prefix),
|
|
198
|
+
}) ?? nextIdForPrefix(index.nodes, ws, prefix)
|
|
199
|
+
: nextIdForPrefix(index.nodes, ws, prefix);
|
|
185
200
|
if (index.nodes[`${ws}:${id}`]) {
|
|
186
201
|
throw new errors_1.UsageError(`node already exists: ${ws}:${id}`);
|
|
187
202
|
}
|
|
@@ -317,12 +332,19 @@ function runNewCommand(options) {
|
|
|
317
332
|
created: today,
|
|
318
333
|
updated: today,
|
|
319
334
|
});
|
|
320
|
-
|
|
321
|
-
|
|
335
|
+
try {
|
|
336
|
+
(0, atomic_1.writeFileExclusive)(filePath, content);
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "";
|
|
340
|
+
if (code === "EEXIST") {
|
|
341
|
+
throw new errors_1.UsageError(`node already exists: ${path_1.default.relative(options.root, filePath)}`);
|
|
342
|
+
}
|
|
343
|
+
throw err;
|
|
344
|
+
}
|
|
322
345
|
if (config.index.auto_reindex && !noReindex) {
|
|
323
346
|
const updatedIndex = (0, indexer_1.buildIndex)(options.root, config, { tolerant: config.index.tolerant });
|
|
324
|
-
|
|
325
|
-
(0, index_cache_1.writeIndex)(outputPath, updatedIndex);
|
|
347
|
+
(0, reindex_1.writeDerivedIndexes)(options.root, config, updatedIndex);
|
|
326
348
|
}
|
|
327
349
|
(0, event_support_1.appendAutomaticEvent)({
|
|
328
350
|
root: options.root,
|
|
@@ -354,3 +376,7 @@ function runNewCommand(options) {
|
|
|
354
376
|
}
|
|
355
377
|
console.log(`node created: ${receipt.qid} (${receipt.path})`);
|
|
356
378
|
}
|
|
379
|
+
function runNewCommand(options) {
|
|
380
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
381
|
+
return (0, lock_1.withMutationLock)(options.root, config.index.lock_timeout_ms, () => runNewCommandLocked(options));
|
|
382
|
+
}
|
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();
|