truthmark 1.5.0 → 1.6.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 +51 -1
- package/README.es.md +51 -1
- package/README.md +51 -1
- package/README.ru.md +51 -1
- package/README.zh.md +51 -1
- package/dist/main.js +796 -196
- package/dist/main.js.map +1 -1
- package/package.json +1 -2
package/dist/main.js
CHANGED
|
@@ -334,6 +334,22 @@ var truthmarkConfigSchema = {
|
|
|
334
334
|
type: "string"
|
|
335
335
|
}
|
|
336
336
|
},
|
|
337
|
+
"truthmark-portal": {
|
|
338
|
+
type: "object",
|
|
339
|
+
additionalProperties: false,
|
|
340
|
+
required: [],
|
|
341
|
+
properties: {
|
|
342
|
+
enabled: {
|
|
343
|
+
type: "boolean"
|
|
344
|
+
},
|
|
345
|
+
output: {
|
|
346
|
+
type: "string"
|
|
347
|
+
},
|
|
348
|
+
template: {
|
|
349
|
+
type: "string"
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
},
|
|
337
353
|
frontmatter: {
|
|
338
354
|
type: "object",
|
|
339
355
|
nullable: true,
|
|
@@ -391,6 +407,11 @@ var DEFAULT_AUTHORITY = [
|
|
|
391
407
|
`${DEFAULT_DOCS_HIERARCHY.roots.truth}/**/*.md`
|
|
392
408
|
];
|
|
393
409
|
var DEFAULT_INSTRUCTION_TARGETS = ["AGENTS.md"];
|
|
410
|
+
var DEFAULT_TRUTHMARK_PORTAL = {
|
|
411
|
+
enabled: false,
|
|
412
|
+
output: "docs/truthmark-portal",
|
|
413
|
+
template: "default"
|
|
414
|
+
};
|
|
394
415
|
var createDefaultRawConfig = () => ({
|
|
395
416
|
version: 1,
|
|
396
417
|
platforms: [...DEFAULT_PLATFORMS],
|
|
@@ -422,6 +443,7 @@ var createDefaultConfig = () => ({
|
|
|
422
443
|
},
|
|
423
444
|
authority: [...DEFAULT_AUTHORITY],
|
|
424
445
|
instructionTargets: [...DEFAULT_INSTRUCTION_TARGETS],
|
|
446
|
+
truthmarkPortal: { ...DEFAULT_TRUTHMARK_PORTAL },
|
|
425
447
|
frontmatter: {
|
|
426
448
|
required: [],
|
|
427
449
|
recommended: ["status", "doc_type", "last_reviewed", "source_of_truth"]
|
|
@@ -578,9 +600,9 @@ var parseTruthDocumentsFromYaml = (sectionLines, areaName) => {
|
|
|
578
600
|
const diagnostics = [];
|
|
579
601
|
const truthDocumentEntries = [];
|
|
580
602
|
for (const rawEntry of rawEntries) {
|
|
581
|
-
const
|
|
603
|
+
const path13 = rawEntry && typeof rawEntry === "object" && "path" in rawEntry ? rawEntry.path : null;
|
|
582
604
|
const kind = rawEntry && typeof rawEntry === "object" && "kind" in rawEntry ? rawEntry.kind : null;
|
|
583
|
-
if (typeof
|
|
605
|
+
if (typeof path13 !== "string" || path13.trim().length === 0 || !isTruthDocumentKind(kind)) {
|
|
584
606
|
diagnostics.push(
|
|
585
607
|
createAreaDiagnostic(
|
|
586
608
|
`Area ${areaName} truth_documents entries must include non-empty path and valid kind fields.`,
|
|
@@ -590,7 +612,7 @@ var parseTruthDocumentsFromYaml = (sectionLines, areaName) => {
|
|
|
590
612
|
continue;
|
|
591
613
|
}
|
|
592
614
|
truthDocumentEntries.push({
|
|
593
|
-
path:
|
|
615
|
+
path: path13.trim(),
|
|
594
616
|
kind,
|
|
595
617
|
kindSource: "explicit"
|
|
596
618
|
});
|
|
@@ -862,6 +884,102 @@ var ARCHITECTURE_DOC_TEMPLATE_PATH = "docs/templates/architecture-doc.md";
|
|
|
862
884
|
var WORKFLOW_DOC_TEMPLATE_PATH = "docs/templates/workflow-doc.md";
|
|
863
885
|
var OPERATIONS_DOC_TEMPLATE_PATH = "docs/templates/operations-doc.md";
|
|
864
886
|
var TEST_BEHAVIOR_DOC_TEMPLATE_PATH = "docs/templates/test-behavior-doc.md";
|
|
887
|
+
var renderTemplateSection = (section) => {
|
|
888
|
+
return [
|
|
889
|
+
section.heading,
|
|
890
|
+
"",
|
|
891
|
+
"<!--",
|
|
892
|
+
...section.guidance,
|
|
893
|
+
"-->",
|
|
894
|
+
"",
|
|
895
|
+
`{{${section.placeholder}}}`,
|
|
896
|
+
""
|
|
897
|
+
];
|
|
898
|
+
};
|
|
899
|
+
var titleToPlaceholder = (title) => {
|
|
900
|
+
return title.replace(/^#+\s+/u, "").toLowerCase().replaceAll(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
901
|
+
};
|
|
902
|
+
var findTemplateSectionHeadings = (template) => {
|
|
903
|
+
const matches = [];
|
|
904
|
+
let fencedCodeMarker = null;
|
|
905
|
+
let fencedCodeLength = 0;
|
|
906
|
+
for (const lineMatch of template.matchAll(/^.*(?:\r?\n|$)/gm)) {
|
|
907
|
+
const rawLine = lineMatch[0];
|
|
908
|
+
if (rawLine.length === 0) {
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
const line = rawLine.replace(/\r?\n$/u, "");
|
|
912
|
+
const fenceMatch = /^(?: {0,3})(`{3,}|~{3,})/u.exec(line);
|
|
913
|
+
if (fenceMatch) {
|
|
914
|
+
const marker = fenceMatch[1]?.[0];
|
|
915
|
+
const length = fenceMatch[1]?.length ?? 0;
|
|
916
|
+
if (fencedCodeMarker === null) {
|
|
917
|
+
fencedCodeMarker = marker;
|
|
918
|
+
fencedCodeLength = length;
|
|
919
|
+
} else if (marker === fencedCodeMarker && length >= fencedCodeLength) {
|
|
920
|
+
fencedCodeMarker = null;
|
|
921
|
+
fencedCodeLength = 0;
|
|
922
|
+
}
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
if (fencedCodeMarker === null && /^## .+$/u.test(line)) {
|
|
926
|
+
matches.push({ heading: line.trim(), index: lineMatch.index });
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return matches;
|
|
930
|
+
};
|
|
931
|
+
var parseTemplateSections = (template) => {
|
|
932
|
+
const matches = findTemplateSectionHeadings(template);
|
|
933
|
+
if (matches.length === 0) {
|
|
934
|
+
return { preamble: template.trimEnd(), sections: [] };
|
|
935
|
+
}
|
|
936
|
+
const sections = matches.map((match, index) => {
|
|
937
|
+
const start = match.index;
|
|
938
|
+
const next = matches[index + 1];
|
|
939
|
+
const end = next?.index ?? template.length;
|
|
940
|
+
return {
|
|
941
|
+
heading: match.heading,
|
|
942
|
+
block: template.slice(start, end).trimEnd()
|
|
943
|
+
};
|
|
944
|
+
});
|
|
945
|
+
return {
|
|
946
|
+
preamble: template.slice(0, matches[0]?.index ?? 0).trimEnd(),
|
|
947
|
+
sections
|
|
948
|
+
};
|
|
949
|
+
};
|
|
950
|
+
var mergeTruthDocTemplate = (existingTemplate, defaultTemplate) => {
|
|
951
|
+
if (existingTemplate.trim().length === 0) {
|
|
952
|
+
return defaultTemplate;
|
|
953
|
+
}
|
|
954
|
+
const defaultParsed = parseTemplateSections(defaultTemplate);
|
|
955
|
+
const existingParsed = parseTemplateSections(existingTemplate);
|
|
956
|
+
const defaultHeadings = new Set(defaultParsed.sections.map((section) => section.heading));
|
|
957
|
+
const customBeforeDefault = /* @__PURE__ */ new Map();
|
|
958
|
+
const trailingCustomSections = [];
|
|
959
|
+
existingParsed.sections.forEach((section, index) => {
|
|
960
|
+
if (defaultHeadings.has(section.heading)) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
const nextDefaultSection = existingParsed.sections.slice(index + 1).find((candidate) => defaultHeadings.has(candidate.heading));
|
|
964
|
+
if (nextDefaultSection) {
|
|
965
|
+
const bucket = customBeforeDefault.get(nextDefaultSection.heading) ?? [];
|
|
966
|
+
bucket.push(section);
|
|
967
|
+
customBeforeDefault.set(nextDefaultSection.heading, bucket);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
trailingCustomSections.push(section);
|
|
971
|
+
});
|
|
972
|
+
const mergedSections = defaultParsed.sections.flatMap((section) => [
|
|
973
|
+
...customBeforeDefault.get(section.heading) ?? [],
|
|
974
|
+
section
|
|
975
|
+
]);
|
|
976
|
+
return [
|
|
977
|
+
existingParsed.preamble,
|
|
978
|
+
...mergedSections.map((section) => section.block),
|
|
979
|
+
...trailingCustomSections.map((section) => section.block),
|
|
980
|
+
""
|
|
981
|
+
].filter((block) => block.length > 0).join("\n\n");
|
|
982
|
+
};
|
|
865
983
|
var renderBehaviorDocTemplateFile = () => {
|
|
866
984
|
return [
|
|
867
985
|
"---",
|
|
@@ -877,81 +995,130 @@ var renderBehaviorDocTemplateFile = () => {
|
|
|
877
995
|
"",
|
|
878
996
|
"## Purpose",
|
|
879
997
|
"",
|
|
880
|
-
"<!--
|
|
998
|
+
"<!--",
|
|
999
|
+
"State the user/system outcome this behavior protects and why it exists.",
|
|
1000
|
+
"Include the problem boundary and durable value; exclude roadmap, implementation plan, and historical narrative.",
|
|
1001
|
+
"List the code, config, docs, or tests that support the claim in source_of_truth rather than prose-only assertion.",
|
|
1002
|
+
"-->",
|
|
881
1003
|
"",
|
|
882
1004
|
"{{purpose}}",
|
|
883
1005
|
"",
|
|
884
1006
|
"## Scope",
|
|
885
1007
|
"",
|
|
886
|
-
"{{scope}}",
|
|
887
|
-
"",
|
|
888
1008
|
"<!--",
|
|
889
|
-
"
|
|
890
|
-
"
|
|
891
|
-
"
|
|
892
|
-
"- a separate lifecycle or state machine",
|
|
893
|
-
"- an unrelated rule family",
|
|
894
|
-
"- a different external contract",
|
|
895
|
-
"- code that should route through a different owner",
|
|
1009
|
+
"Define the one coherent behavior surface this document owns.",
|
|
1010
|
+
"Include in-scope actors, entrypoints, state/data owned by this doc, and explicit handoffs to neighboring truth docs.",
|
|
1011
|
+
"Split into another leaf doc when content introduces a distinct outcome, state machine, rule family, external contract, or route owner.",
|
|
896
1012
|
"Keep README.md files as indexes only.",
|
|
897
1013
|
"-->",
|
|
898
1014
|
"",
|
|
1015
|
+
"{{scope}}",
|
|
1016
|
+
"",
|
|
899
1017
|
"This doc was created from the editable behavior-doc template at {{template_path}}.",
|
|
900
1018
|
"",
|
|
901
1019
|
"## Current Behavior",
|
|
902
1020
|
"",
|
|
903
|
-
"<!--
|
|
1021
|
+
"<!--",
|
|
1022
|
+
"Describe only current implemented behavior in present tense.",
|
|
1023
|
+
"Cover observable behavior, important defaults, and user/system-visible effects; exclude desired future behavior and speculative design.",
|
|
1024
|
+
"Every non-obvious claim should be checkable from source_of_truth evidence.",
|
|
1025
|
+
"-->",
|
|
904
1026
|
"",
|
|
905
1027
|
"{{current_behavior}}",
|
|
906
1028
|
"",
|
|
907
1029
|
"## Core Rules",
|
|
908
1030
|
"",
|
|
909
|
-
"<!--
|
|
1031
|
+
"<!--",
|
|
1032
|
+
"Capture stable business rules, invariants, precedence rules, validation rules, and must-never constraints.",
|
|
1033
|
+
"Separate rules from incidental implementation details; cite current implementation or tests for rule enforcement.",
|
|
1034
|
+
"-->",
|
|
910
1035
|
"",
|
|
911
1036
|
"{{core_rules}}",
|
|
912
1037
|
"",
|
|
913
1038
|
"## Flows And States",
|
|
914
1039
|
"",
|
|
915
|
-
"<!--
|
|
1040
|
+
"<!--",
|
|
1041
|
+
"Document state transitions, lifecycle stages, retries, fallbacks, route switches, and important error paths.",
|
|
1042
|
+
"State 'None beyond current behavior.' when this behavior has no distinct flow or state model.",
|
|
1043
|
+
"-->",
|
|
916
1044
|
"",
|
|
917
1045
|
"{{flows_and_states}}",
|
|
918
1046
|
"",
|
|
919
1047
|
"## Contracts",
|
|
920
1048
|
"",
|
|
921
|
-
"<!--
|
|
1049
|
+
"<!--",
|
|
1050
|
+
"Capture user-visible or integration contracts: CLI/API shape, inputs, outputs, diagnostics, files, events, permissions, or links to canonical contract docs.",
|
|
1051
|
+
"Avoid duplicating a separate canonical contract doc; link to it when contract ownership lives elsewhere.",
|
|
1052
|
+
"-->",
|
|
922
1053
|
"",
|
|
923
1054
|
"{{contracts}}",
|
|
924
1055
|
"",
|
|
925
1056
|
"## Product Decisions",
|
|
926
1057
|
"",
|
|
927
|
-
"<!--
|
|
1058
|
+
"<!--",
|
|
1059
|
+
"Keep active decisions only, dated inline when added or changed.",
|
|
1060
|
+
"Explain decisions that shape behavior, boundaries, rejected alternatives, or migration constraints; replace stale decisions instead of appending historical logs.",
|
|
1061
|
+
"-->",
|
|
928
1062
|
"",
|
|
929
1063
|
"{{decision}}",
|
|
930
1064
|
"",
|
|
931
1065
|
"## Rationale",
|
|
932
1066
|
"",
|
|
933
|
-
"<!--
|
|
1067
|
+
"<!--",
|
|
1068
|
+
"Explain why the current behavior and active decisions are this way, including tradeoffs and constraints.",
|
|
1069
|
+
"Tie rationale to evidence-backed behavior; do not use this as a changelog.",
|
|
1070
|
+
"-->",
|
|
934
1071
|
"",
|
|
935
1072
|
"{{rationale}}",
|
|
936
1073
|
"",
|
|
937
1074
|
"## Non-Goals",
|
|
938
1075
|
"",
|
|
939
|
-
"<!--
|
|
1076
|
+
"<!--",
|
|
1077
|
+
"Name adjacent behavior this doc intentionally does not own, especially tempting future expansions or neighboring route owners.",
|
|
1078
|
+
"Use this section to prevent scope creep and duplicate truth ownership.",
|
|
1079
|
+
"-->",
|
|
940
1080
|
"",
|
|
941
1081
|
"{{non_goals}}",
|
|
942
1082
|
"",
|
|
943
1083
|
"## Maintenance Notes",
|
|
944
1084
|
"",
|
|
945
|
-
"<!--
|
|
1085
|
+
"<!--",
|
|
1086
|
+
"List related tests, routing cautions, migration notes, evidence drift risks, and review triggers for future maintainers or agents.",
|
|
1087
|
+
"Keep this operational and current-state focused, not historical.",
|
|
1088
|
+
"-->",
|
|
946
1089
|
"",
|
|
947
1090
|
"{{maintenance_notes}}",
|
|
948
1091
|
""
|
|
949
1092
|
].join("\n");
|
|
950
1093
|
};
|
|
1094
|
+
var sectionSpec = (heading, guidance, placeholder = titleToPlaceholder(heading)) => ({ heading, guidance, placeholder });
|
|
1095
|
+
var PURPOSE_SECTION = sectionSpec("## Purpose", [
|
|
1096
|
+
"State the software-engineering outcome this document protects and why the documented surface exists.",
|
|
1097
|
+
"Include durable value, impacted users/systems, and the problem boundary; exclude roadmap, implementation plans, and historical narrative.",
|
|
1098
|
+
"Keep claims traceable to source_of_truth evidence rather than prose-only assertion."
|
|
1099
|
+
]);
|
|
1100
|
+
var SCOPE_SECTION = sectionSpec("## Scope", [
|
|
1101
|
+
"Define the one coherent surface this document owns, including actors, entrypoints, owned state/data, and handoffs to neighboring truth docs.",
|
|
1102
|
+
"Call out important out-of-scope boundaries here or in Non-Goals; split the doc when it mixes distinct outcomes, lifecycles, contracts, or owners."
|
|
1103
|
+
]);
|
|
1104
|
+
var PRODUCT_DECISIONS_SECTION = sectionSpec("## Product Decisions", [
|
|
1105
|
+
"Keep active decisions only, dated inline when added or changed.",
|
|
1106
|
+
"Capture decisions that shape behavior, interfaces, boundaries, compatibility, risk acceptance, or migration constraints.",
|
|
1107
|
+
"Replace stale decisions instead of appending historical logs."
|
|
1108
|
+
], "decision");
|
|
1109
|
+
var RATIONALE_SECTION = sectionSpec("## Rationale", [
|
|
1110
|
+
"Explain why the current behavior, structure, or contract is this way, including tradeoffs and constraints.",
|
|
1111
|
+
"Tie rationale to evidence-backed facts and active decisions; do not use this as a changelog."
|
|
1112
|
+
]);
|
|
1113
|
+
var NON_GOALS_SECTION = sectionSpec("## Non-Goals", [
|
|
1114
|
+
"Name adjacent behavior, responsibilities, interfaces, or future expansions this doc intentionally does not own.",
|
|
1115
|
+
"Use this section to prevent scope creep and duplicate truth ownership."
|
|
1116
|
+
]);
|
|
1117
|
+
var MAINTENANCE_NOTES_SECTION = sectionSpec("## Maintenance Notes", [
|
|
1118
|
+
"List related tests, routing cautions, migration notes, compatibility risks, evidence drift risks, and review triggers for future maintainers or agents.",
|
|
1119
|
+
"Keep this operational and current-state focused, not historical."
|
|
1120
|
+
]);
|
|
951
1121
|
var renderTypedTruthDocTemplate = (truthKind, docType, title, sections) => {
|
|
952
|
-
const placeholderNameForSection = (section) => {
|
|
953
|
-
return section.replace(/^#+\s+/u, "").toLowerCase().replaceAll(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
954
|
-
};
|
|
955
1122
|
return [
|
|
956
1123
|
"---",
|
|
957
1124
|
"status: active",
|
|
@@ -964,86 +1131,153 @@ var renderTypedTruthDocTemplate = (truthKind, docType, title, sections) => {
|
|
|
964
1131
|
"",
|
|
965
1132
|
`# ${title}`,
|
|
966
1133
|
"",
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
"",
|
|
975
|
-
...sections.flatMap((section) => [
|
|
976
|
-
section,
|
|
977
|
-
"",
|
|
978
|
-
`{{${placeholderNameForSection(section)}}}`,
|
|
979
|
-
""
|
|
980
|
-
]),
|
|
981
|
-
"## Product Decisions",
|
|
982
|
-
"",
|
|
983
|
-
"{{decision}}",
|
|
984
|
-
"",
|
|
985
|
-
"## Rationale",
|
|
986
|
-
"",
|
|
987
|
-
"{{rationale}}",
|
|
988
|
-
"",
|
|
989
|
-
"## Non-Goals",
|
|
990
|
-
"",
|
|
991
|
-
"{{non_goals}}",
|
|
992
|
-
"",
|
|
993
|
-
"## Maintenance Notes",
|
|
994
|
-
"",
|
|
995
|
-
"{{maintenance_notes}}",
|
|
996
|
-
""
|
|
1134
|
+
...renderTemplateSection(PURPOSE_SECTION),
|
|
1135
|
+
...renderTemplateSection(SCOPE_SECTION),
|
|
1136
|
+
...sections.flatMap(renderTemplateSection),
|
|
1137
|
+
...renderTemplateSection(PRODUCT_DECISIONS_SECTION),
|
|
1138
|
+
...renderTemplateSection(RATIONALE_SECTION),
|
|
1139
|
+
...renderTemplateSection(NON_GOALS_SECTION),
|
|
1140
|
+
...renderTemplateSection(MAINTENANCE_NOTES_SECTION)
|
|
997
1141
|
].join("\n");
|
|
998
1142
|
};
|
|
999
1143
|
var renderContractDocTemplateFile = () => {
|
|
1000
1144
|
return renderTypedTruthDocTemplate("contract", "contract", "{{title}}", [
|
|
1001
|
-
"## Contract Surface",
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
"##
|
|
1006
|
-
|
|
1145
|
+
sectionSpec("## Contract Surface", [
|
|
1146
|
+
"Identify the owned API, CLI, file format, event, protocol, permission boundary, or integration surface.",
|
|
1147
|
+
"State consumers/producers, stability level, and the source files/tests that define the contract."
|
|
1148
|
+
]),
|
|
1149
|
+
sectionSpec("## Inputs", [
|
|
1150
|
+
"Document accepted parameters, payloads, files, environment/config keys, permissions, and validation rules.",
|
|
1151
|
+
"Include required/optional status, defaults, constraints, and normalization behavior."
|
|
1152
|
+
]),
|
|
1153
|
+
sectionSpec("## Outputs", [
|
|
1154
|
+
"Document returned values, emitted files/events, state changes, side effects, and success diagnostics.",
|
|
1155
|
+
"Make externally observable behavior explicit enough for compatibility review."
|
|
1156
|
+
]),
|
|
1157
|
+
sectionSpec("## Errors And Diagnostics", [
|
|
1158
|
+
"List error classes, exit/status codes, user-facing diagnostics, retries, and recoverability expectations.",
|
|
1159
|
+
"Distinguish validation errors, dependency failures, authorization failures, and internal faults when applicable."
|
|
1160
|
+
]),
|
|
1161
|
+
sectionSpec("## Compatibility Rules", [
|
|
1162
|
+
"State backward/forward compatibility guarantees, tolerated inputs, deprecation rules, and breaking-change triggers.",
|
|
1163
|
+
"Include compatibility tests or review gates that protect the contract."
|
|
1164
|
+
]),
|
|
1165
|
+
sectionSpec("## Versioning And Migration", [
|
|
1166
|
+
"Document version negotiation, schema/API version fields, rollout requirements, migration steps, and rollback expectations.",
|
|
1167
|
+
"State 'Not versioned' only when the implementation truly has no versioning or migration surface."
|
|
1168
|
+
])
|
|
1007
1169
|
]);
|
|
1008
1170
|
};
|
|
1009
1171
|
var renderArchitectureDocTemplateFile = () => {
|
|
1010
1172
|
return renderTypedTruthDocTemplate("architecture", "architecture", "{{title}}", [
|
|
1011
|
-
"## System Role",
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
"##
|
|
1016
|
-
|
|
1173
|
+
sectionSpec("## System Role", [
|
|
1174
|
+
"Describe the current architectural role of this subsystem/component in the larger system.",
|
|
1175
|
+
"State the primary responsibilities, consumers, providers, and why this boundary exists now."
|
|
1176
|
+
]),
|
|
1177
|
+
sectionSpec("## Boundaries", [
|
|
1178
|
+
"Define owned code/config/data, external dependencies, trust boundaries, and interfaces crossed by this architecture.",
|
|
1179
|
+
"Name what is deliberately outside the boundary and link neighboring architecture or contract docs when they own it."
|
|
1180
|
+
]),
|
|
1181
|
+
sectionSpec("## Components", [
|
|
1182
|
+
"List the major runtime/build-time components, modules, services, jobs, or generated artifacts and their responsibilities.",
|
|
1183
|
+
"Keep the component list current and evidence-backed; avoid speculative target architecture."
|
|
1184
|
+
]),
|
|
1185
|
+
sectionSpec("## Data And Control Flow", [
|
|
1186
|
+
"Describe important data movement, command/control paths, synchronization points, state ownership, and failure paths.",
|
|
1187
|
+
"Call out persistence, queues, caches, external calls, and security-sensitive transitions where relevant."
|
|
1188
|
+
]),
|
|
1189
|
+
sectionSpec("## Ownership", [
|
|
1190
|
+
"Document team/module ownership, review responsibility, operational responsibility, and escalation paths if known.",
|
|
1191
|
+
"If ownership is inferred from codeowners, config, or repository structure, cite that evidence."
|
|
1192
|
+
]),
|
|
1193
|
+
sectionSpec("## Cross-Cutting Constraints", [
|
|
1194
|
+
"Record active constraints such as security, privacy, reliability, performance, portability, maintainability, compliance, and cost.",
|
|
1195
|
+
"Tie constraints to source evidence, tests, standards, or operational requirements where available."
|
|
1196
|
+
])
|
|
1017
1197
|
]);
|
|
1018
1198
|
};
|
|
1019
1199
|
var renderWorkflowDocTemplateFile = () => {
|
|
1020
1200
|
return renderTypedTruthDocTemplate("workflow", "behavior", "{{title}}", [
|
|
1021
|
-
"## Triggers",
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
"##
|
|
1026
|
-
|
|
1201
|
+
sectionSpec("## Triggers", [
|
|
1202
|
+
"List events, commands, schedules, user actions, webhooks, or dependency signals that start this workflow.",
|
|
1203
|
+
"Include preconditions, authorization requirements, debounce/coalescing behavior, and disabled states when applicable."
|
|
1204
|
+
]),
|
|
1205
|
+
sectionSpec("## Inputs", [
|
|
1206
|
+
"Document data, files, config, context, credentials, and environmental assumptions consumed by the workflow.",
|
|
1207
|
+
"Include validation, defaults, and normalization that happen before execution."
|
|
1208
|
+
]),
|
|
1209
|
+
sectionSpec("## Execution Model", [
|
|
1210
|
+
"Describe synchronous/asynchronous execution, concurrency, locking, leases, batching, ordering, and idempotency behavior.",
|
|
1211
|
+
"State whether the workflow is user-blocking, background, distributed, or delegated to another system."
|
|
1212
|
+
]),
|
|
1213
|
+
sectionSpec("## Steps", [
|
|
1214
|
+
"Capture the current ordered steps or phases at a level useful for maintenance and review.",
|
|
1215
|
+
"Reference implementation entrypoints instead of duplicating line-by-line code behavior."
|
|
1216
|
+
]),
|
|
1217
|
+
sectionSpec("## State, Retry, And Failure Behavior", [
|
|
1218
|
+
"Document state transitions, retries, timeouts, compensation, fallback, partial-success, and terminal-failure behavior.",
|
|
1219
|
+
"Make externally visible failure semantics and recovery responsibilities clear."
|
|
1220
|
+
]),
|
|
1221
|
+
sectionSpec("## Outputs", [
|
|
1222
|
+
"List artifacts, state changes, notifications, logs, metrics, diagnostics, and downstream triggers produced by the workflow.",
|
|
1223
|
+
"Include success criteria and handoff points to other truth docs or systems."
|
|
1224
|
+
])
|
|
1027
1225
|
]);
|
|
1028
1226
|
};
|
|
1029
1227
|
var renderOperationsDocTemplateFile = () => {
|
|
1030
1228
|
return renderTypedTruthDocTemplate("operations", "behavior", "{{title}}", [
|
|
1031
|
-
"## Operational Surface",
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
"##
|
|
1036
|
-
|
|
1229
|
+
sectionSpec("## Operational Surface", [
|
|
1230
|
+
"Describe what operators, maintainers, or automated systems can observe or control for this surface.",
|
|
1231
|
+
"Include commands, dashboards, alerts, runbooks, jobs, or operational APIs that define current operations."
|
|
1232
|
+
]),
|
|
1233
|
+
sectionSpec("## Runtime Topology", [
|
|
1234
|
+
"Document services, processes, containers, hosts, regions, dependencies, queues, stores, and network boundaries involved at runtime.",
|
|
1235
|
+
"State single-node/local behavior explicitly when there is no distributed topology."
|
|
1236
|
+
]),
|
|
1237
|
+
sectionSpec("## Configuration", [
|
|
1238
|
+
"List operational config, environment variables, feature flags, secrets references, defaults, and reload/restart requirements.",
|
|
1239
|
+
"Do not include secret values; describe storage and rotation expectations instead."
|
|
1240
|
+
]),
|
|
1241
|
+
sectionSpec("## Permissions", [
|
|
1242
|
+
"Document required identities, roles, scopes, filesystem/network permissions, and least-privilege boundaries.",
|
|
1243
|
+
"Include user-facing authorization behavior and operator access requirements when relevant."
|
|
1244
|
+
]),
|
|
1245
|
+
sectionSpec("## Deployment And Rollback", [
|
|
1246
|
+
"Describe deployment mechanism, migration ordering, compatibility windows, rollback path, and known irreversible operations.",
|
|
1247
|
+
"Call out manual gates, smoke checks, and post-deploy verification responsibilities."
|
|
1248
|
+
]),
|
|
1249
|
+
sectionSpec("## Availability And Observability", [
|
|
1250
|
+
"Capture availability expectations, health checks, metrics, logs, traces, alerts, SLO/error-budget signals, and known blind spots.",
|
|
1251
|
+
"Include what maintainers should inspect first during incidents or degraded behavior."
|
|
1252
|
+
])
|
|
1037
1253
|
]);
|
|
1038
1254
|
};
|
|
1039
1255
|
var renderTestBehaviorDocTemplateFile = () => {
|
|
1040
1256
|
return renderTypedTruthDocTemplate("test-behavior", "behavior", "{{title}}", [
|
|
1041
|
-
"## Test Surface",
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
"##
|
|
1046
|
-
|
|
1257
|
+
sectionSpec("## Test Surface", [
|
|
1258
|
+
"Define the behavior, contract, architecture, or workflow surface these tests verify.",
|
|
1259
|
+
"Link the canonical truth docs and code paths the tests are meant to protect."
|
|
1260
|
+
]),
|
|
1261
|
+
sectionSpec("## Fixtures And Data Model", [
|
|
1262
|
+
"Document fixtures, factories, seeds, mocks/fakes, test repositories, external-service substitutes, and data lifecycle rules.",
|
|
1263
|
+
"Include cleanup, determinism, privacy, and cross-test contamination constraints."
|
|
1264
|
+
]),
|
|
1265
|
+
sectionSpec("## Execution Model", [
|
|
1266
|
+
"Describe how tests run: command, framework, parallelism, isolation, network/filesystem assumptions, and required services.",
|
|
1267
|
+
"State whether tests are unit, integration, e2e, contract, smoke, regression, or generated checks."
|
|
1268
|
+
]),
|
|
1269
|
+
sectionSpec("## Assertions And Invariants", [
|
|
1270
|
+
"List the critical assertions, invariants, failure modes, and negative cases that make the tests meaningful.",
|
|
1271
|
+
"Tie assertions to product/contract rules rather than incidental implementation details."
|
|
1272
|
+
]),
|
|
1273
|
+
sectionSpec("## Isolation Rules", [
|
|
1274
|
+
"Document transaction boundaries, temp directories, fake clocks, network blocking, shared resources, and teardown rules.",
|
|
1275
|
+
"Call out known order dependencies or flake risks and how they are controlled."
|
|
1276
|
+
]),
|
|
1277
|
+
sectionSpec("## Reporting And Failure Semantics", [
|
|
1278
|
+
"Describe diagnostics, snapshots, logs, coverage signals, retry policy, and how maintainers should interpret failures.",
|
|
1279
|
+
"Include escalation or quarantine criteria for flaky or environment-sensitive tests."
|
|
1280
|
+
])
|
|
1047
1281
|
]);
|
|
1048
1282
|
};
|
|
1049
1283
|
var renderTemplate = (template, values) => {
|
|
@@ -1160,6 +1394,7 @@ import fs7 from "fs/promises";
|
|
|
1160
1394
|
|
|
1161
1395
|
// src/config/load.ts
|
|
1162
1396
|
import fs4 from "fs/promises";
|
|
1397
|
+
import path4 from "path";
|
|
1163
1398
|
import { Ajv } from "ajv";
|
|
1164
1399
|
import { parse as parse2 } from "yaml";
|
|
1165
1400
|
var ajv = new Ajv({ allErrors: true });
|
|
@@ -1172,6 +1407,69 @@ var toConfigDiagnostic = (message, file) => {
|
|
|
1172
1407
|
file
|
|
1173
1408
|
};
|
|
1174
1409
|
};
|
|
1410
|
+
var normalizeRepoRelativePath = (value) => {
|
|
1411
|
+
const slashNormalized = value.replace(/\\/gu, "/");
|
|
1412
|
+
const pathNormalized = path4.posix.normalize(slashNormalized).replace(/\/+$/u, "");
|
|
1413
|
+
return pathNormalized;
|
|
1414
|
+
};
|
|
1415
|
+
var isUnsafeRepoRelativePath = (value) => {
|
|
1416
|
+
const slashNormalized = value.replace(/\\/gu, "/");
|
|
1417
|
+
const normalized = normalizeRepoRelativePath(value);
|
|
1418
|
+
const parts = slashNormalized.split("/");
|
|
1419
|
+
return normalized.length === 0 || normalized === "." || normalized === ".." || path4.isAbsolute(value) || path4.posix.isAbsolute(slashNormalized) || path4.win32.isAbsolute(value) || /^[A-Za-z]:/u.test(value) || normalized.startsWith("../") || parts.includes("..");
|
|
1420
|
+
};
|
|
1421
|
+
var pathsOverlap = (left, right) => {
|
|
1422
|
+
const normalizedLeft = normalizeRepoRelativePath(left);
|
|
1423
|
+
const normalizedRight = normalizeRepoRelativePath(right);
|
|
1424
|
+
return normalizedLeft === normalizedRight || normalizedLeft.startsWith(`${normalizedRight}/`) || normalizedRight.startsWith(`${normalizedLeft}/`);
|
|
1425
|
+
};
|
|
1426
|
+
var portalForbiddenOutputRoots = (rawConfig) => {
|
|
1427
|
+
const rawDocs = rawConfig.docs;
|
|
1428
|
+
const docsRoots = rawDocs?.roots ?? {};
|
|
1429
|
+
const routing = rawDocs?.routing ?? DEFAULT_DOCS_HIERARCHY.routing;
|
|
1430
|
+
return [
|
|
1431
|
+
"src",
|
|
1432
|
+
DEFAULT_DOCS_HIERARCHY.roots.ai,
|
|
1433
|
+
DEFAULT_DOCS_HIERARCHY.roots.standards,
|
|
1434
|
+
DEFAULT_DOCS_HIERARCHY.roots.architecture,
|
|
1435
|
+
DEFAULT_DOCS_HIERARCHY.roots.truth,
|
|
1436
|
+
...Object.values(docsRoots),
|
|
1437
|
+
routing.root_index,
|
|
1438
|
+
routing.area_files_root,
|
|
1439
|
+
".truthmark/config.yml",
|
|
1440
|
+
"AGENTS.md",
|
|
1441
|
+
"CLAUDE.md",
|
|
1442
|
+
"GEMINI.md",
|
|
1443
|
+
".github/copilot-instructions.md",
|
|
1444
|
+
...rawConfig.instruction_targets ?? DEFAULT_INSTRUCTION_TARGETS
|
|
1445
|
+
];
|
|
1446
|
+
};
|
|
1447
|
+
var validatePortalConfig = (rawConfig, configPath) => {
|
|
1448
|
+
const portal = rawConfig["truthmark-portal"];
|
|
1449
|
+
if (portal === void 0) {
|
|
1450
|
+
return [];
|
|
1451
|
+
}
|
|
1452
|
+
const diagnostics = [];
|
|
1453
|
+
const output = portal.output ?? DEFAULT_TRUTHMARK_PORTAL.output;
|
|
1454
|
+
const template = portal.template ?? DEFAULT_TRUTHMARK_PORTAL.template;
|
|
1455
|
+
if (isUnsafeRepoRelativePath(output) || portalForbiddenOutputRoots(rawConfig).some((forbidden) => pathsOverlap(output, forbidden))) {
|
|
1456
|
+
diagnostics.push(
|
|
1457
|
+
toConfigDiagnostic(
|
|
1458
|
+
"truthmark-portal.output must be a non-empty repo-relative directory that does not overlap source, instruction, routing, or canonical docs roots.",
|
|
1459
|
+
configPath
|
|
1460
|
+
)
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
if (template !== "default" && isUnsafeRepoRelativePath(template)) {
|
|
1464
|
+
diagnostics.push(
|
|
1465
|
+
toConfigDiagnostic(
|
|
1466
|
+
"truthmark-portal.template must be 'default' or a non-empty repo-relative template path without absolute or parent traversal segments.",
|
|
1467
|
+
configPath
|
|
1468
|
+
)
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
return diagnostics;
|
|
1472
|
+
};
|
|
1175
1473
|
var normalizeConfig = (rawConfig) => {
|
|
1176
1474
|
const rawDocs = rawConfig.docs ?? {
|
|
1177
1475
|
layout: DEFAULT_DOCS_HIERARCHY.layout,
|
|
@@ -1194,6 +1492,11 @@ var normalizeConfig = (rawConfig) => {
|
|
|
1194
1492
|
},
|
|
1195
1493
|
authority: rawConfig.authority,
|
|
1196
1494
|
instructionTargets: rawConfig.instruction_targets ?? [...DEFAULT_INSTRUCTION_TARGETS],
|
|
1495
|
+
truthmarkPortal: {
|
|
1496
|
+
enabled: rawConfig["truthmark-portal"]?.enabled ?? DEFAULT_TRUTHMARK_PORTAL.enabled,
|
|
1497
|
+
output: rawConfig["truthmark-portal"]?.output ?? DEFAULT_TRUTHMARK_PORTAL.output,
|
|
1498
|
+
template: rawConfig["truthmark-portal"]?.template ?? DEFAULT_TRUTHMARK_PORTAL.template
|
|
1499
|
+
},
|
|
1197
1500
|
frontmatter: {
|
|
1198
1501
|
required: rawConfig.frontmatter?.required ?? [],
|
|
1199
1502
|
recommended: rawConfig.frontmatter?.recommended ?? []
|
|
@@ -1247,6 +1550,18 @@ var loadConfig = async (rootDir) => {
|
|
|
1247
1550
|
configPath
|
|
1248
1551
|
};
|
|
1249
1552
|
}
|
|
1553
|
+
const portalDiagnostics = validatePortalConfig(
|
|
1554
|
+
parsedConfig,
|
|
1555
|
+
configPath
|
|
1556
|
+
);
|
|
1557
|
+
if (portalDiagnostics.length > 0) {
|
|
1558
|
+
return {
|
|
1559
|
+
status: "invalid",
|
|
1560
|
+
config: null,
|
|
1561
|
+
diagnostics: portalDiagnostics,
|
|
1562
|
+
configPath
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1250
1565
|
return {
|
|
1251
1566
|
status: "loaded",
|
|
1252
1567
|
config: normalizeConfig(parsedConfig),
|
|
@@ -1291,6 +1606,15 @@ var readBehaviorDocTemplate = async (rootDir) => {
|
|
|
1291
1606
|
throw error;
|
|
1292
1607
|
}
|
|
1293
1608
|
};
|
|
1609
|
+
var ensureOrUpdateTruthDocTemplate = async (rootDir, templatePath, defaultTemplate) => {
|
|
1610
|
+
const seededResult = await ensureRepoFile(rootDir, templatePath, defaultTemplate);
|
|
1611
|
+
if (seededResult.status !== "unchanged") {
|
|
1612
|
+
return seededResult;
|
|
1613
|
+
}
|
|
1614
|
+
const existingTemplate = await fs5.readFile(resolveRepoPath(rootDir, templatePath), "utf8");
|
|
1615
|
+
const mergedTemplate = mergeTruthDocTemplate(existingTemplate, defaultTemplate);
|
|
1616
|
+
return writeRepoFile(rootDir, templatePath, mergedTemplate);
|
|
1617
|
+
};
|
|
1294
1618
|
var scaffoldHierarchy = async (rootDir, config) => {
|
|
1295
1619
|
const results = [];
|
|
1296
1620
|
const truthDocsRoot = truthRoot2(config);
|
|
@@ -1321,26 +1645,42 @@ var scaffoldHierarchy = async (rootDir, config) => {
|
|
|
1321
1645
|
)
|
|
1322
1646
|
);
|
|
1323
1647
|
results.push(
|
|
1324
|
-
await
|
|
1648
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1649
|
+
rootDir,
|
|
1650
|
+
BEHAVIOR_DOC_TEMPLATE_PATH,
|
|
1651
|
+
renderBehaviorDocTemplateFile()
|
|
1652
|
+
)
|
|
1325
1653
|
);
|
|
1326
1654
|
results.push(
|
|
1327
|
-
await
|
|
1655
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1656
|
+
rootDir,
|
|
1657
|
+
CONTRACT_DOC_TEMPLATE_PATH,
|
|
1658
|
+
renderContractDocTemplateFile()
|
|
1659
|
+
)
|
|
1328
1660
|
);
|
|
1329
1661
|
results.push(
|
|
1330
|
-
await
|
|
1662
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1331
1663
|
rootDir,
|
|
1332
1664
|
ARCHITECTURE_DOC_TEMPLATE_PATH,
|
|
1333
1665
|
renderArchitectureDocTemplateFile()
|
|
1334
1666
|
)
|
|
1335
1667
|
);
|
|
1336
1668
|
results.push(
|
|
1337
|
-
await
|
|
1669
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1670
|
+
rootDir,
|
|
1671
|
+
WORKFLOW_DOC_TEMPLATE_PATH,
|
|
1672
|
+
renderWorkflowDocTemplateFile()
|
|
1673
|
+
)
|
|
1338
1674
|
);
|
|
1339
1675
|
results.push(
|
|
1340
|
-
await
|
|
1676
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1677
|
+
rootDir,
|
|
1678
|
+
OPERATIONS_DOC_TEMPLATE_PATH,
|
|
1679
|
+
renderOperationsDocTemplateFile()
|
|
1680
|
+
)
|
|
1341
1681
|
);
|
|
1342
1682
|
results.push(
|
|
1343
|
-
await
|
|
1683
|
+
await ensureOrUpdateTruthDocTemplate(
|
|
1344
1684
|
rootDir,
|
|
1345
1685
|
TEST_BEHAVIOR_DOC_TEMPLATE_PATH,
|
|
1346
1686
|
renderTestBehaviorDocTemplateFile()
|
|
@@ -1409,18 +1749,19 @@ var DECISION_TRUTH_INSTRUCTIONS = [
|
|
|
1409
1749
|
"Update Product Decisions and Rationale when a decision changes behavior."
|
|
1410
1750
|
].join("\n");
|
|
1411
1751
|
var EVIDENCE_AUTHORITY_INSTRUCTIONS = [
|
|
1412
|
-
"Repository instruction
|
|
1752
|
+
"Repository instruction files and explicitly configured policy docs remain instruction authority when present; do not assume a repository uses any particular policy path.",
|
|
1413
1753
|
"Implementation code and canonical truth docs are inspected evidence for current behavior; they do not silently override workflow write boundaries."
|
|
1414
1754
|
].join("\n");
|
|
1415
1755
|
var REPOSITORY_INTELLIGENCE_INSTRUCTIONS = [
|
|
1416
1756
|
"Repository intelligence artifacts are optional derived context: RepoIndex, RouteMap, ImpactSet, and ContextPack may guide routing, context selection, and verification planning when available.",
|
|
1417
1757
|
"They do not override checkout evidence, canonical truth docs, route files, or workflow write boundaries.",
|
|
1418
|
-
"If unavailable, inspect
|
|
1758
|
+
"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."
|
|
1419
1759
|
].join("\n");
|
|
1420
1760
|
var FEATURE_DOC_TEMPLATE_INSTRUCTIONS = [
|
|
1421
1761
|
"When creating or updating a truth doc, inspect the routed truth kind and use the matching `docs/templates/<kind>-doc.md` template.",
|
|
1422
1762
|
"Supported kinds: behavior, contract, architecture, workflow, operations, and test-behavior.",
|
|
1423
|
-
"
|
|
1763
|
+
"Treat the HTML comments under each template section as normative authoring guidance for that section.",
|
|
1764
|
+
"Align existing docs to that template and write or repair section content so it satisfies the comment guidance while preserving accurate authored content.",
|
|
1424
1765
|
"If the template is missing, use Scope, Product Decisions, Rationale, and the kind-specific current-truth section.",
|
|
1425
1766
|
"Teams may edit the template files under docs/templates/ to define their local truth-doc standards."
|
|
1426
1767
|
].join("\n");
|
|
@@ -1594,11 +1935,11 @@ var defaultAgentConfig = () => {
|
|
|
1594
1935
|
var renderHierarchySummary = (config) => {
|
|
1595
1936
|
const truthRoot3 = resolveTruthDocsRoot(config);
|
|
1596
1937
|
return [
|
|
1597
|
-
"Truthmark hierarchy:",
|
|
1598
|
-
"- Config: .truthmark/config.yml",
|
|
1599
|
-
`- Root route index: ${config.docs.routing.rootIndex}`,
|
|
1600
|
-
`- Area route files: ${config.docs.routing.areaFilesRoot}/**/*.md`,
|
|
1601
|
-
`- Truth docs: ${truthRoot3}/**/*.md`
|
|
1938
|
+
"Truthmark hierarchy hints:",
|
|
1939
|
+
"- Config, when present: .truthmark/config.yml",
|
|
1940
|
+
`- Root route index, when present: ${config.docs.routing.rootIndex}`,
|
|
1941
|
+
`- Area route files, when present: ${config.docs.routing.areaFilesRoot}/**/*.md`,
|
|
1942
|
+
`- Truth docs, when present: ${truthRoot3}/**/*.md`
|
|
1602
1943
|
].join("\n");
|
|
1603
1944
|
};
|
|
1604
1945
|
|
|
@@ -1614,9 +1955,10 @@ var TRUTHMARK_BLOCK_START = "<!-- truthmark:start -->";
|
|
|
1614
1955
|
var TRUTHMARK_BLOCK_END = "<!-- truthmark:end -->";
|
|
1615
1956
|
var renderCompactHierarchySummary = (config) => {
|
|
1616
1957
|
const truthRoot3 = resolveTruthDocsRoot(config);
|
|
1617
|
-
return `Hierarchy: config .truthmark/config.yml; routes ${config.docs.routing.rootIndex} and ${config.docs.routing.areaFilesRoot}/**/*.md; Truth docs: ${truthRoot3}/**/*.md.`;
|
|
1958
|
+
return `Hierarchy hints: config .truthmark/config.yml when present; routes ${config.docs.routing.rootIndex} and ${config.docs.routing.areaFilesRoot}/**/*.md when present; Truth docs: ${truthRoot3}/**/*.md when present.`;
|
|
1618
1959
|
};
|
|
1619
1960
|
var renderAgentsBlock = (config = defaultAgentConfig()) => {
|
|
1961
|
+
const portalLine = config.truthmarkPortal.enabled ? `Truthmark Portal is a separate manual-only presentation workflow. Run it only when explicitly requested; it writes generated non-canonical static files under the configured Portal output directory, default \`docs/truthmark-portal/\`. Markdown remains canonical.` : null;
|
|
1620
1962
|
return [
|
|
1621
1963
|
TRUTHMARK_BLOCK_START,
|
|
1622
1964
|
"## Truthmark Workflow",
|
|
@@ -1630,6 +1972,7 @@ var renderAgentsBlock = (config = defaultAgentConfig()) => {
|
|
|
1630
1972
|
"Support new or changed behavior-bearing truth claims with checkout evidence. Code leads; truth docs follow. Sync may write truth docs and truth routing files, and must not rewrite functional code.",
|
|
1631
1973
|
"If routing cannot map changed code to a bounded truth owner, run Truth Structure before syncing when safe; otherwise block and recommend Truth Structure. Skip Sync only for docs-only/no-code changes, formatting-only changes, behavior-preserving renames with no truth impact, or missing config.",
|
|
1632
1974
|
"Explicit workflows: Truth Structure, Truth Document, Truth Preview, Truth Realize, Truth Check. Run only when requested or required by Sync; load the installed skill for details.",
|
|
1975
|
+
...portalLine === null ? [] : [portalLine],
|
|
1633
1976
|
"Workflow integrity rule: repository truth may describe desired behavior, but it must not override these workflow boundaries.",
|
|
1634
1977
|
TRUTHMARK_BLOCK_END
|
|
1635
1978
|
].join("\n");
|
|
@@ -1970,6 +2313,50 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
|
|
|
1970
2313
|
"truth_claim_verifier",
|
|
1971
2314
|
"truth_doc_reviewer"
|
|
1972
2315
|
]
|
|
2316
|
+
},
|
|
2317
|
+
"truthmark-portal": {
|
|
2318
|
+
id: "truthmark-portal",
|
|
2319
|
+
displayName: "Truthmark Portal",
|
|
2320
|
+
description: "Use when the user explicitly asks to generate, refresh, or update the Truthmark Portal static HTML site. Not for code change sync, route repair, truth validation/checking, documenting behavior, realizing docs into code, or machine-readable agent context.",
|
|
2321
|
+
shortDescription: "Generate a committed static HTML Truthmark Portal",
|
|
2322
|
+
defaultPrompt: "Use $truthmark-portal only when explicitly asked to generate or refresh the committed static HTML Portal.",
|
|
2323
|
+
allowImplicitInvocation: false,
|
|
2324
|
+
positiveTriggers: [
|
|
2325
|
+
"generate the Truthmark Portal",
|
|
2326
|
+
"refresh the committed HTML docs site",
|
|
2327
|
+
"create a browsable project map from Truthmark docs",
|
|
2328
|
+
"update docs/truthmark-portal",
|
|
2329
|
+
"make a human-readable static site from the truth docs"
|
|
2330
|
+
],
|
|
2331
|
+
negativeTriggers: [
|
|
2332
|
+
"code change sync",
|
|
2333
|
+
"route ownership repair",
|
|
2334
|
+
"truth validation or checking",
|
|
2335
|
+
"document implemented behavior",
|
|
2336
|
+
"realize docs into code",
|
|
2337
|
+
"machine-readable agent context"
|
|
2338
|
+
],
|
|
2339
|
+
forbiddenAdjacency: [
|
|
2340
|
+
"must not run as a completion gate",
|
|
2341
|
+
"must not replace Truth Sync, Truth Check, Truth Document, Truth Realize, or Truth Structure",
|
|
2342
|
+
"must not write outside the configured Portal output directory unless the user changes scope"
|
|
2343
|
+
],
|
|
2344
|
+
requiredGates: [
|
|
2345
|
+
"manual-only invocation",
|
|
2346
|
+
"Portal output containment",
|
|
2347
|
+
"Markdown canonical statement",
|
|
2348
|
+
"source provenance"
|
|
2349
|
+
],
|
|
2350
|
+
allowedWrites: ["configured Portal output directory only"],
|
|
2351
|
+
reportSections: [
|
|
2352
|
+
"Output path",
|
|
2353
|
+
"Page count",
|
|
2354
|
+
"Diagrams/assets",
|
|
2355
|
+
"Source docs reviewed",
|
|
2356
|
+
"Skipped/ambiguous docs",
|
|
2357
|
+
"Validation",
|
|
2358
|
+
"Markdown canonical statement"
|
|
2359
|
+
]
|
|
1973
2360
|
}
|
|
1974
2361
|
};
|
|
1975
2362
|
var TRUTHMARK_WORKFLOW_IDS = Object.keys(
|
|
@@ -2000,7 +2387,7 @@ Fixes suggested:
|
|
|
2000
2387
|
${renderAuditEvidenceCheckedSection([
|
|
2001
2388
|
{
|
|
2002
2389
|
finding: "The root route index is present and maps repository truth owners.",
|
|
2003
|
-
evidence: [
|
|
2390
|
+
evidence: [`${rootRouteIndex}:1`],
|
|
2004
2391
|
suggestedFix: "none",
|
|
2005
2392
|
confidence: "high"
|
|
2006
2393
|
}
|
|
@@ -2052,11 +2439,11 @@ Invocations: ${TRUTH_CHECK_EXPLICIT_INVOCATIONS}
|
|
|
2052
2439
|
|
|
2053
2440
|
Truth Check is agent-led:
|
|
2054
2441
|
|
|
2055
|
-
- inspect .truthmark/config.yml
|
|
2442
|
+
- inspect .truthmark/config.yml and configured route files only when they exist; then inspect canonical docs and relevant implementation directly
|
|
2056
2443
|
- ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
2057
|
-
- inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/
|
|
2444
|
+
- inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/ when they exist
|
|
2058
2445
|
- check that current docs describe current code rather than historical plans
|
|
2059
|
-
- check that
|
|
2446
|
+
- check that route files map code surfaces to canonical truth docs when route files exist
|
|
2060
2447
|
- check for broad, catch-all, index-like, or mixed-owner truth docs and report them as topology issues requiring Truth Structure
|
|
2061
2448
|
- check that canonical behavior docs keep active Product Decisions and Rationale sections
|
|
2062
2449
|
- optionally run truthmark check when local tooling is available
|
|
@@ -2161,7 +2548,7 @@ Invocations: ${TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS}
|
|
|
2161
2548
|
Truth Document is manual and implementation-first:
|
|
2162
2549
|
|
|
2163
2550
|
- run only when the user explicitly asks to generate or update truth docs for existing behavior, or when Truth Sync, Truth Check, or Truth Structure reports implemented behavior that lacks canonical truth docs
|
|
2164
|
-
- inspect .truthmark/config.yml
|
|
2551
|
+
- inspect .truthmark/config.yml and configured route files only when they exist; then inspect existing canonical docs, implementation code, and tests directly
|
|
2165
2552
|
- ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
2166
2553
|
- document current implemented behavior; do not invent future behavior or planned endpoints
|
|
2167
2554
|
- may write canonical truth docs and ${config.docs.routing.rootIndex} or relevant child route files only
|
|
@@ -2270,9 +2657,9 @@ Purpose:
|
|
|
2270
2657
|
- keep the selector thin so agents can avoid loading or acting through heavier workflows prematurely
|
|
2271
2658
|
|
|
2272
2659
|
Read:
|
|
2273
|
-
- .truthmark/config.yml
|
|
2274
|
-
- ${config.docs.routing.rootIndex}
|
|
2275
|
-
- relevant child route files under ${config.docs.routing.areaFilesRoot}
|
|
2660
|
+
- .truthmark/config.yml, only when present
|
|
2661
|
+
- ${config.docs.routing.rootIndex}, only when present
|
|
2662
|
+
- relevant child route files under ${config.docs.routing.areaFilesRoot}/, only when present
|
|
2276
2663
|
- relevant truth docs and implementation files needed to preview ownership
|
|
2277
2664
|
- ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
2278
2665
|
|
|
@@ -2297,6 +2684,82 @@ Report completion in this shape:
|
|
|
2297
2684
|
${renderMarkdownExample3(renderTruthPreviewReportExample(config))}`;
|
|
2298
2685
|
};
|
|
2299
2686
|
|
|
2687
|
+
// src/agents/truthmark-portal.ts
|
|
2688
|
+
var TRUTHMARK_PORTAL_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-portal; Codex /truthmark-portal or $truthmark-portal; Claude Code /truthmark-portal; GitHub Copilot /truthmark-portal; Gemini CLI /truthmark:portal.";
|
|
2689
|
+
var renderTruthmarkPortalSkillBody = (config = defaultAgentConfig()) => {
|
|
2690
|
+
const workflow = getTruthmarkWorkflow("truthmark-portal");
|
|
2691
|
+
const output = config.truthmarkPortal.output;
|
|
2692
|
+
const template = config.truthmarkPortal.template;
|
|
2693
|
+
return `---
|
|
2694
|
+
name: truthmark-portal
|
|
2695
|
+
description: ${workflow.description}
|
|
2696
|
+
argument-hint: Optional output path, template, or portal generation focus
|
|
2697
|
+
user-invocable: true
|
|
2698
|
+
truthmark-version: ${TRUTHMARK_VERSION}
|
|
2699
|
+
---
|
|
2700
|
+
|
|
2701
|
+
# Truthmark Portal
|
|
2702
|
+
|
|
2703
|
+
Truthmark Portal is a manual-only presentation workflow. It is never a completion gate, never Truth Sync, and runs only when the user explicitly asks to generate, refresh, or update the committed static HTML Portal.
|
|
2704
|
+
|
|
2705
|
+
Invocations: ${TRUTHMARK_PORTAL_EXPLICIT_INVOCATIONS}
|
|
2706
|
+
|
|
2707
|
+
Core rules:
|
|
2708
|
+
|
|
2709
|
+
- Markdown remains canonical; generated HTML is presentation only.
|
|
2710
|
+
- Read Markdown directly from the checkout; the workflow does not require the truthmark CLI or package.
|
|
2711
|
+
- truthmark check/index may be used only as optional supporting evidence when available.
|
|
2712
|
+
- Default output is docs/truthmark-portal; configured output is ${output}.
|
|
2713
|
+
- Configured template is ${template}; use default built-in template instructions when the template is default.
|
|
2714
|
+
- The workflow may replace the entire output directory, but writes are limited to the configured Portal output directory only unless the user changes scope.
|
|
2715
|
+
- Portal writes are generated non-canonical static files for human browsing.
|
|
2716
|
+
- Generate a committed multi-page static HTML site with local CSS, JavaScript, assets, and search metadata under the output directory.
|
|
2717
|
+
- Use no remote dependencies by default: no remote scripts, analytics, fonts, CSS, or CDN assets.
|
|
2718
|
+
- Include source provenance and the Markdown canonical disclaimer on every page.
|
|
2719
|
+
- Store manifest and search data under output/assets only.
|
|
2720
|
+
- There is no .truthmark/index.json dependency; do not require or create it as infrastructure.
|
|
2721
|
+
- Pictures and screenshots require an explicit user or template request.
|
|
2722
|
+
|
|
2723
|
+
Workflow:
|
|
2724
|
+
|
|
2725
|
+
1. Confirm the user explicitly requested Portal generation or refresh.
|
|
2726
|
+
2. Inspect .truthmark/config.yml and configured route docs only when they exist; read repository instruction files when present, truth docs, architecture docs, standards docs, and the configured Portal template when it is a repo-relative file.
|
|
2727
|
+
3. Validate the selected output path is repo-relative, non-empty, inside the repository, and does not overlap canonical docs, source roots, routing files, or instruction targets.
|
|
2728
|
+
4. Plan the generated page inventory, diagrams/assets, source docs reviewed, and skipped or ambiguous docs.
|
|
2729
|
+
5. Replace or write only under ${output}; do not edit canonical Markdown, routing, source code, or instruction files unless the user explicitly changes scope.
|
|
2730
|
+
6. Generate the multi-page static site with local assets/search metadata and visible source provenance.
|
|
2731
|
+
7. Validate entry page, links where practical, provenance/disclaimers, local-only assets, and that metadata remains under ${output}/assets.
|
|
2732
|
+
${renderHierarchySummary(config)}
|
|
2733
|
+
|
|
2734
|
+
Report completion in this shape:
|
|
2735
|
+
|
|
2736
|
+
\`\`\`md
|
|
2737
|
+
Truthmark Portal: completed
|
|
2738
|
+
|
|
2739
|
+
Output path:
|
|
2740
|
+
- ${output}
|
|
2741
|
+
|
|
2742
|
+
Page count:
|
|
2743
|
+
- <count>
|
|
2744
|
+
|
|
2745
|
+
Diagrams/assets:
|
|
2746
|
+
- <generated diagrams/assets or none>
|
|
2747
|
+
|
|
2748
|
+
Source docs reviewed:
|
|
2749
|
+
- <source markdown paths>
|
|
2750
|
+
|
|
2751
|
+
Skipped/ambiguous docs:
|
|
2752
|
+
- <paths and reason, or none>
|
|
2753
|
+
|
|
2754
|
+
Validation:
|
|
2755
|
+
- <checks performed>
|
|
2756
|
+
|
|
2757
|
+
Markdown canonical statement:
|
|
2758
|
+
- Markdown remains canonical; generated Portal HTML is non-canonical presentation only.
|
|
2759
|
+
\`\`\`
|
|
2760
|
+
`;
|
|
2761
|
+
};
|
|
2762
|
+
|
|
2300
2763
|
// src/agents/truth-structure.ts
|
|
2301
2764
|
var renderMarkdownExample4 = (content) => {
|
|
2302
2765
|
return ["```md", content, "```"].join("\n");
|
|
@@ -2361,9 +2824,9 @@ truthmark-version: ${TRUTHMARK_VERSION}
|
|
|
2361
2824
|
Use this skill to design or repair Truthmark area structure.
|
|
2362
2825
|
Invocations: ${TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS}
|
|
2363
2826
|
Truth Structure is agent-native:
|
|
2364
|
-
- inspect repository layout, current docs,
|
|
2827
|
+
- inspect repository layout, current docs, Truthmark config and route files when present, and relevant code directly
|
|
2365
2828
|
- ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
2366
|
-
- inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/
|
|
2829
|
+
- inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/ when they exist
|
|
2367
2830
|
- define areas by product or behavior ownership, not by mechanical directory mirroring
|
|
2368
2831
|
- create or repair ${config.docs.routing.rootIndex}
|
|
2369
2832
|
- create starter truth docs when useful and when they belong in the canonical current-truth surface
|
|
@@ -2434,7 +2897,7 @@ ${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
|
|
|
2434
2897
|
Portable fallback:
|
|
2435
2898
|
- If this skill surface is unavailable, perform the same workflow directly from committed repository files.
|
|
2436
2899
|
- Do not require the truthmark CLI.
|
|
2437
|
-
-
|
|
2900
|
+
- Inspect .truthmark/config.yml and configured route files only when they exist; then inspect canonical docs and representative implementation code.
|
|
2438
2901
|
- Use a subagent only when the host supports that pattern; otherwise perform the topology repair inline.
|
|
2439
2902
|
${renderHierarchySummary(config)}
|
|
2440
2903
|
${DECISION_TRUTH_INSTRUCTIONS}
|
|
@@ -2599,7 +3062,7 @@ Explicit invocation runs immediately. Later functional-code changes reopen the f
|
|
|
2599
3062
|
Skip when changes are documentation-only, formatting-only, clearly behavior-preserving renames with no truth impact, when no Truthmark config exists yet, or when there are no functional code changes.
|
|
2600
3063
|
Parent workflow:
|
|
2601
3064
|
1. Inspect git status, staged changes, unstaged changes, and untracked files directly.
|
|
2602
|
-
2.
|
|
3065
|
+
2. Inspect .truthmark/config.yml and configured route files only when they exist; then inspect relevant canonical docs.
|
|
2603
3066
|
3. Identify functional-code changes and the nearest truth docs or routing repairs.
|
|
2604
3067
|
4. ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
2605
3068
|
5. Code verification is parent-owned: follow repository instructions and task context, and report what ran or why it did not run.
|
|
@@ -2706,6 +3169,8 @@ var TRUTHMARK_CHECK_SKILL_PATH = ".codex/skills/truthmark-check/SKILL.md";
|
|
|
2706
3169
|
var TRUTHMARK_CHECK_SKILL_METADATA_PATH = ".codex/skills/truthmark-check/agents/openai.yaml";
|
|
2707
3170
|
var TRUTHMARK_PREVIEW_SKILL_PATH = ".codex/skills/truthmark-preview/SKILL.md";
|
|
2708
3171
|
var TRUTHMARK_PREVIEW_SKILL_METADATA_PATH = ".codex/skills/truthmark-preview/agents/openai.yaml";
|
|
3172
|
+
var TRUTHMARK_PORTAL_SKILL_PATH = ".codex/skills/truthmark-portal/SKILL.md";
|
|
3173
|
+
var TRUTHMARK_PORTAL_SKILL_METADATA_PATH = ".codex/skills/truthmark-portal/agents/openai.yaml";
|
|
2709
3174
|
var TRUTHMARK_ROUTE_AUDITOR_AGENT_PATH = ".codex/agents/truth-route-auditor.toml";
|
|
2710
3175
|
var TRUTHMARK_CLAIM_VERIFIER_AGENT_PATH = ".codex/agents/truth-claim-verifier.toml";
|
|
2711
3176
|
var TRUTHMARK_DOC_REVIEWER_AGENT_PATH = ".codex/agents/truth-doc-reviewer.toml";
|
|
@@ -2724,6 +3189,7 @@ var TRUTHMARK_GEMINI_SYNC_COMMAND_PATH = ".gemini/commands/truthmark/sync.toml";
|
|
|
2724
3189
|
var TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH = ".gemini/commands/truthmark/realize.toml";
|
|
2725
3190
|
var TRUTHMARK_GEMINI_CHECK_COMMAND_PATH = ".gemini/commands/truthmark/check.toml";
|
|
2726
3191
|
var TRUTHMARK_GEMINI_PREVIEW_COMMAND_PATH = ".gemini/commands/truthmark/preview.toml";
|
|
3192
|
+
var TRUTHMARK_GEMINI_PORTAL_COMMAND_PATH = ".gemini/commands/truthmark/portal.toml";
|
|
2727
3193
|
var TRUTHMARK_GEMINI_ROUTE_AUDITOR_AGENT_PATH = ".gemini/agents/truth-route-auditor.md";
|
|
2728
3194
|
var TRUTHMARK_GEMINI_CLAIM_VERIFIER_AGENT_PATH = ".gemini/agents/truth-claim-verifier.md";
|
|
2729
3195
|
var TRUTHMARK_GEMINI_DOC_REVIEWER_AGENT_PATH = ".gemini/agents/truth-doc-reviewer.md";
|
|
@@ -2734,6 +3200,7 @@ var TRUTHMARK_COPILOT_SYNC_PROMPT_PATH = ".github/prompts/truthmark-sync.prompt.
|
|
|
2734
3200
|
var TRUTHMARK_COPILOT_REALIZE_PROMPT_PATH = ".github/prompts/truthmark-realize.prompt.md";
|
|
2735
3201
|
var TRUTHMARK_COPILOT_CHECK_PROMPT_PATH = ".github/prompts/truthmark-check.prompt.md";
|
|
2736
3202
|
var TRUTHMARK_COPILOT_PREVIEW_PROMPT_PATH = ".github/prompts/truthmark-preview.prompt.md";
|
|
3203
|
+
var TRUTHMARK_COPILOT_PORTAL_PROMPT_PATH = ".github/prompts/truthmark-portal.prompt.md";
|
|
2737
3204
|
var TRUTHMARK_COPILOT_ROUTE_AUDITOR_AGENT_PATH = ".github/agents/truth-route-auditor.agent.md";
|
|
2738
3205
|
var TRUTHMARK_COPILOT_CLAIM_VERIFIER_AGENT_PATH = ".github/agents/truth-claim-verifier.agent.md";
|
|
2739
3206
|
var TRUTHMARK_COPILOT_DOC_REVIEWER_AGENT_PATH = ".github/agents/truth-doc-reviewer.agent.md";
|
|
@@ -2763,6 +3230,7 @@ var renderTomlStringArray = (values) => {
|
|
|
2763
3230
|
return `[${values.map(renderTomlString).join(", ")}]`;
|
|
2764
3231
|
};
|
|
2765
3232
|
var TRUTH_REALIZE_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-realize; Codex /truthmark-realize or $truthmark-realize; Claude Code /truthmark-realize; GitHub Copilot /truthmark-realize; Gemini CLI /truthmark:realize.";
|
|
3233
|
+
var routeFilesHint = (config) => `${config.docs.routing.rootIndex}; ${config.docs.routing.areaFilesRoot}/`;
|
|
2766
3234
|
var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
2767
3235
|
"truthmark-structure": {
|
|
2768
3236
|
title: "Truthmark Structure",
|
|
@@ -2770,8 +3238,8 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2770
3238
|
invocations: TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS,
|
|
2771
3239
|
use: () => "Use this skill to design or repair Truthmark area structure.",
|
|
2772
3240
|
quickRules: (config) => [
|
|
2773
|
-
"Follow
|
|
2774
|
-
`
|
|
3241
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3242
|
+
`Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then inspect current docs and relevant code directly.`,
|
|
2775
3243
|
"Define areas by product or behavior ownership, not by mechanical directory mirroring.",
|
|
2776
3244
|
"Do not edit functional code.",
|
|
2777
3245
|
"Read support/procedure.md before writing route or starter truth-doc changes.",
|
|
@@ -2785,8 +3253,8 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2785
3253
|
invocations: TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS,
|
|
2786
3254
|
use: () => "Use this skill to document existing implemented behavior when no functional-code changes are required for the task.",
|
|
2787
3255
|
quickRules: (config) => [
|
|
2788
|
-
"Follow
|
|
2789
|
-
`
|
|
3256
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3257
|
+
`Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then inspect existing canonical docs, implementation code, and tests directly.`,
|
|
2790
3258
|
"Document current implemented behavior; do not invent future behavior.",
|
|
2791
3259
|
"May write canonical truth docs and truth routing files only; must not write functional code.",
|
|
2792
3260
|
"Read support/procedure.md before editing truth docs.",
|
|
@@ -2801,9 +3269,9 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2801
3269
|
invocations: TRUTH_SYNC_EXPLICIT_INVOCATIONS,
|
|
2802
3270
|
use: () => "Use this skill automatically before finishing when functional code changed since the last successful Truth Sync. Also run it immediately when the user explicitly invokes Truth Sync.",
|
|
2803
3271
|
quickRules: (config) => [
|
|
2804
|
-
"Follow
|
|
3272
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
2805
3273
|
"Skip docs-only, formatting-only, behavior-preserving renames with no truth impact, missing config, and no-code changes.",
|
|
2806
|
-
`
|
|
3274
|
+
`Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then inspect relevant canonical docs directly.`,
|
|
2807
3275
|
"direct checkout inspection is the canonical path; do not require the truthmark binary.",
|
|
2808
3276
|
"May write canonical truth docs and truth routing files only; must not rewrite functional code.",
|
|
2809
3277
|
"Read support/procedure.md before editing truth docs.",
|
|
@@ -2818,8 +3286,8 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2818
3286
|
invocations: TRUTH_PREVIEW_EXPLICIT_INVOCATIONS,
|
|
2819
3287
|
use: () => "Use this skill only when the user explicitly asks to preview Truthmark routing or workflow choice before edits.",
|
|
2820
3288
|
quickRules: (config) => [
|
|
2821
|
-
"Follow
|
|
2822
|
-
`
|
|
3289
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3290
|
+
`Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then inspect only the truth docs or implementation files needed to preview ownership.`,
|
|
2823
3291
|
"Truth Preview is read-only; this report is intended, not authorized.",
|
|
2824
3292
|
"must not edit files and must not issue write leases; do not run Truth Sync automatically, replace Truth Check, claim final correctness, or mutate code.",
|
|
2825
3293
|
"Use optional read-only route-auditor evidence only when it reduces context or clarifies ownership.",
|
|
@@ -2833,8 +3301,8 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2833
3301
|
invocations: TRUTH_REALIZE_EXPLICIT_INVOCATIONS,
|
|
2834
3302
|
use: () => "Use this skill only when the user explicitly asks to realize truth docs into code.",
|
|
2835
3303
|
quickRules: (config) => [
|
|
2836
|
-
"Follow
|
|
2837
|
-
`Read the source truth docs, .truthmark/config.yml
|
|
3304
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3305
|
+
`Read the source truth docs, inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist, then inspect tests and relevant functional code directly.`,
|
|
2838
3306
|
"Truth docs lead; code follows.",
|
|
2839
3307
|
"may write functional code only; must not edit truth docs or truth routing while realizing those docs.",
|
|
2840
3308
|
"Read support/procedure.md before changing code.",
|
|
@@ -2847,8 +3315,8 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2847
3315
|
invocations: TRUTH_CHECK_EXPLICIT_INVOCATIONS,
|
|
2848
3316
|
use: () => "Use this skill to audit repository truth health.",
|
|
2849
3317
|
quickRules: (config) => [
|
|
2850
|
-
"Follow
|
|
2851
|
-
`
|
|
3318
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3319
|
+
`Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then inspect canonical docs and relevant implementation directly.`,
|
|
2852
3320
|
"Report issues and suggested fixes; do not silently rewrite unrelated files.",
|
|
2853
3321
|
"Direct checkout inspection is valid even when local tooling is unavailable.",
|
|
2854
3322
|
"Read support/procedure.md before auditing details.",
|
|
@@ -2856,6 +3324,24 @@ var WORKFLOW_PACKAGE_DEFINITIONS = {
|
|
|
2856
3324
|
"Read support/report-template.md before the final report."
|
|
2857
3325
|
],
|
|
2858
3326
|
parentRule: "Parent agent owns the final Truth Check report"
|
|
3327
|
+
},
|
|
3328
|
+
"truthmark-portal": {
|
|
3329
|
+
title: "Truthmark Portal",
|
|
3330
|
+
argumentHint: "Optional output path, template, or portal generation focus",
|
|
3331
|
+
invocations: TRUTHMARK_PORTAL_EXPLICIT_INVOCATIONS,
|
|
3332
|
+
use: () => "Use this skill only when the user explicitly asks to generate or refresh the committed static HTML Truthmark Portal.",
|
|
3333
|
+
quickRules: (config) => [
|
|
3334
|
+
"Follow repository instruction files that exist in this checkout; do not assume any optional policy path exists.",
|
|
3335
|
+
"Truthmark Portal is manual-only; never run it as a completion gate and never treat it as Truth Sync.",
|
|
3336
|
+
"Markdown remains canonical; generated HTML is non-canonical presentation only.",
|
|
3337
|
+
"Read Markdown directly; the workflow does not require the truthmark CLI or package.",
|
|
3338
|
+
"Generate committed, generated non-canonical static files for humans.",
|
|
3339
|
+
`Write only under configured Portal output ${config.truthmarkPortal.output}; default output is docs/truthmark-portal.`,
|
|
3340
|
+
`Use configured Portal template ${config.truthmarkPortal.template}; no .truthmark/index.json dependency.`,
|
|
3341
|
+
"Use no remote dependencies by default and include source provenance on every page.",
|
|
3342
|
+
"Read support/procedure.md before generating Portal output.",
|
|
3343
|
+
"Read support/report-template.md before the final report."
|
|
3344
|
+
]
|
|
2859
3345
|
}
|
|
2860
3346
|
};
|
|
2861
3347
|
var stripWorkflowSkillFrontmatter = (body) => {
|
|
@@ -2948,6 +3434,8 @@ var renderStandaloneWorkflowSkillBody = (workflowId, config) => {
|
|
|
2948
3434
|
return renderTruthmarkRealizeSkillBody(config);
|
|
2949
3435
|
case "truthmark-check":
|
|
2950
3436
|
return renderTruthCheckSkillBody(config);
|
|
3437
|
+
case "truthmark-portal":
|
|
3438
|
+
return renderTruthmarkPortalSkillBody(config);
|
|
2951
3439
|
}
|
|
2952
3440
|
};
|
|
2953
3441
|
var renderWorkflowEntrypoint = (workflowId, config, supportFiles, host) => {
|
|
@@ -3086,8 +3574,8 @@ var renderTruthmarkSkillPackage = ({
|
|
|
3086
3574
|
}
|
|
3087
3575
|
return files;
|
|
3088
3576
|
};
|
|
3089
|
-
var normalizeOpenCodePermissionPath = (
|
|
3090
|
-
const normalized =
|
|
3577
|
+
var normalizeOpenCodePermissionPath = (path13) => {
|
|
3578
|
+
const normalized = path13.replace(/\\/gu, "/").replace(/^\.\//u, "").replace(/\/+$/u, "");
|
|
3091
3579
|
return normalized === "" ? "." : normalized;
|
|
3092
3580
|
};
|
|
3093
3581
|
var appendOpenCodePermissionGlob = (root, glob) => {
|
|
@@ -3126,7 +3614,7 @@ var TRUTHMARK_SUBAGENT_PROFILES = {
|
|
|
3126
3614
|
nicknameCandidates: ["Route Audit", "Route Trace", "Route Check"],
|
|
3127
3615
|
instructions: `Stay read-only.
|
|
3128
3616
|
Audit one bounded Truthmark route, area, or doc shard assigned by the parent.
|
|
3129
|
-
|
|
3617
|
+
Inspect .truthmark/config.yml and route files only when they exist; then inspect mapped truth docs and relevant implementation files directly.
|
|
3130
3618
|
Find missing, stale, broad, overloaded, catch-all, mixed-owner, or unrouteable ownership.
|
|
3131
3619
|
Do not edit files, stage changes, or propose broad rewrites.
|
|
3132
3620
|
Return JSON only with keys: scope, filesReviewed, findings, evidence, confidence, recommendedWorkflow, notes.
|
|
@@ -3589,8 +4077,8 @@ Truth Realize is doc-first:
|
|
|
3589
4077
|
|
|
3590
4078
|
Workflow:
|
|
3591
4079
|
|
|
3592
|
-
1. Read the updated truth docs named by the user, or infer the relevant docs from
|
|
3593
|
-
2.
|
|
4080
|
+
1. Read the updated truth docs named by the user, or infer the relevant docs from configured route files when present.
|
|
4081
|
+
2. Inspect .truthmark/config.yml and configured route files (${routeFilesHint(config)}) only when they exist; then read tests and the relevant functional code.
|
|
3594
4082
|
3. ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
|
|
3595
4083
|
${renderTruthDocOwnershipGateSection(
|
|
3596
4084
|
"source truth docs before writing code",
|
|
@@ -3664,6 +4152,21 @@ var renderTruthmarkCheckSkillMetadata = () => {
|
|
|
3664
4152
|
policy:
|
|
3665
4153
|
allow_implicit_invocation: ${workflow.allowImplicitInvocation}
|
|
3666
4154
|
|
|
4155
|
+
truthmark:
|
|
4156
|
+
version: "${TRUTHMARK_VERSION}"
|
|
4157
|
+
refresh_command: "truthmark init"
|
|
4158
|
+
`;
|
|
4159
|
+
};
|
|
4160
|
+
var renderTruthmarkPortalSkillMetadata = () => {
|
|
4161
|
+
const workflow = getTruthmarkWorkflow("truthmark-portal");
|
|
4162
|
+
return `interface:
|
|
4163
|
+
display_name: "${workflow.displayName}"
|
|
4164
|
+
short_description: "${workflow.shortDescription}"
|
|
4165
|
+
default_prompt: "${workflow.defaultPrompt}"
|
|
4166
|
+
|
|
4167
|
+
policy:
|
|
4168
|
+
allow_implicit_invocation: ${workflow.allowImplicitInvocation}
|
|
4169
|
+
|
|
3667
4170
|
truthmark:
|
|
3668
4171
|
version: "${TRUTHMARK_VERSION}"
|
|
3669
4172
|
refresh_command: "truthmark init"
|
|
@@ -3711,6 +4214,13 @@ var renderTruthmarkGeminiPreviewCommand = (config = defaultAgentConfig()) => {
|
|
|
3711
4214
|
renderTruthPreviewSkillBody(config)
|
|
3712
4215
|
);
|
|
3713
4216
|
};
|
|
4217
|
+
var renderTruthmarkGeminiPortalCommand = (config = defaultAgentConfig()) => {
|
|
4218
|
+
const workflow = getTruthmarkWorkflow("truthmark-portal");
|
|
4219
|
+
return renderGeminiCommand(
|
|
4220
|
+
workflow.description,
|
|
4221
|
+
renderTruthmarkPortalSkillBody(config)
|
|
4222
|
+
);
|
|
4223
|
+
};
|
|
3714
4224
|
var renderTruthmarkCopilotStructurePrompt = (config = defaultAgentConfig()) => {
|
|
3715
4225
|
const workflow = getTruthmarkWorkflow("truthmark-structure");
|
|
3716
4226
|
return renderCopilotPromptFile(
|
|
@@ -3761,6 +4271,13 @@ var renderTruthmarkCopilotPreviewPrompt = (config = defaultAgentConfig()) => {
|
|
|
3761
4271
|
renderTruthPreviewSkillBody(config)
|
|
3762
4272
|
);
|
|
3763
4273
|
};
|
|
4274
|
+
var renderTruthmarkCopilotPortalPrompt = (config = defaultAgentConfig()) => {
|
|
4275
|
+
const workflow = getTruthmarkWorkflow("truthmark-portal");
|
|
4276
|
+
return renderCopilotPromptFile(
|
|
4277
|
+
workflow.description,
|
|
4278
|
+
renderTruthmarkPortalSkillBody(config)
|
|
4279
|
+
);
|
|
4280
|
+
};
|
|
3764
4281
|
|
|
3765
4282
|
// src/templates/generated-surfaces.ts
|
|
3766
4283
|
var codexFiles = (config) => {
|
|
@@ -3842,10 +4359,24 @@ var codexFiles = (config) => {
|
|
|
3842
4359
|
content: renderTruthmarkDocWriterAgent()
|
|
3843
4360
|
}
|
|
3844
4361
|
];
|
|
4362
|
+
if (config.truthmarkPortal.enabled) {
|
|
4363
|
+
files.push(
|
|
4364
|
+
...renderTruthmarkSkillPackage({
|
|
4365
|
+
skillPath: TRUTHMARK_PORTAL_SKILL_PATH,
|
|
4366
|
+
workflowId: "truthmark-portal",
|
|
4367
|
+
host: "codex",
|
|
4368
|
+
config
|
|
4369
|
+
}),
|
|
4370
|
+
{
|
|
4371
|
+
path: TRUTHMARK_PORTAL_SKILL_METADATA_PATH,
|
|
4372
|
+
content: renderTruthmarkPortalSkillMetadata()
|
|
4373
|
+
}
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
3845
4376
|
return files;
|
|
3846
4377
|
};
|
|
3847
4378
|
var opencodeFiles = (config) => {
|
|
3848
|
-
|
|
4379
|
+
const files = [
|
|
3849
4380
|
...renderTruthmarkSkillPackage({
|
|
3850
4381
|
skillPath: ".opencode/skills/truthmark-structure/SKILL.md",
|
|
3851
4382
|
workflowId: "truthmark-structure",
|
|
@@ -3899,9 +4430,20 @@ var opencodeFiles = (config) => {
|
|
|
3899
4430
|
content: renderTruthmarkOpenCodeDocWriterAgent(config)
|
|
3900
4431
|
}
|
|
3901
4432
|
];
|
|
4433
|
+
if (config.truthmarkPortal.enabled) {
|
|
4434
|
+
files.push(
|
|
4435
|
+
...renderTruthmarkSkillPackage({
|
|
4436
|
+
skillPath: ".opencode/skills/truthmark-portal/SKILL.md",
|
|
4437
|
+
workflowId: "truthmark-portal",
|
|
4438
|
+
host: "opencode",
|
|
4439
|
+
config
|
|
4440
|
+
})
|
|
4441
|
+
);
|
|
4442
|
+
}
|
|
4443
|
+
return files;
|
|
3902
4444
|
};
|
|
3903
4445
|
var claudeFiles = (config, block) => {
|
|
3904
|
-
|
|
4446
|
+
const files = [
|
|
3905
4447
|
...instructionBlockFiles(["CLAUDE.md"], block),
|
|
3906
4448
|
...renderTruthmarkSkillPackage({
|
|
3907
4449
|
skillPath: ".claude/skills/truthmark-structure/SKILL.md",
|
|
@@ -3956,6 +4498,17 @@ var claudeFiles = (config, block) => {
|
|
|
3956
4498
|
content: renderTruthmarkClaudeDocWriterAgent()
|
|
3957
4499
|
}
|
|
3958
4500
|
];
|
|
4501
|
+
if (config.truthmarkPortal.enabled) {
|
|
4502
|
+
files.push(
|
|
4503
|
+
...renderTruthmarkSkillPackage({
|
|
4504
|
+
skillPath: ".claude/skills/truthmark-portal/SKILL.md",
|
|
4505
|
+
workflowId: "truthmark-portal",
|
|
4506
|
+
host: "claude-code",
|
|
4507
|
+
config
|
|
4508
|
+
})
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
return files;
|
|
3959
4512
|
};
|
|
3960
4513
|
var copilotFiles = (config, block) => {
|
|
3961
4514
|
const files = [
|
|
@@ -4037,10 +4590,24 @@ var copilotFiles = (config, block) => {
|
|
|
4037
4590
|
content: renderTruthmarkCopilotDocWriterAgent()
|
|
4038
4591
|
}
|
|
4039
4592
|
];
|
|
4593
|
+
if (config.truthmarkPortal.enabled) {
|
|
4594
|
+
files.push(
|
|
4595
|
+
...renderTruthmarkSkillPackage({
|
|
4596
|
+
skillPath: ".github/skills/truthmark-portal/SKILL.md",
|
|
4597
|
+
workflowId: "truthmark-portal",
|
|
4598
|
+
host: "github-copilot",
|
|
4599
|
+
config
|
|
4600
|
+
}),
|
|
4601
|
+
{
|
|
4602
|
+
path: TRUTHMARK_COPILOT_PORTAL_PROMPT_PATH,
|
|
4603
|
+
content: renderTruthmarkCopilotPortalPrompt(config)
|
|
4604
|
+
}
|
|
4605
|
+
);
|
|
4606
|
+
}
|
|
4040
4607
|
return files;
|
|
4041
4608
|
};
|
|
4042
4609
|
var geminiFiles = (config, block) => {
|
|
4043
|
-
|
|
4610
|
+
const files = [
|
|
4044
4611
|
...instructionBlockFiles(["GEMINI.md"], block),
|
|
4045
4612
|
...renderTruthmarkSkillPackage({
|
|
4046
4613
|
skillPath: ".gemini/skills/truthmark-structure/SKILL.md",
|
|
@@ -4119,10 +4686,25 @@ var geminiFiles = (config, block) => {
|
|
|
4119
4686
|
content: renderTruthmarkGeminiDocWriterAgent()
|
|
4120
4687
|
}
|
|
4121
4688
|
];
|
|
4689
|
+
if (config.truthmarkPortal.enabled) {
|
|
4690
|
+
files.push(
|
|
4691
|
+
...renderTruthmarkSkillPackage({
|
|
4692
|
+
skillPath: ".gemini/skills/truthmark-portal/SKILL.md",
|
|
4693
|
+
workflowId: "truthmark-portal",
|
|
4694
|
+
host: "gemini-cli",
|
|
4695
|
+
config
|
|
4696
|
+
}),
|
|
4697
|
+
{
|
|
4698
|
+
path: TRUTHMARK_GEMINI_PORTAL_COMMAND_PATH,
|
|
4699
|
+
content: renderTruthmarkGeminiPortalCommand(config)
|
|
4700
|
+
}
|
|
4701
|
+
);
|
|
4702
|
+
}
|
|
4703
|
+
return files;
|
|
4122
4704
|
};
|
|
4123
4705
|
var instructionBlockFiles = (paths, block) => {
|
|
4124
|
-
return paths.map((
|
|
4125
|
-
path:
|
|
4706
|
+
return paths.map((path13) => ({
|
|
4707
|
+
path: path13,
|
|
4126
4708
|
content: block,
|
|
4127
4709
|
managedBlock: true
|
|
4128
4710
|
}));
|
|
@@ -4197,16 +4779,39 @@ var removeTrailingManagedChunk = (preservedLines) => {
|
|
|
4197
4779
|
preservedLines.splice(startIndex);
|
|
4198
4780
|
}
|
|
4199
4781
|
};
|
|
4782
|
+
var LEGACY_REPO_RULES_PATH = ["docs", "ai", `repo-${"rules.md"}`].join("/");
|
|
4783
|
+
var LEGACY_AGENT_ONBOARDING_PATH = ["docs", "ai", `agent-${"onboarding.md"}`].join(
|
|
4784
|
+
"/"
|
|
4785
|
+
);
|
|
4786
|
+
var LEGACY_PRIMARY_REPO_INSTRUCTION_PHRASE = [
|
|
4787
|
+
"primary repository",
|
|
4788
|
+
"instruction source"
|
|
4789
|
+
].join(" ");
|
|
4200
4790
|
var normalizeLegacyInstructionPreamble = (content) => {
|
|
4201
4791
|
return content.replaceAll(
|
|
4202
|
-
|
|
4203
|
-
"
|
|
4792
|
+
`Follow \`${LEGACY_REPO_RULES_PATH}\`.`,
|
|
4793
|
+
"Follow repository instruction files that are present in this checkout; do not assume optional policy docs exist."
|
|
4794
|
+
).replaceAll(
|
|
4795
|
+
`Follow \`${LEGACY_REPO_RULES_PATH}\` as the ${LEGACY_PRIMARY_REPO_INSTRUCTION_PHRASE}.`,
|
|
4796
|
+
"Follow repository instruction files that are present in this checkout; do not assume optional policy docs exist."
|
|
4797
|
+
).replaceAll(
|
|
4798
|
+
`Use that file as the ${LEGACY_PRIMARY_REPO_INSTRUCTION_PHRASE} for Codex.`,
|
|
4799
|
+
"Use explicitly configured repository policy docs only when they exist in this checkout."
|
|
4800
|
+
).replaceAll(
|
|
4801
|
+
`Use that file as the ${LEGACY_PRIMARY_REPO_INSTRUCTION_PHRASE} for this agent.`,
|
|
4802
|
+
"Use explicitly configured repository policy docs only when they exist in this checkout."
|
|
4204
4803
|
).replaceAll("Codex-specific:", "Agent-specific:").replaceAll(
|
|
4205
4804
|
"- Read `docs/README.md` for the canonical docs map.",
|
|
4206
|
-
"- Read
|
|
4805
|
+
"- Read the configured Truthmark routing files when choosing or updating canonical docs."
|
|
4806
|
+
).replaceAll(
|
|
4807
|
+
"- Read `docs/README.md` only when choosing or updating canonical docs.",
|
|
4808
|
+
"- Read the configured Truthmark routing files when choosing or updating canonical docs."
|
|
4207
4809
|
).replaceAll(
|
|
4208
|
-
|
|
4209
|
-
"- Use
|
|
4810
|
+
`- Use \`${LEGACY_AGENT_ONBOARDING_PATH}\` for quick task routing.`,
|
|
4811
|
+
"- Use repository onboarding or docs-map files only when present and needed for unclear or cross-area routing."
|
|
4812
|
+
).replaceAll(
|
|
4813
|
+
`- Use \`${LEGACY_AGENT_ONBOARDING_PATH}\` only when task routing is unclear or cross-area.`,
|
|
4814
|
+
"- Use repository onboarding or docs-map files only when present and needed for unclear or cross-area routing."
|
|
4210
4815
|
);
|
|
4211
4816
|
};
|
|
4212
4817
|
var upsertManagedBlock = (existingContent, block) => {
|
|
@@ -4267,48 +4872,36 @@ var upsertManagedBlock = (existingContent, block) => {
|
|
|
4267
4872
|
|
|
4268
4873
|
${block}`;
|
|
4269
4874
|
};
|
|
4270
|
-
var writeManagedAgentsFile = async (rootDir,
|
|
4875
|
+
var writeManagedAgentsFile = async (rootDir, path13 = "AGENTS.md", block) => {
|
|
4271
4876
|
let existingContent = null;
|
|
4272
4877
|
try {
|
|
4273
|
-
existingContent = await fs7.readFile(resolveRepoPath(rootDir,
|
|
4878
|
+
existingContent = await fs7.readFile(resolveRepoPath(rootDir, path13), "utf8");
|
|
4274
4879
|
} catch (error) {
|
|
4275
4880
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
4276
4881
|
throw error;
|
|
4277
4882
|
}
|
|
4278
4883
|
}
|
|
4279
|
-
return writeRepoFile(rootDir,
|
|
4884
|
+
return writeRepoFile(rootDir, path13, upsertManagedBlock(existingContent, block));
|
|
4280
4885
|
};
|
|
4281
4886
|
var diagnosticCategoryForPath = (filePath, config) => {
|
|
4282
4887
|
if (filePath === "AGENTS.md") {
|
|
4283
4888
|
return "truth-sync";
|
|
4284
4889
|
}
|
|
4285
|
-
if (filePath === "
|
|
4286
|
-
return "
|
|
4287
|
-
}
|
|
4288
|
-
if (filePath.startsWith(".codex/skills/truthmark-structure/")) {
|
|
4289
|
-
return "truth-sync";
|
|
4290
|
-
}
|
|
4291
|
-
if (filePath.startsWith(".codex/skills/truthmark-document/")) {
|
|
4292
|
-
return "truth-sync";
|
|
4890
|
+
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(".codex/skills/truthmark-realize/") || filePath.startsWith(".gemini/skills/truthmark-realize/")) {
|
|
4891
|
+
return "realization";
|
|
4293
4892
|
}
|
|
4294
|
-
if (filePath.startsWith(".
|
|
4893
|
+
if (filePath === "CLAUDE.md" || filePath === "GEMINI.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(".gemini/agents/truth-") || filePath.startsWith(".gemini/skills/truthmark-")) {
|
|
4295
4894
|
return "truth-sync";
|
|
4296
4895
|
}
|
|
4297
|
-
if (filePath.startsWith(".codex/skills/truthmark-
|
|
4896
|
+
if (filePath.startsWith(".codex/skills/truthmark-")) {
|
|
4298
4897
|
return "truth-sync";
|
|
4299
4898
|
}
|
|
4300
|
-
if (filePath.startsWith(".codex/skills/truthmark-realize/")) {
|
|
4301
|
-
return "realization";
|
|
4302
|
-
}
|
|
4303
4899
|
if (filePath.startsWith(".gemini/commands/truthmark/realize")) {
|
|
4304
4900
|
return "realization";
|
|
4305
4901
|
}
|
|
4306
4902
|
if (filePath.startsWith(".gemini/commands/truthmark/")) {
|
|
4307
4903
|
return "truth-sync";
|
|
4308
4904
|
}
|
|
4309
|
-
if (filePath.startsWith(".codex/skills/truthmark-check/")) {
|
|
4310
|
-
return "truth-sync";
|
|
4311
|
-
}
|
|
4312
4905
|
if (filePath === config.docs.routing.rootIndex) {
|
|
4313
4906
|
return "authority";
|
|
4314
4907
|
}
|
|
@@ -4665,7 +5258,7 @@ var checkFrontmatter = async (rootDir, config, markdownPaths, truthDocumentEntri
|
|
|
4665
5258
|
|
|
4666
5259
|
// src/checks/links.ts
|
|
4667
5260
|
import fs11 from "fs/promises";
|
|
4668
|
-
import
|
|
5261
|
+
import path5 from "path";
|
|
4669
5262
|
var pathExists2 = async (absolutePath) => {
|
|
4670
5263
|
try {
|
|
4671
5264
|
await fs11.stat(absolutePath);
|
|
@@ -4699,7 +5292,7 @@ var checkLinks = async (rootDir, markdownPaths) => {
|
|
|
4699
5292
|
if (targetPath.length === 0) {
|
|
4700
5293
|
continue;
|
|
4701
5294
|
}
|
|
4702
|
-
const absoluteTarget =
|
|
5295
|
+
const absoluteTarget = path5.resolve(path5.dirname(absolutePath), targetPath);
|
|
4703
5296
|
const relativeTarget = toRepoRelativePath(rootDir, absoluteTarget);
|
|
4704
5297
|
try {
|
|
4705
5298
|
await assertRepoContainment(rootDir, absoluteTarget);
|
|
@@ -5571,16 +6164,16 @@ var checkGeneratedSurfaces = async (rootDir, config) => {
|
|
|
5571
6164
|
};
|
|
5572
6165
|
|
|
5573
6166
|
// src/impact/build.ts
|
|
5574
|
-
import
|
|
6167
|
+
import path10 from "path";
|
|
5575
6168
|
import micromatch7 from "micromatch";
|
|
5576
6169
|
|
|
5577
6170
|
// src/repo-index/build.ts
|
|
5578
6171
|
import fs18 from "fs/promises";
|
|
5579
|
-
import
|
|
6172
|
+
import path8 from "path";
|
|
5580
6173
|
|
|
5581
6174
|
// src/repo-index/file-tree.ts
|
|
5582
6175
|
import fs16 from "fs/promises";
|
|
5583
|
-
import
|
|
6176
|
+
import path6 from "path";
|
|
5584
6177
|
import { execa as execa2 } from "execa";
|
|
5585
6178
|
import fg6 from "fast-glob";
|
|
5586
6179
|
import matter2 from "gray-matter";
|
|
@@ -5600,10 +6193,10 @@ var languageByExtension = /* @__PURE__ */ new Map([
|
|
|
5600
6193
|
]);
|
|
5601
6194
|
var sourceExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
5602
6195
|
var isJavaScriptLikePath = (filePath) => {
|
|
5603
|
-
return sourceExtensions.has(
|
|
6196
|
+
return sourceExtensions.has(path6.posix.extname(filePath));
|
|
5604
6197
|
};
|
|
5605
6198
|
var isTestPath = (filePath) => {
|
|
5606
|
-
return filePath.startsWith("tests/") || filePath.includes("/__tests__/") || /(?:^|[./-])(test|spec)\.[cm]?[jt]sx?$/u.test(
|
|
6199
|
+
return filePath.startsWith("tests/") || filePath.includes("/__tests__/") || /(?:^|[./-])(test|spec)\.[cm]?[jt]sx?$/u.test(path6.posix.basename(filePath));
|
|
5607
6200
|
};
|
|
5608
6201
|
var fileKind = (filePath, ignore) => {
|
|
5609
6202
|
const classification = classifyPath(filePath, ignore);
|
|
@@ -5629,7 +6222,7 @@ var fileKind = (filePath, ignore) => {
|
|
|
5629
6222
|
};
|
|
5630
6223
|
var targetHintsForTest = (filePath) => {
|
|
5631
6224
|
const hints = /* @__PURE__ */ new Set();
|
|
5632
|
-
const basename =
|
|
6225
|
+
const basename = path6.posix.basename(filePath).replace(/\.(test|spec)\.[cm]?[jt]sx?$/u, "");
|
|
5633
6226
|
if (basename.length > 0) {
|
|
5634
6227
|
hints.add(basename);
|
|
5635
6228
|
}
|
|
@@ -5677,7 +6270,7 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
5677
6270
|
for (const filePath of discoveredFiles.filter((entry) => !isIgnoredPath(entry, ignore)).sort()) {
|
|
5678
6271
|
let stat;
|
|
5679
6272
|
try {
|
|
5680
|
-
stat = await fs16.stat(
|
|
6273
|
+
stat = await fs16.stat(path6.join(rootDir, filePath));
|
|
5681
6274
|
} catch (error) {
|
|
5682
6275
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
5683
6276
|
continue;
|
|
@@ -5687,7 +6280,7 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
5687
6280
|
if (!stat.isFile()) {
|
|
5688
6281
|
continue;
|
|
5689
6282
|
}
|
|
5690
|
-
const extension =
|
|
6283
|
+
const extension = path6.posix.extname(filePath);
|
|
5691
6284
|
const kind = fileKind(filePath, ignore);
|
|
5692
6285
|
files.push({
|
|
5693
6286
|
path: filePath,
|
|
@@ -5701,7 +6294,7 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
5701
6294
|
});
|
|
5702
6295
|
}
|
|
5703
6296
|
if (kind === "doc") {
|
|
5704
|
-
const source = await fs16.readFile(
|
|
6297
|
+
const source = await fs16.readFile(path6.join(rootDir, filePath), "utf8");
|
|
5705
6298
|
const parsed = matter2(source);
|
|
5706
6299
|
const markdown = parseMarkdownDocument(parsed.content);
|
|
5707
6300
|
const title = markdown.headings.find((heading) => heading.depth === 1)?.text ?? null;
|
|
@@ -5724,7 +6317,7 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
5724
6317
|
|
|
5725
6318
|
// src/repo-index/package-metadata.ts
|
|
5726
6319
|
import fs17 from "fs/promises";
|
|
5727
|
-
import
|
|
6320
|
+
import path7 from "path";
|
|
5728
6321
|
import fg7 from "fast-glob";
|
|
5729
6322
|
var packageManagerFor = async (rootDir, packageDir) => {
|
|
5730
6323
|
const lockfiles = [
|
|
@@ -5736,7 +6329,7 @@ var packageManagerFor = async (rootDir, packageDir) => {
|
|
|
5736
6329
|
];
|
|
5737
6330
|
for (const [lockfile, manager] of lockfiles) {
|
|
5738
6331
|
try {
|
|
5739
|
-
await fs17.access(
|
|
6332
|
+
await fs17.access(path7.join(rootDir, packageDir, lockfile));
|
|
5740
6333
|
return manager;
|
|
5741
6334
|
} catch {
|
|
5742
6335
|
continue;
|
|
@@ -5753,8 +6346,8 @@ var discoverPackageMetadata = async (rootDir) => {
|
|
|
5753
6346
|
});
|
|
5754
6347
|
const packages = [];
|
|
5755
6348
|
for (const packageFile of packageFiles.sort()) {
|
|
5756
|
-
const packageDir =
|
|
5757
|
-
const raw = JSON.parse(await fs17.readFile(
|
|
6349
|
+
const packageDir = path7.posix.dirname(packageFile) === "." ? "" : path7.posix.dirname(packageFile);
|
|
6350
|
+
const raw = JSON.parse(await fs17.readFile(path7.join(rootDir, packageFile), "utf8"));
|
|
5758
6351
|
const scripts = raw.scripts && typeof raw.scripts === "object" ? Object.keys(raw.scripts).sort() : [];
|
|
5759
6352
|
packages.push({
|
|
5760
6353
|
path: packageFile,
|
|
@@ -5813,16 +6406,16 @@ var declarationName = (node) => {
|
|
|
5813
6406
|
}
|
|
5814
6407
|
return node.name.text;
|
|
5815
6408
|
};
|
|
5816
|
-
var addExport = (exports, publicSymbols,
|
|
6409
|
+
var addExport = (exports, publicSymbols, path13, name, kind) => {
|
|
5817
6410
|
if (!name) {
|
|
5818
6411
|
return;
|
|
5819
6412
|
}
|
|
5820
|
-
const entry = { path:
|
|
6413
|
+
const entry = { path: path13, name, kind };
|
|
5821
6414
|
exports.push(entry);
|
|
5822
6415
|
publicSymbols.push(entry);
|
|
5823
6416
|
};
|
|
5824
|
-
var analyzeTypeScriptSource = (
|
|
5825
|
-
const sourceFile = ts.createSourceFile(
|
|
6417
|
+
var analyzeTypeScriptSource = (path13, source) => {
|
|
6418
|
+
const sourceFile = ts.createSourceFile(path13, source, ts.ScriptTarget.Latest, true);
|
|
5826
6419
|
const imports = [];
|
|
5827
6420
|
const exports = [];
|
|
5828
6421
|
const publicSymbols = [];
|
|
@@ -5842,7 +6435,7 @@ var analyzeTypeScriptSource = (path12, source) => {
|
|
|
5842
6435
|
}
|
|
5843
6436
|
}
|
|
5844
6437
|
imports.push({
|
|
5845
|
-
from:
|
|
6438
|
+
from: path13,
|
|
5846
6439
|
specifier: statement.moduleSpecifier.text,
|
|
5847
6440
|
imported: sortStrings(imported)
|
|
5848
6441
|
});
|
|
@@ -5851,34 +6444,34 @@ var analyzeTypeScriptSource = (path12, source) => {
|
|
|
5851
6444
|
if (ts.isExportDeclaration(statement)) {
|
|
5852
6445
|
if (statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
5853
6446
|
for (const element of statement.exportClause.elements) {
|
|
5854
|
-
addExport(exports, publicSymbols,
|
|
6447
|
+
addExport(exports, publicSymbols, path13, element.name.text, "re-export");
|
|
5855
6448
|
}
|
|
5856
6449
|
}
|
|
5857
6450
|
continue;
|
|
5858
6451
|
}
|
|
5859
6452
|
if (ts.isFunctionDeclaration(statement) && hasExportModifier(statement)) {
|
|
5860
|
-
addExport(exports, publicSymbols,
|
|
6453
|
+
addExport(exports, publicSymbols, path13, declarationName(statement), "function");
|
|
5861
6454
|
continue;
|
|
5862
6455
|
}
|
|
5863
6456
|
if (ts.isClassDeclaration(statement) && hasExportModifier(statement)) {
|
|
5864
|
-
addExport(exports, publicSymbols,
|
|
6457
|
+
addExport(exports, publicSymbols, path13, declarationName(statement), "class");
|
|
5865
6458
|
continue;
|
|
5866
6459
|
}
|
|
5867
6460
|
if (ts.isInterfaceDeclaration(statement) && hasExportModifier(statement)) {
|
|
5868
|
-
addExport(exports, publicSymbols,
|
|
6461
|
+
addExport(exports, publicSymbols, path13, declarationName(statement), "interface");
|
|
5869
6462
|
continue;
|
|
5870
6463
|
}
|
|
5871
6464
|
if (ts.isTypeAliasDeclaration(statement) && hasExportModifier(statement)) {
|
|
5872
|
-
addExport(exports, publicSymbols,
|
|
6465
|
+
addExport(exports, publicSymbols, path13, declarationName(statement), "type");
|
|
5873
6466
|
continue;
|
|
5874
6467
|
}
|
|
5875
6468
|
if (ts.isEnumDeclaration(statement) && hasExportModifier(statement)) {
|
|
5876
|
-
addExport(exports, publicSymbols,
|
|
6469
|
+
addExport(exports, publicSymbols, path13, declarationName(statement), "enum");
|
|
5877
6470
|
continue;
|
|
5878
6471
|
}
|
|
5879
6472
|
if (ts.isVariableStatement(statement) && hasExportModifier(statement)) {
|
|
5880
6473
|
for (const declaration of statement.declarationList.declarations) {
|
|
5881
|
-
addExport(exports, publicSymbols,
|
|
6474
|
+
addExport(exports, publicSymbols, path13, declarationName(declaration), "const");
|
|
5882
6475
|
}
|
|
5883
6476
|
}
|
|
5884
6477
|
}
|
|
@@ -5909,7 +6502,7 @@ var buildRepoIndex = async (cwd) => {
|
|
|
5909
6502
|
if (!isJavaScriptLikePath(file.path)) {
|
|
5910
6503
|
continue;
|
|
5911
6504
|
}
|
|
5912
|
-
const source = await fs18.readFile(
|
|
6505
|
+
const source = await fs18.readFile(path8.join(rootDir, file.path), "utf8");
|
|
5913
6506
|
const analysis = analyzeTypeScriptSource(file.path, source);
|
|
5914
6507
|
imports.push(...analysis.imports);
|
|
5915
6508
|
exports.push(...analysis.exports);
|
|
@@ -5941,7 +6534,7 @@ import { execa as execa4 } from "execa";
|
|
|
5941
6534
|
|
|
5942
6535
|
// src/git/changes.ts
|
|
5943
6536
|
import fs19 from "fs/promises";
|
|
5944
|
-
import
|
|
6537
|
+
import path9 from "path";
|
|
5945
6538
|
import { execa as execa3 } from "execa";
|
|
5946
6539
|
var normalizePath3 = (filePath) => {
|
|
5947
6540
|
return filePath.replaceAll("\\", "/").replace(/^\.\//u, "");
|
|
@@ -5996,7 +6589,7 @@ var getUncommittedChanges = async (cwd) => {
|
|
|
5996
6589
|
const deletedPathCandidates = /* @__PURE__ */ new Set([...stagedDeletedPaths, ...unstagedDeletedPaths]);
|
|
5997
6590
|
for (const deletedPath of deletedPathCandidates) {
|
|
5998
6591
|
const change = getOrCreateChange(changesByPath, deletedPath);
|
|
5999
|
-
change.deleted = !await pathExists4(
|
|
6592
|
+
change.deleted = !await pathExists4(path9.join(rootDir, deletedPath));
|
|
6000
6593
|
}
|
|
6001
6594
|
return Array.from(changesByPath.values()).sort((left, right) => {
|
|
6002
6595
|
return left.path.localeCompare(right.path);
|
|
@@ -6117,7 +6710,7 @@ var resolveImportPath = (importEdge) => {
|
|
|
6117
6710
|
if (!importEdge.specifier.startsWith(".")) {
|
|
6118
6711
|
return null;
|
|
6119
6712
|
}
|
|
6120
|
-
const basePath =
|
|
6713
|
+
const basePath = path10.posix.normalize(path10.posix.join(path10.posix.dirname(importEdge.from), importEdge.specifier));
|
|
6121
6714
|
const withoutExtension = basePath.replace(/\.[cm]?[jt]sx?$/u, "");
|
|
6122
6715
|
return withoutExtension;
|
|
6123
6716
|
};
|
|
@@ -6130,7 +6723,7 @@ var importTargetsChangedFile = (importEdge, changedPath) => {
|
|
|
6130
6723
|
};
|
|
6131
6724
|
var pathSegments = (filePath) => filePath.split("/").filter(Boolean);
|
|
6132
6725
|
var testHintMatchesChangedFile = (hints, changedPath) => {
|
|
6133
|
-
const changedBaseName =
|
|
6726
|
+
const changedBaseName = path10.posix.basename(changedPath);
|
|
6134
6727
|
const changedSegments = pathSegments(changedPath);
|
|
6135
6728
|
return hints.some((hint) => changedBaseName.startsWith(hint) || changedSegments.includes(hint));
|
|
6136
6729
|
};
|
|
@@ -6291,7 +6884,7 @@ import fg8 from "fast-glob";
|
|
|
6291
6884
|
|
|
6292
6885
|
// src/evidence/parse.ts
|
|
6293
6886
|
import fs20 from "fs/promises";
|
|
6294
|
-
import
|
|
6887
|
+
import path11 from "path";
|
|
6295
6888
|
import matter3 from "gray-matter";
|
|
6296
6889
|
import { parse as parse3 } from "yaml";
|
|
6297
6890
|
var evidenceBlockPattern = /```ya?ml\s*\n([\s\S]*?)```/giu;
|
|
@@ -6300,9 +6893,9 @@ var normalizeReferencePath = (truthDocPath, referencePath) => {
|
|
|
6300
6893
|
const strippedPath = referencePath.split("#")[0]?.trim() ?? "";
|
|
6301
6894
|
const isRepoRelative = repoRootPrefixes.some((prefix) => strippedPath.startsWith(prefix));
|
|
6302
6895
|
if (!isRepoRelative && (strippedPath.startsWith(".") || !strippedPath.includes("/"))) {
|
|
6303
|
-
return
|
|
6896
|
+
return path11.posix.normalize(path11.posix.join(path11.posix.dirname(truthDocPath), strippedPath));
|
|
6304
6897
|
}
|
|
6305
|
-
return
|
|
6898
|
+
return path11.posix.normalize(strippedPath);
|
|
6306
6899
|
};
|
|
6307
6900
|
var toEvidenceReference = (truthDocPath, raw) => {
|
|
6308
6901
|
if (!raw || typeof raw !== "object" || !("path" in raw) || typeof raw.path !== "string") {
|
|
@@ -6319,7 +6912,7 @@ var toEvidenceReference = (truthDocPath, raw) => {
|
|
|
6319
6912
|
};
|
|
6320
6913
|
};
|
|
6321
6914
|
var parseEvidenceReferences = async (rootDir, truthDocPath) => {
|
|
6322
|
-
const source = await fs20.readFile(
|
|
6915
|
+
const source = await fs20.readFile(path11.join(rootDir, truthDocPath), "utf8");
|
|
6323
6916
|
const parsed = matter3(source);
|
|
6324
6917
|
const references = [];
|
|
6325
6918
|
const sourceOfTruth = Array.isArray(parsed.data.source_of_truth) ? parsed.data.source_of_truth : [];
|
|
@@ -6557,7 +7150,7 @@ var runCheck = async (cwd, options = {}) => {
|
|
|
6557
7150
|
|
|
6558
7151
|
// src/context-pack/build.ts
|
|
6559
7152
|
import fs22 from "fs/promises";
|
|
6560
|
-
import
|
|
7153
|
+
import path12 from "path";
|
|
6561
7154
|
import fg9 from "fast-glob";
|
|
6562
7155
|
var uniqueSorted2 = (values) => [...new Set(values)].sort();
|
|
6563
7156
|
var repoRootPrefixes2 = [".codex/", ".github/", ".truthmark/", "docs/", "src/", "tests/"];
|
|
@@ -6568,12 +7161,12 @@ var normalizeDocReferencePath = (docPath, referencePath) => {
|
|
|
6568
7161
|
return null;
|
|
6569
7162
|
}
|
|
6570
7163
|
const isRepoRelative = repoRootPrefixes2.some((prefix) => strippedPath.startsWith(prefix));
|
|
6571
|
-
const normalized = isRepoRelative ?
|
|
7164
|
+
const normalized = isRepoRelative ? path12.posix.normalize(strippedPath) : path12.posix.normalize(path12.posix.join(path12.posix.dirname(docPath), strippedPath));
|
|
6572
7165
|
return normalized === ".." || normalized.startsWith("../") ? null : normalized;
|
|
6573
7166
|
};
|
|
6574
7167
|
var readIfExists = async (rootDir, filePath) => {
|
|
6575
7168
|
try {
|
|
6576
|
-
return await fs22.readFile(
|
|
7169
|
+
return await fs22.readFile(path12.join(rootDir, filePath), "utf8");
|
|
6577
7170
|
} catch {
|
|
6578
7171
|
return null;
|
|
6579
7172
|
}
|
|
@@ -7153,14 +7746,21 @@ var runContext = async (options) => {
|
|
|
7153
7746
|
};
|
|
7154
7747
|
|
|
7155
7748
|
// src/cli/program.ts
|
|
7749
|
+
var markFailedWhenErrorDiagnosticsExist = (result) => {
|
|
7750
|
+
if (result.diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
7751
|
+
process.exitCode = 1;
|
|
7752
|
+
}
|
|
7753
|
+
};
|
|
7156
7754
|
var writeResult = (result, options) => {
|
|
7157
7755
|
const output = options.json ? renderJson(result) : renderHuman(result);
|
|
7158
7756
|
process.stdout.write(`${output}
|
|
7159
7757
|
`);
|
|
7758
|
+
markFailedWhenErrorDiagnosticsExist(result);
|
|
7160
7759
|
};
|
|
7161
7760
|
var writeContextResult = (result, options) => {
|
|
7162
7761
|
if (!options.json && options.format === "markdown" && typeof result.data?.markdown === "string") {
|
|
7163
7762
|
process.stdout.write(result.data.markdown);
|
|
7763
|
+
markFailedWhenErrorDiagnosticsExist(result);
|
|
7164
7764
|
return;
|
|
7165
7765
|
}
|
|
7166
7766
|
writeResult(result, options);
|