truthmark 2.3.0 → 2.3.1

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/dist/main.js CHANGED
@@ -60,6 +60,7 @@ var isPathInsideRoot = (rootDir, targetPath) => {
60
60
  var isNodeErrorWithCode = (error, code) => {
61
61
  return error instanceof Error && "code" in error && error.code === code;
62
62
  };
63
+ var isExcludedPath = (targetPath, excludedRoots) => excludedRoots.some((root) => isPathInsideRoot(root, targetPath));
63
64
  var pathSegments = (absolutePath) => {
64
65
  return absolutePath.split(path.sep);
65
66
  };
@@ -107,10 +108,15 @@ var resolveRepoPath = (rootDir, relativePath) => {
107
108
  }
108
109
  return resolvedPath;
109
110
  };
110
- var isSafeExactFile = async (rootDir, relativePath, allowMissing) => {
111
+ var isSafeExactFile = async (rootDir, relativePath, allowMissing, excludedRoots = []) => {
111
112
  try {
112
113
  const absolutePath = resolveRepoPath(rootDir, relativePath);
113
114
  await assertRepoContainment(rootDir, absolutePath);
115
+ if (isExcludedPath(
116
+ await resolveThroughExistingAncestor(absolutePath),
117
+ excludedRoots
118
+ ))
119
+ return false;
114
120
  const relative = path.relative(rootDir, absolutePath);
115
121
  const segments = pathSegments(relative);
116
122
  if (segments.length === 0 || segments.every((segment) => segment.length === 0)) {
@@ -144,6 +150,43 @@ var isSafeExactFile = async (rootDir, relativePath, allowMissing) => {
144
150
  return false;
145
151
  }
146
152
  };
153
+ var resolveSafeExactFileTarget = async (rootDir, relativePath, allowMissing, allowFinalSymlink, excludedRoots = []) => {
154
+ if (await isSafeExactFile(rootDir, relativePath, allowMissing, excludedRoots)) {
155
+ const absolutePath = resolveRepoPath(rootDir, relativePath);
156
+ try {
157
+ const [resolvedRootDir, resolvedPath] = await Promise.all([
158
+ fs.realpath(rootDir),
159
+ fs.realpath(absolutePath)
160
+ ]);
161
+ return {
162
+ path: toRepoRelativePath(resolvedRootDir, resolvedPath),
163
+ aliased: false
164
+ };
165
+ } catch (error) {
166
+ if (!allowMissing || !isNodeErrorWithCode(error, "ENOENT")) return null;
167
+ return {
168
+ path: toRepoRelativePath(rootDir, absolutePath),
169
+ aliased: false
170
+ };
171
+ }
172
+ }
173
+ if (!allowFinalSymlink) return null;
174
+ try {
175
+ const absolutePath = resolveRepoPath(rootDir, relativePath);
176
+ if (!(await fs.lstat(absolutePath)).isSymbolicLink()) return null;
177
+ const resolvedPath = await fs.realpath(absolutePath);
178
+ await assertRepoContainment(rootDir, resolvedPath);
179
+ if (isExcludedPath(resolvedPath, excludedRoots)) return null;
180
+ const stat = await fs.lstat(resolvedPath);
181
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) return null;
182
+ return {
183
+ path: toRepoRelativePath(await fs.realpath(rootDir), resolvedPath),
184
+ aliased: true
185
+ };
186
+ } catch {
187
+ return null;
188
+ }
189
+ };
147
190
  var assertRepoContainment = async (rootDir, targetPath) => {
148
191
  const [resolvedRootDir, resolvedTargetPath] = await Promise.all([
149
192
  resolveThroughExistingAncestor(rootDir),
@@ -1062,9 +1105,15 @@ var getGitRepository = async (cwd) => {
1062
1105
  const worktreePath = await realpathOrResolved(
1063
1106
  (await runGit(cwd, ["rev-parse", "--show-toplevel"])).stdout.trim()
1064
1107
  );
1065
- const commonDirOutput = (await runGit(cwd, ["rev-parse", "--git-common-dir"])).stdout.trim();
1066
- const commonDir = await realpathOrResolved(path3.resolve(worktreePath, commonDirOutput));
1067
- const repositoryRoot = path3.basename(commonDir) === ".git" ? path3.dirname(commonDir) : worktreePath;
1108
+ const [gitDirOutput, gitCommonDirOutput] = await Promise.all([
1109
+ runGit(cwd, ["rev-parse", "--git-dir"]),
1110
+ runGit(cwd, ["rev-parse", "--git-common-dir"])
1111
+ ]);
1112
+ const [gitDir, gitCommonDir] = await Promise.all([
1113
+ realpathOrResolved(path3.resolve(cwd, gitDirOutput.stdout.trim())),
1114
+ realpathOrResolved(path3.resolve(cwd, gitCommonDirOutput.stdout.trim()))
1115
+ ]);
1116
+ const repositoryRoot = path3.basename(gitCommonDir) === ".git" ? path3.dirname(gitCommonDir) : worktreePath;
1068
1117
  const branchResult = await runGit(cwd, ["symbolic-ref", "--quiet", "--short", "HEAD"], false);
1069
1118
  const headResult = await runGit(cwd, ["rev-parse", "--verify", "HEAD"], false);
1070
1119
  const branchName = branchResult.exitCode === 0 ? branchResult.stdout.trim() : null;
@@ -1074,6 +1123,9 @@ var getGitRepository = async (cwd) => {
1074
1123
  return {
1075
1124
  repositoryRoot,
1076
1125
  worktreePath,
1126
+ gitEntryPath: path3.join(worktreePath, ".git"),
1127
+ gitDir,
1128
+ gitCommonDir,
1077
1129
  branchName,
1078
1130
  headSha,
1079
1131
  isDetached,
@@ -4432,6 +4484,7 @@ var renderTruthmarkCopilotPortalPrompt = (config = defaultAgentConfig()) => {
4432
4484
  // src/templates/generated-surfaces.ts
4433
4485
  var RETIRED_GENERATED_SURFACES = {
4434
4486
  exactPaths: [
4487
+ "CLAUDE.md",
4435
4488
  "GEMINI.md",
4436
4489
  ".github/prompts/truthmark-preview.prompt.md",
4437
4490
  ".cursor/rules/truthmark-structure.mdc",
@@ -4602,7 +4655,10 @@ var opencodeFiles = (config, block) => {
4602
4655
  };
4603
4656
  var claudeFiles = (config, block) => {
4604
4657
  const files = [
4605
- ...instructionBlockFiles(["CLAUDE.md"], block),
4658
+ {
4659
+ path: ".claude/rules/truthmark.md",
4660
+ content: block
4661
+ },
4606
4662
  ...renderTruthmarkSkillPackage({
4607
4663
  skillPath: ".claude/skills/truthmark-structure/SKILL.md",
4608
4664
  workflowId: "truthmark-structure",
@@ -4866,16 +4922,18 @@ var renderGeneratedSurfaceCatalog = (config) => {
4866
4922
  generated: { portal: { enabled: false } }
4867
4923
  }
4868
4924
  };
4869
- const basePaths = new Set(
4870
- renderGeneratedSurfaces(baseConfig).map(({ path: path13 }) => path13)
4871
- );
4872
- for (const surface of renderGeneratedSurfaces({
4873
- ...baseConfig,
4874
- truthmark: {
4875
- ...baseConfig.truthmark,
4876
- generated: { portal: { enabled: true } }
4877
- }
4878
- })) {
4925
+ const baseSurfaces = renderGeneratedSurfaces(baseConfig);
4926
+ const basePaths = new Set(baseSurfaces.map(({ path: path13 }) => path13));
4927
+ for (const surface of [
4928
+ ...baseSurfaces,
4929
+ ...renderGeneratedSurfaces({
4930
+ ...baseConfig,
4931
+ truthmark: {
4932
+ ...baseConfig.truthmark,
4933
+ generated: { portal: { enabled: true } }
4934
+ }
4935
+ })
4936
+ ]) {
4879
4937
  const owner = {
4880
4938
  kind: basePaths.has(surface.path) ? "platform" : "portal",
4881
4939
  platform
@@ -4884,7 +4942,10 @@ var renderGeneratedSurfaceCatalog = (config) => {
4884
4942
  const recognizedContent = surface.content.endsWith("\n") ? surface.content : `${surface.content}
4885
4943
  `;
4886
4944
  if (existing) {
4887
- existing.owners.push(owner);
4945
+ if (!existing.owners.some(
4946
+ (existingOwner) => existingOwner.kind === owner.kind && "platform" in existingOwner && existingOwner.platform === owner.platform
4947
+ ))
4948
+ existing.owners.push(owner);
4888
4949
  if (!existing.recognizedContents.includes(recognizedContent)) {
4889
4950
  existing.recognizedContents.push(recognizedContent);
4890
4951
  }
@@ -4902,6 +4963,7 @@ var renderGeneratedSurfaceCatalog = (config) => {
4902
4963
  catalog.set(retiredPath, {
4903
4964
  path: retiredPath,
4904
4965
  content: "",
4966
+ ...retiredPath === "CLAUDE.md" ? { managedBlock: true } : {},
4905
4967
  owners: [
4906
4968
  {
4907
4969
  kind: "retired",
@@ -4919,6 +4981,8 @@ var renderGeneratedSurfaceCatalog = (config) => {
4919
4981
  // src/init/lifecycle.ts
4920
4982
  import fs5 from "fs/promises";
4921
4983
  var plannedContents = /* @__PURE__ */ new WeakMap();
4984
+ var plannedTargets = /* @__PURE__ */ new WeakMap();
4985
+ var plannedExcludedRoots = /* @__PURE__ */ new WeakMap();
4922
4986
  var readFile = async (rootDir, filePath) => {
4923
4987
  try {
4924
4988
  return await fs5.readFile(resolveRepoPath(rootDir, filePath), "utf8");
@@ -4993,23 +5057,38 @@ var findRetiredSurfaces = async (rootDir) => {
4993
5057
  }
4994
5058
  return [...paths];
4995
5059
  };
4996
- var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGeneratedSurfaces(config)) => {
5060
+ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGeneratedSurfaces(config), excludedRoots = []) => {
4997
5061
  const desiredPaths = new Set(desired.map(({ path: path13 }) => path13));
5062
+ const desiredTargetPaths = /* @__PURE__ */ new Set();
4998
5063
  const entries = [];
4999
5064
  const diagnostics = [];
5065
+ const desiredTargets = /* @__PURE__ */ new Map();
5066
+ const targets = /* @__PURE__ */ new Map();
5000
5067
  let applicable = true;
5001
- for (const surface of desired.filter(({ managedBlock }) => managedBlock)) {
5002
- if (!await isSafeExactFile(rootDir, surface.path, true)) {
5068
+ for (const surface of desired) {
5069
+ const target = await resolveSafeExactFileTarget(
5070
+ rootDir,
5071
+ surface.path,
5072
+ true,
5073
+ surface.managedBlock === true,
5074
+ excludedRoots
5075
+ );
5076
+ if (!target) {
5003
5077
  applicable = false;
5004
5078
  entries.push({
5005
5079
  path: surface.path,
5006
5080
  action: "manual-review",
5007
- reason: "Managed instruction destination is aliased or not a regular single-link file."
5081
+ reason: surface.managedBlock ? "Managed instruction destination does not resolve to a regular single-link file inside the worktree." : "Generated file destination is aliased or not a regular single-link file."
5008
5082
  });
5083
+ } else {
5084
+ desiredTargets.set(surface.path, target);
5085
+ desiredTargetPaths.add(target.path);
5009
5086
  }
5010
5087
  }
5011
5088
  for (const surface of desired.filter(({ managedBlock }) => managedBlock)) {
5012
- const content = await readFile(rootDir, surface.path);
5089
+ const target = desiredTargets.get(surface.path);
5090
+ if (!target) continue;
5091
+ const content = await readFile(rootDir, target.path);
5013
5092
  if (content !== null && parseManagedBlock(content).status === "malformed") {
5014
5093
  applicable = false;
5015
5094
  entries.push({
@@ -5019,6 +5098,7 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5019
5098
  });
5020
5099
  }
5021
5100
  }
5101
+ const plannedManagedRemovalTargets = /* @__PURE__ */ new Set();
5022
5102
  const catalog = renderGeneratedSurfaceCatalog(config);
5023
5103
  for (const retiredPath of await findRetiredSurfaces(rootDir)) {
5024
5104
  if (!catalog.some(({ path: catalogPath }) => catalogPath === retiredPath))
@@ -5036,9 +5116,21 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5036
5116
  }
5037
5117
  for (const surface of catalog) {
5038
5118
  if (desiredPaths.has(surface.path)) continue;
5039
- const content = await readFile(rootDir, surface.path);
5040
- if (content === null) continue;
5041
- if (!await isSafeExactFile(rootDir, surface.path, false)) {
5119
+ try {
5120
+ await fs5.lstat(resolveRepoPath(rootDir, surface.path));
5121
+ } catch (error) {
5122
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
5123
+ continue;
5124
+ throw error;
5125
+ }
5126
+ const target = await resolveSafeExactFileTarget(
5127
+ rootDir,
5128
+ surface.path,
5129
+ false,
5130
+ surface.managedBlock === true,
5131
+ excludedRoots
5132
+ );
5133
+ if (!target) {
5042
5134
  applicable = false;
5043
5135
  entries.push({
5044
5136
  path: surface.path,
@@ -5047,6 +5139,9 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5047
5139
  });
5048
5140
  continue;
5049
5141
  }
5142
+ if (desiredTargetPaths.has(target.path)) continue;
5143
+ const content = await readFile(rootDir, target.path);
5144
+ if (content === null) continue;
5050
5145
  if (surface.path === "GEMINI.md" || surface.path.startsWith(".gemini/")) {
5051
5146
  entries.push({
5052
5147
  path: surface.path,
@@ -5063,11 +5158,14 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5063
5158
  reason: "Truthmark managed-block markers are malformed."
5064
5159
  });
5065
5160
  } else if (block.status === "valid") {
5161
+ if (plannedManagedRemovalTargets.has(target.path)) continue;
5162
+ plannedManagedRemovalTargets.add(target.path);
5066
5163
  entries.push({
5067
5164
  path: surface.path,
5068
5165
  action: "remove-managed-block",
5069
5166
  reason: "No configured platform owns this managed block."
5070
5167
  });
5168
+ targets.set(surface.path, target);
5071
5169
  }
5072
5170
  } else if (surface.recognizedContents.includes(content)) {
5073
5171
  entries.push({
@@ -5075,6 +5173,7 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5075
5173
  action: "remove-file",
5076
5174
  reason: "Generated file has no active platform owner."
5077
5175
  });
5176
+ targets.set(surface.path, target);
5078
5177
  } else {
5079
5178
  entries.push({
5080
5179
  path: surface.path,
@@ -5109,22 +5208,34 @@ var buildLifecyclePlan = async (rootDir, config, mode, desired = renderGenerated
5109
5208
  const contents = /* @__PURE__ */ new Map();
5110
5209
  for (const entry of entries) {
5111
5210
  if (entry.action === "remove-file" || entry.action === "remove-managed-block") {
5112
- const content = await readFile(rootDir, entry.path);
5211
+ const target = targets.get(entry.path);
5212
+ const content = target ? await readFile(rootDir, target.path) : null;
5113
5213
  if (content !== null) contents.set(entry.path, content);
5114
5214
  }
5115
5215
  }
5116
5216
  plannedContents.set(plan, contents);
5217
+ plannedTargets.set(plan, targets);
5218
+ plannedExcludedRoots.set(plan, excludedRoots);
5117
5219
  return plan;
5118
5220
  };
5119
5221
  var applyLifecyclePlan = async (rootDir, plan) => {
5120
5222
  if (!plan.applicable || plan.mode !== "apply") return plan;
5121
5223
  const expected = plannedContents.get(plan);
5224
+ const expectedTargets = plannedTargets.get(plan);
5122
5225
  const failure = async (entry) => {
5123
5226
  if (entry.action !== "remove-file" && entry.action !== "remove-managed-block")
5124
5227
  return null;
5125
- if (!await isSafeExactFile(rootDir, entry.path, false))
5228
+ const target = await resolveSafeExactFileTarget(
5229
+ rootDir,
5230
+ entry.path,
5231
+ false,
5232
+ entry.action === "remove-managed-block",
5233
+ plannedExcludedRoots.get(plan)
5234
+ );
5235
+ const expectedTarget = expectedTargets?.get(entry.path);
5236
+ if (!target || !expectedTarget || target.path !== expectedTarget.path || target.aliased !== expectedTarget.aliased)
5126
5237
  return `Unsafe lifecycle target: ${entry.path}`;
5127
- const content = await readFile(rootDir, entry.path);
5238
+ const content = await readFile(rootDir, target.path);
5128
5239
  if (content === null || expected?.get(entry.path) !== content)
5129
5240
  return `Lifecycle target changed after planning: ${entry.path}`;
5130
5241
  if (entry.action === "remove-managed-block" && parseManagedBlock(content).status !== "valid")
@@ -5150,7 +5261,9 @@ var applyLifecyclePlan = async (rootDir, plan) => {
5150
5261
  };
5151
5262
  }
5152
5263
  for (const entry of plan.entries) {
5153
- const absolutePath = resolveRepoPath(rootDir, entry.path);
5264
+ const target = expectedTargets?.get(entry.path);
5265
+ if (!target) continue;
5266
+ const absolutePath = resolveRepoPath(rootDir, target.path);
5154
5267
  if (entry.action === "remove-file") {
5155
5268
  const stat = await fs5.lstat(absolutePath);
5156
5269
  if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1)
@@ -5167,7 +5280,8 @@ var applyLifecyclePlan = async (rootDir, plan) => {
5167
5280
  if (block.status !== "valid")
5168
5281
  throw new Error(`Managed block changed during removal: ${entry.path}`);
5169
5282
  const remaining = `${content.slice(0, block.start)}${content.slice(block.end)}`;
5170
- if (remaining.trim().length === 0) await fs5.rm(absolutePath);
5283
+ if (remaining.trim().length === 0 && !target.aliased)
5284
+ await fs5.rm(absolutePath);
5171
5285
  else await fs5.writeFile(absolutePath, remaining, "utf8");
5172
5286
  }
5173
5287
  }
@@ -5175,20 +5289,33 @@ var applyLifecyclePlan = async (rootDir, plan) => {
5175
5289
  };
5176
5290
 
5177
5291
  // src/init/init.ts
5178
- var writeManagedAgentsFile = async (rootDir, path13 = "AGENTS.md", block) => {
5292
+ var writeManagedAgentsFile = async (rootDir, path13, block, excludedRoots) => {
5293
+ const target = await resolveSafeExactFileTarget(
5294
+ rootDir,
5295
+ path13,
5296
+ true,
5297
+ true,
5298
+ excludedRoots
5299
+ );
5300
+ if (!target)
5301
+ throw new Error(`Refusing unsafe managed instruction write: ${path13}`);
5179
5302
  let existingContent = null;
5180
5303
  try {
5181
- existingContent = await fs6.readFile(resolveRepoPath(rootDir, path13), "utf8");
5304
+ existingContent = await fs6.readFile(
5305
+ resolveRepoPath(rootDir, target.path),
5306
+ "utf8"
5307
+ );
5182
5308
  } catch (error) {
5183
5309
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
5184
5310
  throw error;
5185
5311
  }
5186
5312
  }
5187
- return writeRepoFile(
5313
+ const result = await writeRepoFile(
5188
5314
  rootDir,
5189
- path13,
5315
+ target.path,
5190
5316
  upsertManagedBlock(existingContent, block)
5191
5317
  );
5318
+ return { ...result, path: path13 };
5192
5319
  };
5193
5320
  var diagnosticCategoryForPath = (filePath, config) => {
5194
5321
  if (filePath === "AGENTS.md") {
@@ -5197,7 +5324,7 @@ var diagnosticCategoryForPath = (filePath, config) => {
5197
5324
  if (filePath === ".github/prompts/truthmark-realize.prompt.md" || filePath.startsWith(".github/skills/truthmark-realize/") || filePath.startsWith(".claude/skills/truthmark-realize/") || filePath.startsWith(".opencode/skills/truthmark-realize/") || filePath.startsWith(".agents/skills/truthmark-realize/") || filePath.startsWith(".antigravity/rules/truthmark-realize") || filePath.startsWith(".cursor/rules/truthmark-realize") || filePath.startsWith(".cursor/skills/truthmark-realize/")) {
5198
5325
  return "realization";
5199
5326
  }
5200
- if (filePath === "CLAUDE.md" || filePath === ".github/copilot-instructions.md" || filePath.startsWith(".github/prompts/truthmark-") || filePath.startsWith(".github/agents/truth-") || filePath.startsWith(".github/skills/truthmark-") || filePath.startsWith(".claude/agents/truth-") || filePath.startsWith(".claude/skills/truthmark-") || filePath.startsWith(".opencode/skills/truthmark-") || filePath.startsWith(".opencode/agents/") || filePath.startsWith(".codex/agents/") || filePath.startsWith(".antigravity/rules/truthmark-") || filePath.startsWith(".cursor/rules/truthmark-") || filePath.startsWith(".cursor/skills/truthmark-")) {
5327
+ if (filePath === "CLAUDE.md" || filePath === ".claude/rules/truthmark.md" || filePath === ".github/copilot-instructions.md" || filePath.startsWith(".github/prompts/truthmark-") || filePath.startsWith(".github/agents/truth-") || filePath.startsWith(".github/skills/truthmark-") || filePath.startsWith(".claude/agents/truth-") || filePath.startsWith(".claude/skills/truthmark-") || filePath.startsWith(".opencode/skills/truthmark-") || filePath.startsWith(".opencode/agents/") || filePath.startsWith(".codex/agents/") || filePath.startsWith(".antigravity/rules/truthmark-") || filePath.startsWith(".cursor/rules/truthmark-") || filePath.startsWith(".cursor/skills/truthmark-")) {
5201
5328
  return "truth-sync";
5202
5329
  }
5203
5330
  if (filePath.startsWith(".agents/skills/truthmark-")) {
@@ -5208,9 +5335,14 @@ var diagnosticCategoryForPath = (filePath, config) => {
5208
5335
  }
5209
5336
  return "config";
5210
5337
  };
5211
- var writePlatformFile = async (rootDir, file) => {
5338
+ var writePlatformFile = async (rootDir, file, excludedRoots) => {
5212
5339
  if (file.managedBlock) {
5213
- return writeManagedAgentsFile(rootDir, file.path, file.content);
5340
+ return writeManagedAgentsFile(
5341
+ rootDir,
5342
+ file.path,
5343
+ file.content,
5344
+ excludedRoots
5345
+ );
5214
5346
  }
5215
5347
  return writeRepoFile(rootDir, file.path, file.content);
5216
5348
  };
@@ -5245,6 +5377,11 @@ var normalizeRequestedPlatforms = (values) => {
5245
5377
  var runInit = async (cwd, options = {}) => {
5246
5378
  const repository = await getGitRepository(cwd);
5247
5379
  const rootDir = repository.worktreePath;
5380
+ const excludedGeneratedRoots = [
5381
+ repository.gitEntryPath,
5382
+ repository.gitDir,
5383
+ repository.gitCommonDir
5384
+ ];
5248
5385
  const loadedConfig = await loadConfig(rootDir);
5249
5386
  const repositoryData = {
5250
5387
  repositoryRoot: repository.repositoryRoot,
@@ -5317,7 +5454,8 @@ var runInit = async (cwd, options = {}) => {
5317
5454
  rootDir,
5318
5455
  config,
5319
5456
  "apply",
5320
- platformFiles
5457
+ platformFiles,
5458
+ excludedGeneratedRoots
5321
5459
  );
5322
5460
  if (!lifecyclePlan.applicable) {
5323
5461
  return {
@@ -5329,7 +5467,9 @@ var runInit = async (cwd, options = {}) => {
5329
5467
  }
5330
5468
  results.push(...await scaffoldHierarchy(rootDir, config));
5331
5469
  for (const file of platformFiles) {
5332
- results.push(await writePlatformFile(rootDir, file));
5470
+ results.push(
5471
+ await writePlatformFile(rootDir, file, excludedGeneratedRoots)
5472
+ );
5333
5473
  }
5334
5474
  results.push(
5335
5475
  await writeRepoFile(rootDir, loadedConfig.configPath, configSource)
@@ -5453,7 +5593,8 @@ var runUninstall = async (cwd, mode) => {
5453
5593
  repository.worktreePath,
5454
5594
  loaded.config,
5455
5595
  mode,
5456
- []
5596
+ [],
5597
+ [repository.gitEntryPath, repository.gitDir, repository.gitCommonDir]
5457
5598
  );
5458
5599
  const plan = await applyLifecyclePlan(repository.worktreePath, planned);
5459
5600
  return {
@@ -6906,11 +7047,19 @@ var obsoleteGeneratedSurfaceMessage = (surfacePath) => {
6906
7047
  }
6907
7048
  return `Generated surface ${surfacePath} is obsolete; rerun truthmark init.`;
6908
7049
  };
6909
- var checkGeneratedSurfaces = async (rootDir, config) => {
7050
+ var checkGeneratedSurfaces = async (rootDir, config, excludedRoots = []) => {
6910
7051
  const diagnostics = [];
6911
7052
  const renderedSurfaces = renderGeneratedSurfaces(config);
6912
7053
  for (const surface of renderedSurfaces) {
6913
- const content = await readOptionalFile(rootDir, surface.path);
7054
+ const target = await resolveSafeExactFileTarget(
7055
+ rootDir,
7056
+ surface.path,
7057
+ true,
7058
+ surface.managedBlock === true,
7059
+ excludedRoots
7060
+ );
7061
+ if (!target) continue;
7062
+ const content = await readOptionalFile(rootDir, target.path);
6914
7063
  if (content === null) {
6915
7064
  diagnostics.push({
6916
7065
  category: "generated-surface",
@@ -6937,13 +7086,14 @@ var checkGeneratedSurfaces = async (rootDir, config) => {
6937
7086
  rootDir,
6938
7087
  config,
6939
7088
  "dry-run",
6940
- renderedSurfaces
7089
+ renderedSurfaces,
7090
+ excludedRoots
6941
7091
  );
6942
7092
  for (const entry of lifecyclePlan.entries) {
6943
7093
  diagnostics.push({
6944
7094
  category: "generated-surface",
6945
7095
  severity: entry.action === "manual-review" ? "error" : "review",
6946
- message: entry.action === "preserve" && (entry.path.includes("truthmark-preview") || entry.path.endsWith("helper-manifest.yml") || entry.path.endsWith("support/helper-policy.md") || isRetiredGeminiSurfacePath(entry.path)) ? obsoleteGeneratedSurfaceMessage(entry.path) : entry.action === "preserve" ? `Generated surface ${entry.path} is inactive but was preserved: ${entry.reason}` : `Generated surface ${entry.path} is inactive; rerun truthmark init to reconcile it.`,
7096
+ message: entry.action === "manual-review" ? `Generated surface ${entry.path} requires manual review: ${entry.reason}` : entry.action === "preserve" && (entry.path.includes("truthmark-preview") || entry.path.endsWith("helper-manifest.yml") || entry.path.endsWith("support/helper-policy.md") || isRetiredGeminiSurfacePath(entry.path)) ? obsoleteGeneratedSurfaceMessage(entry.path) : entry.action === "preserve" ? `Generated surface ${entry.path} is inactive but was preserved: ${entry.reason}` : `Generated surface ${entry.path} is inactive; rerun truthmark init to reconcile it.`,
6947
7097
  file: entry.path
6948
7098
  });
6949
7099
  }
@@ -7894,7 +8044,11 @@ var runCheck = async (cwd, options = {}) => {
7894
8044
  markdownPaths,
7895
8045
  areas.truthDocumentEntries
7896
8046
  );
7897
- const generatedSurfaces = await checkGeneratedSurfaces(rootDir, loadResult.config);
8047
+ const generatedSurfaces = await checkGeneratedSurfaces(
8048
+ rootDir,
8049
+ loadResult.config,
8050
+ [repository.gitEntryPath, repository.gitDir, repository.gitCommonDir]
8051
+ );
7898
8052
  const sourceTraceability = await validateEvidenceReferences(rootDir, areas.truthDocumentPaths);
7899
8053
  const freshness = options.base ? await checkFreshness(rootDir, loadResult.config, areas.truthDocumentPaths, options.base) : null;
7900
8054
  const diagnostics = [