mdkg 0.3.6 → 0.3.8

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.
Files changed (68) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/CLI_COMMAND_MATRIX.md +132 -24
  3. package/README.md +80 -25
  4. package/dist/cli.js +193 -36
  5. package/dist/command-contract.json +882 -122
  6. package/dist/commands/bundle.js +2 -0
  7. package/dist/commands/capability.js +1 -0
  8. package/dist/commands/checkpoint.js +139 -1
  9. package/dist/commands/db.js +8 -0
  10. package/dist/commands/doctor.js +7 -7
  11. package/dist/commands/format.js +155 -0
  12. package/dist/commands/goal.js +60 -0
  13. package/dist/commands/graph.js +148 -0
  14. package/dist/commands/handoff.js +301 -0
  15. package/dist/commands/mcp.js +9 -0
  16. package/dist/commands/new.js +12 -3
  17. package/dist/commands/pack.js +3 -1
  18. package/dist/commands/query_output.js +2 -0
  19. package/dist/commands/show.js +8 -0
  20. package/dist/commands/spec.js +76 -17
  21. package/dist/commands/status.js +1 -0
  22. package/dist/commands/subgraph.js +7 -4
  23. package/dist/commands/task.js +2 -0
  24. package/dist/commands/upgrade.js +128 -3
  25. package/dist/commands/validate.js +268 -6
  26. package/dist/commands/work.js +176 -5
  27. package/dist/core/project_db_queue_contract.js +101 -0
  28. package/dist/graph/agent_file_types.js +59 -20
  29. package/dist/graph/capabilities_indexer.js +45 -3
  30. package/dist/graph/edges.js +15 -0
  31. package/dist/graph/frontmatter.js +4 -1
  32. package/dist/graph/indexer.js +13 -0
  33. package/dist/graph/node.js +12 -1
  34. package/dist/graph/sqlite_index.js +2 -0
  35. package/dist/graph/subgraphs.js +2 -0
  36. package/dist/graph/template_schema.js +37 -17
  37. package/dist/graph/validate_graph.js +16 -5
  38. package/dist/graph/visibility.js +6 -0
  39. package/dist/init/AGENT_START.md +9 -6
  40. package/dist/init/CLI_COMMAND_MATRIX.md +50 -16
  41. package/dist/init/README.md +26 -9
  42. package/dist/init/init-manifest.json +67 -12
  43. package/dist/init/templates/default/bug.md +2 -0
  44. package/dist/init/templates/default/chk.md +3 -0
  45. package/dist/init/templates/default/epic.md +2 -0
  46. package/dist/init/templates/default/feat.md +2 -0
  47. package/dist/init/templates/default/goal.md +3 -0
  48. package/dist/init/templates/default/manifest.md +45 -0
  49. package/dist/init/templates/default/spike.md +2 -0
  50. package/dist/init/templates/default/task.md +2 -0
  51. package/dist/init/templates/default/test.md +2 -0
  52. package/dist/init/templates/specs/agent.MANIFEST.md +80 -0
  53. package/dist/init/templates/specs/api.MANIFEST.md +33 -0
  54. package/dist/init/templates/specs/base.MANIFEST.md +120 -0
  55. package/dist/init/templates/specs/capability.MANIFEST.md +45 -0
  56. package/dist/init/templates/specs/integration.MANIFEST.md +25 -0
  57. package/dist/init/templates/specs/model.MANIFEST.md +21 -0
  58. package/dist/init/templates/specs/project.MANIFEST.md +39 -0
  59. package/dist/init/templates/specs/runtime-agent.MANIFEST.md +49 -0
  60. package/dist/init/templates/specs/runtime-image.MANIFEST.md +21 -0
  61. package/dist/init/templates/specs/tool.MANIFEST.md +25 -0
  62. package/dist/pack/export_json.js +20 -8
  63. package/dist/pack/export_md.js +15 -4
  64. package/dist/pack/export_xml.js +9 -4
  65. package/dist/pack/metrics.js +12 -4
  66. package/dist/pack/pack.js +9 -1
  67. package/dist/util/argparse.js +3 -0
  68. package/package.json +21 -3
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runGraphCloneCommand = runGraphCloneCommand;
7
7
  exports.runGraphForkCommand = runGraphForkCommand;
