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
@@ -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(`SPEC reference is ambiguous: ${id}`);
49
+ throw new errors_1.UsageError(`${surface === "manifest" ? "manifest capability" : "SPEC"} reference is ambiguous: ${id}`);
44
50
  }
45
- throw new errors_1.NotFoundError(`SPEC not found: ${id}`);
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 printSpecList(records, json) {
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
- console.log(JSON.stringify({
56
- kind: "spec",
57
- count: records.length,
58
- items: records,
59
- }, null, 2));
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(`SPEC.md capabilities: ${records.length}`);
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
- console.log(JSON.stringify({ kind: "spec", item: record }, null, 2));
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
- printSpecList(loadSpecRecords(options), options.json);
138
+ const surface = commandSurface(options);
139
+ printSpecList(loadSpecRecords(options), options.json, surface);
92
140
  }
93
141
  function runSpecShowCommand(options) {
94
- printSpec(resolveSpecRecord(loadSpecRecords(options), options.id), options.json);
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
+ }
@@ -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
- ? `source_path has dirty tracked changes: ${gitState.dirtyTrackedPaths.join(", ")}`
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(`source_path has dirty tracked changes: ${options.audit.dirty_tracked_paths?.join(", ")}`);
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} source_path has dirty tracked changes: ${dirtyTrackedPaths.join(", ")}`);
711
+ throw new errors_1.UsageError(`subgraph ${alias} ${dirtySourceGuidance(dirtyTrackedPaths)}`);
709
712
  }
710
713
  return {
711
714
  sourceRoot,
@@ -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,
@@ -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
- console.log(` ${change.action}: ${change.path} (${change.reason})`);
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((change) => change.path);
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,