@mindfoldhq/trellis 0.6.5 → 0.6.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.
Files changed (115) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.js +1 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/channel/guard.d.ts.map +1 -1
  5. package/dist/commands/channel/guard.js +7 -2
  6. package/dist/commands/channel/guard.js.map +1 -1
  7. package/dist/commands/channel/store/paths.d.ts +14 -0
  8. package/dist/commands/channel/store/paths.d.ts.map +1 -1
  9. package/dist/commands/channel/store/paths.js +26 -0
  10. package/dist/commands/channel/store/paths.js.map +1 -1
  11. package/dist/commands/channel/supervisor/stdout.d.ts +7 -5
  12. package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -1
  13. package/dist/commands/channel/supervisor/stdout.js +65 -18
  14. package/dist/commands/channel/supervisor/stdout.js.map +1 -1
  15. package/dist/commands/channel/supervisor.d.ts +13 -0
  16. package/dist/commands/channel/supervisor.d.ts.map +1 -1
  17. package/dist/commands/channel/supervisor.js +36 -16
  18. package/dist/commands/channel/supervisor.js.map +1 -1
  19. package/dist/commands/init.d.ts +1 -0
  20. package/dist/commands/init.d.ts.map +1 -1
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/uninstall.d.ts +9 -0
  23. package/dist/commands/uninstall.d.ts.map +1 -1
  24. package/dist/commands/uninstall.js +74 -4
  25. package/dist/commands/uninstall.js.map +1 -1
  26. package/dist/commands/update.d.ts +29 -1
  27. package/dist/commands/update.d.ts.map +1 -1
  28. package/dist/commands/update.js +128 -58
  29. package/dist/commands/update.js.map +1 -1
  30. package/dist/configurators/copilot.d.ts +1 -0
  31. package/dist/configurators/copilot.d.ts.map +1 -1
  32. package/dist/configurators/copilot.js +4 -1
  33. package/dist/configurators/copilot.js.map +1 -1
  34. package/dist/configurators/index.d.ts.map +1 -1
  35. package/dist/configurators/index.js +7 -1
  36. package/dist/configurators/index.js.map +1 -1
  37. package/dist/configurators/omp.d.ts +11 -0
  38. package/dist/configurators/omp.d.ts.map +1 -0
  39. package/dist/configurators/omp.js +51 -0
  40. package/dist/configurators/omp.js.map +1 -0
  41. package/dist/configurators/shared.d.ts +7 -0
  42. package/dist/configurators/shared.d.ts.map +1 -1
  43. package/dist/configurators/shared.js +27 -0
  44. package/dist/configurators/shared.js.map +1 -1
  45. package/dist/configurators/zcode.d.ts +3 -3
  46. package/dist/configurators/zcode.js +12 -12
  47. package/dist/configurators/zcode.js.map +1 -1
  48. package/dist/migrations/manifests/0.6.6.json +17 -0
  49. package/dist/migrations/manifests/0.6.7.json +9 -0
  50. package/dist/templates/codex/hooks/session-start.py +6 -6
  51. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +1 -1
  52. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +1 -1
  53. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +2 -1
  54. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +2 -2
  55. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +1 -1
  56. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +3 -3
  57. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +19 -2
  58. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +1 -1
  59. package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +1 -1
  60. package/dist/templates/copilot/copilot-instructions.md +11 -0
  61. package/dist/templates/copilot/hooks/session-start.py +6 -6
  62. package/dist/templates/copilot/index.d.ts +6 -1
  63. package/dist/templates/copilot/index.d.ts.map +1 -1
  64. package/dist/templates/copilot/index.js +8 -1
  65. package/dist/templates/copilot/index.js.map +1 -1
  66. package/dist/templates/omp/agents/trellis-check.md +41 -0
  67. package/dist/templates/omp/agents/trellis-implement.md +45 -0
  68. package/dist/templates/omp/agents/trellis-research.md +30 -0
  69. package/dist/templates/omp/extensions/trellis/index.ts.txt +462 -0
  70. package/dist/templates/omp/index.d.ts +4 -0
  71. package/dist/templates/omp/index.d.ts.map +1 -0
  72. package/dist/templates/omp/index.js +9 -0
  73. package/dist/templates/omp/index.js.map +1 -0
  74. package/dist/templates/pi/extensions/trellis/index.ts.txt +47 -21
  75. package/dist/templates/shared-hooks/inject-workflow-state.py +5 -5
  76. package/dist/templates/shared-hooks/session-start.py +7 -7
  77. package/dist/templates/trellis/scripts/add_session.py +65 -17
  78. package/dist/templates/trellis/scripts/common/cli_adapter.py +36 -1
  79. package/dist/templates/trellis/scripts/common/config.py +29 -0
  80. package/dist/templates/trellis/scripts/common/io.py +20 -3
  81. package/dist/templates/trellis/scripts/common/session_context.py +1 -1
  82. package/dist/templates/trellis/scripts/common/task_store.py +90 -19
  83. package/dist/templates/trellis/scripts/common/task_utils.py +22 -0
  84. package/dist/templates/trellis/scripts/task.py +8 -2
  85. package/dist/templates/trellis/workflow.md +13 -13
  86. package/dist/templates/zcode/agents/trellis-research.md +133 -0
  87. package/dist/templates/zcode/index.d.ts +6 -5
  88. package/dist/templates/zcode/index.d.ts.map +1 -1
  89. package/dist/templates/zcode/index.js +6 -5
  90. package/dist/templates/zcode/index.js.map +1 -1
  91. package/dist/types/ai-tools.d.ts +3 -3
  92. package/dist/types/ai-tools.d.ts.map +1 -1
  93. package/dist/types/ai-tools.js +29 -2
  94. package/dist/types/ai-tools.js.map +1 -1
  95. package/dist/utils/atomic-write.d.ts +12 -0
  96. package/dist/utils/atomic-write.d.ts.map +1 -0
  97. package/dist/utils/atomic-write.js +30 -0
  98. package/dist/utils/atomic-write.js.map +1 -0
  99. package/dist/utils/file-writer.d.ts.map +1 -1
  100. package/dist/utils/file-writer.js +6 -5
  101. package/dist/utils/file-writer.js.map +1 -1
  102. package/dist/utils/registry-config.d.ts.map +1 -1
  103. package/dist/utils/registry-config.js +3 -2
  104. package/dist/utils/registry-config.js.map +1 -1
  105. package/dist/utils/template-fetcher.d.ts.map +1 -1
  106. package/dist/utils/template-fetcher.js +36 -4
  107. package/dist/utils/template-fetcher.js.map +1 -1
  108. package/dist/utils/template-hash.d.ts.map +1 -1
  109. package/dist/utils/template-hash.js +2 -1
  110. package/dist/utils/template-hash.js.map +1 -1
  111. package/dist/utils/uninstall-scrubbers.d.ts +1 -0
  112. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  113. package/dist/utils/uninstall-scrubbers.js +19 -0
  114. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  115. package/package.json +2 -2
