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/README.md +119 -157
- package/dist/main.js +198 -44
- package/dist/main.js.map +1 -1
- package/docs/README.md +45 -33
- package/docs/assets/truthmark-workflow-mobile.svg +118 -0
- package/docs/assets/truthmark-workflow.svg +182 -0
- package/docs/readmes/README.ar.md +125 -151
- package/docs/readmes/README.de.md +127 -153
- package/docs/readmes/README.el.md +127 -153
- package/docs/readmes/README.es.md +125 -151
- package/docs/readmes/README.fr.md +125 -151
- package/docs/readmes/README.id.md +126 -152
- package/docs/readmes/README.it.md +125 -151
- package/docs/readmes/README.ja.md +126 -152
- package/docs/readmes/README.ko.md +127 -153
- package/docs/readmes/README.pl.md +125 -151
- package/docs/readmes/README.pt.md +126 -152
- package/docs/readmes/README.ru.md +124 -150
- package/docs/readmes/README.tr.md +125 -151
- package/docs/readmes/README.vi.md +126 -152
- package/docs/readmes/README.zh.md +128 -154
- package/package.json +3 -1
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
|
|
1066
|
-
|
|
1067
|
-
|
|
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
|
-
|
|
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
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
...
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
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.
|
|
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
|
|
5002
|
-
|
|
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
|
|
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
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
5313
|
+
const result = await writeRepoFile(
|
|
5188
5314
|
rootDir,
|
|
5189
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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 = [
|