8
8
  exports.runGraphImportTemplateCommand = runGraphImportTemplateCommand;
9
+ exports.runGraphRefsCommand = runGraphRefsCommand;
9
10
  const fs_1 = __importDefault(require("fs"));
10
11
  const path_1 = __importDefault(require("path"));
11
12
  const bundle_1 = require("./bundle");
@@ -14,6 +15,7 @@ const validate_1 = require("./validate");
14
15
  const config_1 = require("../core/config");
15
16
  const workspace_path_1 = require("../core/workspace_path");
16
17
  const indexer_1 = require("../graph/indexer");
18
+ const index_cache_1 = require("../graph/index_cache");
17
19
  const frontmatter_1 = require("../graph/frontmatter");
18
20
  const errors_1 = require("../util/errors");
19
21
  const qid_1 = require("../util/qid");
@@ -21,9 +23,116 @@ const atomic_1 = require("../util/atomic");
21
23
  const zip_1 = require("../util/zip");
22
24
  const lock_1 = require("../util/lock");
23
25
  const date_1 = require("../util/date");
26
+ const refs_1 = require("../util/refs");
24
27
  function writeJson(value) {
25
28
  console.log(JSON.stringify(value, null, 2));
26
29
  }
30
+ function toStringList(value) {
31
+ if (!Array.isArray(value)) {
32
+ return [];
33
+ }
34
+ return value.filter((item) => typeof item === "string");
35
+ }
36
+ function summarizeNode(node) {
37
+ return {
38
+ qid: node.qid,
39
+ id: node.id,
40
+ workspace: node.ws,
41
+ type: node.type,
42
+ title: node.title,
43
+ status: node.status,
44
+ path: node.path,
45
+ read_only: Boolean(node.source?.read_only ?? node.source?.imported),
46
+ source: node.source,
47
+ };
48
+ }
49
+ function summarizeRef(index, value, ws) {
50
+ if ((0, refs_1.isUriRef)(value)) {
51
+ return {
52
+ ref: value,
53
+ kind: "uri",
54
+ exists: true,
55
+ };
56
+ }
57
+ const resolved = (0, qid_1.resolveQid)(index, value, ws);
58
+ if (resolved.status !== "ok") {
59
+ return {
60
+ ref: value,
61
+ kind: "missing",
62
+ exists: false,
63
+ };
64
+ }
65
+ const node = index.nodes[resolved.qid];
66
+ if (!node) {
67
+ return {
68
+ ref: value,
69
+ kind: "missing",
70
+ exists: false,
71
+ qid: resolved.qid,
72
+ };
73
+ }
74
+ return {
75
+ ref: value,
76
+ kind: "node",
77
+ exists: true,
78
+ qid: node.qid,
79
+ node: summarizeNode(node),
80
+ };
81
+ }
82
+ function summarizeRefs(index, values, ws) {
83
+ return [...new Set(values)].sort().map((value) => summarizeRef(index, value, ws));
84
+ }
85
+ function compactOutgoing(node) {
86
+ return {
87
+ scope_refs: toStringList(node.attributes.scope_refs),
88
+ epic: node.edges.epic ? [node.edges.epic] : [],
89
+ parent: node.edges.parent ? [node.edges.parent] : [],
90
+ prev: node.edges.prev ? [node.edges.prev] : [],
91
+ next: node.edges.next ? [node.edges.next] : [],
92
+ relates: node.edges.relates,
93
+ blocked_by: node.edges.blocked_by,
94
+ blocks: node.edges.blocks,
95
+ context_refs: node.edges.context_refs ?? [],
96
+ evidence_refs: node.edges.evidence_refs ?? [],
97
+ };
98
+ }
99
+ function incomingScopeRefs(index, targetQid) {
100
+ const sources = [];
101
+ for (const node of Object.values(index.nodes)) {
102
+ for (const ref of toStringList(node.attributes.scope_refs)) {
103
+ const resolved = (0, qid_1.resolveQid)(index, ref, node.ws);
104
+ if (resolved.status === "ok" && resolved.qid === targetQid) {
105
+ sources.push(node.qid);
106
+ }
107
+ }
108
+ }
109
+ return sources.sort();
110
+ }
111
+ function buildGraphRefsReceipt(index, node, warnings) {
112
+ const outgoingRaw = compactOutgoing(node);
113
+ const incomingRaw = {
114
+ scope_refs: incomingScopeRefs(index, node.qid),
115
+ epic: index.reverse_edges.epic?.[node.qid] ?? [],
116
+ parent: index.reverse_edges.parent?.[node.qid] ?? [],
117
+ prev: index.reverse_edges.prev?.[node.qid] ?? [],
118
+ next: index.reverse_edges.next?.[node.qid] ?? [],
119
+ relates: index.reverse_edges.relates?.[node.qid] ?? [],
120
+ blocked_by: index.reverse_edges.blocked_by?.[node.qid] ?? [],
121
+ blocks: index.reverse_edges.blocks?.[node.qid] ?? [],
122
+ context_refs: index.reverse_edges.context_refs?.[node.qid] ?? [],
123
+ evidence_refs: index.reverse_edges.evidence_refs?.[node.qid] ?? [],
124
+ };
125
+ const outgoing = Object.fromEntries(Object.entries(outgoingRaw).map(([key, values]) => [key, summarizeRefs(index, values, node.ws)]));
126
+ const incoming = Object.fromEntries(Object.entries(incomingRaw).map(([key, values]) => [key, summarizeRefs(index, values, node.ws)]));
127
+ return {
128
+ action: "graph.refs",
129
+ ok: true,
130
+ target: summarizeNode(node),
131
+ outgoing,
132
+ incoming,
133
+ warnings,
134
+ };
135
+ }
27
136
  function toPosixPath(value) {
28
137
  return value.split(path_1.default.sep).join("/");
29
138
  }
