mdkg 0.3.6 → 0.3.7
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 +69 -0
- package/CLI_COMMAND_MATRIX.md +56 -7
- package/README.md +33 -3
- package/dist/cli.js +132 -11
- package/dist/command-contract.json +431 -16
- package/dist/commands/bundle.js +2 -0
- package/dist/commands/checkpoint.js +139 -1
- package/dist/commands/db.js +8 -0
- package/dist/commands/format.js +116 -0
- package/dist/commands/goal.js +60 -0
- package/dist/commands/graph.js +148 -0
- package/dist/commands/handoff.js +295 -0
- package/dist/commands/mcp.js +9 -0
- package/dist/commands/pack.js +3 -1
- package/dist/commands/query_output.js +2 -0
- package/dist/commands/show.js +8 -0
- package/dist/commands/status.js +1 -0
- package/dist/commands/task.js +2 -0
- package/dist/commands/upgrade.js +61 -0
- package/dist/commands/validate.js +162 -3
- package/dist/commands/work.js +164 -0
- package/dist/core/project_db_queue_contract.js +101 -0
- package/dist/graph/edges.js +15 -0
- package/dist/graph/frontmatter.js +4 -1
- package/dist/graph/indexer.js +8 -0
- package/dist/graph/node.js +12 -1
- package/dist/graph/sqlite_index.js +2 -0
- package/dist/graph/subgraphs.js +2 -0
- package/dist/graph/validate_graph.js +5 -0
- package/dist/graph/visibility.js +6 -0
- package/dist/init/AGENT_START.md +4 -1
- package/dist/init/CLI_COMMAND_MATRIX.md +24 -3
- package/dist/init/README.md +17 -2
- package/dist/init/init-manifest.json +12 -12
- package/dist/init/templates/default/bug.md +2 -0
- package/dist/init/templates/default/chk.md +3 -0
- package/dist/init/templates/default/epic.md +2 -0
- package/dist/init/templates/default/feat.md +2 -0
- package/dist/init/templates/default/goal.md +3 -0
- package/dist/init/templates/default/spike.md +2 -0
- package/dist/init/templates/default/task.md +2 -0
- package/dist/init/templates/default/test.md +2 -0
- package/dist/pack/export_json.js +20 -8
- package/dist/pack/export_md.js +15 -4
- package/dist/pack/export_xml.js +9 -4
- package/dist/pack/metrics.js +12 -4
- package/dist/pack/pack.js +9 -1
- package/package.json +6 -2
|
@@ -0,0 +1,295 @@
|
|
|
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.runHandoffCreateCommand = runHandoffCreateCommand;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const config_1 = require("../core/config");
|
|
10
|
+
const index_cache_1 = require("../graph/index_cache");
|
|
11
|
+
const pack_1 = require("../pack/pack");
|
|
12
|
+
const metrics_1 = require("../pack/metrics");
|
|
13
|
+
const atomic_1 = require("../util/atomic");
|
|
14
|
+
const errors_1 = require("../util/errors");
|
|
15
|
+
const qid_1 = require("../util/qid");
|
|
16
|
+
const version_1 = require("../core/version");
|
|
17
|
+
const RAW_CONTENT_MARKERS = [
|
|
18
|
+
{ id: "raw_prompt", pattern: /\bRAW_PROMPT_MARKER\b/i, description: "raw prompt marker" },
|
|
19
|
+
{ id: "raw_payload", pattern: /\bRAW_PAYLOAD_MARKER\b/i, description: "raw payload marker" },
|
|
20
|
+
{ id: "raw_secret", pattern: /\bRAW_SECRET_MARKER\b|BEGIN [A-Z ]*PRIVATE KEY|secret\s*=/i, description: "raw secret marker" },
|
|
21
|
+
];
|
|
22
|
+
function normalizeWorkspace(value) {
|
|
23
|
+
if (!value || value === "all") {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function outputPath(root, out) {
|
|
29
|
+
if (!out) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
const resolved = path_1.default.resolve(root, out);
|
|
33
|
+
const rootWithSep = root.endsWith(path_1.default.sep) ? root : `${root}${path_1.default.sep}`;
|
|
34
|
+
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
35
|
+
throw new errors_1.UsageError("--out must stay within the repo root");
|
|
36
|
+
}
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
function sha256(value) {
|
|
40
|
+
return `sha256:${crypto_1.default.createHash("sha256").update(value).digest("hex")}`;
|
|
41
|
+
}
|
|
42
|
+
function listAttribute(node, key) {
|
|
43
|
+
const value = "attributes" in node ? node.attributes[key] : undefined;
|
|
44
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
45
|
+
}
|
|
46
|
+
function stringAttribute(node, key) {
|
|
47
|
+
const value = "attributes" in node ? node.attributes[key] : undefined;
|
|
48
|
+
return typeof value === "string" ? value : undefined;
|
|
49
|
+
}
|
|
50
|
+
function collectRawMarkerWarnings(pack) {
|
|
51
|
+
const warnings = [];
|
|
52
|
+
for (const node of pack.nodes) {
|
|
53
|
+
for (const marker of RAW_CONTENT_MARKERS) {
|
|
54
|
+
if (marker.pattern.test(node.body)) {
|
|
55
|
+
warnings.push({
|
|
56
|
+
qid: node.qid,
|
|
57
|
+
path: node.path,
|
|
58
|
+
marker_id: marker.id,
|
|
59
|
+
message: `${marker.description} detected; handoff omitted raw body content for this node`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return warnings;
|
|
65
|
+
}
|
|
66
|
+
function nodeLine(node) {
|
|
67
|
+
const parts = [`${node.qid}`, node.type, node.title];
|
|
68
|
+
const state = [node.status, node.priority !== undefined ? `p${node.priority}` : undefined].filter(Boolean).join("/");
|
|
69
|
+
if (state) {
|
|
70
|
+
parts.push(state);
|
|
71
|
+
}
|
|
72
|
+
parts.push(node.path);
|
|
73
|
+
return `- ${parts.join(" | ")}`;
|
|
74
|
+
}
|
|
75
|
+
function renderList(values, empty = "- none") {
|
|
76
|
+
if (values.length === 0) {
|
|
77
|
+
return [empty];
|
|
78
|
+
}
|
|
79
|
+
return values.map((value) => `- ${value}`);
|
|
80
|
+
}
|
|
81
|
+
function renderNodeRefs(node) {
|
|
82
|
+
const lines = [];
|
|
83
|
+
if (node.refs.length > 0) {
|
|
84
|
+
lines.push(` refs: ${node.refs.join(", ")}`);
|
|
85
|
+
}
|
|
86
|
+
if (node.context_refs.length > 0) {
|
|
87
|
+
lines.push(` context_refs: ${node.context_refs.join(", ")}`);
|
|
88
|
+
}
|
|
89
|
+
if (node.evidence_refs.length > 0) {
|
|
90
|
+
lines.push(` evidence_refs: ${node.evidence_refs.join(", ")}`);
|
|
91
|
+
}
|
|
92
|
+
return lines;
|
|
93
|
+
}
|
|
94
|
+
function renderHandoff(params) {
|
|
95
|
+
const { rootNode, indexNode, pack, rawWarnings } = params;
|
|
96
|
+
const stats = (0, metrics_1.measurePack)(pack);
|
|
97
|
+
const lines = [];
|
|
98
|
+
const requiredChecks = listAttribute(indexNode, "required_checks");
|
|
99
|
+
const requiredSkills = listAttribute(indexNode, "required_skills");
|
|
100
|
+
const goalCondition = stringAttribute(indexNode, "goal_condition");
|
|
101
|
+
const activeNode = stringAttribute(indexNode, "active_node");
|
|
102
|
+
const lastActiveNode = stringAttribute(indexNode, "last_active_node");
|
|
103
|
+
const latestCheckpoint = pack.meta.latest_checkpoint_qid
|
|
104
|
+
? pack.nodes.find((node) => node.qid === pack.meta.latest_checkpoint_qid)
|
|
105
|
+
: undefined;
|
|
106
|
+
lines.push("# mdkg Agent Handoff");
|
|
107
|
+
lines.push("");
|
|
108
|
+
lines.push("Use this handoff as a sanitized graph summary. Inspect source files before mutating durable state.");
|
|
109
|
+
lines.push("");
|
|
110
|
+
lines.push("## Target");
|
|
111
|
+
lines.push(`- qid: ${rootNode.qid}`);
|
|
112
|
+
lines.push(`- type: ${rootNode.type}`);
|
|
113
|
+
lines.push(`- title: ${rootNode.title}`);
|
|
114
|
+
if (rootNode.status) {
|
|
115
|
+
lines.push(`- status: ${rootNode.status}`);
|
|
116
|
+
}
|
|
117
|
+
if (rootNode.priority !== undefined) {
|
|
118
|
+
lines.push(`- priority: ${rootNode.priority}`);
|
|
119
|
+
}
|
|
120
|
+
lines.push(`- path: ${rootNode.path}`);
|
|
121
|
+
if (goalCondition) {
|
|
122
|
+
lines.push(`- goal_condition: ${goalCondition}`);
|
|
123
|
+
}
|
|
124
|
+
if (activeNode) {
|
|
125
|
+
lines.push(`- active_node: ${activeNode}`);
|
|
126
|
+
}
|
|
127
|
+
if (lastActiveNode) {
|
|
128
|
+
lines.push(`- last_active_node: ${lastActiveNode}`);
|
|
129
|
+
}
|
|
130
|
+
lines.push("");
|
|
131
|
+
lines.push("## Boundaries");
|
|
132
|
+
lines.push("- mdkg is durable semantic memory and graph state, not raw execution trace storage.");
|
|
133
|
+
lines.push("- Do not include raw secrets, credentials, model prompts, provider payloads, cookies, tokens, or bulky runtime artifacts in mdkg nodes or handoffs.");
|
|
134
|
+
lines.push("- Use refs, hashes, redacted summaries, archive links, artifact links, and checkpoints for evidence.");
|
|
135
|
+
lines.push("- Treat subgraph nodes as read-only planning context unless you are operating in the owning repo.");
|
|
136
|
+
lines.push("- Run validation before closing work or handing execution to another agent.");
|
|
137
|
+
lines.push("");
|
|
138
|
+
lines.push("## Recommended Next Steps");
|
|
139
|
+
if (rootNode.type === "goal") {
|
|
140
|
+
lines.push(`- Run \`mdkg goal current --json\` and \`mdkg goal next ${rootNode.id} --json\` to confirm routing.`);
|
|
141
|
+
lines.push("- Claim one actionable local node before implementation with `mdkg goal claim <goal-id> <work-id> --json`.");
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
lines.push(`- Run \`mdkg show ${rootNode.id} --json\` and \`mdkg pack ${rootNode.id}\` to refresh local context.`);
|
|
145
|
+
lines.push("- Use `mdkg task start|update|done` for lifecycle updates when the node is task-like.");
|
|
146
|
+
}
|
|
147
|
+
lines.push("- Keep detailed implementation notes in Markdown body sections, not CLI flags.");
|
|
148
|
+
lines.push("");
|
|
149
|
+
lines.push("## Required Checks");
|
|
150
|
+
lines.push(...renderList(requiredChecks));
|
|
151
|
+
lines.push("");
|
|
152
|
+
lines.push("## Required Skills");
|
|
153
|
+
lines.push(...renderList(requiredSkills));
|
|
154
|
+
lines.push("");
|
|
155
|
+
lines.push("## Latest Checkpoint");
|
|
156
|
+
if (latestCheckpoint) {
|
|
157
|
+
lines.push(nodeLine(latestCheckpoint));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
lines.push("- none");
|
|
161
|
+
}
|
|
162
|
+
lines.push("");
|
|
163
|
+
lines.push("## Included Graph Context");
|
|
164
|
+
for (const node of pack.nodes) {
|
|
165
|
+
lines.push(nodeLine(node));
|
|
166
|
+
lines.push(...renderNodeRefs(node));
|
|
167
|
+
}
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("## Raw Content Warnings");
|
|
170
|
+
if (rawWarnings.length === 0) {
|
|
171
|
+
lines.push("- none");
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
for (const warning of rawWarnings) {
|
|
175
|
+
lines.push(`- ${warning.qid} (${warning.path}): ${warning.marker_id} - ${warning.message}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
lines.push("");
|
|
179
|
+
lines.push("## Pack Summary");
|
|
180
|
+
lines.push(`- generated_at: ${pack.meta.generated_at}`);
|
|
181
|
+
lines.push(`- node_count: ${pack.nodes.length}`);
|
|
182
|
+
lines.push(`- tokens_estimate: ${stats.totals.tokens_estimate}`);
|
|
183
|
+
lines.push(`- truncated: max_nodes=${pack.meta.truncated.max_nodes} max_bytes=${pack.meta.truncated.max_bytes}`);
|
|
184
|
+
if (pack.meta.truncated.dropped.length > 0) {
|
|
185
|
+
lines.push(`- dropped: ${pack.meta.truncated.dropped.join(", ")}`);
|
|
186
|
+
}
|
|
187
|
+
lines.push("");
|
|
188
|
+
lines.push("## Handoff Prompt");
|
|
189
|
+
lines.push("Continue from the target above. Preserve the boundaries, verify current repo state, use mdkg commands for structured lifecycle changes, and record validation evidence before closeout.");
|
|
190
|
+
lines.push("");
|
|
191
|
+
return lines.join("\n");
|
|
192
|
+
}
|
|
193
|
+
function runHandoffCreateCommand(options) {
|
|
194
|
+
if (!options.id) {
|
|
195
|
+
throw new errors_1.UsageError("mdkg handoff create requires <id-or-qid>");
|
|
196
|
+
}
|
|
197
|
+
const config = (0, config_1.loadConfig)(options.root);
|
|
198
|
+
const ws = normalizeWorkspace(options.ws);
|
|
199
|
+
if (ws && !config.workspaces[ws] && !config.subgraphs[ws]) {
|
|
200
|
+
throw new errors_1.NotFoundError(`workspace not found: ${ws}`);
|
|
201
|
+
}
|
|
202
|
+
const { index, stale, rebuilt, warnings } = (0, index_cache_1.loadIndex)({
|
|
203
|
+
root: options.root,
|
|
204
|
+
config,
|
|
205
|
+
useCache: true,
|
|
206
|
+
allowReindex: true,
|
|
207
|
+
});
|
|
208
|
+
if (stale && !rebuilt) {
|
|
209
|
+
console.error("warning: index is stale; run mdkg index to refresh");
|
|
210
|
+
}
|
|
211
|
+
for (const warning of warnings) {
|
|
212
|
+
console.error(`warning: ${warning}`);
|
|
213
|
+
}
|
|
214
|
+
const resolved = (0, qid_1.resolveQid)(index, options.id, ws);
|
|
215
|
+
if (resolved.status !== "ok") {
|
|
216
|
+
throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("id", options.id, resolved, ws));
|
|
217
|
+
}
|
|
218
|
+
const indexNode = index.nodes[resolved.qid];
|
|
219
|
+
if (!indexNode) {
|
|
220
|
+
throw new errors_1.NotFoundError(`node not found: ${resolved.qid}`);
|
|
221
|
+
}
|
|
222
|
+
const depth = options.depth ?? config.pack.default_depth;
|
|
223
|
+
if (!Number.isInteger(depth) || depth < 0) {
|
|
224
|
+
throw new errors_1.UsageError("--depth must be a non-negative integer");
|
|
225
|
+
}
|
|
226
|
+
const buildResult = (0, pack_1.buildPack)({
|
|
227
|
+
root: options.root,
|
|
228
|
+
index,
|
|
229
|
+
rootQid: resolved.qid,
|
|
230
|
+
depth,
|
|
231
|
+
edges: ["parent", "epic", "relates", "blocked_by", "blocks", "context_refs", "evidence_refs"],
|
|
232
|
+
verbose: false,
|
|
233
|
+
maxNodes: config.pack.limits.max_nodes,
|
|
234
|
+
verboseCoreListPath: path_1.default.resolve(options.root, config.pack.verbose_core_list_path),
|
|
235
|
+
wsHint: ws,
|
|
236
|
+
includeLatestCheckpoint: true,
|
|
237
|
+
});
|
|
238
|
+
for (const warning of buildResult.warnings) {
|
|
239
|
+
console.error(`warning: ${warning}`);
|
|
240
|
+
}
|
|
241
|
+
const rootNode = buildResult.pack.nodes[0];
|
|
242
|
+
if (!rootNode) {
|
|
243
|
+
throw new errors_1.NotFoundError(`node not found: ${resolved.qid}`);
|
|
244
|
+
}
|
|
245
|
+
const rawWarnings = collectRawMarkerWarnings(buildResult.pack);
|
|
246
|
+
const content = renderHandoff({
|
|
247
|
+
rootNode,
|
|
248
|
+
indexNode,
|
|
249
|
+
pack: buildResult.pack,
|
|
250
|
+
rawWarnings,
|
|
251
|
+
});
|
|
252
|
+
const contentHash = sha256(content);
|
|
253
|
+
const outPath = outputPath(options.root, options.out);
|
|
254
|
+
if (outPath) {
|
|
255
|
+
(0, atomic_1.atomicWriteFile)(outPath, content);
|
|
256
|
+
}
|
|
257
|
+
const receipt = {
|
|
258
|
+
action: "handoff-created",
|
|
259
|
+
ok: true,
|
|
260
|
+
mdkg_version: (0, version_1.readPackageVersion)(),
|
|
261
|
+
target: {
|
|
262
|
+
qid: rootNode.qid,
|
|
263
|
+
id: rootNode.id,
|
|
264
|
+
type: rootNode.type,
|
|
265
|
+
title: rootNode.title,
|
|
266
|
+
path: rootNode.path,
|
|
267
|
+
status: rootNode.status,
|
|
268
|
+
},
|
|
269
|
+
output_path: outPath ? path_1.default.relative(options.root, outPath).split(path_1.default.sep).join("/") : null,
|
|
270
|
+
content_sha256: contentHash,
|
|
271
|
+
raw_marker_warning_count: rawWarnings.length,
|
|
272
|
+
raw_marker_warnings: rawWarnings,
|
|
273
|
+
latest_checkpoint_qid: buildResult.pack.meta.latest_checkpoint_qid ?? null,
|
|
274
|
+
included_qids: buildResult.pack.nodes.map((node) => node.qid),
|
|
275
|
+
pack: {
|
|
276
|
+
node_count: buildResult.pack.nodes.length,
|
|
277
|
+
generated_at: buildResult.pack.meta.generated_at,
|
|
278
|
+
truncated: buildResult.pack.meta.truncated,
|
|
279
|
+
},
|
|
280
|
+
content,
|
|
281
|
+
};
|
|
282
|
+
if (options.json) {
|
|
283
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (outPath) {
|
|
287
|
+
console.log(`handoff written: ${outPath}`);
|
|
288
|
+
console.log(`sha256: ${contentHash}`);
|
|
289
|
+
if (rawWarnings.length > 0) {
|
|
290
|
+
console.log(`raw marker warnings: ${rawWarnings.length}`);
|
|
291
|
+
}
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
console.log(content);
|
|
295
|
+
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -464,6 +464,15 @@ function goalNextTool(root, args) {
|
|
|
464
464
|
warnings,
|
|
465
465
|
};
|
|
466
466
|
}
|
|
467
|
+
if (loaded.node.status === "done" || String(loaded.node.attributes.goal_state ?? "") === "achieved") {
|
|
468
|
+
return {
|
|
469
|
+
command: "mcp.goal_next",
|
|
470
|
+
goal_source: loaded.source,
|
|
471
|
+
goal: (0, query_output_1.toNodeSummaryJson)(loaded.node),
|
|
472
|
+
node: null,
|
|
473
|
+
warnings,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
467
476
|
const statusPreference = config.work.next.status_preference.map((status) => status.toLowerCase());
|
|
468
477
|
const statusRanks = new Set(statusPreference);
|
|
469
478
|
const scope = (0, goal_scope_1.collectGoalScope)(index, loaded.node);
|
package/dist/commands/pack.js
CHANGED
|
@@ -25,7 +25,7 @@ const headings_1 = require("../templates/headings");
|
|
|
25
25
|
const errors_1 = require("../util/errors");
|
|
26
26
|
const output_1 = require("../util/output");
|
|
27
27
|
const qid_1 = require("../util/qid");
|
|
28
|
-
const EDGE_KEYS = new Set(["parent", "epic", "relates", "blocked_by", "blocks", "prev", "next"]);
|
|
28
|
+
const EDGE_KEYS = new Set(["parent", "epic", "relates", "blocked_by", "blocks", "prev", "next", "context_refs", "evidence_refs"]);
|
|
29
29
|
const FORMAT_KEYS = new Set(["md", "json", "toon", "xml"]);
|
|
30
30
|
const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
31
31
|
function normalizeWorkspace(value) {
|
|
@@ -183,6 +183,8 @@ function appendSkillsToPack(pack, skillEntries, depth, root) {
|
|
|
183
183
|
links: skill.links,
|
|
184
184
|
artifacts: [],
|
|
185
185
|
refs: [],
|
|
186
|
+
context_refs: [],
|
|
187
|
+
evidence_refs: [],
|
|
186
188
|
aliases: [skill.slug, ...skill.tags],
|
|
187
189
|
attributes: {},
|
|
188
190
|
body: depth === "full" ? loadSkillFullBody(root, skill) : renderSkillMetaBody(skill),
|
|
@@ -35,6 +35,8 @@ function toNodeSummaryJson(node) {
|
|
|
35
35
|
relates: [...node.edges.relates],
|
|
36
36
|
blocked_by: [...node.edges.blocked_by],
|
|
37
37
|
blocks: [...node.edges.blocks],
|
|
38
|
+
context_refs: [...(node.edges.context_refs ?? [])],
|
|
39
|
+
evidence_refs: [...(node.edges.evidence_refs ?? [])],
|
|
38
40
|
},
|
|
39
41
|
...(node.source ? { source: node.source } : {}),
|
|
40
42
|
};
|
package/dist/commands/show.js
CHANGED
|
@@ -103,6 +103,14 @@ function runShowCommand(options) {
|
|
|
103
103
|
if (blocksLine) {
|
|
104
104
|
lines.push(blocksLine);
|
|
105
105
|
}
|
|
106
|
+
const contextRefsLine = maybeLine("context_refs", node.edges.context_refs ?? []);
|
|
107
|
+
if (contextRefsLine) {
|
|
108
|
+
lines.push(contextRefsLine);
|
|
109
|
+
}
|
|
110
|
+
const evidenceRefsLine = maybeLine("evidence_refs", node.edges.evidence_refs ?? []);
|
|
111
|
+
if (evidenceRefsLine) {
|
|
112
|
+
lines.push(evidenceRefsLine);
|
|
113
|
+
}
|
|
106
114
|
if (!options.metaOnly && body.length > 0) {
|
|
107
115
|
lines.push("");
|
|
108
116
|
lines.push(body);
|
package/dist/commands/status.js
CHANGED
|
@@ -229,6 +229,7 @@ function collectStatus(root) {
|
|
|
229
229
|
selected_exists: selected.state === null ? null : !selectedMissing,
|
|
230
230
|
selected_achieved: selected.state === null ? null : selectedAchieved,
|
|
231
231
|
active_node: selectedNode?.attributes.active_node ?? null,
|
|
232
|
+
last_active_node: selectedNode?.attributes.last_active_node ?? null,
|
|
232
233
|
goal_state: selectedNode?.attributes.goal_state ?? null,
|
|
233
234
|
status: selectedNode?.status ?? null,
|
|
234
235
|
},
|
package/dist/commands/task.js
CHANGED
|
@@ -297,6 +297,7 @@ function runTaskDoneCommandLocked(options) {
|
|
|
297
297
|
ws: loaded.ws,
|
|
298
298
|
relates: loaded.id,
|
|
299
299
|
scope: loaded.id,
|
|
300
|
+
kind: options.checkpointKind,
|
|
300
301
|
runId: options.runId,
|
|
301
302
|
note: `checkpoint created from mdkg task done for ${loaded.id}`,
|
|
302
303
|
now,
|
|
@@ -309,6 +310,7 @@ function runTaskDoneCommandLocked(options) {
|
|
|
309
310
|
ws: loaded.ws,
|
|
310
311
|
relates: loaded.id,
|
|
311
312
|
scope: loaded.id,
|
|
313
|
+
kind: options.checkpointKind,
|
|
312
314
|
runId: options.runId,
|
|
313
315
|
note: `checkpoint created from mdkg task done for ${loaded.id}`,
|
|
314
316
|
now,
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -13,6 +13,8 @@ const paths_1 = require("../core/paths");
|
|
|
13
13
|
const version_1 = require("../core/version");
|
|
14
14
|
const project_db_1 = require("../core/project_db");
|
|
15
15
|
const errors_1 = require("../util/errors");
|
|
16
|
+
const frontmatter_1 = require("../graph/frontmatter");
|
|
17
|
+
const workspace_files_1 = require("../graph/workspace_files");
|
|
16
18
|
const init_manifest_1 = require("./init_manifest");
|
|
17
19
|
const skill_support_1 = require("./skill_support");
|
|
18
20
|
const skill_mirror_1 = require("./skill_mirror");
|
|
@@ -273,6 +275,64 @@ function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
|
273
275
|
writeFile(cfgPath, `${JSON.stringify(nextConfig.config, null, 2)}\n`);
|
|
274
276
|
}
|
|
275
277
|
}
|
|
278
|
+
function migrateClosedGoalActiveNodes(root, dryRun, summary, changes) {
|
|
279
|
+
const config = (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(JSON.parse(fs_1.default.readFileSync((0, paths_1.configPath)(root), "utf8"))).config);
|
|
280
|
+
const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(root, config);
|
|
281
|
+
let planned = 0;
|
|
282
|
+
for (const files of Object.values(filesByAlias)) {
|
|
283
|
+
for (const filePath of files) {
|
|
284
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
285
|
+
let parsed;
|
|
286
|
+
try {
|
|
287
|
+
parsed = (0, frontmatter_1.parseFrontmatter)(content, filePath);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const frontmatter = { ...parsed.frontmatter };
|
|
293
|
+
if (frontmatter.type !== "goal") {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const status = typeof frontmatter.status === "string" ? frontmatter.status : "";
|
|
297
|
+
const goalState = typeof frontmatter.goal_state === "string" ? frontmatter.goal_state : "";
|
|
298
|
+
const activeNode = typeof frontmatter.active_node === "string" ? frontmatter.active_node : undefined;
|
|
299
|
+
if (!activeNode || (status !== "done" && goalState !== "achieved")) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const relativePath = path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
|
|
303
|
+
const lastActiveNode = typeof frontmatter.last_active_node === "string" ? frontmatter.last_active_node : undefined;
|
|
304
|
+
if (lastActiveNode && lastActiveNode !== activeNode) {
|
|
305
|
+
planned += 1;
|
|
306
|
+
record(summary, changes, {
|
|
307
|
+
path: relativePath,
|
|
308
|
+
category: "goal_lifecycle",
|
|
309
|
+
action: "conflict",
|
|
310
|
+
reason: `closed goal has active_node ${activeNode} but different last_active_node ${lastActiveNode}; local content preserved`,
|
|
311
|
+
});
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
planned += 1;
|
|
315
|
+
record(summary, changes, {
|
|
316
|
+
path: relativePath,
|
|
317
|
+
category: "goal_lifecycle",
|
|
318
|
+
action: "migrate",
|
|
319
|
+
reason: "move closed goal active_node to last_active_node",
|
|
320
|
+
});
|
|
321
|
+
if (!dryRun) {
|
|
322
|
+
if (!lastActiveNode) {
|
|
323
|
+
frontmatter.last_active_node = activeNode;
|
|
324
|
+
}
|
|
325
|
+
delete frontmatter.active_node;
|
|
326
|
+
const frontmatterBlock = ["---", ...(0, frontmatter_1.formatFrontmatter)(frontmatter, frontmatter_1.DEFAULT_FRONTMATTER_KEY_ORDER), "---"].join("\n");
|
|
327
|
+
const body = parsed.body.length > 0 ? parsed.body : "";
|
|
328
|
+
writeFile(filePath, body.length > 0 ? `${frontmatterBlock}\n${body}` : frontmatterBlock);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (planned === 0) {
|
|
333
|
+
summary.unchanged += 1;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
276
336
|
function isIgnoredBySimpleGitignore(root, relativePath) {
|
|
277
337
|
const ignorePath = path_1.default.join(root, ".gitignore");
|
|
278
338
|
if (!fs_1.default.existsSync(ignorePath)) {
|
|
@@ -440,6 +500,7 @@ function runUpgradeCommand(options) {
|
|
|
440
500
|
const agentWorkspace = isAgentWorkspace(root);
|
|
441
501
|
const managedCurrentFiles = [];
|
|
442
502
|
migrateConfigIfNeeded(root, dryRun, summary, changes);
|
|
503
|
+
migrateClosedGoalActiveNodes(root, dryRun, summary, changes);
|
|
443
504
|
for (const file of currentManifest.files) {
|
|
444
505
|
if (!shouldIncludeFile(file, agentWorkspace)) {
|
|
445
506
|
continue;
|