truthmark 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -43,7 +43,7 @@ var renderJson = (result) => {
43
43
  };
44
44
 
45
45
  // src/config/command.ts
46
- import fs3 from "fs/promises";
46
+ import fs4 from "fs/promises";
47
47
 
48
48
  // src/fs/paths.ts
49
49
  import path from "path";
@@ -423,14 +423,26 @@ var createDefaultConfig = () => ({
423
423
  });
424
424
 
425
425
  // src/version.ts
426
- var TRUTHMARK_VERSION = "1.2.0";
426
+ import fs3 from "fs";
427
+ var packageJson = JSON.parse(
428
+ fs3.readFileSync(new URL("../package.json", import.meta.url), "utf8")
429
+ );
430
+ var TRUTHMARK_VERSION = packageJson.version;
427
431
 
428
432
  // src/templates/init-files.ts
429
433
  var renderConfigTemplate = () => {
430
434
  return stringify(createDefaultRawConfig());
431
435
  };
432
436
  var renderTruthmarkTemplate = () => {
433
- return `# Truthmark
437
+ return `---
438
+ status: active
439
+ doc_type: workflow-contract
440
+ last_reviewed: 2026-05-09
441
+ source_of_truth:
442
+ - .truthmark/config.yml
443
+ ---
444
+
445
+ # Truthmark
434
446
 
435
447
  Markdown in the current checkout is authoritative for this branch.
436
448
 
@@ -459,6 +471,14 @@ var renderHierarchicalAreasIndexTemplate = (config) => {
459
471
  const childPath = `${config.docs.routing.areaFilesRoot}/${defaultArea}.md`;
460
472
  const title = titleCase(defaultArea);
461
473
  return [
474
+ "---",
475
+ "status: active",
476
+ "doc_type: route-index",
477
+ "last_reviewed: 2026-05-09",
478
+ "source_of_truth:",
479
+ " - ../../.truthmark/config.yml",
480
+ "---",
481
+ "",
462
482
  "# Truthmark Areas",
463
483
  "",
464
484
  `## ${title}`,
@@ -481,6 +501,14 @@ var renderChildAreaTemplate = (config) => {
481
501
  const featureRoot = config.docs.roots.features ?? config.docs.roots.features_current ?? "docs/features";
482
502
  const leafTruthDoc = `${featureRoot}/${defaultArea}/overview.md`;
483
503
  return [
504
+ "---",
505
+ "status: active",
506
+ "doc_type: area-route",
507
+ "last_reviewed: 2026-05-09",
508
+ "source_of_truth:",
509
+ " - ../../../.truthmark/config.yml",
510
+ "---",
511
+ "",
484
512
  `# ${title} Areas`,
485
513
  "",
486
514
  `## ${title}`,
@@ -575,7 +603,7 @@ var renderFeatureLeafDocTemplate = (config) => {
575
603
  var CONFIG_PATH = ".truthmark/config.yml";
576
604
  var configExists = async (rootDir) => {
577
605
  try {
578
- await fs3.stat(resolveRepoPath(rootDir, CONFIG_PATH));
606
+ await fs4.stat(resolveRepoPath(rootDir, CONFIG_PATH));
579
607
  return true;
580
608
  } catch (error) {
581
609
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -648,10 +676,10 @@ var runConfig = async (cwd, options = {}) => {
648
676
  };
649
677
 
650
678
  // src/init/init.ts
651
- import fs5 from "fs/promises";
679
+ import fs6 from "fs/promises";
652
680
 
653
681
  // src/config/load.ts
654
- import fs4 from "fs/promises";
682
+ import fs5 from "fs/promises";
655
683
  import { Ajv } from "ajv";
656
684
  import { parse } from "yaml";
657
685
  var ajv = new Ajv({ allErrors: true });
@@ -700,7 +728,7 @@ var loadConfig = async (rootDir) => {
700
728
  const absolutePath = resolveRepoPath(rootDir, configPath);
701
729
  let source;
702
730
  try {
703
- source = await fs4.readFile(absolutePath, "utf8");
731
+ source = await fs5.readFile(absolutePath, "utf8");
704
732
  } catch (error) {
705
733
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
706
734
  return {
@@ -941,6 +969,8 @@ Truth Structure is agent-native:
941
969
  - define areas by product or behavior ownership, not by mechanical directory mirroring
942
970
  - create or repair docs/truthmark/areas.md
943
971
  - create starter truth docs when useful and when they belong in the canonical current-truth surface
972
+ - Starter truth docs must use closed YAML frontmatter bounded by opening and closing --- lines; include status, doc_type, last_reviewed, and source_of_truth inside that frontmatter.
973
+ - Starter truth docs must include ## Product Decisions and ## Rationale sections.
944
974
  - use docs/features/**, docs/architecture/**, or docs/standards/** for current truth destinations
945
975
  - use only canonical current-truth destinations for starter truth docs
946
976
  - keep active Product Decisions and Rationale in the canonical doc that owns the behavior
@@ -972,6 +1002,8 @@ Repair rules:
972
1002
  - keep API endpoint details in the nearest contract truth doc when such a doc exists
973
1003
  - update routing so future Truth Sync can target small docs
974
1004
  - preserve existing authored docs; move or rewrite only when needed to remove ambiguity
1005
+ - Do not finish topology repair with routed canonical current-truth docs missing Product Decisions or Rationale sections.
1006
+ - If an existing canonical doc lacks either section, add the missing heading beside Current Behavior with a concise current-state placeholder or active decision.
975
1007
  Portable fallback:
976
1008
  - If this skill surface is unavailable, perform the same workflow directly from committed repository files.
977
1009
  - Do not require the truthmark CLI.
@@ -1514,7 +1546,7 @@ ${block}`;
1514
1546
  var writeManagedAgentsFile = async (rootDir, path4 = "AGENTS.md", block) => {
1515
1547
  let existingContent = null;
1516
1548
  try {
1517
- existingContent = await fs5.readFile(resolveRepoPath(rootDir, path4), "utf8");
1549
+ existingContent = await fs6.readFile(resolveRepoPath(rootDir, path4), "utf8");
1518
1550
  } catch (error) {
1519
1551
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
1520
1552
  throw error;
@@ -1532,21 +1564,12 @@ var diagnosticCategoryForPath = (filePath) => {
1532
1564
  if (filePath.startsWith(".codex/skills/truthmark-structure/")) {
1533
1565
  return "truth-sync";
1534
1566
  }
1535
- if (filePath.startsWith("skills/truthmark-structure/")) {
1536
- return "truth-sync";
1537
- }
1538
1567
  if (filePath.startsWith(".codex/skills/truthmark-sync/")) {
1539
1568
  return "truth-sync";
1540
1569
  }
1541
- if (filePath.startsWith("skills/truthmark-sync/")) {
1542
- return "truth-sync";
1543
- }
1544
1570
  if (filePath.startsWith(".codex/skills/truthmark-realize/")) {
1545
1571
  return "realization";
1546
1572
  }
1547
- if (filePath.startsWith("skills/truthmark-realize/")) {
1548
- return "realization";
1549
- }
1550
1573
  if (filePath.startsWith(".gemini/commands/truthmark/realize")) {
1551
1574
  return "realization";
1552
1575
  }
@@ -1556,9 +1579,6 @@ var diagnosticCategoryForPath = (filePath) => {
1556
1579
  if (filePath.startsWith(".codex/skills/truthmark-check/")) {
1557
1580
  return "truth-sync";
1558
1581
  }
1559
- if (filePath.startsWith("skills/truthmark-check/")) {
1560
- return "truth-sync";
1561
- }
1562
1582
  if (filePath === "TRUTHMARK.md" || filePath === "docs/truthmark/areas.md") {
1563
1583
  return "authority";
1564
1584
  }
@@ -1640,12 +1660,9 @@ var filesForPlatform = (platform, config, block) => {
1640
1660
  case "codex":
1641
1661
  return codexFiles(config);
1642
1662
  case "opencode":
1643
- return [
1644
- ...workflowSkillFiles("skills", config),
1645
- ...workflowSkillFiles(".opencode/skills", config)
1646
- ];
1663
+ return workflowSkillFiles(".opencode/skills", config);
1647
1664
  case "claude-code":
1648
- return instructionBlockFiles([...config.instructionTargets, "CLAUDE.md"], block);
1665
+ return instructionBlockFiles(["CLAUDE.md"], block);
1649
1666
  case "cursor":
1650
1667
  return instructionBlockFiles([".cursor/rules/truthmark.mdc"], block);
1651
1668
  case "github-copilot":
@@ -1726,9 +1743,10 @@ var runInit = async (cwd) => {
1726
1743
  results.push(...await scaffoldHierarchy(rootDir, config));
1727
1744
  const migrationDiagnostics = await detectHierarchyMigrationDiagnostics(rootDir, config);
1728
1745
  const block = renderAgentsBlock(config);
1729
- const platformFiles = config.platforms.flatMap(
1730
- (platform) => filesForPlatform(platform, config, block)
1731
- );
1746
+ const platformFiles = [
1747
+ ...instructionBlockFiles(config.instructionTargets, block),
1748
+ ...config.platforms.flatMap((platform) => filesForPlatform(platform, config, block))
1749
+ ];
1732
1750
  const uniquePlatformFiles = Array.from(
1733
1751
  new Map(platformFiles.map((file) => [file.path, file])).values()
1734
1752
  ).sort((left, right) => left.path.localeCompare(right.path));
@@ -1751,7 +1769,7 @@ var runInit = async (cwd) => {
1751
1769
  };
1752
1770
 
1753
1771
  // src/checks/branch-scope.ts
1754
- import fs6 from "fs/promises";
1772
+ import fs7 from "fs/promises";
1755
1773
  import fg2 from "fast-glob";
1756
1774
 
1757
1775
  // src/markdown/hash.ts
@@ -1806,7 +1824,7 @@ var getBranchScopeData = async (cwd) => {
1806
1824
  }
1807
1825
  for (const relativePath of [...relevantFiles].sort()) {
1808
1826
  try {
1809
- const source = await fs6.readFile(resolveWorktreePath(repository, relativePath), "utf8");
1827
+ const source = await fs7.readFile(resolveWorktreePath(repository, relativePath), "utf8");
1810
1828
  relevantFileHashes[relativePath] = hashText(source);
1811
1829
  } catch (error) {
1812
1830
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -1823,14 +1841,14 @@ var getBranchScopeData = async (cwd) => {
1823
1841
  };
1824
1842
 
1825
1843
  // src/checks/authority.ts
1826
- import fs7 from "fs/promises";
1844
+ import fs8 from "fs/promises";
1827
1845
  import fg3 from "fast-glob";
1828
1846
  var looksLikeGlob = (pattern) => {
1829
1847
  return /[*?[\]{}()!+@]/u.test(pattern);
1830
1848
  };
1831
1849
  var pathExists = async (absolutePath) => {
1832
1850
  try {
1833
- await fs7.stat(absolutePath);
1851
+ await fs8.stat(absolutePath);
1834
1852
  return true;
1835
1853
  } catch (error) {
1836
1854
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -1919,7 +1937,7 @@ var checkAuthority = async (rootDir, config) => {
1919
1937
  };
1920
1938
 
1921
1939
  // src/checks/frontmatter.ts
1922
- import fs8 from "fs/promises";
1940
+ import fs9 from "fs/promises";
1923
1941
 
1924
1942
  // src/markdown/parse.ts
1925
1943
  import matter from "gray-matter";
@@ -1967,7 +1985,7 @@ var checkFrontmatter = async (rootDir, config, markdownPaths) => {
1967
1985
  }
1968
1986
  const absolutePath = resolveRepoPath(rootDir, markdownPath);
1969
1987
  await assertRepoContainment(rootDir, absolutePath);
1970
- const source = await fs8.readFile(absolutePath, "utf8");
1988
+ const source = await fs9.readFile(absolutePath, "utf8");
1971
1989
  let document;
1972
1990
  try {
1973
1991
  document = parseMarkdownDocument(source);
@@ -2005,11 +2023,11 @@ var checkFrontmatter = async (rootDir, config, markdownPaths) => {
2005
2023
  };
2006
2024
 
2007
2025
  // src/checks/links.ts
2008
- import fs9 from "fs/promises";
2026
+ import fs10 from "fs/promises";
2009
2027
  import path3 from "path";
2010
2028
  var pathExists2 = async (absolutePath) => {
2011
2029
  try {
2012
- await fs9.stat(absolutePath);
2030
+ await fs10.stat(absolutePath);
2013
2031
  return true;
2014
2032
  } catch (error) {
2015
2033
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -2025,7 +2043,7 @@ var checkLinks = async (rootDir, markdownPaths) => {
2025
2043
  continue;
2026
2044
  }
2027
2045
  const absolutePath = resolveRepoPath(rootDir, markdownPath);
2028
- const source = await fs9.readFile(absolutePath, "utf8");
2046
+ const source = await fs10.readFile(absolutePath, "utf8");
2029
2047
  let document;
2030
2048
  try {
2031
2049
  document = parseMarkdownDocument(source);
@@ -2067,12 +2085,12 @@ var checkLinks = async (rootDir, markdownPaths) => {
2067
2085
  };
2068
2086
 
2069
2087
  // src/checks/areas.ts
2070
- import fs11 from "fs/promises";
2088
+ import fs12 from "fs/promises";
2071
2089
  import fg5 from "fast-glob";
2072
2090
  import micromatch3 from "micromatch";
2073
2091
 
2074
2092
  // src/routing/area-resolver.ts
2075
- import fs10 from "fs/promises";
2093
+ import fs11 from "fs/promises";
2076
2094
  import fg4 from "fast-glob";
2077
2095
  import micromatch from "micromatch";
2078
2096
 
@@ -2229,7 +2247,7 @@ var ensureChildPath = async (rootDir, areaFilesRoot, filePath) => {
2229
2247
  var readRouteFile = async (rootDir, filePath) => {
2230
2248
  try {
2231
2249
  return {
2232
- source: await fs10.readFile(resolveRepoPath(rootDir, filePath), "utf8"),
2250
+ source: await fs11.readFile(resolveRepoPath(rootDir, filePath), "utf8"),
2233
2251
  diagnostic: null
2234
2252
  };
2235
2253
  } catch (error) {
@@ -2502,7 +2520,7 @@ var classifyPath = (filePath, ignorePatterns) => {
2502
2520
  if (normalizedPath.startsWith(".truthmark/")) {
2503
2521
  return "derived";
2504
2522
  }
2505
- if (normalizedPath.startsWith(".codex/") || normalizedPath.startsWith(".cursor/") || normalizedPath.startsWith(".gemini/commands/") || normalizedPath.startsWith(".opencode/") || normalizedPath === ".github/copilot-instructions.md" || normalizedPath === "AGENTS.md" || normalizedPath === "CLAUDE.md" || normalizedPath === "GEMINI.md" || normalizedPath.startsWith(".gemini/commands/truthmark/") || normalizedPath.startsWith("skills/truthmark-")) {
2523
+ if (normalizedPath.startsWith(".codex/") || normalizedPath.startsWith(".cursor/") || normalizedPath.startsWith(".gemini/commands/") || normalizedPath.startsWith(".opencode/") || normalizedPath === ".github/copilot-instructions.md" || normalizedPath === "AGENTS.md" || normalizedPath === "CLAUDE.md" || normalizedPath === "GEMINI.md" || normalizedPath.startsWith(".gemini/commands/truthmark/")) {
2506
2524
  return "derived";
2507
2525
  }
2508
2526
  if (ignorePatterns.length > 0 && micromatch2.isMatch(normalizedPath, ignorePatterns)) {
@@ -2529,7 +2547,7 @@ var looksLikeGlob2 = (pattern) => {
2529
2547
  };
2530
2548
  var pathExists3 = async (absolutePath) => {
2531
2549
  try {
2532
- await fs11.stat(absolutePath);
2550
+ await fs12.stat(absolutePath);
2533
2551
  return true;
2534
2552
  } catch (error) {
2535
2553
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -2798,7 +2816,7 @@ var checkAreas = async (rootDir, config) => {
2798
2816
  };
2799
2817
 
2800
2818
  // src/checks/decisions.ts
2801
- import fs12 from "fs/promises";
2819
+ import fs13 from "fs/promises";
2802
2820
  import micromatch4 from "micromatch";
2803
2821
  var REQUIRED_DECISION_HEADINGS = ["Product Decisions", "Rationale"];
2804
2822
  var escapeRegExp2 = (value) => {
@@ -2821,7 +2839,7 @@ var checkDecisionSections = async (rootDir, config, markdownPaths) => {
2821
2839
  const diagnostics = [];
2822
2840
  const candidatePaths = [...new Set(markdownPaths)].filter((filePath) => isDecisionTruthCandidate(config, filePath)).sort();
2823
2841
  for (const filePath of candidatePaths) {
2824
- const source = await fs12.readFile(resolveRepoPath(rootDir, filePath), "utf8");
2842
+ const source = await fs13.readFile(resolveRepoPath(rootDir, filePath), "utf8");
2825
2843
  const missingHeadings = REQUIRED_DECISION_HEADINGS.filter((heading) => !hasHeading(source, heading));
2826
2844
  if (missingHeadings.length === 0) {
2827
2845
  continue;
@@ -2837,7 +2855,7 @@ var checkDecisionSections = async (rootDir, config, markdownPaths) => {
2837
2855
  };
2838
2856
 
2839
2857
  // src/checks/generated-surfaces.ts
2840
- import fs13 from "fs/promises";
2858
+ import fs14 from "fs/promises";
2841
2859
 
2842
2860
  // src/templates/generated-surfaces.ts
2843
2861
  var workflowSkillFiles2 = (basePath, config) => {
@@ -2916,12 +2934,9 @@ var filesForPlatform2 = (platform, config, block) => {
2916
2934
  case "codex":
2917
2935
  return codexFiles2(config);
2918
2936
  case "opencode":
2919
- return [
2920
- ...workflowSkillFiles2("skills", config),
2921
- ...workflowSkillFiles2(".opencode/skills", config)
2922
- ];
2937
+ return workflowSkillFiles2(".opencode/skills", config);
2923
2938
  case "claude-code":
2924
- return instructionBlockFiles2([...config.instructionTargets, "CLAUDE.md"], block);
2939
+ return instructionBlockFiles2(["CLAUDE.md"], block);
2925
2940
  case "cursor":
2926
2941
  return instructionBlockFiles2([".cursor/rules/truthmark.mdc"], block);
2927
2942
  case "github-copilot":
@@ -2951,7 +2966,10 @@ var filesForPlatform2 = (platform, config, block) => {
2951
2966
  }
2952
2967
  };
2953
2968
  var renderGeneratedSurfaces = (config, block = renderAgentsBlock(config)) => {
2954
- const files = config.platforms.flatMap((platform) => filesForPlatform2(platform, config, block));
2969
+ const files = [
2970
+ ...instructionBlockFiles2(config.instructionTargets, block),
2971
+ ...config.platforms.flatMap((platform) => filesForPlatform2(platform, config, block))
2972
+ ];
2955
2973
  return Array.from(new Map(files.map((file) => [file.path, file])).values()).sort(
2956
2974
  (left, right) => left.path.localeCompare(right.path)
2957
2975
  );
@@ -2960,7 +2978,7 @@ var renderGeneratedSurfaces = (config, block = renderAgentsBlock(config)) => {
2960
2978
  // src/checks/generated-surfaces.ts
2961
2979
  var readOptionalFile = async (rootDir, filePath) => {
2962
2980
  try {
2963
- return await fs13.readFile(resolveRepoPath(rootDir, filePath), "utf8");
2981
+ return await fs14.readFile(resolveRepoPath(rootDir, filePath), "utf8");
2964
2982
  } catch (error) {
2965
2983
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2966
2984
  return null;