@@ -702,3 +811,42 @@ function runGraphImportTemplateCommand(options) {
702
811
  console.log(`selected_goal: ${receipt.selected_goal.qid}${receipt.selected_goal.planned ? " (planned)" : ""}`);
703
812
  }
704
813
  }
814
+ function runGraphRefsCommand(options) {
815
+ const config = (0, config_1.loadConfig)(options.root);
816
+ const { index, warnings } = (0, index_cache_1.loadIndex)({ root: options.root, config });
817
+ const resolved = (0, qid_1.resolveQid)(index, options.id, options.ws);
818
+ if (resolved.status !== "ok") {
819
+ throw new errors_1.NotFoundError((0, qid_1.formatResolveError)("node", options.id, resolved, options.ws));
820
+ }
821
+ const node = index.nodes[resolved.qid];
822
+ if (!node) {
823
+ throw new errors_1.NotFoundError(`node not found: ${options.id}`);
824
+ }
825
+ const receipt = buildGraphRefsReceipt(index, node, warnings);
826
+ if (options.json) {
827
+ writeJson(receipt);
828
+ return;
829
+ }
830
+ console.log(`graph refs: ${node.qid}`);
831
+ if (node.source?.imported) {
832
+ console.log(`source: subgraph:${node.source.subgraph_alias} read-only`);
833
+ }
834
+ for (const [direction, lanes] of Object.entries({ outgoing: receipt.outgoing, incoming: receipt.incoming })) {
835
+ console.log(`${direction}:`);
836
+ for (const [lane, refs] of Object.entries(lanes)) {
837
+ if (refs.length === 0) {
838
+ continue;
839
+ }
840
+ console.log(` ${lane}:`);
841
+ for (const ref of refs) {
842
+ const target = ref.node
843
+ ? `${ref.node.qid}${ref.node.read_only ? " (read-only)" : ""}`
844
+ : ref.ref;
845
+ console.log(` - ${target}`);
846
+ }
847
+ }
848
+ }
849
+ for (const warning of warnings) {
850
+ console.error(`warning: ${warning}`);
851
+ }
852
+ }
@@ -0,0 +1,301 @@
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
+ warning_count: warnings.length + buildResult.warnings.length,
272
+ warnings: [...warnings, ...buildResult.warnings],
273
+ index_warning_count: warnings.length,
274
+ index_warnings: warnings,
275
+ pack_warning_count: buildResult.warnings.length,
276
+ pack_warnings: buildResult.warnings,
277
+ raw_marker_warning_count: rawWarnings.length,
278
+ raw_marker_warnings: rawWarnings,
279
+ latest_checkpoint_qid: buildResult.pack.meta.latest_checkpoint_qid ?? null,
280
+ included_qids: buildResult.pack.nodes.map((node) => node.qid),
281
+ pack: {
282
+ node_count: buildResult.pack.nodes.length,
283
+ generated_at: buildResult.pack.meta.generated_at,
284
+ truncated: buildResult.pack.meta.truncated,
285
+ },
286
+ content,
287
+ };
288
+ if (options.json) {
289
+ console.log(JSON.stringify(receipt, null, 2));
290
+ return;
291
+ }
292
+ if (outPath) {
293
+ console.log(`handoff written: ${outPath}`);
294
+ console.log(`sha256: ${contentHash}`);
295
+ if (rawWarnings.length > 0) {
296
+ console.log(`raw marker warnings: ${rawWarnings.length}`);
297
+ }
298
+ return;
299
+ }
300
+ console.log(content);
301
+ }
@@ -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);
@@ -27,6 +27,7 @@ const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
27
27
  const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