@@ -16,14 +16,15 @@ import { getAllScripts, getAllAgents,
16
16
  // Configuration
17
17
  configYamlTemplate, gitignoreTemplate, workflowMdTemplate, } from "../templates/trellis/index.js";
18
18
  import { agentsMdContent } from "../templates/markdown/index.js";
19
+ import { COPILOT_INSTRUCTIONS_BLOCK_END, COPILOT_INSTRUCTIONS_BLOCK_START, COPILOT_INSTRUCTIONS_PATH, getCopilotInstructions, } from "../templates/copilot/index.js";
19
20
  import { ALL_MANAGED_DIRS, getConfiguredPlatforms, collectPlatformTemplates, isManagedPath, isManagedRootDir, } from "../configurators/index.js";
20
21
  import { replacePythonCommandLiterals } from "../configurators/shared.js";
21
22
  import { pruneOrphanManifestKeys } from "../utils/manifest-prune.js";
22
23
  import { fetchRegistrySpecTemplates, collectDirectoryFiles, removeDirectory, parseRegistrySource, probeRegistryIndex, downloadTemplateById, } from "../utils/template-fetcher.js";
23
24
  import { loadSpecRegistryConfig } from "../utils/registry-config.js";
24
25
  const CLAUDE_SETTINGS_PATH = ".claude/settings.json";
