truthmark 2.2.0 → 2.2.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.de.md +14 -14
- package/README.es.md +14 -14
- package/README.md +14 -14
- package/README.ru.md +14 -14
- package/README.zh.md +14 -14
- package/dist/main.js +97 -564
- package/dist/main.js.map +1 -1
- package/package.json +1 -2
package/dist/main.js
CHANGED
|
@@ -618,14 +618,14 @@ var parseTruthDocumentsFromYaml = (sectionLines, areaName, options) => {
|
|
|
618
618
|
const diagnostics = [];
|
|
619
619
|
const truthDocumentEntries = [];
|
|
620
620
|
for (const rawEntry of rawEntries) {
|
|
621
|
-
const
|
|
621
|
+
const path12 = rawEntry && typeof rawEntry === "object" && "path" in rawEntry ? rawEntry.path : null;
|
|
622
622
|
const kind = rawEntry && typeof rawEntry === "object" && "kind" in rawEntry ? rawEntry.kind : null;
|
|
623
623
|
const lane = rawEntry && typeof rawEntry === "object" && "lane" in rawEntry ? rawEntry.lane : null;
|
|
624
|
-
const inferredKind = typeof
|
|
625
|
-
const inferredLane = typeof
|
|
624
|
+
const inferredKind = typeof path12 === "string" ? inferTruthDocumentKindFromPath(path12, options) : null;
|
|
625
|
+
const inferredLane = typeof path12 === "string" ? inferTruthDocumentLaneFromPath(path12, options) : null;
|
|
626
626
|
const normalizedKind = isTruthDocumentKind(kind) ? kind : inferredKind;
|
|
627
627
|
const normalizedLane = lane === "product" || lane === "engineering" ? lane : normalizedKind ? laneForTruthDocumentKind(normalizedKind) : inferredLane;
|
|
628
|
-
if (typeof
|
|
628
|
+
if (typeof path12 !== "string" || path12.trim().length === 0 || !normalizedKind || !normalizedLane) {
|
|
629
629
|
diagnostics.push(
|
|
630
630
|
createAreaDiagnostic(
|
|
631
631
|
`Area ${areaName} truth_documents entries must include non-empty path plus valid lane and kind fields.`,
|
|
@@ -635,7 +635,7 @@ var parseTruthDocumentsFromYaml = (sectionLines, areaName, options) => {
|
|
|
635
635
|
continue;
|
|
636
636
|
}
|
|
637
637
|
truthDocumentEntries.push({
|
|
638
|
-
path:
|
|
638
|
+
path: path12.trim(),
|
|
639
639
|
kind: normalizedKind,
|
|
640
640
|
kindSource: isTruthDocumentKind(kind) ? "explicit" : "inferred",
|
|
641
641
|
lane: normalizedLane,
|
|
@@ -2059,7 +2059,7 @@ var EVIDENCE_AUTHORITY_INSTRUCTIONS = [
|
|
|
2059
2059
|
"Implementation code and canonical truth docs are inspected evidence for current behavior; they do not silently override workflow write boundaries."
|
|
2060
2060
|
].join("\n");
|
|
2061
2061
|
var REPOSITORY_INTELLIGENCE_INSTRUCTIONS = [
|
|
2062
|
-
"Repository intelligence artifacts are optional derived context: RepoIndex, RouteMap, ImpactSet, and
|
|
2062
|
+
"Repository intelligence artifacts are optional derived context: RepoIndex, RouteMap, ImpactSet, and WorkflowState/action context may guide routing, write boundaries, and verification planning when available.",
|
|
2063
2063
|
"They do not override checkout evidence, canonical truth docs, route files, or workflow write boundaries.",
|
|
2064
2064
|
"If unavailable, inspect any present Truthmark config, route files, source files, truth docs, and tests directly, then report that repository-intelligence artifacts were not generated."
|
|
2065
2065
|
].join("\n");
|
|
@@ -3275,7 +3275,7 @@ ${renderTruthDocOwnershipGateSection(
|
|
|
3275
3275
|
${TRUTH_DOC_DECISION_RATIONALE_PRESERVATION_INSTRUCTIONS}
|
|
3276
3276
|
${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
|
|
3277
3277
|
${renderTruthDocRestructureGateSection(
|
|
3278
|
-
"Truth Sync may restructure
|
|
3278
|
+
"Truth Sync may restructure leased canonical truth docs when the current sync evidence shows repository truth is stale, even when the doc is outside the initially affected route focus."
|
|
3279
3279
|
)}
|
|
3280
3280
|
${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
|
|
3281
3281
|
${renderRouteFirstEvidenceGateSection(
|
|
@@ -3302,7 +3302,7 @@ Parent post-sync verification:
|
|
|
3302
3302
|
- block if functional code changed during sync
|
|
3303
3303
|
- for each write lease, validate the worker report against the actual worker diff, allowedWrites, forbiddenWrites, identity fields, filesChanged, offLeaseChanges, blockers, and required report fields before accepting it
|
|
3304
3304
|
- validate the final report against the structured Truth Sync report contract, including Claim, indented Evidence, and Result values supported, narrowed, removed, or blocked under Evidence checked
|
|
3305
|
-
- verify the updated docs correspond to
|
|
3305
|
+
- verify the updated docs correspond to reviewed checkout evidence, changed-code impact, or a recorded stale-truth correction made within the sync write lease
|
|
3306
3306
|
- verify the final report records ownership review, structure requirement, split, restructure, or blocked reason when the ownership gate fired
|
|
3307
3307
|
- blocked outcomes must preserve the working tree as-is: no rollback, no post-block cleanup edits, and manual-review reporting of any remaining files`;
|
|
3308
3308
|
};
|
|
@@ -3865,8 +3865,8 @@ var renderTruthmarkSkillPackage = ({
|
|
|
3865
3865
|
}
|
|
3866
3866
|
return files;
|
|
3867
3867
|
};
|
|
3868
|
-
var normalizeOpenCodePermissionPath = (
|
|
3869
|
-
const normalized =
|
|
3868
|
+
var normalizeOpenCodePermissionPath = (path12) => {
|
|
3869
|
+
const normalized = path12.replace(/\\/gu, "/").replace(/^\.\//u, "").replace(/\/+$/u, "");
|
|
3870
3870
|
return normalized === "" ? "." : normalized;
|
|
3871
3871
|
};
|
|
3872
3872
|
var appendOpenCodePermissionGlob = (root, glob) => {
|
|
@@ -4994,8 +4994,8 @@ var geminiFiles = (config, block) => {
|
|
|
4994
4994
|
return files;
|
|
4995
4995
|
};
|
|
4996
4996
|
var instructionBlockFiles = (paths, block) => {
|
|
4997
|
-
return paths.map((
|
|
4998
|
-
path:
|
|
4997
|
+
return paths.map((path12) => ({
|
|
4998
|
+
path: path12,
|
|
4999
4999
|
content: block,
|
|
5000
5000
|
managedBlock: true
|
|
5001
5001
|
}));
|
|
@@ -5119,16 +5119,16 @@ var upsertManagedBlock = (existingContent, block) => {
|
|
|
5119
5119
|
|
|
5120
5120
|
${block}`;
|
|
5121
5121
|
};
|
|
5122
|
-
var writeManagedAgentsFile = async (rootDir,
|
|
5122
|
+
var writeManagedAgentsFile = async (rootDir, path12 = "AGENTS.md", block) => {
|
|
5123
5123
|
let existingContent = null;
|
|
5124
5124
|
try {
|
|
5125
|
-
existingContent = await fs7.readFile(resolveRepoPath(rootDir,
|
|
5125
|
+
existingContent = await fs7.readFile(resolveRepoPath(rootDir, path12), "utf8");
|
|
5126
5126
|
} catch (error) {
|
|
5127
5127
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
5128
5128
|
throw error;
|
|
5129
5129
|
}
|
|
5130
5130
|
}
|
|
5131
|
-
return writeRepoFile(rootDir,
|
|
5131
|
+
return writeRepoFile(rootDir, path12, upsertManagedBlock(existingContent, block));
|
|
5132
5132
|
};
|
|
5133
5133
|
var diagnosticCategoryForPath = (filePath, config) => {
|
|
5134
5134
|
if (filePath === "AGENTS.md") {
|
|
@@ -5394,8 +5394,53 @@ var checkAuthority = async (rootDir, config) => {
|
|
|
5394
5394
|
// src/checks/frontmatter.ts
|
|
5395
5395
|
import fs10 from "fs/promises";
|
|
5396
5396
|
|
|
5397
|
+
// src/markdown/frontmatter.ts
|
|
5398
|
+
import { parse as parse3 } from "yaml";
|
|
5399
|
+
var openingDelimiterPattern = /^(?:\uFEFF)?---[ \t]*(?:\r?\n|$)/u;
|
|
5400
|
+
var closingDelimiterPattern = /^---[ \t]*(?:\r?\n|$)/mu;
|
|
5401
|
+
var asRecord = (value) => {
|
|
5402
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
5403
|
+
return value;
|
|
5404
|
+
}
|
|
5405
|
+
return {};
|
|
5406
|
+
};
|
|
5407
|
+
var parseFrontmatter = (source, options = {}) => {
|
|
5408
|
+
const openingMatch = openingDelimiterPattern.exec(source);
|
|
5409
|
+
if (!openingMatch) {
|
|
5410
|
+
return {
|
|
5411
|
+
data: {},
|
|
5412
|
+
content: source.replace(/^\uFEFF/u, "")
|
|
5413
|
+
};
|
|
5414
|
+
}
|
|
5415
|
+
const bodyStart = openingMatch[0].length;
|
|
5416
|
+
const bodyAndContent = source.slice(bodyStart);
|
|
5417
|
+
const closingMatch = closingDelimiterPattern.exec(bodyAndContent);
|
|
5418
|
+
if (!closingMatch || typeof closingMatch.index !== "number") {
|
|
5419
|
+
return {
|
|
5420
|
+
data: {},
|
|
5421
|
+
content: source.replace(/^\uFEFF/u, "")
|
|
5422
|
+
};
|
|
5423
|
+
}
|
|
5424
|
+
const yamlSource = bodyAndContent.slice(0, closingMatch.index);
|
|
5425
|
+
const content = bodyAndContent.slice(closingMatch.index + closingMatch[0].length);
|
|
5426
|
+
let data = {};
|
|
5427
|
+
if (yamlSource.trim().length > 0) {
|
|
5428
|
+
try {
|
|
5429
|
+
data = asRecord(parse3(yamlSource));
|
|
5430
|
+
} catch (error) {
|
|
5431
|
+
if (options.throwOnInvalid) {
|
|
5432
|
+
throw error;
|
|
5433
|
+
}
|
|
5434
|
+
data = {};
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
return {
|
|
5438
|
+
data,
|
|
5439
|
+
content
|
|
5440
|
+
};
|
|
5441
|
+
};
|
|
5442
|
+
|
|
5397
5443
|
// src/markdown/parse.ts
|
|
5398
|
-
import matter from "gray-matter";
|
|
5399
5444
|
import { unified } from "unified";
|
|
5400
5445
|
import remarkParse from "remark-parse";
|
|
5401
5446
|
import { visit } from "unist-util-visit";
|
|
@@ -5409,7 +5454,7 @@ var isInternalLink = (url) => {
|
|
|
5409
5454
|
return url.startsWith("#") || !url.includes("://") && !url.startsWith("mailto:");
|
|
5410
5455
|
};
|
|
5411
5456
|
var parseMarkdownDocument = (source) => {
|
|
5412
|
-
const parsed =
|
|
5457
|
+
const parsed = parseFrontmatter(source);
|
|
5413
5458
|
const tree = unified().use(remarkParse).parse(parsed.content);
|
|
5414
5459
|
const headings = [];
|
|
5415
5460
|
const internalLinks = [];
|
|
@@ -5452,6 +5497,7 @@ var checkFrontmatter = async (rootDir, config, markdownPaths, truthDocumentEntri
|
|
|
5452
5497
|
const source = await fs10.readFile(absolutePath, "utf8");
|
|
5453
5498
|
let document;
|
|
5454
5499
|
try {
|
|
5500
|
+
parseFrontmatter(source, { throwOnInvalid: true });
|
|
5455
5501
|
document = parseMarkdownDocument(source);
|
|
5456
5502
|
} catch (error) {
|
|
5457
5503
|
diagnostics.push({
|
|
@@ -6646,24 +6692,18 @@ var checkGeneratedSurfaces = async (rootDir, config) => {
|
|
|
6646
6692
|
};
|
|
6647
6693
|
|
|
6648
6694
|
// src/impact/build.ts
|
|
6649
|
-
import
|
|
6695
|
+
import path10 from "path";
|
|
6650
6696
|
import micromatch7 from "micromatch";
|
|
6651
6697
|
|
|
6652
|
-
// src/repo-index/build.ts
|
|
6653
|
-
import fs18 from "fs/promises";
|
|
6654
|
-
import path9 from "path";
|
|
6655
|
-
|
|
6656
6698
|
// src/repo-index/file-tree.ts
|
|
6657
6699
|
import fs16 from "fs/promises";
|
|
6658
6700
|
import path7 from "path";
|
|
6659
6701
|
import { execa as execa2 } from "execa";
|
|
6660
6702
|
import fg5 from "fast-glob";
|
|
6661
|
-
import matter3 from "gray-matter";
|
|
6662
6703
|
import micromatch6 from "micromatch";
|
|
6663
6704
|
|
|
6664
6705
|
// src/truth/source-references.ts
|
|
6665
6706
|
import path6 from "path";
|
|
6666
|
-
import matter2 from "gray-matter";
|
|
6667
6707
|
var repoRootPrefixes = [
|
|
6668
6708
|
".codex/",
|
|
6669
6709
|
".github/",
|
|
@@ -6724,7 +6764,7 @@ var parseSourceReferencesSection = (content) => {
|
|
|
6724
6764
|
return references;
|
|
6725
6765
|
};
|
|
6726
6766
|
var parseSourceReferences = (source, truthDocPath) => {
|
|
6727
|
-
const parsed =
|
|
6767
|
+
const parsed = parseFrontmatter(source);
|
|
6728
6768
|
const references = /* @__PURE__ */ new Set();
|
|
6729
6769
|
const frontmatterSourceOfTruth = Array.isArray(parsed.data.source_of_truth) ? parsed.data.source_of_truth : [];
|
|
6730
6770
|
for (const entry of frontmatterSourceOfTruth) {
|
|
@@ -6752,17 +6792,6 @@ var languageByExtension = /* @__PURE__ */ new Map([
|
|
|
6752
6792
|
[".yaml", "yaml"],
|
|
6753
6793
|
[".toml", "toml"]
|
|
6754
6794
|
]);
|
|
6755
|
-
var sourceExtensions = /* @__PURE__ */ new Set([
|
|
6756
|
-
".ts",
|
|
6757
|
-
".tsx",
|
|
6758
|
-
".js",
|
|
6759
|
-
".jsx",
|
|
6760
|
-
".mjs",
|
|
6761
|
-
".cjs"
|
|
6762
|
-
]);
|
|
6763
|
-
var isJavaScriptLikePath = (filePath) => {
|
|
6764
|
-
return sourceExtensions.has(path7.posix.extname(filePath));
|
|
6765
|
-
};
|
|
6766
6795
|
var isTestPath = (filePath) => {
|
|
6767
6796
|
return filePath.startsWith("tests/") || filePath.includes("/__tests__/") || /(?:^|[./-])(test|spec)\.[cm]?[jt]sx?$/u.test(path7.posix.basename(filePath));
|
|
6768
6797
|
};
|
|
@@ -6868,7 +6897,7 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
6868
6897
|
}
|
|
6869
6898
|
if (kind === "doc") {
|
|
6870
6899
|
const source = await fs16.readFile(path7.join(rootDir, filePath), "utf8");
|
|
6871
|
-
const parsed =
|
|
6900
|
+
const parsed = parseFrontmatter(source);
|
|
6872
6901
|
const markdown = parseMarkdownDocument(parsed.content);
|
|
6873
6902
|
const title = markdown.headings.find((heading) => heading.depth === 1)?.text ?? null;
|
|
6874
6903
|
const sourceOfTruth = parseSourceReferences(source, filePath);
|
|
@@ -6998,96 +7027,6 @@ var buildRouteMap = async (rootDir) => {
|
|
|
6998
7027
|
};
|
|
6999
7028
|
};
|
|
7000
7029
|
|
|
7001
|
-
// src/repo-index/typescript-symbols.ts
|
|
7002
|
-
import ts from "typescript";
|
|
7003
|
-
var sortStrings = (values) => [...new Set(values)].sort();
|
|
7004
|
-
var hasExportModifier = (node) => {
|
|
7005
|
-
return Boolean(
|
|
7006
|
-
ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)
|
|
7007
|
-
);
|
|
7008
|
-
};
|
|
7009
|
-
var declarationName = (node) => {
|
|
7010
|
-
if (!node.name || !ts.isIdentifier(node.name)) {
|
|
7011
|
-
return null;
|
|
7012
|
-
}
|
|
7013
|
-
return node.name.text;
|
|
7014
|
-
};
|
|
7015
|
-
var addExport = (exports, publicSymbols, path14, name, kind) => {
|
|
7016
|
-
if (!name) {
|
|
7017
|
-
return;
|
|
7018
|
-
}
|
|
7019
|
-
const entry = { path: path14, name, kind };
|
|
7020
|
-
exports.push(entry);
|
|
7021
|
-
publicSymbols.push(entry);
|
|
7022
|
-
};
|
|
7023
|
-
var analyzeTypeScriptSource = (path14, source) => {
|
|
7024
|
-
const sourceFile = ts.createSourceFile(path14, source, ts.ScriptTarget.Latest, true);
|
|
7025
|
-
const imports = [];
|
|
7026
|
-
const exports = [];
|
|
7027
|
-
const publicSymbols = [];
|
|
7028
|
-
for (const statement of sourceFile.statements) {
|
|
7029
|
-
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
7030
|
-
const imported = [];
|
|
7031
|
-
const clause = statement.importClause;
|
|
7032
|
-
if (clause?.name) {
|
|
7033
|
-
imported.push("default");
|
|
7034
|
-
}
|
|
7035
|
-
if (clause?.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
|
|
7036
|
-
imported.push("*");
|
|
7037
|
-
}
|
|
7038
|
-
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
7039
|
-
for (const element of clause.namedBindings.elements) {
|
|
7040
|
-
imported.push(element.propertyName?.text ?? element.name.text);
|
|
7041
|
-
}
|
|
7042
|
-
}
|
|
7043
|
-
imports.push({
|
|
7044
|
-
from: path14,
|
|
7045
|
-
specifier: statement.moduleSpecifier.text,
|
|
7046
|
-
imported: sortStrings(imported)
|
|
7047
|
-
});
|
|
7048
|
-
continue;
|
|
7049
|
-
}
|
|
7050
|
-
if (ts.isExportDeclaration(statement)) {
|
|
7051
|
-
if (statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
7052
|
-
for (const element of statement.exportClause.elements) {
|
|
7053
|
-
addExport(exports, publicSymbols, path14, element.name.text, "re-export");
|
|
7054
|
-
}
|
|
7055
|
-
}
|
|
7056
|
-
continue;
|
|
7057
|
-
}
|
|
7058
|
-
if (ts.isFunctionDeclaration(statement) && hasExportModifier(statement)) {
|
|
7059
|
-
addExport(exports, publicSymbols, path14, declarationName(statement), "function");
|
|
7060
|
-
continue;
|
|
7061
|
-
}
|
|
7062
|
-
if (ts.isClassDeclaration(statement) && hasExportModifier(statement)) {
|
|
7063
|
-
addExport(exports, publicSymbols, path14, declarationName(statement), "class");
|
|
7064
|
-
continue;
|
|
7065
|
-
}
|
|
7066
|
-
if (ts.isInterfaceDeclaration(statement) && hasExportModifier(statement)) {
|
|
7067
|
-
addExport(exports, publicSymbols, path14, declarationName(statement), "interface");
|
|
7068
|
-
continue;
|
|
7069
|
-
}
|
|
7070
|
-
if (ts.isTypeAliasDeclaration(statement) && hasExportModifier(statement)) {
|
|
7071
|
-
addExport(exports, publicSymbols, path14, declarationName(statement), "type");
|
|
7072
|
-
continue;
|
|
7073
|
-
}
|
|
7074
|
-
if (ts.isEnumDeclaration(statement) && hasExportModifier(statement)) {
|
|
7075
|
-
addExport(exports, publicSymbols, path14, declarationName(statement), "enum");
|
|
7076
|
-
continue;
|
|
7077
|
-
}
|
|
7078
|
-
if (ts.isVariableStatement(statement) && hasExportModifier(statement)) {
|
|
7079
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
7080
|
-
addExport(exports, publicSymbols, path14, declarationName(declaration), "const");
|
|
7081
|
-
}
|
|
7082
|
-
}
|
|
7083
|
-
}
|
|
7084
|
-
return {
|
|
7085
|
-
imports: imports.sort((left, right) => left.specifier.localeCompare(right.specifier)),
|
|
7086
|
-
exports: exports.sort((left, right) => left.name.localeCompare(right.name)),
|
|
7087
|
-
publicSymbols: publicSymbols.sort((left, right) => left.name.localeCompare(right.name))
|
|
7088
|
-
};
|
|
7089
|
-
};
|
|
7090
|
-
|
|
7091
7030
|
// src/repo-index/build.ts
|
|
7092
7031
|
var buildRepoIndex = async (cwd) => {
|
|
7093
7032
|
const repository = await getGitRepository(cwd);
|
|
@@ -7100,20 +7039,7 @@ var buildRepoIndex = async (cwd) => {
|
|
|
7100
7039
|
discoverRepoFiles(rootDir, ignore),
|
|
7101
7040
|
buildRouteMap(rootDir)
|
|
7102
7041
|
]);
|
|
7103
|
-
const imports = [];
|
|
7104
|
-
const exports = [];
|
|
7105
|
-
const publicSymbols = [];
|
|
7106
7042
|
diagnostics.push(...routeMap.diagnostics);
|
|
7107
|
-
for (const file of fileTree.files) {
|
|
7108
|
-
if (!isJavaScriptLikePath(file.path)) {
|
|
7109
|
-
continue;
|
|
7110
|
-
}
|
|
7111
|
-
const source = await fs18.readFile(path9.join(rootDir, file.path), "utf8");
|
|
7112
|
-
const analysis = analyzeTypeScriptSource(file.path, source);
|
|
7113
|
-
imports.push(...analysis.imports);
|
|
7114
|
-
exports.push(...analysis.exports);
|
|
7115
|
-
publicSymbols.push(...analysis.publicSymbols);
|
|
7116
|
-
}
|
|
7117
7043
|
return {
|
|
7118
7044
|
schemaVersion: "repo-index/v0",
|
|
7119
7045
|
repository: {
|
|
@@ -7125,11 +7051,6 @@ var buildRepoIndex = async (cwd) => {
|
|
|
7125
7051
|
files: fileTree.files,
|
|
7126
7052
|
docs: fileTree.docs,
|
|
7127
7053
|
tests: fileTree.tests,
|
|
7128
|
-
imports: imports.sort((left, right) => `${left.from}:${left.specifier}`.localeCompare(`${right.from}:${right.specifier}`)),
|
|
7129
|
-
exports: exports.sort((left, right) => `${left.path}:${left.name}`.localeCompare(`${right.path}:${right.name}`)),
|
|
7130
|
-
publicSymbols: publicSymbols.sort(
|
|
7131
|
-
(left, right) => `${left.path}:${left.name}`.localeCompare(`${right.path}:${right.name}`)
|
|
7132
|
-
),
|
|
7133
7054
|
routeMap,
|
|
7134
7055
|
diagnostics
|
|
7135
7056
|
};
|
|
@@ -7139,8 +7060,8 @@ var buildRepoIndex = async (cwd) => {
|
|
|
7139
7060
|
import { execa as execa4 } from "execa";
|
|
7140
7061
|
|
|
7141
7062
|
// src/git/changes.ts
|
|
7142
|
-
import
|
|
7143
|
-
import
|
|
7063
|
+
import fs18 from "fs/promises";
|
|
7064
|
+
import path9 from "path";
|
|
7144
7065
|
import { execa as execa3 } from "execa";
|
|
7145
7066
|
var normalizePath3 = (filePath) => {
|
|
7146
7067
|
return filePath.replaceAll("\\", "/").replace(/^\.\//u, "");
|
|
@@ -7151,7 +7072,7 @@ var listChangedPaths = async (cwd, args) => {
|
|
|
7151
7072
|
};
|
|
7152
7073
|
var pathExists4 = async (filePath) => {
|
|
7153
7074
|
try {
|
|
7154
|
-
await
|
|
7075
|
+
await fs18.access(filePath);
|
|
7155
7076
|
return true;
|
|
7156
7077
|
} catch {
|
|
7157
7078
|
return false;
|
|
@@ -7195,7 +7116,7 @@ var getUncommittedChanges = async (cwd) => {
|
|
|
7195
7116
|
const deletedPathCandidates = /* @__PURE__ */ new Set([...stagedDeletedPaths, ...unstagedDeletedPaths]);
|
|
7196
7117
|
for (const deletedPath of deletedPathCandidates) {
|
|
7197
7118
|
const change = getOrCreateChange(changesByPath, deletedPath);
|
|
7198
|
-
change.deleted = !await pathExists4(
|
|
7119
|
+
change.deleted = !await pathExists4(path9.join(rootDir, deletedPath));
|
|
7199
7120
|
}
|
|
7200
7121
|
return Array.from(changesByPath.values()).sort((left, right) => {
|
|
7201
7122
|
return left.path.localeCompare(right.path);
|
|
@@ -7279,14 +7200,6 @@ var getChangedFiles = async (cwd, base) => {
|
|
|
7279
7200
|
diagnostics
|
|
7280
7201
|
};
|
|
7281
7202
|
};
|
|
7282
|
-
var readBaseFile = async (cwd, base, filePath) => {
|
|
7283
|
-
const repository = await getGitRepository(cwd);
|
|
7284
|
-
const result = await execa4("git", ["show", `${base}:${filePath}`], {
|
|
7285
|
-
cwd: repository.worktreePath,
|
|
7286
|
-
reject: false
|
|
7287
|
-
});
|
|
7288
|
-
return (result.exitCode ?? 1) === 0 ? result.stdout : null;
|
|
7289
|
-
};
|
|
7290
7203
|
|
|
7291
7204
|
// src/impact/build.ts
|
|
7292
7205
|
var uniqueSorted2 = (values) => [...new Set(values)].sort();
|
|
@@ -7304,65 +7217,15 @@ var toImpactRoute = (route) => ({
|
|
|
7304
7217
|
truthDocs: [...route.truthDocs].sort(),
|
|
7305
7218
|
codeSurface: [...route.codeSurface].sort()
|
|
7306
7219
|
});
|
|
7307
|
-
var changedPathSet = (changedFiles) => {
|
|
7308
|
-
return new Set(
|
|
7309
|
-
changedFiles.flatMap((file) => [file.path, ...file.previousPath ? [file.previousPath] : []])
|
|
7310
|
-
);
|
|
7311
|
-
};
|
|
7312
7220
|
var changedFilePaths = (changedFile) => {
|
|
7313
7221
|
return [changedFile.path, ...changedFile.previousPath ? [changedFile.previousPath] : []];
|
|
7314
7222
|
};
|
|
7315
|
-
var resolveImportPath = (importEdge) => {
|
|
7316
|
-
if (!importEdge.specifier.startsWith(".")) {
|
|
7317
|
-
return null;
|
|
7318
|
-
}
|
|
7319
|
-
const basePath = path11.posix.normalize(path11.posix.join(path11.posix.dirname(importEdge.from), importEdge.specifier));
|
|
7320
|
-
const withoutExtension = basePath.replace(/\.[cm]?[jt]sx?$/u, "");
|
|
7321
|
-
return withoutExtension;
|
|
7322
|
-
};
|
|
7323
|
-
var importTargetsChangedFile = (importEdge, changedPath) => {
|
|
7324
|
-
const resolved = resolveImportPath(importEdge);
|
|
7325
|
-
if (!resolved) {
|
|
7326
|
-
return false;
|
|
7327
|
-
}
|
|
7328
|
-
return changedPath.replace(/\.[cm]?[jt]sx?$/u, "") === resolved;
|
|
7329
|
-
};
|
|
7330
7223
|
var pathSegments = (filePath) => filePath.split("/").filter(Boolean);
|
|
7331
7224
|
var testHintMatchesChangedFile = (hints, changedPath) => {
|
|
7332
|
-
const changedBaseName =
|
|
7225
|
+
const changedBaseName = path10.posix.basename(changedPath);
|
|
7333
7226
|
const changedSegments = pathSegments(changedPath);
|
|
7334
7227
|
return hints.some((hint) => changedBaseName.startsWith(hint) || changedSegments.includes(hint));
|
|
7335
7228
|
};
|
|
7336
|
-
var changedSymbolsFor = async (cwd, base, basePath, currentPath, currentExports) => {
|
|
7337
|
-
if (!isJavaScriptLikePath(basePath) && !isJavaScriptLikePath(currentPath)) {
|
|
7338
|
-
return [];
|
|
7339
|
-
}
|
|
7340
|
-
const baseSource = await readBaseFile(cwd, base, basePath);
|
|
7341
|
-
const baseExports = baseSource ? analyzeTypeScriptSource(basePath, baseSource).exports : [];
|
|
7342
|
-
const currentByName = new Map(currentExports.map((entry) => [entry.name, entry]));
|
|
7343
|
-
const baseByName = new Map(baseExports.map((entry) => [entry.name, entry]));
|
|
7344
|
-
const changes = [];
|
|
7345
|
-
if (basePath !== currentPath) {
|
|
7346
|
-
for (const entry of currentExports) {
|
|
7347
|
-
changes.push({ path: currentPath, name: entry.name, kind: entry.kind, change: "added" });
|
|
7348
|
-
}
|
|
7349
|
-
for (const entry of baseExports) {
|
|
7350
|
-
changes.push({ path: basePath, name: entry.name, kind: entry.kind, change: "removed" });
|
|
7351
|
-
}
|
|
7352
|
-
return changes;
|
|
7353
|
-
}
|
|
7354
|
-
for (const [name, entry] of currentByName) {
|
|
7355
|
-
if (!baseByName.has(name)) {
|
|
7356
|
-
changes.push({ path: currentPath, name, kind: entry.kind, change: "added" });
|
|
7357
|
-
}
|
|
7358
|
-
}
|
|
7359
|
-
for (const [name, entry] of baseByName) {
|
|
7360
|
-
if (!currentByName.has(name)) {
|
|
7361
|
-
changes.push({ path: basePath, name, kind: entry.kind, change: "removed" });
|
|
7362
|
-
}
|
|
7363
|
-
}
|
|
7364
|
-
return changes;
|
|
7365
|
-
};
|
|
7366
7229
|
var buildImpactSet = async (cwd, options) => {
|
|
7367
7230
|
const repository = await getGitRepository(cwd);
|
|
7368
7231
|
const rootDir = repository.worktreePath;
|
|
@@ -7377,7 +7240,6 @@ var buildImpactSet = async (cwd, options) => {
|
|
|
7377
7240
|
const affectedRoutes = /* @__PURE__ */ new Map();
|
|
7378
7241
|
const affectedTruthDocs = [];
|
|
7379
7242
|
const affectedTests = [];
|
|
7380
|
-
const changedPublicSymbols = [];
|
|
7381
7243
|
const knownTestPaths = new Set(repoIndex.tests.map((test) => test.path));
|
|
7382
7244
|
for (const changedFile of changedFiles) {
|
|
7383
7245
|
const routeCandidatePaths = changedFilePaths(changedFile);
|
|
@@ -7410,60 +7272,15 @@ var buildImpactSet = async (cwd, options) => {
|
|
|
7410
7272
|
file: changedFile.path
|
|
7411
7273
|
});
|
|
7412
7274
|
}
|
|
7413
|
-
const currentExports = repoIndex.exports.filter((entry) => entry.path === changedFile.path);
|
|
7414
|
-
changedPublicSymbols.push(
|
|
7415
|
-
...await changedSymbolsFor(
|
|
7416
|
-
rootDir,
|
|
7417
|
-
options.base,
|
|
7418
|
-
changedFile.previousPath ?? changedFile.path,
|
|
7419
|
-
changedFile.path,
|
|
7420
|
-
currentExports
|
|
7421
|
-
)
|
|
7422
|
-
);
|
|
7423
7275
|
}
|
|
7424
7276
|
const uniqueAffectedTruthDocs = uniqueSorted2(affectedTruthDocs);
|
|
7425
|
-
const changedPaths = changedPathSet(changedFiles);
|
|
7426
|
-
for (const symbol of changedPublicSymbols) {
|
|
7427
|
-
if (uniqueAffectedTruthDocs.length === 0) {
|
|
7428
|
-
diagnostics.push({
|
|
7429
|
-
category: "impact",
|
|
7430
|
-
severity: "review",
|
|
7431
|
-
message: `Changed public symbol ${symbol.name} in ${symbol.path} has no affected truth document.`,
|
|
7432
|
-
file: symbol.path,
|
|
7433
|
-
data: {
|
|
7434
|
-
symbol: symbol.name,
|
|
7435
|
-
change: symbol.change
|
|
7436
|
-
}
|
|
7437
|
-
});
|
|
7438
|
-
continue;
|
|
7439
|
-
}
|
|
7440
|
-
if (!uniqueAffectedTruthDocs.some((truthDoc) => changedPaths.has(truthDoc))) {
|
|
7441
|
-
diagnostics.push({
|
|
7442
|
-
category: "impact",
|
|
7443
|
-
severity: "review",
|
|
7444
|
-
message: `Changed public symbol ${symbol.name} in ${symbol.path} has affected truth docs but none were changed in this impact set.`,
|
|
7445
|
-
file: symbol.path,
|
|
7446
|
-
data: {
|
|
7447
|
-
symbol: symbol.name,
|
|
7448
|
-
change: symbol.change,
|
|
7449
|
-
affectedTruthDocs: uniqueAffectedTruthDocs
|
|
7450
|
-
}
|
|
7451
|
-
});
|
|
7452
|
-
}
|
|
7453
|
-
}
|
|
7454
7277
|
for (const test of repoIndex.tests) {
|
|
7455
|
-
const testImports = repoIndex.imports.filter((edge) => edge.from === test.path);
|
|
7456
|
-
const importsChangedFile = changedFiles.some(
|
|
7457
|
-
(changedFile) => changedFilePaths(changedFile).some(
|
|
7458
|
-
(filePath) => testImports.some((importEdge) => importTargetsChangedFile(importEdge, filePath))
|
|
7459
|
-
)
|
|
7460
|
-
);
|
|
7461
7278
|
const hintMatchesChangedFile = changedFiles.some(
|
|
7462
7279
|
(changedFile) => changedFilePaths(changedFile).some(
|
|
7463
7280
|
(filePath) => testHintMatchesChangedFile(test.targetHints, filePath)
|
|
7464
7281
|
)
|
|
7465
7282
|
);
|
|
7466
|
-
if (
|
|
7283
|
+
if (hintMatchesChangedFile) {
|
|
7467
7284
|
affectedTests.push(test.path);
|
|
7468
7285
|
}
|
|
7469
7286
|
}
|
|
@@ -7477,9 +7294,6 @@ var buildImpactSet = async (cwd, options) => {
|
|
|
7477
7294
|
),
|
|
7478
7295
|
affectedTruthDocs: uniqueAffectedTruthDocs,
|
|
7479
7296
|
affectedTests: uniqueSorted2(affectedTests),
|
|
7480
|
-
changedPublicSymbols: changedPublicSymbols.sort(
|
|
7481
|
-
(left, right) => `${left.path}:${left.name}:${left.change}`.localeCompare(`${right.path}:${right.name}:${right.change}`)
|
|
7482
|
-
),
|
|
7483
7297
|
diagnostics
|
|
7484
7298
|
};
|
|
7485
7299
|
};
|
|
@@ -7505,14 +7319,13 @@ var checkFreshness = async (rootDir, _config, _truthDocumentPaths, base) => {
|
|
|
7505
7319
|
};
|
|
7506
7320
|
|
|
7507
7321
|
// src/evidence/validate.ts
|
|
7508
|
-
import
|
|
7322
|
+
import fs20 from "fs/promises";
|
|
7509
7323
|
import fg7 from "fast-glob";
|
|
7510
7324
|
|
|
7511
7325
|
// src/evidence/parse.ts
|
|
7512
|
-
import
|
|
7513
|
-
import
|
|
7514
|
-
import
|
|
7515
|
-
import { parse as parse3 } from "yaml";
|
|
7326
|
+
import fs19 from "fs/promises";
|
|
7327
|
+
import path11 from "path";
|
|
7328
|
+
import { parse as parse4 } from "yaml";
|
|
7516
7329
|
var yamlFencePattern = /```ya?ml\s*\n([\s\S]*?)```/giu;
|
|
7517
7330
|
var topLevelEvidenceMarkerPattern = /^evidence\s*:/imu;
|
|
7518
7331
|
var toEvidenceReference = (truthDocPath, raw) => {
|
|
@@ -7530,8 +7343,8 @@ var toEvidenceReference = (truthDocPath, raw) => {
|
|
|
7530
7343
|
};
|
|
7531
7344
|
};
|
|
7532
7345
|
var parseEvidenceReferences = async (rootDir, truthDocPath) => {
|
|
7533
|
-
const source = await
|
|
7534
|
-
const parsed =
|
|
7346
|
+
const source = await fs19.readFile(path11.join(rootDir, truthDocPath), "utf8");
|
|
7347
|
+
const parsed = parseFrontmatter(source);
|
|
7535
7348
|
const references = [];
|
|
7536
7349
|
for (const entry of parseSourceReferences(source, truthDocPath)) {
|
|
7537
7350
|
references.push({
|
|
@@ -7545,7 +7358,7 @@ var parseEvidenceReferences = async (rootDir, truthDocPath) => {
|
|
|
7545
7358
|
if (!topLevelEvidenceMarkerPattern.test(yamlBlock)) {
|
|
7546
7359
|
continue;
|
|
7547
7360
|
}
|
|
7548
|
-
const block =
|
|
7361
|
+
const block = parse4(yamlBlock);
|
|
7549
7362
|
const rawEvidence = block && typeof block === "object" && "evidence" in block ? block.evidence : null;
|
|
7550
7363
|
if (!Array.isArray(rawEvidence)) {
|
|
7551
7364
|
continue;
|
|
@@ -7563,7 +7376,7 @@ var parseEvidenceReferences = async (rootDir, truthDocPath) => {
|
|
|
7563
7376
|
// src/evidence/validate.ts
|
|
7564
7377
|
var pathExists5 = async (filePath) => {
|
|
7565
7378
|
try {
|
|
7566
|
-
await
|
|
7379
|
+
await fs20.access(filePath);
|
|
7567
7380
|
return true;
|
|
7568
7381
|
} catch {
|
|
7569
7382
|
return false;
|
|
@@ -7601,15 +7414,6 @@ var validateGlob = async (rootDir, reference) => {
|
|
|
7601
7414
|
});
|
|
7602
7415
|
return matches.length > 0 ? null : diagnosticFor(reference, `Referenced file pattern ${reference.path} does not match any file.`);
|
|
7603
7416
|
};
|
|
7604
|
-
var validateSymbol = async (rootDir, reference) => {
|
|
7605
|
-
if (!reference.symbol || !isJavaScriptLikePath(reference.path)) {
|
|
7606
|
-
return null;
|
|
7607
|
-
}
|
|
7608
|
-
const source = await fs21.readFile(resolveRepoPath(rootDir, reference.path), "utf8");
|
|
7609
|
-
const analysis = analyzeTypeScriptSource(reference.path, source);
|
|
7610
|
-
const hasSymbol = analysis.publicSymbols.some((symbol) => symbol.name === reference.symbol);
|
|
7611
|
-
return hasSymbol ? null : diagnosticFor(reference, `Evidence symbol ${reference.symbol} was not found in ${reference.path}.`);
|
|
7612
|
-
};
|
|
7613
7417
|
var validateHash = async (rootDir, reference) => {
|
|
7614
7418
|
if (!reference.contentHash) {
|
|
7615
7419
|
return null;
|
|
@@ -7617,7 +7421,7 @@ var validateHash = async (rootDir, reference) => {
|
|
|
7617
7421
|
if (!reference.contentHash.startsWith("sha256:")) {
|
|
7618
7422
|
return diagnosticFor(reference, `Evidence hash for ${reference.path} must use sha256:.`);
|
|
7619
7423
|
}
|
|
7620
|
-
const source = await
|
|
7424
|
+
const source = await fs20.readFile(resolveRepoPath(rootDir, reference.path), "utf8");
|
|
7621
7425
|
const lines = source.split("\n");
|
|
7622
7426
|
const startLine = reference.startLine ?? 1;
|
|
7623
7427
|
const endLine = reference.endLine ?? lines.length;
|
|
@@ -7631,7 +7435,7 @@ var validateLineSpan = async (rootDir, reference) => {
|
|
|
7631
7435
|
if (reference.startLine === void 0 && reference.endLine === void 0) {
|
|
7632
7436
|
return null;
|
|
7633
7437
|
}
|
|
7634
|
-
const source = await
|
|
7438
|
+
const source = await fs20.readFile(resolveRepoPath(rootDir, reference.path), "utf8");
|
|
7635
7439
|
const lines = source.split("\n");
|
|
7636
7440
|
const startLine = reference.startLine ?? 1;
|
|
7637
7441
|
const endLine = reference.endLine ?? lines.length;
|
|
@@ -7650,10 +7454,6 @@ var validateReference = async (rootDir, reference) => {
|
|
|
7650
7454
|
diagnostics.push(diagnosticFor(reference, `Referenced file ${reference.path} does not exist.`));
|
|
7651
7455
|
return diagnostics;
|
|
7652
7456
|
}
|
|
7653
|
-
const symbolDiagnostic = await validateSymbol(rootDir, reference);
|
|
7654
|
-
if (symbolDiagnostic) {
|
|
7655
|
-
diagnostics.push(symbolDiagnostic);
|
|
7656
|
-
}
|
|
7657
7457
|
const lineSpanDiagnostic = await validateLineSpan(rootDir, reference);
|
|
7658
7458
|
if (lineSpanDiagnostic) {
|
|
7659
7459
|
diagnostics.push(lineSpanDiagnostic);
|
|
@@ -7910,195 +7710,11 @@ var runCheck = async (cwd, options = {}) => {
|
|
|
7910
7710
|
};
|
|
7911
7711
|
};
|
|
7912
7712
|
|
|
7913
|
-
// src/context-pack/build.ts
|
|
7914
|
-
import fs22 from "fs/promises";
|
|
7915
|
-
import path13 from "path";
|
|
7916
|
-
import fg8 from "fast-glob";
|
|
7917
|
-
var uniqueSorted3 = (values) => [...new Set(values)].sort();
|
|
7918
|
-
var repoRootPrefixes2 = [".codex/", ".github/", ".truthmark/", "docs/", "src/", "tests/"];
|
|
7919
|
-
var isGlobReference2 = (referencePath) => /[*?[\]{}()]/u.test(referencePath);
|
|
7920
|
-
var normalizeDocReferencePath = (docPath, referencePath) => {
|
|
7921
|
-
const strippedPath = referencePath.split("#")[0]?.trim() ?? "";
|
|
7922
|
-
if (strippedPath.length === 0 || strippedPath.startsWith("/")) {
|
|
7923
|
-
return null;
|
|
7924
|
-
}
|
|
7925
|
-
const isRepoRelative = repoRootPrefixes2.some((prefix) => strippedPath.startsWith(prefix));
|
|
7926
|
-
const normalized = isRepoRelative ? path13.posix.normalize(strippedPath) : path13.posix.normalize(path13.posix.join(path13.posix.dirname(docPath), strippedPath));
|
|
7927
|
-
return normalized === ".." || normalized.startsWith("../") ? null : normalized;
|
|
7928
|
-
};
|
|
7929
|
-
var readIfExists = async (rootDir, filePath) => {
|
|
7930
|
-
try {
|
|
7931
|
-
return await fs22.readFile(path13.join(rootDir, filePath), "utf8");
|
|
7932
|
-
} catch {
|
|
7933
|
-
return null;
|
|
7934
|
-
}
|
|
7935
|
-
};
|
|
7936
|
-
var boundContent = (content) => {
|
|
7937
|
-
const lines = content.split("\n");
|
|
7938
|
-
if (lines.length <= 200) {
|
|
7939
|
-
return { content, truncated: false };
|
|
7940
|
-
}
|
|
7941
|
-
return {
|
|
7942
|
-
content: [...lines.slice(0, 80), "...", ...lines.slice(-40)].join("\n"),
|
|
7943
|
-
truncated: true
|
|
7944
|
-
};
|
|
7945
|
-
};
|
|
7946
|
-
var boundedContent = (filePath, content, warnings) => {
|
|
7947
|
-
const bounded = boundContent(content);
|
|
7948
|
-
if (!bounded.truncated) {
|
|
7949
|
-
return { path: filePath, content, truncated: false };
|
|
7950
|
-
}
|
|
7951
|
-
warnings.push({
|
|
7952
|
-
category: "context-pack",
|
|
7953
|
-
severity: "review",
|
|
7954
|
-
message: `Context source file ${filePath} was truncated to fit ContextPack v0 bounds.`,
|
|
7955
|
-
file: filePath
|
|
7956
|
-
});
|
|
7957
|
-
return {
|
|
7958
|
-
path: filePath,
|
|
7959
|
-
content: bounded.content,
|
|
7960
|
-
truncated: true
|
|
7961
|
-
};
|
|
7962
|
-
};
|
|
7963
|
-
var documentsFor = async (rootDir, paths, warnings) => {
|
|
7964
|
-
const documents = [];
|
|
7965
|
-
for (const filePath of uniqueSorted3(paths)) {
|
|
7966
|
-
const content = await readIfExists(rootDir, filePath);
|
|
7967
|
-
if (content !== null) {
|
|
7968
|
-
const bounded = boundContent(content);
|
|
7969
|
-
if (bounded.truncated) {
|
|
7970
|
-
warnings.push({
|
|
7971
|
-
category: "context-pack",
|
|
7972
|
-
severity: "review",
|
|
7973
|
-
message: `Context truth doc ${filePath} was truncated to fit ContextPack v0 bounds.`,
|
|
7974
|
-
file: filePath
|
|
7975
|
-
});
|
|
7976
|
-
}
|
|
7977
|
-
documents.push({ path: filePath, content: bounded.content, truncated: bounded.truncated });
|
|
7978
|
-
}
|
|
7979
|
-
}
|
|
7980
|
-
return documents;
|
|
7981
|
-
};
|
|
7982
|
-
var sourceFilesFor = async (rootDir, paths, warnings) => {
|
|
7983
|
-
const sourceFiles = [];
|
|
7984
|
-
for (const filePath of uniqueSorted3(paths)) {
|
|
7985
|
-
const content = await readIfExists(rootDir, filePath);
|
|
7986
|
-
if (content !== null) {
|
|
7987
|
-
sourceFiles.push(boundedContent(filePath, content, warnings));
|
|
7988
|
-
}
|
|
7989
|
-
}
|
|
7990
|
-
return sourceFiles;
|
|
7991
|
-
};
|
|
7992
|
-
var sourceOfTruthPathsFor = async (rootDir, docs, truthDocPaths) => {
|
|
7993
|
-
const selectedTruthDocs = new Set(truthDocPaths);
|
|
7994
|
-
const sourcePaths = [];
|
|
7995
|
-
for (const doc of docs) {
|
|
7996
|
-
if (!selectedTruthDocs.has(doc.path)) {
|
|
7997
|
-
continue;
|
|
7998
|
-
}
|
|
7999
|
-
for (const referencePath of doc.sourceOfTruth) {
|
|
8000
|
-
const normalizedPath = normalizeDocReferencePath(doc.path, referencePath);
|
|
8001
|
-
if (!normalizedPath) {
|
|
8002
|
-
continue;
|
|
8003
|
-
}
|
|
8004
|
-
if (isGlobReference2(normalizedPath)) {
|
|
8005
|
-
sourcePaths.push(
|
|
8006
|
-
...await fg8(normalizedPath, {
|
|
8007
|
-
cwd: rootDir,
|
|
8008
|
-
dot: true,
|
|
8009
|
-
onlyFiles: true,
|
|
8010
|
-
followSymbolicLinks: false
|
|
8011
|
-
})
|
|
8012
|
-
);
|
|
8013
|
-
} else {
|
|
8014
|
-
sourcePaths.push(normalizedPath);
|
|
8015
|
-
}
|
|
8016
|
-
}
|
|
8017
|
-
}
|
|
8018
|
-
return uniqueSorted3(sourcePaths);
|
|
8019
|
-
};
|
|
8020
|
-
var writePathsFor = (workflow, routeIndexPath, truthDocs, routes) => {
|
|
8021
|
-
if (workflow === "truth-sync") {
|
|
8022
|
-
return uniqueSorted3([routeIndexPath, ...truthDocs]);
|
|
8023
|
-
}
|
|
8024
|
-
if (workflow === "truth-document") {
|
|
8025
|
-
return uniqueSorted3([routeIndexPath, ...truthDocs]);
|
|
8026
|
-
}
|
|
8027
|
-
return uniqueSorted3(routes.flatMap((route) => route.codeSurface));
|
|
8028
|
-
};
|
|
8029
|
-
var testCommandsFor = (affectedTests) => {
|
|
8030
|
-
return affectedTests.length === 0 ? ["npm test"] : [`npm test -- ${affectedTests.join(" ")}`];
|
|
8031
|
-
};
|
|
8032
|
-
var buildContextPack = async (cwd, options) => {
|
|
8033
|
-
const repoIndex = await buildRepoIndex(cwd);
|
|
8034
|
-
const rootDir = repoIndex.repository.root;
|
|
8035
|
-
const loadResult = await loadConfig(rootDir);
|
|
8036
|
-
const config = loadResult.config ?? (loadResult.status === "missing" ? createDefaultConfig() : null);
|
|
8037
|
-
const impactSet = options.base ? await buildImpactSet(rootDir, { base: options.base }) : null;
|
|
8038
|
-
const routeMap = impactSet ? repoIndex.routeMap : repoIndex.routeMap;
|
|
8039
|
-
const warnings = loadResult.status === "invalid" ? [...loadResult.diagnostics] : [];
|
|
8040
|
-
const truthDocPaths = impactSet?.affectedTruthDocs ?? (options.workflow === "truth-realize" ? [] : routeMap.routes.flatMap((route) => route.truthDocs));
|
|
8041
|
-
const contextRoutes = impactSet?.affectedRoutes ?? (options.workflow === "truth-realize" ? [] : routeMap.routes);
|
|
8042
|
-
if (options.workflow === "truth-realize" && !impactSet) {
|
|
8043
|
-
warnings.push({
|
|
8044
|
-
category: "context-pack",
|
|
8045
|
-
severity: "review",
|
|
8046
|
-
message: "truth-realize requires --base to derive bounded allowed write paths."
|
|
8047
|
-
});
|
|
8048
|
-
}
|
|
8049
|
-
const sourceOfTruthPaths = await sourceOfTruthPathsFor(rootDir, repoIndex.docs, truthDocPaths);
|
|
8050
|
-
const sourceFilePaths = uniqueSorted3([
|
|
8051
|
-
...impactSet?.changedFiles.filter((file) => !file.deleted).map((file) => file.path) ?? [],
|
|
8052
|
-
...sourceOfTruthPaths
|
|
8053
|
-
]);
|
|
8054
|
-
return {
|
|
8055
|
-
schemaVersion: "context-pack/v0",
|
|
8056
|
-
workflow: options.workflow,
|
|
8057
|
-
base: options.base ?? null,
|
|
8058
|
-
impactSet,
|
|
8059
|
-
routeMap,
|
|
8060
|
-
allowedWritePaths: config === null ? [] : writePathsFor(
|
|
8061
|
-
options.workflow,
|
|
8062
|
-
config.truthmark.paths.routesIndex,
|
|
8063
|
-
truthDocPaths,
|
|
8064
|
-
contextRoutes
|
|
8065
|
-
),
|
|
8066
|
-
truthDocs: await documentsFor(rootDir, truthDocPaths, warnings),
|
|
8067
|
-
sourceFiles: await sourceFilesFor(rootDir, sourceFilePaths, warnings),
|
|
8068
|
-
testCommands: testCommandsFor(impactSet?.affectedTests ?? []),
|
|
8069
|
-
warnings
|
|
8070
|
-
};
|
|
8071
|
-
};
|
|
8072
|
-
|
|
8073
|
-
// src/context-pack/render.ts
|
|
8074
|
-
var renderContextPackMarkdown = (pack) => {
|
|
8075
|
-
const lines = [
|
|
8076
|
-
`# Truthmark ContextPack (${pack.workflow})`,
|
|
8077
|
-
"",
|
|
8078
|
-
`Schema: ${pack.schemaVersion}`,
|
|
8079
|
-
`Base: ${pack.base ?? "none"}`,
|
|
8080
|
-
"",
|
|
8081
|
-
"## Allowed Write Paths",
|
|
8082
|
-
...pack.allowedWritePaths.map((filePath) => `- ${filePath}`),
|
|
8083
|
-
"",
|
|
8084
|
-
"## Truth Docs",
|
|
8085
|
-
...pack.truthDocs.map((doc) => `- ${doc.path}${doc.truncated ? " (truncated)" : ""}`),
|
|
8086
|
-
"",
|
|
8087
|
-
"## Source Files",
|
|
8088
|
-
...pack.sourceFiles.map((file) => `- ${file.path}${file.truncated ? " (truncated)" : ""}`),
|
|
8089
|
-
"",
|
|
8090
|
-
"## Test Commands",
|
|
8091
|
-
...pack.testCommands.map((command) => `- ${command}`)
|
|
8092
|
-
];
|
|
8093
|
-
return `${lines.join("\n")}
|
|
8094
|
-
`;
|
|
8095
|
-
};
|
|
8096
|
-
|
|
8097
7713
|
// src/workflow-state/build.ts
|
|
8098
7714
|
import { execa as execa5 } from "execa";
|
|
8099
7715
|
|
|
8100
7716
|
// src/workflow-state/action-context.ts
|
|
8101
|
-
var
|
|
7717
|
+
var uniqueSorted3 = (values) => [...new Set(values.filter((value) => value.length > 0))].sort();
|
|
8102
7718
|
var helperCommandsFor = (manifestEntry) => (manifestEntry.helpers ?? []).map((helper) => ({
|
|
8103
7719
|
id: helper.id,
|
|
8104
7720
|
runner: helper.runner,
|
|
@@ -8108,8 +7724,8 @@ var helperCommandsFor = (manifestEntry) => (manifestEntry.helpers ?? []).map((he
|
|
|
8108
7724
|
var evidenceFor = (manifestEntry) => manifestEntry.requiredGates.filter((gate) => /evidence|ownership|containment/iu.test(gate));
|
|
8109
7725
|
var baseContext = (manifestEntry, mode, allowedWritePaths, forbiddenWritePaths, writeLeaseRequired) => ({
|
|
8110
7726
|
mode,
|
|
8111
|
-
allowedWritePaths:
|
|
8112
|
-
forbiddenWritePaths:
|
|
7727
|
+
allowedWritePaths: uniqueSorted3(allowedWritePaths),
|
|
7728
|
+
forbiddenWritePaths: uniqueSorted3(forbiddenWritePaths),
|
|
8113
7729
|
stopConditions: [...manifestEntry.negativeTriggers, ...manifestEntry.forbiddenAdjacency],
|
|
8114
7730
|
requiredEvidence: evidenceFor(manifestEntry),
|
|
8115
7731
|
helperValidationCommands: helperCommandsFor(manifestEntry),
|
|
@@ -8171,7 +7787,7 @@ var helperCommandsFor2 = (workflow) => (TRUTHMARK_WORKFLOW_MANIFEST[workflow].he
|
|
|
8171
7787
|
argv: [...helper.command.argv],
|
|
8172
7788
|
optional: helper.optional
|
|
8173
7789
|
}));
|
|
8174
|
-
var
|
|
7790
|
+
var uniqueSorted4 = (values) => [...new Set(values.filter((value) => value.length > 0))].sort();
|
|
8175
7791
|
var isWriteCapable = (workflow) => !["truthmark-preview", "truthmark-check"].includes(workflow);
|
|
8176
7792
|
var DEFAULT_BASE_CANDIDATES = ["@{upstream}", "origin/main", "main", "origin/master", "master"];
|
|
8177
7793
|
var selectComparisonBase = async (rootDir, suppliedBase) => {
|
|
@@ -8189,7 +7805,7 @@ var selectComparisonBase = async (rootDir, suppliedBase) => {
|
|
|
8189
7805
|
}
|
|
8190
7806
|
return null;
|
|
8191
7807
|
};
|
|
8192
|
-
var routeFilesFor = (repoIndex) =>
|
|
7808
|
+
var routeFilesFor = (repoIndex) => uniqueSorted4(repoIndex.routeMap.routes.map((route) => route.sourcePath));
|
|
8193
7809
|
var hasUnmappedFunctionalChange = (impactSet) => impactSet?.diagnostics.some(
|
|
8194
7810
|
(diagnostic) => diagnostic.category === "impact" && /not mapped to a Truthmark route|no affected truth document/u.test(diagnostic.message)
|
|
8195
7811
|
) ?? false;
|
|
@@ -8200,7 +7816,7 @@ var applicabilityFor = (workflow, diagnostics, impactSet) => {
|
|
|
8200
7816
|
return { state: isWriteCapable(workflow) ? "blocked" : "not_applicable", reasons };
|
|
8201
7817
|
}
|
|
8202
7818
|
if (workflow === "truthmark-sync" && !impactSet) {
|
|
8203
|
-
reasons.push("truthmark-sync requires --base to derive
|
|
7819
|
+
reasons.push("truthmark-sync requires --base to derive changed-file impact before exposing sync write paths.");
|
|
8204
7820
|
return { state: "blocked", reasons };
|
|
8205
7821
|
}
|
|
8206
7822
|
if (workflow === "truthmark-realize" && !impactSet) {
|
|
@@ -8222,16 +7838,15 @@ var contextDataFor = (workflow, repoIndex, config, impactSet) => {
|
|
|
8222
7838
|
return {};
|
|
8223
7839
|
}
|
|
8224
7840
|
const routeFiles = routeFilesFor(repoIndex);
|
|
8225
|
-
const
|
|
8226
|
-
|
|
8227
|
-
);
|
|
7841
|
+
const indexedTruthDocs = uniqueSorted4(repoIndex.routeMap.routes.flatMap((route) => route.truthDocs));
|
|
7842
|
+
const truthDocs = workflow === "truthmark-sync" ? indexedTruthDocs : uniqueSorted4(impactSet?.affectedTruthDocs ?? indexedTruthDocs);
|
|
8228
7843
|
return {
|
|
8229
7844
|
routeIndexPath: config.truthmark.paths.routesIndex,
|
|
8230
7845
|
routeFiles,
|
|
8231
7846
|
truthRoot: config.truthmark.paths.truthRoot,
|
|
8232
7847
|
truthDocs,
|
|
8233
7848
|
starterTruthDocs: workflow === "truthmark-structure" ? truthDocs : [],
|
|
8234
|
-
codeWritePaths: workflow === "truthmark-realize" ?
|
|
7849
|
+
codeWritePaths: workflow === "truthmark-realize" ? uniqueSorted4(impactSet?.affectedRoutes.flatMap((route) => route.codeSurface) ?? []) : [],
|
|
8235
7850
|
portalEnabled: config.truthmark.generated.portal.enabled,
|
|
8236
7851
|
portalOutputPath: config.truthmark.paths.portalOutput,
|
|
8237
7852
|
routes: repoIndex.routeMap.routes
|
|
@@ -8243,7 +7858,7 @@ var nextStepsFor = (workflow, applicability, comparisonBase) => {
|
|
|
8243
7858
|
}
|
|
8244
7859
|
if ((workflow === "truthmark-sync" || workflow === "truthmark-realize") && applicability.state === "blocked" && !comparisonBase) {
|
|
8245
7860
|
return [
|
|
8246
|
-
workflow === "truthmark-sync" ? "Rerun with --base <ref> so Truthmark can derive
|
|
7861
|
+
workflow === "truthmark-sync" ? "Rerun with --base <ref> so Truthmark can derive changed-file impact before exposing sync write paths." : "Rerun with --base <ref> so Truthmark can derive bounded allowed code-write paths."
|
|
8247
7862
|
];
|
|
8248
7863
|
}
|
|
8249
7864
|
return [];
|
|
@@ -8279,7 +7894,8 @@ var buildWorkflowState = async (cwd, options) => {
|
|
|
8279
7894
|
checks: {
|
|
8280
7895
|
required: [...manifestEntry.requiredGates],
|
|
8281
7896
|
recommended: [...manifestEntry.positiveTriggers],
|
|
8282
|
-
helpers: helperCommandsFor2(options.workflow)
|
|
7897
|
+
helpers: helperCommandsFor2(options.workflow),
|
|
7898
|
+
affectedTests: impactSet?.affectedTests ?? []
|
|
8283
7899
|
},
|
|
8284
7900
|
nextSteps: nextStepsFor(options.workflow, applicability, comparisonBase),
|
|
8285
7901
|
reportSections: [...manifestEntry.reportSections]
|
|
@@ -8287,7 +7903,7 @@ var buildWorkflowState = async (cwd, options) => {
|
|
|
8287
7903
|
};
|
|
8288
7904
|
|
|
8289
7905
|
// src/cli/handlers.ts
|
|
8290
|
-
import
|
|
7906
|
+
import fs21 from "fs/promises";
|
|
8291
7907
|
|
|
8292
7908
|
// src/agents/workflow-helper-validation.ts
|
|
8293
7909
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -8649,12 +8265,6 @@ var runImpact = async (options) => {
|
|
|
8649
8265
|
}
|
|
8650
8266
|
};
|
|
8651
8267
|
};
|
|
8652
|
-
var isContextPackWorkflow = (value) => {
|
|
8653
|
-
return value === "truth-sync" || value === "truth-document" || value === "truth-realize";
|
|
8654
|
-
};
|
|
8655
|
-
var isContextMarkdownFormat = (value) => {
|
|
8656
|
-
return value === void 0 || value === "markdown";
|
|
8657
|
-
};
|
|
8658
8268
|
var isTruthmarkWorkflowId = (value) => {
|
|
8659
8269
|
return typeof value === "string" && TRUTHMARK_WORKFLOW_IDS.includes(value);
|
|
8660
8270
|
};
|
|
@@ -8674,7 +8284,7 @@ var invalidWorkflowResult = (command, workflow) => ({
|
|
|
8674
8284
|
});
|
|
8675
8285
|
var readHelperFile = async (filePath, helper) => {
|
|
8676
8286
|
try {
|
|
8677
|
-
return await
|
|
8287
|
+
return await fs21.readFile(filePath, "utf8");
|
|
8678
8288
|
} catch (error) {
|
|
8679
8289
|
const message = error instanceof Error ? error.message : String(error);
|
|
8680
8290
|
return { ok: false, helper, errors: [`could not read file: ${message}`] };
|
|
@@ -8699,63 +8309,6 @@ var runValidateWriteLease = async (leaseFile, changedFilesFile) => {
|
|
|
8699
8309
|
}
|
|
8700
8310
|
return validateWriteLeaseText(leaseText, changedText);
|
|
8701
8311
|
};
|
|
8702
|
-
var runContext = async (options) => {
|
|
8703
|
-
if (!isContextPackWorkflow(options.workflow)) {
|
|
8704
|
-
return {
|
|
8705
|
-
command: "context",
|
|
8706
|
-
summary: "Truthmark context requires a supported --workflow value.",
|
|
8707
|
-
diagnostics: [
|
|
8708
|
-
{
|
|
8709
|
-
category: "context-pack",
|
|
8710
|
-
severity: "error",
|
|
8711
|
-
message: "truthmark context requires --workflow truth-sync, truth-document, or truth-realize."
|
|
8712
|
-
}
|
|
8713
|
-
]
|
|
8714
|
-
};
|
|
8715
|
-
}
|
|
8716
|
-
if (options.format === "json") {
|
|
8717
|
-
return {
|
|
8718
|
-
command: "context",
|
|
8719
|
-
summary: "Truthmark context no longer supports JSON ContextPack output.",
|
|
8720
|
-
diagnostics: [
|
|
8721
|
-
{
|
|
8722
|
-
category: "context-pack",
|
|
8723
|
-
severity: "error",
|
|
8724
|
-
message: "JSON ContextPack output was removed in v2; use --format markdown."
|
|
8725
|
-
}
|
|
8726
|
-
]
|
|
8727
|
-
};
|
|
8728
|
-
}
|
|
8729
|
-
if (!isContextMarkdownFormat(options.format)) {
|
|
8730
|
-
return {
|
|
8731
|
-
command: "context",
|
|
8732
|
-
summary: "Truthmark context requires a supported --format value.",
|
|
8733
|
-
diagnostics: [
|
|
8734
|
-
{
|
|
8735
|
-
category: "context-pack",
|
|
8736
|
-
severity: "error",
|
|
8737
|
-
message: "truthmark context supports only --format markdown; JSON ContextPack output was removed in v2."
|
|
8738
|
-
}
|
|
8739
|
-
]
|
|
8740
|
-
};
|
|
8741
|
-
}
|
|
8742
|
-
const contextPack = await buildContextPack(process.cwd(), {
|
|
8743
|
-
workflow: options.workflow,
|
|
8744
|
-
base: options.base
|
|
8745
|
-
});
|
|
8746
|
-
const diagnostics = contextPack.warnings;
|
|
8747
|
-
const summary = `Truthmark context generated ${contextPack.workflow} ContextPack with ${diagnostics.length} warnings.`;
|
|
8748
|
-
const markdown = renderContextPackMarkdown(contextPack);
|
|
8749
|
-
return {
|
|
8750
|
-
command: "context",
|
|
8751
|
-
summary,
|
|
8752
|
-
diagnostics,
|
|
8753
|
-
data: {
|
|
8754
|
-
markdown,
|
|
8755
|
-
summary
|
|
8756
|
-
}
|
|
8757
|
-
};
|
|
8758
|
-
};
|
|
8759
8312
|
var runWorkflowStatus = async (options) => {
|
|
8760
8313
|
if (!isTruthmarkWorkflowId(options.workflow)) {
|
|
8761
8314
|
return invalidWorkflowResult("workflow status", options.workflow);
|
|
@@ -8790,14 +8343,6 @@ var writeResult = (result, options) => {
|
|
|
8790
8343
|
`);
|
|
8791
8344
|
markFailedWhenErrorDiagnosticsExist(result);
|
|
8792
8345
|
};
|
|
8793
|
-
var writeContextResult = (result, options) => {
|
|
8794
|
-
if (!options.json && typeof result.data?.markdown === "string") {
|
|
8795
|
-
process.stdout.write(result.data.markdown);
|
|
8796
|
-
markFailedWhenErrorDiagnosticsExist(result);
|
|
8797
|
-
return;
|
|
8798
|
-
}
|
|
8799
|
-
writeResult(result, options);
|
|
8800
|
-
};
|
|
8801
8346
|
var renderValidationHuman = (result) => {
|
|
8802
8347
|
if (result.ok === true) {
|
|
8803
8348
|
return [`${result.helper}: ok`, ...result.checks.map((check) => `- ${check}`)].join("\n");
|
|
@@ -8842,7 +8387,7 @@ var buildProgram = () => {
|
|
|
8842
8387
|
writeResult(await runCheck2({ base: options.base }), options);
|
|
8843
8388
|
});
|
|
8844
8389
|
addJsonOption(
|
|
8845
|
-
program.command("index").description("
|
|
8390
|
+
program.command("index").description("Inspect derived Truthmark workflow routing metadata for the current checkout.")
|
|
8846
8391
|
).action(async (options) => {
|
|
8847
8392
|
writeResult(await runIndex(), options);
|
|
8848
8393
|
});
|
|
@@ -8851,18 +8396,6 @@ var buildProgram = () => {
|
|
|
8851
8396
|
).action(async (options) => {
|
|
8852
8397
|
writeResult(await runImpact({ base: options.base }), options);
|
|
8853
8398
|
});
|
|
8854
|
-
addJsonOption(
|
|
8855
|
-
program.command("context").description("Generate a bounded workflow context pack.").requiredOption("--workflow <workflow>", "Workflow name: truth-sync, truth-document, or truth-realize").option("--base <ref>", "Base Git ref for impact-backed packs").option("--format <format>", "Output format: markdown", "markdown")
|
|
8856
|
-
).action(async (options) => {
|
|
8857
|
-
writeContextResult(
|
|
8858
|
-
await runContext({
|
|
8859
|
-
workflow: options.workflow,
|
|
8860
|
-
base: options.base,
|
|
8861
|
-
format: options.format
|
|
8862
|
-
}),
|
|
8863
|
-
options
|
|
8864
|
-
);
|
|
8865
|
-
});
|
|
8866
8399
|
const workflow = program.command("workflow").description("Inspect agent-facing Truthmark workflow state.");
|
|
8867
8400
|
addJsonOption(
|
|
8868
8401
|
workflow.command("status").description("Return schema-versioned workflow state for a canonical workflow ID.").option("--workflow <workflow>", "Canonical workflow ID, such as truthmark-sync").option("--base <ref>", "Base Git ref for impact-backed workflow state")
|