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.
- package/CHANGELOG.md +93 -0
- package/CLI_COMMAND_MATRIX.md +132 -24
- package/README.md +80 -25
- package/dist/cli.js +193 -36
- package/dist/command-contract.json +882 -122
- package/dist/commands/bundle.js +2 -0
- package/dist/commands/capability.js +1 -0
- package/dist/commands/checkpoint.js +139 -1
- package/dist/commands/db.js +8 -0
- package/dist/commands/doctor.js +7 -7
- package/dist/commands/format.js +155 -0
- package/dist/commands/goal.js +60 -0
- package/dist/commands/graph.js +148 -0
- package/dist/commands/handoff.js +301 -0
- package/dist/commands/mcp.js +9 -0
- package/dist/commands/new.js +12 -3
- 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/spec.js +76 -17
- package/dist/commands/status.js +1 -0
- package/dist/commands/subgraph.js +7 -4
- package/dist/commands/task.js +2 -0
- package/dist/commands/upgrade.js +128 -3
- package/dist/commands/validate.js +268 -6
- package/dist/commands/work.js +176 -5
- package/dist/core/project_db_queue_contract.js +101 -0
- package/dist/graph/agent_file_types.js +59 -20
- package/dist/graph/capabilities_indexer.js +45 -3
- package/dist/graph/edges.js +15 -0
- package/dist/graph/frontmatter.js +4 -1
- package/dist/graph/indexer.js +13 -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/template_schema.js +37 -17
- package/dist/graph/validate_graph.js +16 -5
- package/dist/graph/visibility.js +6 -0
- package/dist/init/AGENT_START.md +9 -6
- package/dist/init/CLI_COMMAND_MATRIX.md +50 -16
- package/dist/init/README.md +26 -9
- package/dist/init/init-manifest.json +67 -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/manifest.md +45 -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/init/templates/specs/agent.MANIFEST.md +80 -0
- package/dist/init/templates/specs/api.MANIFEST.md +33 -0
- package/dist/init/templates/specs/base.MANIFEST.md +120 -0
- package/dist/init/templates/specs/capability.MANIFEST.md +45 -0
- package/dist/init/templates/specs/integration.MANIFEST.md +25 -0
- package/dist/init/templates/specs/model.MANIFEST.md +21 -0
- package/dist/init/templates/specs/project.MANIFEST.md +39 -0
- package/dist/init/templates/specs/runtime-agent.MANIFEST.md +49 -0
- package/dist/init/templates/specs/runtime-image.MANIFEST.md +21 -0
- package/dist/init/templates/specs/tool.MANIFEST.md +25 -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/dist/util/argparse.js +3 -0
- package/package.json +21 -3
package/dist/commands/spec.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runSpecListCommand = runSpecListCommand;
|
|
4
4
|
exports.runSpecShowCommand = runSpecShowCommand;
|
|
5
5
|
exports.runSpecValidateCommand = runSpecValidateCommand;
|
|
6
|
+
exports.runManifestListCommand = runManifestListCommand;
|
|
7
|
+
exports.runManifestShowCommand = runManifestShowCommand;
|
|
8
|
+
exports.runManifestValidateCommand = runManifestValidateCommand;
|
|
6
9
|
const capability_1 = require("./capability");
|
|
7
10
|
const validate_1 = require("./validate");
|
|
8
11
|
const errors_1 = require("../util/errors");
|
|
@@ -24,6 +27,9 @@ function loadSpecRecords(options) {
|
|
|
24
27
|
};
|
|
25
28
|
return sortSpecRecords((0, capability_1.filterCapabilityRecords)((0, capability_1.loadCapabilityRecords)(listOptions), listOptions));
|
|
26
29
|
}
|
|
30
|
+
function commandSurface(options) {
|
|
31
|
+
return options.surface ?? "spec";
|
|
32
|
+
}
|
|
27
33
|
function matchesSpecRef(record, id) {
|
|
28
34
|
const normalized = id.toLowerCase();
|
|
29
35
|
return (record.id === id ||
|
|
@@ -34,15 +40,15 @@ function matchesSpecRef(record, id) {
|
|
|
34
40
|
record.path.toLowerCase() === normalized ||
|
|
35
41
|
record.aliases.some((alias) => alias.toLowerCase() === normalized));
|
|
36
42
|
}
|
|
37
|
-
function resolveSpecRecord(records, id) {
|
|
43
|
+
function resolveSpecRecord(records, id, surface) {
|
|
38
44
|
const matches = records.filter((record) => matchesSpecRef(record, id));
|
|
39
45
|
if (matches.length === 1) {
|
|
40
46
|
return matches[0];
|
|
41
47
|
}
|
|
42
48
|
if (matches.length > 1) {
|
|
43
|
-
throw new errors_1.UsageError(
|
|
49
|
+
throw new errors_1.UsageError(`${surface === "manifest" ? "manifest capability" : "SPEC"} reference is ambiguous: ${id}`);
|
|
44
50
|
}
|
|
45
|
-
throw new errors_1.NotFoundError(
|
|
51
|
+
throw new errors_1.NotFoundError(`${surface === "manifest" ? "manifest capability" : "SPEC"} not found: ${id}`);
|
|
46
52
|
}
|
|
47
53
|
function stringValue(value) {
|
|
48
54
|
return typeof value === "string" ? value : undefined;
|
|
@@ -50,33 +56,74 @@ function stringValue(value) {
|
|
|
50
56
|
function stringArrayValue(value) {
|
|
51
57
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
52
58
|
}
|
|
53
|
-
function
|
|
59
|
+
function compatibilityLabel(record) {
|
|
60
|
+
const mode = record.manifest?.compatibility_mode;
|
|
61
|
+
if (mode === "legacy") {
|
|
62
|
+
return "legacy SPEC.md";
|
|
63
|
+
}
|
|
64
|
+
if (mode === "transitional") {
|
|
65
|
+
return "transitional MANIFEST.md type: spec";
|
|
66
|
+
}
|
|
67
|
+
return "MANIFEST.md";
|
|
68
|
+
}
|
|
69
|
+
function legacySpecDeprecation() {
|
|
70
|
+
return "mdkg spec is a legacy alias for mdkg manifest during the one-compatibility-release bridge.";
|
|
71
|
+
}
|
|
72
|
+
function printSpecList(records, json, surface = "spec") {
|
|
54
73
|
if (json) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
const receipt = surface === "manifest"
|
|
75
|
+
? {
|
|
76
|
+
kind: "manifest",
|
|
77
|
+
compatibility_kind: "spec",
|
|
78
|
+
count: records.length,
|
|
79
|
+
items: records,
|
|
80
|
+
}
|
|
81
|
+
: {
|
|
82
|
+
kind: "spec",
|
|
83
|
+
canonical_kind: "manifest",
|
|
84
|
+
legacy_alias: true,
|
|
85
|
+
deprecation: legacySpecDeprecation(),
|
|
86
|
+
count: records.length,
|
|
87
|
+
items: records,
|
|
88
|
+
};
|
|
89
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
60
90
|
return;
|
|
61
91
|
}
|
|
92
|
+
if (surface === "spec") {
|
|
93
|
+
console.log(legacySpecDeprecation());
|
|
94
|
+
}
|
|
62
95
|
if (records.length === 0) {
|
|
63
|
-
console.log("no SPEC.md capabilities found");
|
|
96
|
+
console.log("no MANIFEST.md/SPEC.md capabilities found");
|
|
64
97
|
return;
|
|
65
98
|
}
|
|
66
|
-
console.log(
|
|
99
|
+
console.log(`${surface === "manifest" ? "MANIFEST.md" : "MANIFEST.md/SPEC.md"} capabilities: ${records.length}`);
|
|
67
100
|
for (const record of records) {
|
|
68
101
|
const kind = stringValue(record.spec?.spec_kind);
|
|
69
102
|
const kindLabel = kind ? ` | ${kind}` : "";
|
|
70
|
-
console.log(`${record.qid} | ${record.visibility}${kindLabel} | ${record.title}`);
|
|
103
|
+
console.log(`${record.qid} | ${record.visibility}${kindLabel} | ${compatibilityLabel(record)} | ${record.title}`);
|
|
71
104
|
}
|
|
72
105
|
}
|
|
73
|
-
function printSpec(record, json) {
|
|
106
|
+
function printSpec(record, json, surface = "spec") {
|
|
74
107
|
if (json) {
|
|
75
|
-
|
|
108
|
+
const receipt = surface === "manifest"
|
|
109
|
+
? { kind: "manifest", compatibility_kind: "spec", item: record }
|
|
110
|
+
: {
|
|
111
|
+
kind: "spec",
|
|
112
|
+
canonical_kind: "manifest",
|
|
113
|
+
legacy_alias: true,
|
|
114
|
+
deprecation: legacySpecDeprecation(),
|
|
115
|
+
item: record,
|
|
116
|
+
};
|
|
117
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
76
118
|
return;
|
|
77
119
|
}
|
|
120
|
+
if (surface === "spec") {
|
|
121
|
+
console.log(legacySpecDeprecation());
|
|
122
|
+
}
|
|
78
123
|
console.log(`${record.qid} | ${record.visibility}`);
|
|
79
124
|
console.log(`title: ${record.title}`);
|
|
125
|
+
console.log(`semantic_kind: ${record.manifest?.semantic_kind ?? "manifest"}`);
|
|
126
|
+
console.log(`compatibility: ${compatibilityLabel(record)}`);
|
|
80
127
|
const specKind = stringValue(record.spec?.spec_kind);
|
|
81
128
|
if (specKind) {
|
|
82
129
|
console.log(`spec_kind: ${specKind}`);
|
|
@@ -88,14 +135,26 @@ function printSpec(record, json) {
|
|
|
88
135
|
}
|
|
89
136
|
}
|
|
90
137
|
function runSpecListCommand(options) {
|
|
91
|
-
|
|
138
|
+
const surface = commandSurface(options);
|
|
139
|
+
printSpecList(loadSpecRecords(options), options.json, surface);
|
|
92
140
|
}
|
|
93
141
|
function runSpecShowCommand(options) {
|
|
94
|
-
|
|
142
|
+
const surface = commandSurface(options);
|
|
143
|
+
printSpec(resolveSpecRecord(loadSpecRecords(options), options.id, surface), options.json, surface);
|
|
95
144
|
}
|
|
96
145
|
function runSpecValidateCommand(options) {
|
|
146
|
+
const surface = commandSurface(options);
|
|
97
147
|
if (options.id) {
|
|
98
|
-
resolveSpecRecord(loadSpecRecords(options), options.id);
|
|
148
|
+
resolveSpecRecord(loadSpecRecords(options), options.id, surface);
|
|
99
149
|
}
|
|
100
150
|
(0, validate_1.runValidateCommand)({ root: options.root, json: options.json });
|
|
101
151
|
}
|
|
152
|
+
function runManifestListCommand(options) {
|
|
153
|
+
runSpecListCommand({ ...options, surface: "manifest" });
|
|
154
|
+
}
|
|
155
|
+
function runManifestShowCommand(options) {
|
|
156
|
+
runSpecShowCommand({ ...options, surface: "manifest" });
|
|
157
|
+
}
|
|
158
|
+
function runManifestValidateCommand(options) {
|
|
159
|
+
runSpecValidateCommand({ ...options, surface: "manifest" });
|
|
160
|
+
}
|
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
|
},
|
|
@@ -323,6 +323,9 @@ function runSubgraphVerifyCommand(options) {
|
|
|
323
323
|
throw new errors_1.ValidationError("subgraph verify failed");
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
+
function dirtySourceGuidance(paths) {
|
|
327
|
+
return `source_path has dirty tracked changes: ${paths.join(", ")}; commit or stash the child repo first, then refresh the root-owned subgraph bundle from the clean accepted child commit`;
|
|
328
|
+
}
|
|
326
329
|
function pushAuditCheck(receipt, check) {
|
|
327
330
|
receipt.checks.push(check);
|
|
328
331
|
if (!check.ok && check.severity === "error") {
|
|
@@ -349,7 +352,7 @@ function auditOneAlias(options) {
|
|
|
349
352
|
source_repo: options.health.source_repo,
|
|
350
353
|
capability_summary: {
|
|
351
354
|
node_count: options.nodeTypes.length,
|
|
352
|
-
spec_count: options.nodeTypes.filter((type) => type === "spec").length,
|
|
355
|
+
spec_count: options.nodeTypes.filter((type) => type === "manifest" || type === "spec").length,
|
|
353
356
|
work_count: options.nodeTypes.filter((type) => type === "work").length,
|
|
354
357
|
skill_count: options.nodeTypes.filter((type) => type === "skill").length,
|
|
355
358
|
},
|
|
@@ -392,7 +395,7 @@ function auditOneAlias(options) {
|
|
|
392
395
|
ok: !gitState.dirtyTracked,
|
|
393
396
|
severity: "warning",
|
|
394
397
|
message: gitState.dirtyTracked
|
|
395
|
-
?
|
|
398
|
+
? dirtySourceGuidance(gitState.dirtyTrackedPaths)
|
|
396
399
|
: "source_path has no dirty tracked changes",
|
|
397
400
|
path: options.subgraph.source_path,
|
|
398
401
|
details: { dirty_tracked_paths: gitState.dirtyTrackedPaths },
|
|
@@ -539,7 +542,7 @@ function upgradePlanForAlias(options) {
|
|
|
539
542
|
blockers.push(sourceGitError.message);
|
|
540
543
|
}
|
|
541
544
|
if (options.audit.dirty_tracked) {
|
|
542
|
-
blockers.push(
|
|
545
|
+
blockers.push(dirtySourceGuidance(options.audit.dirty_tracked_paths ?? []));
|
|
543
546
|
}
|
|
544
547
|
const rootOwnedErrors = options.audit.checks.filter((check) => check.id === "subgraph.bundle.root_owned" && !check.ok);
|
|
545
548
|
blockers.push(...rootOwnedErrors.map((check) => check.message));
|
|
@@ -705,7 +708,7 @@ function inspectSourcePath(root, alias, subgraph, allowDirty) {
|
|
|
705
708
|
? status.stdout.split(/\r?\n/).map((line) => line.slice(3)).filter(Boolean).sort()
|
|
706
709
|
: [];
|
|
707
710
|
if (dirtyTrackedPaths.length > 0 && !allowDirty) {
|
|
708
|
-
throw new errors_1.UsageError(`subgraph ${alias}
|
|
711
|
+
throw new errors_1.UsageError(`subgraph ${alias} ${dirtySourceGuidance(dirtyTrackedPaths)}`);
|
|
709
712
|
}
|
|
710
713
|
return {
|
|
711
714
|
sourceRoot,
|
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,10 @@ 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");
|
|
18
|
+
const agent_file_types_1 = require("../graph/agent_file_types");
|
|
19
|
+
const atomic_1 = require("../util/atomic");
|
|
16
20
|
const init_manifest_1 = require("./init_manifest");
|
|
17
21
|
const skill_support_1 = require("./skill_support");
|
|
18
22
|
const skill_mirror_1 = require("./skill_mirror");
|
|
@@ -63,6 +67,13 @@ function writeFile(filePath, content) {
|
|
|
63
67
|
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
64
68
|
fs_1.default.writeFileSync(filePath, content, "utf8");
|
|
65
69
|
}
|
|
70
|
+
function repoRelativePath(root, filePath) {
|
|
71
|
+
return path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
|
|
72
|
+
}
|
|
73
|
+
function renderFrontmatterDocument(frontmatter, body) {
|
|
74
|
+
const frontmatterBlock = ["---", ...(0, frontmatter_1.formatFrontmatter)(frontmatter, frontmatter_1.DEFAULT_FRONTMATTER_KEY_ORDER), "---"].join("\n");
|
|
75
|
+
return body.length > 0 ? `${frontmatterBlock}\n${body}` : frontmatterBlock;
|
|
76
|
+
}
|
|
66
77
|
function createSummary() {
|
|
67
78
|
return {
|
|
68
79
|
created: 0,
|
|
@@ -273,6 +284,114 @@ function migrateConfigIfNeeded(root, dryRun, summary, changes) {
|
|
|
273
284
|
writeFile(cfgPath, `${JSON.stringify(nextConfig.config, null, 2)}\n`);
|
|
274
285
|
}
|
|
275
286
|
}
|
|
287
|
+
function migrateClosedGoalActiveNodes(root, dryRun, summary, changes) {
|
|
288
|
+
const config = (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(JSON.parse(fs_1.default.readFileSync((0, paths_1.configPath)(root), "utf8"))).config);
|
|
289
|
+
const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(root, config);
|
|
290
|
+
let planned = 0;
|
|
291
|
+
for (const files of Object.values(filesByAlias)) {
|
|
292
|
+
for (const filePath of files) {
|
|
293
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
294
|
+
let parsed;
|
|
295
|
+
try {
|
|
296
|
+
parsed = (0, frontmatter_1.parseFrontmatter)(content, filePath);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const frontmatter = { ...parsed.frontmatter };
|
|
302
|
+
if (frontmatter.type !== "goal") {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const status = typeof frontmatter.status === "string" ? frontmatter.status : "";
|
|
306
|
+
const goalState = typeof frontmatter.goal_state === "string" ? frontmatter.goal_state : "";
|
|
307
|
+
const activeNode = typeof frontmatter.active_node === "string" ? frontmatter.active_node : undefined;
|
|
308
|
+
if (!activeNode || (status !== "done" && goalState !== "achieved")) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const relativePath = path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
|
|
312
|
+
const lastActiveNode = typeof frontmatter.last_active_node === "string" ? frontmatter.last_active_node : undefined;
|
|
313
|
+
if (lastActiveNode && lastActiveNode !== activeNode) {
|
|
314
|
+
planned += 1;
|
|
315
|
+
record(summary, changes, {
|
|
316
|
+
path: relativePath,
|
|
317
|
+
category: "goal_lifecycle",
|
|
318
|
+
action: "conflict",
|
|
319
|
+
reason: `closed goal has active_node ${activeNode} but different last_active_node ${lastActiveNode}; local content preserved`,
|
|
320
|
+
});
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
planned += 1;
|
|
324
|
+
record(summary, changes, {
|
|
325
|
+
path: relativePath,
|
|
326
|
+
category: "goal_lifecycle",
|
|
327
|
+
action: "migrate",
|
|
328
|
+
reason: "move closed goal active_node to last_active_node",
|
|
329
|
+
});
|
|
330
|
+
if (!dryRun) {
|
|
331
|
+
if (!lastActiveNode) {
|
|
332
|
+
frontmatter.last_active_node = activeNode;
|
|
333
|
+
}
|
|
334
|
+
delete frontmatter.active_node;
|
|
335
|
+
writeFile(filePath, renderFrontmatterDocument(frontmatter, parsed.body.length > 0 ? parsed.body : ""));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (planned === 0) {
|
|
340
|
+
summary.unchanged += 1;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function migrateLegacySpecManifests(root, dryRun, summary, changes) {
|
|
344
|
+
const config = (0, config_1.validateConfigSchema)((0, migrate_1.migrateConfig)(JSON.parse(fs_1.default.readFileSync((0, paths_1.configPath)(root), "utf8"))).config);
|
|
345
|
+
const filesByAlias = (0, workspace_files_1.listWorkspaceDocFilesByAlias)(root, config);
|
|
346
|
+
let planned = 0;
|
|
347
|
+
for (const files of Object.values(filesByAlias)) {
|
|
348
|
+
for (const filePath of files) {
|
|
349
|
+
if (path_1.default.basename(filePath) !== agent_file_types_1.LEGACY_SPEC_BASENAME) {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
353
|
+
let parsed;
|
|
354
|
+
try {
|
|
355
|
+
parsed = (0, frontmatter_1.parseFrontmatter)(content, filePath);
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (parsed.frontmatter.type !== "spec") {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
planned += 1;
|
|
364
|
+
const targetPath = path_1.default.join(path_1.default.dirname(filePath), agent_file_types_1.CANONICAL_MANIFEST_BASENAME);
|
|
365
|
+
const relativePath = repoRelativePath(root, filePath);
|
|
366
|
+
const relativeTargetPath = repoRelativePath(root, targetPath);
|
|
367
|
+
if (fs_1.default.existsSync(targetPath)) {
|
|
368
|
+
record(summary, changes, {
|
|
369
|
+
path: relativePath,
|
|
370
|
+
target_path: relativeTargetPath,
|
|
371
|
+
category: "manifest_migration",
|
|
372
|
+
action: "conflict",
|
|
373
|
+
reason: "sibling MANIFEST.md already exists; legacy SPEC.md content preserved",
|
|
374
|
+
});
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
record(summary, changes, {
|
|
378
|
+
path: relativePath,
|
|
379
|
+
target_path: relativeTargetPath,
|
|
380
|
+
category: "manifest_migration",
|
|
381
|
+
action: "migrate",
|
|
382
|
+
reason: "rename legacy SPEC.md to MANIFEST.md and normalize type: spec to type: manifest",
|
|
383
|
+
});
|
|
384
|
+
if (!dryRun) {
|
|
385
|
+
const frontmatter = { ...parsed.frontmatter, type: "manifest" };
|
|
386
|
+
(0, atomic_1.atomicWriteFile)(filePath, renderFrontmatterDocument(frontmatter, parsed.body));
|
|
387
|
+
fs_1.default.renameSync(filePath, targetPath);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (planned === 0) {
|
|
392
|
+
summary.unchanged += 1;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
276
395
|
function isIgnoredBySimpleGitignore(root, relativePath) {
|
|
277
396
|
const ignorePath = path_1.default.join(root, ".gitignore");
|
|
278
397
|
if (!fs_1.default.existsSync(ignorePath)) {
|
|
@@ -362,6 +481,9 @@ function ensureArchiveIgnorePolicy(root, dryRun, summary, changes) {
|
|
|
362
481
|
function isWritableChange(change) {
|
|
363
482
|
return change.action === "create" || change.action === "update" || change.action === "migrate" || change.action === "sync";
|
|
364
483
|
}
|
|
484
|
+
function writablePathForChange(change) {
|
|
485
|
+
return change.target_path ?? change.path;
|
|
486
|
+
}
|
|
365
487
|
function buildApplySideEffects(options) {
|
|
366
488
|
const hasDirectWrites = options.changes.some(isWritableChange);
|
|
367
489
|
if (!hasDirectWrites && options.existingManifest) {
|
|
@@ -408,7 +530,8 @@ function emitHumanReceipt(receipt) {
|
|
|
408
530
|
}
|
|
409
531
|
else {
|
|
410
532
|
for (const change of receipt.changes) {
|
|
411
|
-
|
|
533
|
+
const target = change.target_path ? ` -> ${change.target_path}` : "";
|
|
534
|
+
console.log(` ${change.action}: ${change.path}${target} (${change.reason})`);
|
|
412
535
|
}
|
|
413
536
|
}
|
|
414
537
|
if (receipt.apply_side_effects.length > 0) {
|
|
@@ -440,6 +563,8 @@ function runUpgradeCommand(options) {
|
|
|
440
563
|
const agentWorkspace = isAgentWorkspace(root);
|
|
441
564
|
const managedCurrentFiles = [];
|
|
442
565
|
migrateConfigIfNeeded(root, dryRun, summary, changes);
|
|
566
|
+
migrateClosedGoalActiveNodes(root, dryRun, summary, changes);
|
|
567
|
+
migrateLegacySpecManifests(root, dryRun, summary, changes);
|
|
443
568
|
for (const file of currentManifest.files) {
|
|
444
569
|
if (!shouldIncludeFile(file, agentWorkspace)) {
|
|
445
570
|
continue;
|
|
@@ -483,8 +608,8 @@ function runUpgradeCommand(options) {
|
|
|
483
608
|
}
|
|
484
609
|
}
|
|
485
610
|
const preservedCustomizations = changes.filter((change) => change.action === "conflict");
|
|
486
|
-
const blockingConflicts =
|
|
487
|
-
const willWritePaths = changes.filter(isWritableChange).map(
|
|
611
|
+
const blockingConflicts = changes.filter((change) => change.action === "conflict" && change.category === "manifest_migration");
|
|
612
|
+
const willWritePaths = changes.filter(isWritableChange).map(writablePathForChange);
|
|
488
613
|
const receipt = {
|
|
489
614
|
action: "upgrade",
|
|
490
615
|
dry_run: dryRun,
|