25
- const TRELLIS_BLOCK_START = "<!-- TRELLIS:START -->";
26
- const TRELLIS_BLOCK_END = "<!-- TRELLIS:END -->";
26
+ export const TRELLIS_BLOCK_START = "<!-- TRELLIS:START -->";
27
+ export const TRELLIS_BLOCK_END = "<!-- TRELLIS:END -->";
27
28
  const LEGACY_UNTRACKED_AGENTS_MD_BLOCK_HASHES = new Set([
28
29
  // v0.5.0-beta.17 and earlier wrote AGENTS.md but did not hash-track it.
29
30
  // This hash is the pristine Trellis-managed block before the Subagents
@@ -40,57 +41,63 @@ const PROTECTED_PATHS = [
40
41
  `${DIR_NAMES.WORKFLOW}/.developer`,
41
42
  `${DIR_NAMES.WORKFLOW}/.current-task`,
42
43
  ];
43
- function getTrellisManagedBlock(content) {
44
- const start = content.indexOf(TRELLIS_BLOCK_START);
44
+ function getManagedBlock(content, startMarker, endMarker) {
45
+ const start = content.indexOf(startMarker);
45
46
  if (start === -1) {
46
47
  return null;
47
48
  }
48
- const end = content.indexOf(TRELLIS_BLOCK_END, start);
49
+ const end = content.indexOf(endMarker, start);
49
50
  if (end === -1) {
50
51
  return null;
51
52
  }
52
- return content.slice(start, end + TRELLIS_BLOCK_END.length);
53
+ return content.slice(start, end + endMarker.length);
54
+ }
55
+ function getTrellisManagedBlock(content) {
56
+ return getManagedBlock(content, TRELLIS_BLOCK_START, TRELLIS_BLOCK_END);
53
57
  }
54
- function replaceTrellisManagedBlock(existingContent, templateContent) {
55
- const existingStart = existingContent.indexOf(TRELLIS_BLOCK_START);
58
+ function replaceManagedBlock(existingContent, templateContent, startMarker, endMarker) {
59
+ const existingStart = existingContent.indexOf(startMarker);
56
60
  if (existingStart === -1) {
57
61
  return null;
58
62
  }
59
- const existingEnd = existingContent.indexOf(TRELLIS_BLOCK_END, existingStart);
63
+ const existingEnd = existingContent.indexOf(endMarker, existingStart);
60
64
  if (existingEnd === -1) {
61
65
  return null;
62
66
  }
63
- const templateBlock = getTrellisManagedBlock(templateContent);
67
+ const templateBlock = getManagedBlock(templateContent, startMarker, endMarker);
64
68
  if (!templateBlock) {
65
69
  return null;
66
70
  }
67
71
  return (existingContent.slice(0, existingStart) +
68
72
  templateBlock +
69
- existingContent.slice(existingEnd + TRELLIS_BLOCK_END.length));
73
+ existingContent.slice(existingEnd + endMarker.length));
70
74
  }
71
- function buildAgentsMdTemplate(cwd) {
72
- const fullPath = path.join(cwd, FILE_NAMES.AGENTS);
73
- if (!fs.existsSync(fullPath)) {
74
- return agentsMdContent;
75
- }
76
- const existingContent = fs.readFileSync(fullPath, "utf-8");
77
- // Existing file already has TRELLIS:START/END markers — replace just the
78
- // managed block, preserving everything outside it.
79
- const replaced = replaceTrellisManagedBlock(existingContent, agentsMdContent);
75
+ function mergeManagedBlockContent(existingContent, templateContent, startMarker, endMarker) {
76
+ const replaced = replaceManagedBlock(existingContent, templateContent, startMarker, endMarker);
80
77
  if (replaced !== null) {
81
78
  return replaced;
82
79
  }
83
- // Existing file has no managed-block markers (pre-0.5.0-beta.18 project, or
84
- // user hand-wrote AGENTS.md without ever running through Trellis). Append
85
- // the template's managed block at the end so user content is preserved
86
- // instead of clobbered.
87
- const templateBlock = getTrellisManagedBlock(agentsMdContent);
80
+ const templateBlock = getManagedBlock(templateContent, startMarker, endMarker);
88
81
  if (!templateBlock) {
89
- return agentsMdContent;
82
+ return templateContent;
90
83
  }
91
84
  const trimmed = existingContent.replace(/\s+$/, "");
92
85
  return `${trimmed}\n\n${templateBlock}\n`;
93
86
  }
87
+ function buildManagedBlockTemplate(cwd, relativePath, templateContent, startMarker, endMarker) {
88
+ const fullPath = path.join(cwd, ...relativePath.split("/"));
89
+ if (!fs.existsSync(fullPath)) {
90
+ return templateContent;
91
+ }
92
+ const existingContent = fs.readFileSync(fullPath, "utf-8");
93
+ return mergeManagedBlockContent(existingContent, templateContent, startMarker, endMarker);
94
+ }
95
+ function buildAgentsMdTemplate(cwd) {
96
+ return buildManagedBlockTemplate(cwd, FILE_NAMES.AGENTS, agentsMdContent, TRELLIS_BLOCK_START, TRELLIS_BLOCK_END);
97
+ }
98
+ function buildCopilotInstructionsTemplate(cwd) {
99
+ return buildManagedBlockTemplate(cwd, COPILOT_INSTRUCTIONS_PATH, getCopilotInstructions(), COPILOT_INSTRUCTIONS_BLOCK_START, COPILOT_INSTRUCTIONS_BLOCK_END);
100
+ }
94
101
  function isKnownUntrackedTemplate(relativePath, existingContent) {
95
102
  if (relativePath !== FILE_NAMES.AGENTS) {
96
103
  return false;
@@ -101,6 +108,15 @@ function isKnownUntrackedTemplate(relativePath, existingContent) {
101
108
  }
102
109
  return LEGACY_UNTRACKED_AGENTS_MD_BLOCK_HASHES.has(computeHash(managedBlock));
103
110
  }
111
+ function isSafeUntrackedCopilotInstructionsMerge(relativePath, existingContent, newContent) {
112
+ if (relativePath !== COPILOT_INSTRUCTIONS_PATH) {
113
+ return false;
114
+ }
115
+ if (getManagedBlock(existingContent, COPILOT_INSTRUCTIONS_BLOCK_START, COPILOT_INSTRUCTIONS_BLOCK_END)) {
116
+ return false;
117
+ }
118
+ return (mergeManagedBlockContent(existingContent, getCopilotInstructions(), COPILOT_INSTRUCTIONS_BLOCK_START, COPILOT_INSTRUCTIONS_BLOCK_END) === newContent);
119
+ }
104
120
  /**
105
121
  * Check if a path is blocked by PROTECTED_PATHS
106
122
  */
@@ -557,6 +573,9 @@ bypassUpdateSkip = false) {
557
573
  for (const [filePath, content] of platformFiles) {
558
574
  files.set(filePath, content);
559
575
  }
576
+ if (platformId === "copilot") {
577
+ files.set(COPILOT_INSTRUCTIONS_PATH, buildCopilotInstructionsTemplate(cwd));
578
+ }
560
579
  }
561
580
  }
562
581
  preserveExistingClaudeStatusLine(cwd, files);
@@ -631,7 +650,9 @@ function analyzeChanges(cwd, hashes, templates) {
631
650
  const currentHash = computeHash(existingContent);
632
651
  if ((storedHash && storedHash === currentHash) ||
633
652
  (!storedHash &&
634
- isKnownUntrackedTemplate(relativePath, existingContent))) {
653
+ isKnownUntrackedTemplate(relativePath, existingContent)) ||
654
+ (!storedHash &&
655
+ isSafeUntrackedCopilotInstructionsMerge(relativePath, existingContent, newContent))) {
635
656
  // Either the tracked hash matches, or this is a known pristine template
636
657
  // from before the path was hash-tracked. Safe to auto-update.
637
658
  change.status = "changed";
@@ -648,10 +669,11 @@ function analyzeChanges(cwd, hashes, templates) {
648
669
  }
649
670
  return result;
650
671
  }
651
- function collectMissingAgentsMdHash(changes, hashes) {
672
+ function collectMissingManagedFileHashes(changes, hashes) {
652
673
  const files = new Map();
674
+ const managedFiles = new Set([FILE_NAMES.AGENTS, COPILOT_INSTRUCTIONS_PATH]);
653
675
  for (const file of changes.unchangedFiles) {
654
- if (file.relativePath === FILE_NAMES.AGENTS && !hashes[file.relativePath]) {
676
+ if (managedFiles.has(file.relativePath) && !hashes[file.relativePath]) {
655
677
  files.set(file.relativePath, file.newContent);
656
678
  }
657
679
  }
@@ -912,6 +934,13 @@ async function getLatestNpmVersion() {
912
934
  function collectAllFiles(dirPath, cwd = process.cwd()) {
913
935
  if (!fs.existsSync(dirPath))
914
936
  return [];
937
+ const rootStat = fs.statSync(dirPath);
938
+ if (rootStat.isFile()) {
939
+ return [dirPath];
940
+ }
941
+ if (!rootStat.isDirectory()) {
942
+ return [];
943
+ }
915
944
  const files = [];
916
945
  const stack = [dirPath];
917
946
  while (stack.length > 0) {
@@ -1000,7 +1029,20 @@ function isFileSafeToReplace(cwd, relativePath, templates) {
1000
1029
  /**
1001
1030
  * Classify migrations based on file state and user modifications
1002
1031
  */
1003
- function classifyMigrations(migrations, cwd, hashes, templates) {
1032
+ /**
1033
+ * Whether the manifest records any file under `dirRelativePath` — i.e. whether
1034
+ * Trellis actually created this directory. Used to gate rename-dir migrations:
1035
+ * a directory Trellis never wrote (e.g. a user's own `.windsurf/` editor
1036
+ * config that merely shares a path with a retired Trellis platform dir) must
1037
+ * not be auto-moved.
1038
+ */
1039
+ export function dirHasManifestEntries(dirRelativePath, hashes) {
1040
+ const prefix = dirRelativePath.endsWith("/")
1041
+ ? dirRelativePath
1042
+ : dirRelativePath + "/";
1043
+ return Object.keys(hashes).some((key) => key === dirRelativePath || key.startsWith(prefix));
1044
+ }
1045
+ export function classifyMigrations(migrations, cwd, hashes, templates) {
1004
1046
  const result = {
1005
1047
  auto: [],
1006
1048
  confirm: [],
@@ -1069,10 +1111,19 @@ function classifyMigrations(migrations, cwd, hashes, templates) {
1069
1111
  result.conflict.push(item);
1070
1112
  }
1071
1113
  }
1072
- else {
1073
- // Directory rename - always auto (includes user files)
1114
+ else if (dirHasManifestEntries(item.from, hashes)) {
1115
+ // Trellis created this directory (the manifest tracks files under it),
1116
+ // so the rename is ours to make.
1074
1117
  result.auto.push(item);
1075
1118
  }
1119
+ else {
1120
+ // Target absent and the source has no manifest record: this is very
1121
+ // likely a user-owned directory that merely shares a path with a
1122
+ // retired Trellis platform dir (e.g. a real `.windsurf/` editor
1123
+ // config). Skipping avoids silently moving the user's data out from
1124
+ // under their editor — even under --force, since skip never executes.
1125
+ result.skip.push(item);
1126
+ }
1076
1127
  }
1077
1128
  else if (item.type === "delete") {
1078
1129
  if (isTemplateModified(cwd, item.from, hashes)) {
@@ -1140,7 +1191,7 @@ function printMigrationSummary(classified) {
1140
1191
  console.log("");
1141
1192
  }
1142
1193
  if (classified.skip.length > 0) {
1143
- console.log(chalk.gray(" ○ Skipping (old file not found):"));
1194
+ console.log(chalk.gray(" ○ Skipping (not found, protected, or not Trellis-owned):"));
1144
1195
  for (const item of classified.skip.slice(0, 3)) {
1145
1196
  console.log(chalk.gray(` ${item.from}`));
1146
1197
  }
@@ -1430,6 +1481,40 @@ function printMigrationResult(result) {
1430
1481
  console.log(chalk.cyan(`Migration complete: ${parts.join(", ")}`));
1431
1482
  }
1432
1483
  }
1484
+ /**
1485
+ * One-time 0.2.0 migration: rename `traces-*.md` → `journal-*.md` in every
1486
+ * developer workspace directory.
1487
+ *
1488
+ * Never overwrites an existing `journal-N.md`: a newer session may already
1489
+ * have created it, and `.trellis/workspace/` is excluded from the update
1490
+ * backup (see `BACKUP_EXCLUDE_PATTERNS`), so clobbering it would be
1491
+ * unrecoverable data loss. Conflicting `traces-N.md` files are left in place
1492
+ * and reported instead.
1493
+ */
1494
+ export function renameTracesToJournal(workspaceDir) {
1495
+ const skipped = [];
1496
+ let renamed = 0;
1497
+ if (!fs.existsSync(workspaceDir))
1498
+ return { renamed, skipped };
1499
+ for (const dev of fs.readdirSync(workspaceDir)) {
1500
+ const devPath = path.join(workspaceDir, dev);
1501
+ if (!fs.statSync(devPath).isDirectory())
1502
+ continue;
1503
+ for (const file of fs.readdirSync(devPath)) {
1504
+ if (!(file.startsWith("traces-") && file.endsWith(".md")))
1505
+ continue;
1506
+ const oldPath = path.join(devPath, file);
1507
+ const newPath = path.join(devPath, file.replace("traces-", "journal-"));
1508
+ if (fs.existsSync(newPath)) {
1509
+ skipped.push(oldPath);
1510
+ continue;
1511
+ }
1512
+ fs.renameSync(oldPath, newPath);
1513
+ renamed++;
1514
+ }
1515
+ }
1516
+ return { renamed, skipped };
1517
+ }
1433
1518
  /**
1434
1519
  * Main update command
1435
1520
  */
@@ -1623,7 +1708,7 @@ export async function update(options) {
1623
1708
  }
1624
1709
  // Analyze changes (pass hashes for modification detection)
1625
1710
  const changes = analyzeChanges(cwd, hashes, templates);
1626
- const missingAgentsMdHash = collectMissingAgentsMdHash(changes, hashes);
1711
+ const missingManagedFileHashes = collectMissingManagedFileHashes(changes, hashes);
1627
1712
  // Print summary
1628
1713
  printChangeSummary(changes);
1629
1714
  // First-time hash tracking hint
@@ -1646,8 +1731,8 @@ export async function update(options) {
1646
1731
  changes.changedFiles.length === 0 &&
1647
1732
  !hasPendingMigrations &&
1648
1733
  !hasSafeDeletes) {
1649
- if (!options.dryRun && missingAgentsMdHash.size > 0) {
1650
- updateHashes(cwd, missingAgentsMdHash);
1734
+ if (!options.dryRun && missingManagedFileHashes.size > 0) {
1735
+ updateHashes(cwd, missingManagedFileHashes);
1651
1736
  }
1652
1737
  if (isSameVersion) {
1653
1738
  console.log(chalk.green("✓ Already up to date!"));
@@ -1743,27 +1828,12 @@ export async function update(options) {
1743
1828
  // and variable file numbers (traces-1.md, traces-2.md, etc.), so we can't enumerate them
1744
1829
  // in the migration manifest. This is a one-time migration for the 0.2.0 naming redesign.
1745
1830
  const workspaceDir = path.join(cwd, PATHS.WORKSPACE);
1746
- if (fs.existsSync(workspaceDir)) {
1747
- let journalRenamed = 0;
1748
- const devDirs = fs.readdirSync(workspaceDir);
1749
- for (const dev of devDirs) {
1750
- const devPath = path.join(workspaceDir, dev);
1751
- if (!fs.statSync(devPath).isDirectory())
1752
- continue;
1753
- const files = fs.readdirSync(devPath);
1754
- for (const file of files) {
1755
- if (file.startsWith("traces-") && file.endsWith(".md")) {
1756
- const oldPath = path.join(devPath, file);
1757
- const newFile = file.replace("traces-", "journal-");
1758
- const newPath = path.join(devPath, newFile);
1759
- fs.renameSync(oldPath, newPath);
1760
- journalRenamed++;
1761
- }
1762
- }
1763
- }
1764
- if (journalRenamed > 0) {
1765
- console.log(chalk.cyan(`Renamed ${journalRenamed} traces file(s) to journal`));
1766
- }
1831
+ const { renamed: journalRenamed, skipped: journalSkipped } = renameTracesToJournal(workspaceDir);
1832
+ if (journalRenamed > 0) {
1833
+ console.log(chalk.cyan(`Renamed ${journalRenamed} traces file(s) to journal`));
1834
+ }
1835
+ for (const oldPath of journalSkipped) {
1836
+ console.warn(chalk.yellow(`Kept ${path.relative(cwd, oldPath)}: its journal target already exists`));
1767
1837
  }
1768
1838
  }
1769
1839
  // Execute safe-file-delete (after backup, before template writes)
@@ -1851,7 +1921,7 @@ export async function update(options) {
1851
1921
  // Update version file
1852
1922
  updateVersionFile(cwd);
1853
1923
  // Update template hashes for new, auto-updated, and overwritten files
1854
- const filesToHash = new Map(missingAgentsMdHash);
1924
+ const filesToHash = new Map(missingManagedFileHashes);
1855
1925
  for (const file of changes.newFiles) {
1856
1926
  filesToHash.set(file.relativePath, file.newContent);
1857
1927
  }