28
28
  const CORE_TYPES = new Set(["rule"]);
29
29
  const DESIGN_TYPES = new Set(["prd", "edd", "dec", "prop"]);
30
+ const LEGACY_NEW_SPEC_WARNING = "warning: mdkg new spec is legacy; use mdkg new manifest. This alias creates MANIFEST.md with type: manifest during the compatibility release.";
30
31
  function parseCsvList(raw) {
31
32
  if (!raw) {
32
33
  return [];
@@ -162,6 +163,9 @@ function fileNameForType(type, id, slug) {
162
163
  }
163
164
  return `${id}-${slug}.md`;
164
165
  }
166
+ function canonicalCreationType(requestedType) {
167
+ return requestedType === "spec" ? "manifest" : requestedType;
168
+ }
165
169
  function ensureExists(index, value, ws, label) {
166
170
  const resolved = (0, qid_1.resolveQid)(index, value, ws);
167
171
  if (resolved.status !== "ok") {
@@ -177,13 +181,15 @@ function runNewCommandLocked(options) {
177
181
  if (!title) {
178
182
  throw new errors_1.UsageError("title cannot be empty");
179
183
  }
180
- const type = options.type.toLowerCase();
181
- if (type === "archive") {
184
+ const requestedType = options.type.toLowerCase();
185
+ if (requestedType === "archive") {
182
186
  throw new errors_1.UsageError("use `mdkg archive add <file>` to create archive sidecars");
183
187
  }
184
- if (!node_1.ALLOWED_TYPES.has(type)) {
188
+ if (!node_1.ALLOWED_TYPES.has(requestedType)) {
185
189
  throw new errors_1.UsageError(`type must be one of ${Array.from(node_1.ALLOWED_TYPES).join(", ")}`);
186
190
  }
191
+ const type = canonicalCreationType(requestedType);
192
+ const legacySpecAlias = requestedType === "spec";
187
193
  const config = (0, config_1.loadConfig)(options.root);
188
194
  const ws = normalizeWorkspace(options.ws);
189
195
  if (!config.workspaces[ws]) {
@@ -389,6 +395,9 @@ function runNewCommandLocked(options) {
389
395
  ...(status ? { status } : {}),
390
396
  ...(priority !== undefined ? { priority } : {}),
391
397
  };
398
+ if (legacySpecAlias) {
399
+ console.error(LEGACY_NEW_SPEC_WARNING);
400
+ }
392
401
  if (options.json) {
393
402
  console.log(JSON.stringify({
394
403
  action: "created",
@@ -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
  };
@@ -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);