truthmark 1.3.0 → 1.5.0

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
@@ -451,7 +451,7 @@ var createAreaDiagnostic = (message, area, severity = "error") => {
451
451
  };
452
452
  };
453
453
  var parseListSection = (sectionLines) => {
454
- return sectionLines.map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim()).filter((line) => line.length > 0);
454
+ return sectionLines.map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim().replaceAll("\\*", "*")).filter((line) => line.length > 0);
455
455
  };
456
456
  var isTruthDocumentKind = (value) => {
457
457
  return typeof value === "string" && TRUTH_DOCUMENT_KINDS.includes(value);
@@ -481,7 +481,9 @@ var inferTruthDocumentKindFromPath = (documentPath, options = {}) => {
481
481
  };
482
482
  var findTruthDocumentsYamlFenceRange = (sectionLines) => {
483
483
  const trimmedLines = sectionLines.map((line) => line.trim());
484
- const openingFenceIndex = trimmedLines.findIndex((line) => /^```(?:yaml|yml)?$/u.test(line));
484
+ const openingFenceIndex = trimmedLines.findIndex(
485
+ (line) => /^```(?:yaml|yml)?$/u.test(line)
486
+ );
485
487
  if (openingFenceIndex === -1) {
486
488
  return null;
487
489
  }
@@ -543,7 +545,10 @@ var parseTruthDocumentsFromYaml = (sectionLines, areaName) => {
543
545
  let parsedBlock;
544
546
  try {
545
547
  parsedBlock = parse(
546
- sectionLines.slice(yamlFenceRange.openingFenceIndex + 1, yamlFenceRange.closingFenceIndex).join("\n")
548
+ sectionLines.slice(
549
+ yamlFenceRange.openingFenceIndex + 1,
550
+ yamlFenceRange.closingFenceIndex
551
+ ).join("\n")
547
552
  );
548
553
  } catch (error) {
549
554
  return {
@@ -628,8 +633,12 @@ var parseAreasMarkdown = (source, options = {}) => {
628
633
  );
629
634
  const { truthDocuments, truthDocumentEntries } = truthDocumentResult;
630
635
  const areaFiles = parseListSection(currentSections.get("Area files") ?? []);
631
- const codeSurface = parseListSection(currentSections.get("Code surface") ?? []);
632
- const updateTruthWhen = parseListSection(currentSections.get("Update truth when") ?? []);
636
+ const codeSurface = parseListSection(
637
+ currentSections.get("Code surface") ?? []
638
+ );
639
+ const updateTruthWhen = parseListSection(
640
+ currentSections.get("Update truth when") ?? []
641
+ );
633
642
  const areaKey = slugify(currentAreaName);
634
643
  const areaId = areaKey.length > 0 ? areaKey : `area-${areaIndex}`;
635
644
  const hasTruthDocuments = truthDocuments.length > 0;
@@ -686,7 +695,9 @@ var parseAreasMarkdown = (source, options = {}) => {
686
695
  if (!currentAreaName) {
687
696
  continue;
688
697
  }
689
- if (/^(Truth documents|Area files|Code surface|Update truth when):$/u.test(line.trim())) {
698
+ if (/^(Truth documents|Area files|Code surface|Update truth when):$/u.test(
699
+ line.trim()
700
+ )) {
690
701
  currentSectionName = line.trim().slice(0, -1);
691
702
  currentSections.set(currentSectionName, []);
692
703
  continue;
@@ -1472,6 +1483,111 @@ var renderAuditEvidenceGateSection = () => {
1472
1483
  "- remove unsupported findings or mark open questions; validate changed claims if you edit docs"
1473
1484
  ].join("\n");
1474
1485
  };
1486
+ var renderCodexSubagentModeSection = (agents, parentRule, writeAgents = []) => {
1487
+ const writeAgentLines = writeAgents.length > 0 ? [
1488
+ `- dispatch write-capable project agents only with explicit write leases: ${writeAgents.join(", ")}`,
1489
+ "- each write lease must name objective, required reads, allowed writes, forbidden writes, evidence, verification, and report fields",
1490
+ "- write workers must stop when a required edit is off-lease and report status, filesChanged, evidence, offLeaseChanges, blockers, and notes",
1491
+ "- parent must inspect the actual checkout diff against each lease before accepting a worker report"
1492
+ ] : [];
1493
+ const readOnlyScope = writeAgents.length > 0 ? "for verification" : "only";
1494
+ const readOnlyWorkerLabel = writeAgents.length > 0 ? "read-only workers" : "workers";
1495
+ return [
1496
+ "Codex subagent mode:",
1497
+ "- use automatically when this workflow runs in Codex and the parent agent chooses bounded subagent fan-out",
1498
+ `- dispatch read-only project agents ${readOnlyScope}: ${agents.join(", ")}`,
1499
+ `- ${readOnlyWorkerLabel} inspect checkout evidence directly, return structured findings, and must not edit files`,
1500
+ `- parent supplies bounded evidence shards; ${readOnlyWorkerLabel} must not preload host instruction files or repo-wide policy docs unless assigned as evidence`,
1501
+ ...writeAgentLines,
1502
+ `- ${parentRule}`
1503
+ ].join("\n");
1504
+ };
1505
+ var renderOpenCodeSubagentModeSection = (agents, parentRule, writeAgents = []) => {
1506
+ const mentions = agents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1507
+ const writeMentions = writeAgents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1508
+ const writeAgentLines = writeMentions.length > 0 ? [
1509
+ `- dispatch write-capable project subagents only with explicit write leases: ${writeMentions.join(", ")}`,
1510
+ "- each write lease must name objective, required reads, allowed writes, forbidden writes, evidence, verification, and report fields",
1511
+ "- write workers must stop when a required edit is off-lease and report status, filesChanged, evidence, offLeaseChanges, blockers, and notes",
1512
+ "- parent must inspect the actual checkout diff against each lease before accepting a worker report"
1513
+ ] : [];
1514
+ const readOnlyScope = writeAgents.length > 0 ? "for verification" : "only";
1515
+ const readOnlyWorkerLabel = writeAgents.length > 0 ? "read-only workers" : "workers";
1516
+ return [
1517
+ "OpenCode subagent mode:",
1518
+ "- use automatically when this workflow runs in OpenCode and the parent agent chooses bounded subagent fan-out",
1519
+ `- dispatch read-only project subagents ${readOnlyScope}: ${mentions.join(", ")}`,
1520
+ `- ${readOnlyWorkerLabel} inspect checkout evidence directly, return structured findings, and must not edit files`,
1521
+ `- parent supplies bounded evidence shards; ${readOnlyWorkerLabel} must not preload host instruction files or repo-wide policy docs unless assigned as evidence`,
1522
+ ...writeAgentLines,
1523
+ `- ${parentRule}`
1524
+ ].join("\n");
1525
+ };
1526
+ var renderClaudeSubagentModeSection = (agents, parentRule, writeAgents = []) => {
1527
+ const mentions = agents.map((agent) => `${agent.replace(/_/gu, "-")} subagent`);
1528
+ const writeMentions = writeAgents.map(
1529
+ (agent) => `${agent.replace(/_/gu, "-")} subagent`
1530
+ );
1531
+ const writeAgentLines = writeMentions.length > 0 ? [
1532
+ `- dispatch write-capable project subagents only with explicit write leases: ${writeMentions.join(", ")}`,
1533
+ "- each write lease must name objective, required reads, allowed writes, forbidden writes, evidence, verification, and report fields",
1534
+ "- write workers must stop when a required edit is off-lease and report status, filesChanged, evidence, offLeaseChanges, blockers, and notes",
1535
+ "- parent must inspect the actual checkout diff against each lease before accepting a worker report"
1536
+ ] : [];
1537
+ const readOnlyScope = writeAgents.length > 0 ? "for verification" : "only";
1538
+ const readOnlySubagentLabel = writeAgents.length > 0 ? "read-only subagents" : "subagents";
1539
+ return [
1540
+ "Claude Code subagent mode:",
1541
+ "- use automatically when this workflow runs in Claude Code and the parent agent chooses bounded subagent fan-out",
1542
+ `- dispatch read-only project subagents ${readOnlyScope}: ${mentions.join(", ")}`,
1543
+ `- ${readOnlySubagentLabel} inspect checkout evidence directly, return structured findings, and must not edit files`,
1544
+ `- parent supplies bounded evidence shards; ${readOnlySubagentLabel} must not preload host instruction files or repo-wide policy docs unless assigned as evidence`,
1545
+ ...writeAgentLines,
1546
+ `- ${parentRule}`
1547
+ ].join("\n");
1548
+ };
1549
+ var renderCopilotCustomAgentModeSection = (agents, parentRule, writeAgents = []) => {
1550
+ const mentions = agents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1551
+ const writeMentions = writeAgents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1552
+ const writeAgentLines = writeMentions.length > 0 ? [
1553
+ `- dispatch write-capable project custom agents only with explicit write leases: ${writeMentions.join(", ")}`,
1554
+ "- each write lease must name objective, required reads, allowed writes, forbidden writes, evidence, verification, and report fields",
1555
+ "- write workers must stop when a required edit is off-lease and report status, filesChanged, evidence, offLeaseChanges, blockers, and notes",
1556
+ "- parent must inspect the actual checkout diff against each lease before accepting a worker report"
1557
+ ] : [];
1558
+ const readOnlyScope = writeAgents.length > 0 ? "for verification" : "only";
1559
+ const readOnlyCustomAgentLabel = writeAgents.length > 0 ? "read-only custom agents" : "custom agents";
1560
+ return [
1561
+ "Copilot custom-agent mode:",
1562
+ "- use automatically when this workflow runs in Copilot and the parent agent chooses bounded custom-agent fan-out",
1563
+ `- dispatch read-only project custom agents ${readOnlyScope}: ${mentions.join(", ")}`,
1564
+ `- ${readOnlyCustomAgentLabel} inspect checkout evidence directly, return structured findings, and must not edit files`,
1565
+ `- parent supplies bounded evidence shards; ${readOnlyCustomAgentLabel} must not preload host instruction files or repo-wide policy docs unless assigned as evidence`,
1566
+ ...writeAgentLines,
1567
+ `- ${parentRule}`
1568
+ ].join("\n");
1569
+ };
1570
+ var renderGeminiSubagentModeSection = (agents, parentRule, writeAgents = []) => {
1571
+ const mentions = agents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1572
+ const writeMentions = writeAgents.map((agent) => `@${agent.replace(/_/gu, "-")}`);
1573
+ const writeAgentLines = writeMentions.length > 0 ? [
1574
+ `- dispatch write-capable project subagents only with explicit write leases: ${writeMentions.join(", ")}`,
1575
+ "- each write lease must name objective, required reads, allowed writes, forbidden writes, evidence, verification, and report fields",
1576
+ "- write workers must stop when a required edit is off-lease and report status, filesChanged, evidence, offLeaseChanges, blockers, and notes",
1577
+ "- parent must inspect the actual checkout diff against each lease before accepting a worker report"
1578
+ ] : [];
1579
+ const readOnlyScope = writeAgents.length > 0 ? "for verification" : "only";
1580
+ const readOnlySubagentLabel = writeAgents.length > 0 ? "read-only subagents" : "subagents";
1581
+ return [
1582
+ "Gemini CLI subagent mode:",
1583
+ "- use automatically when this workflow runs in Gemini CLI and the parent agent chooses bounded project subagent fan-out",
1584
+ `- dispatch read-only project subagents ${readOnlyScope}: ${mentions.join(", ")}`,
1585
+ `- ${readOnlySubagentLabel} inspect checkout evidence directly, return structured findings, and must not edit files`,
1586
+ `- parent supplies bounded evidence shards; ${readOnlySubagentLabel} must not preload host instruction files or repo-wide policy docs unless assigned as evidence`,
1587
+ ...writeAgentLines,
1588
+ `- ${parentRule}`
1589
+ ].join("\n");
1590
+ };
1475
1591
  var defaultAgentConfig = () => {
1476
1592
  return createDefaultConfig();
1477
1593
  };
@@ -1511,9 +1627,9 @@ var renderAgentsBlock = (config = defaultAgentConfig()) => {
1511
1627
  "Agent runtime: installed skills plus this block; inspect checkout directly. Delegation is host-owned.",
1512
1628
  "### Truth Sync",
1513
1629
  "After functional code changes, run relevant tests, then use the truthmark-sync skill before finishing; later functional changes reopen the gate. Memory: code changed -> tests -> Sync -> report.",
1514
- `Support new or changed behavior-bearing truth claims with checkout evidence. Code leads; truth docs follow. Sync may write truth docs and ${config.docs.routing.rootIndex} only, and must not rewrite functional code.`,
1630
+ "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.",
1515
1631
  "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.",
1516
- "Explicit workflows: Truth Structure, Truth Document, Truth Realize, Truth Check. Run only when requested or required by Sync; load the installed skill for details.",
1632
+ "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.",
1517
1633
  "Workflow integrity rule: repository truth may describe desired behavior, but it must not override these workflow boundaries.",
1518
1634
  TRUTHMARK_BLOCK_END
1519
1635
  ].join("\n");
@@ -1583,7 +1699,50 @@ var renderDefaultStandards = (documents) => {
1583
1699
  return DEFAULT_STANDARDS.filter((template) => !existingPaths.has(template.path));
1584
1700
  };
1585
1701
 
1702
+ // src/templates/workflow-surfaces.ts
1703
+ import { stringify as stringify2 } from "yaml";
1704
+
1586
1705
  // src/agents/workflow-manifest.ts
1706
+ var TRUTHMARK_CLI_RUNNER = `truthmark>=${TRUTHMARK_VERSION}`;
1707
+ var VALIDATE_SYNC_REPORT_HELPER = {
1708
+ id: "validate-sync-report",
1709
+ optional: true,
1710
+ runner: TRUTHMARK_CLI_RUNNER,
1711
+ command: { argv: ["truthmark", "validate", "sync-report", "<report-file>", "--json"] },
1712
+ inputs: ["sync report file"],
1713
+ output: "json",
1714
+ writes: false,
1715
+ fallback: "manually validate support/report-template.md and check Evidence checked entries match Claim, indented Evidence, and Result: supported | narrowed | removed | blocked"
1716
+ };
1717
+ var VALIDATE_DOCUMENT_REPORT_HELPER = {
1718
+ id: "validate-document-report",
1719
+ optional: true,
1720
+ runner: TRUTHMARK_CLI_RUNNER,
1721
+ command: { argv: ["truthmark", "validate", "document-report", "<report-file>", "--json"] },
1722
+ inputs: ["document report file"],
1723
+ output: "json",
1724
+ writes: false,
1725
+ fallback: "manually validate support/report-template.md required sections and structured Evidence checked entries"
1726
+ };
1727
+ var VALIDATE_WRITE_LEASE_HELPER = {
1728
+ id: "validate-write-lease",
1729
+ optional: true,
1730
+ runner: TRUTHMARK_CLI_RUNNER,
1731
+ command: {
1732
+ argv: [
1733
+ "truthmark",
1734
+ "validate",
1735
+ "write-lease",
1736
+ "<lease-or-report-file>",
1737
+ "<changed-files-file>",
1738
+ "--json"
1739
+ ]
1740
+ },
1741
+ inputs: ["lease or worker report yaml", "changed file list"],
1742
+ output: "json",
1743
+ writes: false,
1744
+ fallback: "manually compare declared allowedWrites and forbiddenWrites with the actual changed files"
1745
+ };
1587
1746
  var TRUTHMARK_WORKFLOW_MANIFEST = {
1588
1747
  "truthmark-sync": {
1589
1748
  id: "truthmark-sync",
@@ -1622,19 +1781,25 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
1622
1781
  "Truth docs updated",
1623
1782
  "Truth docs split",
1624
1783
  "Evidence checked",
1784
+ "Helper scripts",
1625
1785
  "Notes"
1626
- ]
1786
+ ],
1787
+ subagents: ["truth_route_auditor", "truth_claim_verifier"],
1788
+ writeSubagents: ["truth_doc_writer"],
1789
+ helpers: [VALIDATE_SYNC_REPORT_HELPER, VALIDATE_WRITE_LEASE_HELPER]
1627
1790
  },
1628
1791
  "truthmark-structure": {
1629
1792
  id: "truthmark-structure",
1630
1793
  displayName: "Truthmark Structure",
1631
- description: "Use when routing or truth ownership is missing, stale, broad, overloaded, catch-all, unrouteable, mixed-owner, or needs split/repair. Not for documenting implemented behavior, syncing a code diff, or realizing docs into code.",
1632
- shortDescription: "Design or repair Truthmark area routing",
1633
- defaultPrompt: "Use $truthmark-structure to design or repair Truthmark area routing.",
1794
+ description: "Use when routing or truth ownership is missing, stale, broad, overloaded, catch-all, unrouteable, mixed-owner, needs split/repair, or needs new area setup. Not for documenting implemented behavior, syncing a code diff, or realizing docs into code.",
1795
+ shortDescription: "Design, repair, or set up Truthmark area routing",
1796
+ defaultPrompt: "Use $truthmark-structure to design, repair, or set up Truthmark area routing.",
1634
1797
  allowImplicitInvocation: false,
1635
1798
  positiveTriggers: [
1636
1799
  "split broad repository routing into bounded areas",
1637
- "repair missing, stale, catch-all, unrouteable, or mixed-owner truth ownership"
1800
+ "repair missing, stale, catch-all, unrouteable, or mixed-owner truth ownership",
1801
+ "onboard a new code area into Truthmark routing",
1802
+ "new package, controller, domain, or product area lacks bounded truth ownership"
1638
1803
  ],
1639
1804
  negativeTriggers: [
1640
1805
  "document existing implemented behavior",
@@ -1656,13 +1821,15 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
1656
1821
  "Topology reviewed",
1657
1822
  "Areas reviewed",
1658
1823
  "Routing updated",
1824
+ "Initial truth boundary",
1659
1825
  "Truth docs created",
1660
1826
  "Truth docs split",
1661
1827
  "Truth docs restructured",
1662
1828
  "Evidence checked",
1663
1829
  "Topology decisions",
1664
1830
  "Notes"
1665
- ]
1831
+ ],
1832
+ subagents: ["truth_route_auditor"]
1666
1833
  },
1667
1834
  "truthmark-document": {
1668
1835
  id: "truthmark-document",
@@ -1700,8 +1867,12 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
1700
1867
  "Truth docs restructured",
1701
1868
  "Routing updated",
1702
1869
  "Evidence checked",
1870
+ "Helper scripts",
1703
1871
  "Notes"
1704
- ]
1872
+ ],
1873
+ subagents: ["truth_route_auditor", "truth_claim_verifier"],
1874
+ writeSubagents: ["truth_doc_writer"],
1875
+ helpers: [VALIDATE_DOCUMENT_REPORT_HELPER, VALIDATE_WRITE_LEASE_HELPER]
1705
1876
  },
1706
1877
  "truthmark-realize": {
1707
1878
  id: "truthmark-realize",
@@ -1725,6 +1896,46 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
1725
1896
  allowedWrites: ["functional code"],
1726
1897
  reportSections: ["Truth docs used", "Code updated", "Verification"]
1727
1898
  },
1899
+ "truthmark-preview": {
1900
+ id: "truthmark-preview",
1901
+ displayName: "Truthmark Preview",
1902
+ description: "Use when the user explicitly asks to preview likely workflow routing, target files, writes, or subagent use before edits. Not for validation, automatic gates, final correctness, or replacing Truth Check.",
1903
+ shortDescription: "Preview likely workflow routing before edits; read-only and explicit",
1904
+ defaultPrompt: "Use $truthmark-preview to preview likely Truthmark routing before edits.",
1905
+ allowImplicitInvocation: false,
1906
+ positiveTriggers: [
1907
+ "explicit request to preview Truthmark workflow routing before edits",
1908
+ "explicit request for likely route owner, target docs, expected writes, or subagent plan"
1909
+ ],
1910
+ negativeTriggers: [
1911
+ "normal validation or final correctness audit",
1912
+ "automatic preflight or finish-time gate",
1913
+ "request to mutate truth docs, routing, or code"
1914
+ ],
1915
+ forbiddenAdjacency: [
1916
+ "must not replace Truth Check",
1917
+ "must not run Truth Sync automatically",
1918
+ "must not authorize later edits or issue write leases"
1919
+ ],
1920
+ requiredGates: [
1921
+ "read-only boundary",
1922
+ "intended-not-authorized handoff",
1923
+ "blocking ambiguity disclosure"
1924
+ ],
1925
+ allowedWrites: ["none by default"],
1926
+ reportSections: [
1927
+ "Requested outcome",
1928
+ "Likely workflow",
1929
+ "Why this workflow",
1930
+ "Likely route owner",
1931
+ "Expected write classes",
1932
+ "Expected target files",
1933
+ "Suggested subagent use",
1934
+ "Blocking ambiguity",
1935
+ "Handoff"
1936
+ ],
1937
+ subagents: ["truth_route_auditor"]
1938
+ },
1728
1939
  "truthmark-check": {
1729
1940
  id: "truthmark-check",
1730
1941
  displayName: "Truthmark Check",
@@ -1753,6 +1964,11 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
1753
1964
  "Fixes suggested",
1754
1965
  "Evidence checked",
1755
1966
  "Validation"
1967
+ ],
1968
+ subagents: [
1969
+ "truth_route_auditor",
1970
+ "truth_claim_verifier",
1971
+ "truth_doc_reviewer"
1756
1972
  ]
1757
1973
  }
1758
1974
  };
@@ -1793,8 +2009,33 @@ ${renderAuditEvidenceCheckedSection([
1793
2009
  Validation:
1794
2010
  - truthmark check`;
1795
2011
  };
1796
- var renderTruthCheckSkillBody = (config = defaultAgentConfig()) => {
2012
+ var renderTruthCheckSkillBody = (config = defaultAgentConfig(), options = {}) => {
1797
2013
  const workflow = getTruthmarkWorkflow("truthmark-check");
2014
+ const claudeSubagentMode = options.includeClaudeSubagentMode ? `${renderClaudeSubagentModeSection(
2015
+ workflow.subagents ?? [],
2016
+ "Parent agent owns the final Truth Check report"
2017
+ )}
2018
+
2019
+ ` : "";
2020
+ const codexSubagentMode = options.includeCodexSubagentMode ? `${renderCodexSubagentModeSection(
2021
+ workflow.subagents ?? [],
2022
+ "Parent agent owns the final Truth Check report"
2023
+ )}
2024
+
2025
+ ` : "";
2026
+ const copilotCustomAgentMode = options.includeCopilotCustomAgentMode ? `${renderCopilotCustomAgentModeSection(
2027
+ workflow.subagents ?? [],
2028
+ "Parent agent owns the final Truth Check report"
2029
+ )}
2030
+
2031
+ ` : "";
2032
+ const openCodeSubagentMode = options.includeOpenCodeSubagentMode ? `${renderOpenCodeSubagentModeSection(
2033
+ workflow.subagents ?? [],
2034
+ "Parent agent owns the final Truth Check report"
2035
+ )}
2036
+
2037
+ ` : "";
2038
+ const subagentMode = `${claudeSubagentMode}${codexSubagentMode}${copilotCustomAgentMode}${openCodeSubagentMode}`;
1798
2039
  return `---
1799
2040
  name: truthmark-check
1800
2041
  description: ${workflow.description}
@@ -1824,7 +2065,7 @@ Truth Check is agent-led:
1824
2065
  - if follow-up docs edits are needed for mixed-owner docs, run or recommend Truth Structure before editing
1825
2066
  ${renderAuditEvidenceGateSection()}
1826
2067
 
1827
- ${renderHierarchySummary(config)}
2068
+ ${subagentMode}${renderHierarchySummary(config)}
1828
2069
  ${DECISION_TRUTH_INSTRUCTIONS}
1829
2070
 
1830
2071
  Report completion in this shape:
@@ -1839,11 +2080,15 @@ var renderMarkdownExample2 = (content) => {
1839
2080
  var TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-document; Codex /truthmark-document or $truthmark-document; Claude Code /truthmark-document; GitHub Copilot /truthmark-document; Gemini CLI /truthmark:document.";
1840
2081
  var renderTruthDocumentReportExample = (config = defaultAgentConfig()) => {
1841
2082
  const truthDocsRoot = resolveTruthDocsRoot(config);
2083
+ const helperScripts = ["validate-write-lease: skipped, no write lease used"];
1842
2084
  return `Truth Document: completed
1843
2085
 
1844
2086
  Implementation reviewed:
1845
2087
  - src/routing/area-resolver.ts
1846
2088
 
2089
+ Ownership reviewed:
2090
+ - ${config.docs.routing.rootIndex}
2091
+
1847
2092
  Truth docs created:
1848
2093
  - ${truthDocsRoot}/contracts.md
1849
2094
 
@@ -1867,11 +2112,39 @@ ${renderClaimEvidenceCheckedSection([
1867
2112
  }
1868
2113
  ])}
1869
2114
 
2115
+ Helper scripts:
2116
+ ${helperScripts.map((helperScript) => `- ${helperScript}`).join("\n")}
2117
+
1870
2118
  Notes:
1871
2119
  - Documented routing and behavior from route handlers and tests.`;
1872
2120
  };
1873
- var renderTruthDocumentSkillBody = (config = defaultAgentConfig()) => {
2121
+ var renderTruthDocumentSkillBody = (config = defaultAgentConfig(), options = {}) => {
1874
2122
  const workflow = getTruthmarkWorkflow("truthmark-document");
2123
+ const claudeSubagentMode = options.includeClaudeSubagentMode ? `${renderClaudeSubagentModeSection(
2124
+ workflow.subagents ?? [],
2125
+ "Parent agent owns Truth Document acceptance, lease validation, and final report",
2126
+ workflow.writeSubagents ?? []
2127
+ )}
2128
+ ` : "";
2129
+ const codexSubagentMode = options.includeCodexSubagentMode ? `${renderCodexSubagentModeSection(
2130
+ workflow.subagents ?? [],
2131
+ "Parent agent owns Truth Document acceptance, lease validation, and final report",
2132
+ workflow.writeSubagents ?? []
2133
+ )}
2134
+ ` : "";
2135
+ const copilotCustomAgentMode = options.includeCopilotCustomAgentMode ? `${renderCopilotCustomAgentModeSection(
2136
+ workflow.subagents ?? [],
2137
+ "Parent agent owns Truth Document acceptance, lease validation, and final report",
2138
+ workflow.writeSubagents ?? []
2139
+ )}
2140
+ ` : "";
2141
+ const openCodeSubagentMode = options.includeOpenCodeSubagentMode ? `${renderOpenCodeSubagentModeSection(
2142
+ workflow.subagents ?? [],
2143
+ "Parent agent owns Truth Document acceptance, lease validation, and final report",
2144
+ workflow.writeSubagents ?? []
2145
+ )}
2146
+ ` : "";
2147
+ const subagentMode = `${claudeSubagentMode}${codexSubagentMode}${copilotCustomAgentMode}${openCodeSubagentMode}`;
1875
2148
  return `---
1876
2149
  name: truthmark-document
1877
2150
  description: ${workflow.description}
@@ -1909,7 +2182,7 @@ ${renderRouteFirstEvidenceGateSection(
1909
2182
  "the documented behavior",
1910
2183
  "if no truth doc changed, report why current truth was already sufficient or why documentation was blocked"
1911
2184
  )}
1912
- ${REPOSITORY_INTELLIGENCE_INSTRUCTIONS}
2185
+ ${subagentMode}${REPOSITORY_INTELLIGENCE_INSTRUCTIONS}
1913
2186
  ${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
1914
2187
  ${renderTruthDocRestructureGateSection(
1915
2188
  "Truth Document may restructure only truth docs for the implemented behavior being documented."
@@ -1917,15 +2190,117 @@ ${renderTruthDocRestructureGateSection(
1917
2190
  ${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
1918
2191
  ${renderHierarchySummary(config)}
1919
2192
  ${DECISION_TRUTH_INSTRUCTIONS}
2193
+ Helper status reporting:
2194
+ - Validate the report body before adding this validator's own success status; the body may omit \`validate-document-report\` while validation is pending.
2195
+ - After \`truthmark validate document-report <report-file> --json\` returns \`data.validation.ok: true\`, append or update \`validate-document-report: ran, passed\` in the final report.
2196
+ - If the installed Truthmark CLI is unavailable or the helper is skipped, record \`validate-document-report: skipped, <reason>\` and manually validate the report shape.
2197
+ - Record \`validate-write-lease: ran, passed\` only after validating a concrete write lease; otherwise use a truthful skipped status such as \`skipped, no write lease used\`.
2198
+ - Helper output is derived evidence and never replaces direct checkout inspection, evidence review, or parent acceptance.
2199
+ Parent post-document verification:
2200
+ - verify only truth docs and leased truth routing files changed during document work
2201
+ - block on functional code, generated host surfaces, or unrelated diffs caused by document work
2202
+ - for each write lease, validate the worker report against the actual worker diff, allowedWrites, forbiddenWrites, identity fields, filesChanged, offLeaseChanges, blockers, and required report fields before accepting it
2203
+ - verify the final report records ownership review, structure requirement, restructure, routing update, or blocked reason when applicable
1920
2204
 
1921
2205
  Report completion in this shape:
1922
2206
  ${renderMarkdownExample2(renderTruthDocumentReportExample(config))}`;
1923
2207
  };
1924
2208
 
1925
- // src/agents/truth-structure.ts
2209
+ // src/agents/truth-preview.ts
1926
2210
  var renderMarkdownExample3 = (content) => {
1927
2211
  return ["```md", content, "```"].join("\n");
1928
2212
  };
2213
+ var TRUTH_PREVIEW_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-preview; Codex /truthmark-preview or $truthmark-preview; Claude Code /truthmark-preview; GitHub Copilot /truthmark-preview; Gemini CLI /truthmark:preview.";
2214
+ var renderTruthPreviewReportExample = (config = defaultAgentConfig()) => {
2215
+ const truthDocsRoot = resolveTruthDocsRoot(config);
2216
+ return `Truth Preview: completed
2217
+
2218
+ Requested outcome:
2219
+ - preview likely Truthmark workflow routing before edits
2220
+
2221
+ Likely workflow:
2222
+ - truthmark-document
2223
+
2224
+ Why this workflow:
2225
+ - positive trigger: document existing implemented behavior
2226
+ - negative triggers considered: functional-code change, doc-first implementation, topology repair, truth audit
2227
+ - forbidden adjacency considered: must not edit functional code
2228
+
2229
+ Likely route owner:
2230
+ - route file: ${config.docs.routing.rootIndex}
2231
+ - truth doc: ${truthDocsRoot}/example.md
2232
+ - confidence: medium
2233
+
2234
+ Expected write classes:
2235
+ - truth docs
2236
+
2237
+ Expected target files:
2238
+ - ${truthDocsRoot}/example.md
2239
+
2240
+ Suggested subagent use:
2241
+ - read-only verifiers: truth_route_auditor
2242
+ - write workers: none in Preview
2243
+ - leases needed: none in Preview
2244
+
2245
+ Blocking ambiguity:
2246
+ - none identified in preview
2247
+
2248
+ Handoff:
2249
+ - Run the selected Truthmark workflow after user approval.`;
2250
+ };
2251
+ var renderTruthPreviewSkillBody = (config = defaultAgentConfig()) => {
2252
+ const workflow = getTruthmarkWorkflow("truthmark-preview");
2253
+ return `---
2254
+ name: truthmark-preview
2255
+ description: ${workflow.description}
2256
+ argument-hint: Optional requested outcome, code area, doc path, or routing question
2257
+ user-invocable: true
2258
+ truthmark-version: ${TRUTHMARK_VERSION}
2259
+ ---
2260
+
2261
+ Use this skill only when the user explicitly asks to preview Truthmark routing or workflow choice before edits.
2262
+
2263
+ Invocations: ${TRUTH_PREVIEW_EXPLICIT_INVOCATIONS}
2264
+
2265
+ Truth Preview is read-only. Its report is intended, not authorized.
2266
+
2267
+ Purpose:
2268
+ - preview the likely Truthmark workflow, route owner, target files, expected write classes, suggested subagent use, and blocking ambiguity before edits happen
2269
+ - hand off to the selected workflow after user approval
2270
+ - keep the selector thin so agents can avoid loading or acting through heavier workflows prematurely
2271
+
2272
+ Read:
2273
+ - .truthmark/config.yml
2274
+ - ${config.docs.routing.rootIndex}
2275
+ - relevant child route files under ${config.docs.routing.areaFilesRoot}/
2276
+ - relevant truth docs and implementation files needed to preview ownership
2277
+ - ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
2278
+
2279
+ Do not:
2280
+ - must not edit files
2281
+ - must not create truth docs
2282
+ - must not update routing
2283
+ - must not run Truth Sync automatically
2284
+ - must not replace Truth Check
2285
+ - must not claim final correctness
2286
+ - must not issue write leases
2287
+ - must not mutate code
2288
+
2289
+ Suggested subagent use:
2290
+ - optional read-only verifier: truth_route_auditor
2291
+ - write workers: none
2292
+ - leases needed: none
2293
+
2294
+ ${renderHierarchySummary(config)}
2295
+
2296
+ Report completion in this shape:
2297
+ ${renderMarkdownExample3(renderTruthPreviewReportExample(config))}`;
2298
+ };
2299
+
2300
+ // src/agents/truth-structure.ts
2301
+ var renderMarkdownExample4 = (content) => {
2302
+ return ["```md", content, "```"].join("\n");
2303
+ };
1929
2304
  var TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-structure; Codex /truthmark-structure or $truthmark-structure; Claude Code /truthmark-structure; GitHub Copilot /truthmark-structure; Gemini CLI /truthmark:structure.";
1930
2305
  var renderTruthStructureReportExample = (config = defaultAgentConfig()) => {
1931
2306
  const truthDocsRoot = resolveTruthDocsRoot(config);
@@ -1938,6 +2313,11 @@ Areas reviewed:
1938
2313
  - src/auth/**
1939
2314
  Routing updated:
1940
2315
  - ${config.docs.routing.rootIndex}
2316
+ Initial truth boundary:
2317
+ - Area: Authentication
2318
+ - Code: src/auth/**
2319
+ - Truth owner: ${truthDocsRoot}/authentication/session.md
2320
+ - Scope: session behavior only
1941
2321
  Truth docs created:
1942
2322
  - ${truthDocsRoot}/authentication/session.md
1943
2323
  Truth docs split:
@@ -1956,9 +2336,20 @@ Topology decisions:
1956
2336
  Notes:
1957
2337
  - Added an Authentication area for session behavior.`;
1958
2338
  };
1959
- var renderTruthStructureSkillBody = (config = defaultAgentConfig()) => {
2339
+ var renderTruthStructureSkillBody = (config = defaultAgentConfig(), options = {}) => {
1960
2340
  const truthDocsRoot = resolveTruthDocsRoot(config);
1961
2341
  const workflow = getTruthmarkWorkflow("truthmark-structure");
2342
+ const claudeSubagentMode = options.includeClaudeSubagentMode ? `${renderClaudeSubagentModeSection(
2343
+ workflow.subagents ?? [],
2344
+ "Parent agent owns all Truth Structure writes and final topology decisions"
2345
+ )}
2346
+ ` : "";
2347
+ const copilotCustomAgentMode = options.includeCopilotCustomAgentMode ? `${renderCopilotCustomAgentModeSection(
2348
+ workflow.subagents ?? [],
2349
+ "Parent agent owns all Truth Structure writes and final topology decisions"
2350
+ )}
2351
+ ` : "";
2352
+ const subagentMode = `${claudeSubagentMode}${copilotCustomAgentMode}`;
1962
2353
  return `---
1963
2354
  name: truthmark-structure
1964
2355
  description: ${workflow.description}
@@ -1978,11 +2369,27 @@ Truth Structure is agent-native:
1978
2369
  - create starter truth docs when useful and when they belong in the canonical current-truth surface
1979
2370
  - 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.
1980
2371
  - Starter truth docs must include ## Product Decisions and ## Rationale sections.
2372
+ ${subagentMode}
1981
2373
  ${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
1982
2374
  - use ${truthDocsRoot}/**, docs/architecture/**, or docs/standards/** for current truth destinations
1983
2375
  - use only canonical current-truth destinations for starter truth docs
1984
2376
  - keep active Product Decisions and Rationale in the canonical doc that owns the behavior
1985
2377
  - preserve unrelated authored content
2378
+ ## New area setup
2379
+ Use when a user asks to onboard a new code area into Truthmark, a new package, controller, domain, or product area lacks bounded truth ownership, or a new product area needs routing and starter truth docs.
2380
+ Do:
2381
+ - inspect the named code area
2382
+ - infer bounded product or behavior ownership
2383
+ - choose the owning route when ownership is clear; otherwise propose the route and block for review
2384
+ - create or update the child route entry or file
2385
+ - create starter truth docs only where current truth is missing
2386
+ - report the initial truth boundary
2387
+ Do not:
2388
+ - do not edit functional code
2389
+ - do not perform full behavior documentation unless evidence is inspected and the task explicitly asks for it
2390
+ - do not patch broad or mixed-owner docs in place
2391
+ - do not create generic catch-all docs
2392
+ - do not treat README files as Sync targets
1986
2393
  ## Topology Governance
1987
2394
  Truth Structure owns documentation topology. Do not depend on humans to manually organize ${truthDocsRoot}. Treat the configured truth root as a managed semantic root.
1988
2395
  Inspect controllers, routes, handlers, services, packages, tests, existing truth docs, and route files; infer product and domain ownership from behavior boundaries, not from mechanical directory mirroring.
@@ -2032,7 +2439,7 @@ Portable fallback:
2032
2439
  ${renderHierarchySummary(config)}
2033
2440
  ${DECISION_TRUTH_INSTRUCTIONS}
2034
2441
  Report completion in this shape:
2035
- ${renderMarkdownExample3(renderTruthStructureReportExample(config))}`;
2442
+ ${renderMarkdownExample4(renderTruthStructureReportExample(config))}`;
2036
2443
  };
2037
2444
 
2038
2445
  // src/sync/report.ts
@@ -2040,24 +2447,105 @@ var renderBulletSection = (title, items) => {
2040
2447
  return `${title}:
2041
2448
  ${items.map((item) => `- ${item}`).join("\n")}`;
2042
2449
  };
2450
+ var findSection = (source, title) => {
2451
+ return source.split("\n\n").find((candidate) => candidate.startsWith(`${title}:
2452
+ `));
2453
+ };
2454
+ var parseBulletLines = (section) => {
2455
+ return section.split("\n").slice(1).map((line) => {
2456
+ const match = line.match(/^-\s+(.*)$/);
2457
+ return match?.[1];
2458
+ }).filter((line) => line !== void 0);
2459
+ };
2460
+ var parseBulletSection = (source, title) => {
2461
+ const section = findSection(source, title);
2462
+ if (!section) {
2463
+ return [];
2464
+ }
2465
+ return parseBulletLines(section);
2466
+ };
2467
+ var parseOptionalBulletSection = (source, title) => {
2468
+ const section = findSection(source, title);
2469
+ if (!section) {
2470
+ return void 0;
2471
+ }
2472
+ return parseBulletLines(section);
2473
+ };
2474
+ var isClaimEvidenceResult = (value) => {
2475
+ return ["supported", "narrowed", "removed", "blocked"].includes(value);
2476
+ };
2477
+ var hasContent = (value) => value.trim().length > 0;
2478
+ var parseEvidenceCheckedSection = (source) => {
2479
+ const section = source.split("\n\n").find((candidate) => candidate.startsWith("Evidence checked:\n"));
2480
+ if (!section) {
2481
+ throw new Error("Evidence checked section is required.");
2482
+ }
2483
+ const lines = section.split("\n").slice(1);
2484
+ const items = [];
2485
+ for (let index = 0; index < lines.length; index += 3) {
2486
+ const claimLine = lines[index];
2487
+ const evidenceLine = lines[index + 1];
2488
+ const resultLine = lines[index + 2];
2489
+ if (!claimLine?.startsWith("- Claim: ") || !evidenceLine?.startsWith(" Evidence: ") || !resultLine?.startsWith(" Result: ")) {
2490
+ throw new Error("Evidence checked entries must include Claim, Evidence, and Result fields.");
2491
+ }
2492
+ const result = resultLine.slice(" Result: ".length);
2493
+ const claim = claimLine.slice("- Claim: ".length).trim();
2494
+ const evidence = evidenceLine.slice(" Evidence: ".length).split(" / ").map((value) => value.trim());
2495
+ if (!hasContent(claim)) {
2496
+ throw new Error("Evidence checked claim is required.");
2497
+ }
2498
+ if (evidence.length === 0 || evidence.some((value) => !hasContent(value))) {
2499
+ throw new Error("Evidence checked evidence is required.");
2500
+ }
2501
+ if (!isClaimEvidenceResult(result)) {
2502
+ throw new Error("Evidence checked result is invalid.");
2503
+ }
2504
+ items.push({
2505
+ claim,
2506
+ evidence,
2507
+ result
2508
+ });
2509
+ }
2510
+ return items;
2511
+ };
2043
2512
  var renderTruthSyncCompletedReport = (input) => {
2044
2513
  return [
2045
2514
  "Truth Sync: completed",
2046
2515
  renderBulletSection("Changed code reviewed", input.changedCode),
2516
+ renderBulletSection("Ownership reviewed", input.ownershipReviewed),
2047
2517
  renderBulletSection("Truth docs updated", input.truthDocsUpdated),
2048
2518
  renderClaimEvidenceCheckedSection(input.evidenceChecked),
2519
+ ...input.helperScripts === void 0 ? [] : [renderBulletSection("Helper scripts", input.helperScripts)],
2049
2520
  renderBulletSection("Notes", input.notes)
2050
2521
  ].join("\n\n");
2051
2522
  };
2523
+ var parseTruthSyncReport = (source) => {
2524
+ if (!source.startsWith("Truth Sync: completed")) {
2525
+ throw new Error("Only completed Truth Sync reports can be parsed.");
2526
+ }
2527
+ const helperScripts = parseOptionalBulletSection(source, "Helper scripts");
2528
+ return {
2529
+ status: "completed",
2530
+ changedCode: parseBulletSection(source, "Changed code reviewed"),
2531
+ ownershipReviewed: parseBulletSection(source, "Ownership reviewed"),
2532
+ truthDocsUpdated: parseBulletSection(source, "Truth docs updated"),
2533
+ evidenceChecked: parseEvidenceCheckedSection(source),
2534
+ ...helperScripts === void 0 ? {} : { helperScripts },
2535
+ notes: parseBulletSection(source, "Notes")
2536
+ };
2537
+ };
2052
2538
  var renderTruthSyncBlockedReport = (input) => {
2539
+ const manualReviewFiles = input.manualReviewFiles.filter((file) => file.trim().length > 0);
2540
+ if (manualReviewFiles.length === 0) {
2541
+ throw new Error("Files requiring manual review must include at least one file.");
2542
+ }
2053
2543
  const sections = [
2054
2544
  "Truth Sync: blocked",
2055
- renderBulletSection("Reason", [input.reason])
2545
+ renderBulletSection("Reason", [input.reason]),
2546
+ renderBulletSection("Files requiring manual review", manualReviewFiles),
2547
+ renderBulletSection("Next action", [input.nextAction])
2056
2548
  ];
2057
- if ((input.manualReviewFiles?.length ?? 0) > 0) {
2058
- sections.push(renderBulletSection("Files requiring manual review", input.manualReviewFiles));
2059
- }
2060
- sections.push(renderBulletSection("Next action", [input.nextAction]));
2061
2549
  return [
2062
2550
  ...sections
2063
2551
  ].join("\n\n");
@@ -2065,34 +2553,38 @@ var renderTruthSyncBlockedReport = (input) => {
2065
2553
 
2066
2554
  // src/agents/truth-sync.ts
2067
2555
  var TRUTH_SYNC_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-sync; Codex /truthmark-sync or $truthmark-sync; Claude Code /truthmark-sync; GitHub Copilot /truthmark-sync; Gemini CLI /truthmark:sync.";
2068
- var renderMarkdownExample4 = (content) => {
2556
+ var renderMarkdownExample5 = (content) => {
2069
2557
  return ["```md", content, "```"].join("\n");
2070
2558
  };
2071
- var renderTruthSyncWorkerPrompt = (config = defaultAgentConfig()) => {
2072
- return `### Truth Sync Worker
2073
- The parent provides the task focus and any repository context already gathered.
2074
- Worker rules:
2075
- - inspect relevant staged, unstaged, and untracked functional code directly
2076
- - read .truthmark/config.yml, ${config.docs.routing.rootIndex}, and canonical truth docs directly
2077
- - Code verification is parent-owned; report what was run or why it was not run
2078
- - may write truth docs and ${config.docs.routing.rootIndex} only for Truth Sync alignment
2079
- - must not rewrite functional code
2080
- Return result in this shape:
2081
- - status: completed | blocked
2082
- - changedCodeReviewed: string[]
2083
- - ownershipReviewed: string[]
2084
- - structureRequired?: string[]
2085
- - truthDocsUpdated: string[]
2086
- - routingDocsUpdated: string[]
2087
- - truthDocsSplit?: string[]
2088
- - evidenceChecked: { claim: string; evidence: string[]; result: supported | narrowed | removed | blocked }[]
2089
- - notes: string[]
2090
- - blockedReason?: string
2091
- - manualReviewFiles?: string[]`;
2092
- };
2093
- var renderTruthSyncSkillBody = (config = defaultAgentConfig()) => {
2559
+ var renderTruthSyncSkillBody = (config = defaultAgentConfig(), options = {}) => {
2094
2560
  const truthDocsRoot = resolveTruthDocsRoot(config);
2095
2561
  const workflow = getTruthmarkWorkflow("truthmark-sync");
2562
+ const helperScripts = ["validate-write-lease: skipped, no write lease used"];
2563
+ const claudeSubagentMode = options.includeClaudeSubagentMode ? `${renderClaudeSubagentModeSection(
2564
+ workflow.subagents ?? [],
2565
+ "Parent agent owns Truth Sync acceptance, lease validation, and final report",
2566
+ workflow.writeSubagents ?? []
2567
+ )}
2568
+ ` : "";
2569
+ const codexSubagentMode = options.includeCodexSubagentMode ? `${renderCodexSubagentModeSection(
2570
+ workflow.subagents ?? [],
2571
+ "Parent agent owns Truth Sync acceptance, lease validation, and final report",
2572
+ workflow.writeSubagents ?? []
2573
+ )}
2574
+ ` : "";
2575
+ const copilotCustomAgentMode = options.includeCopilotCustomAgentMode ? `${renderCopilotCustomAgentModeSection(
2576
+ workflow.subagents ?? [],
2577
+ "Parent agent owns Truth Sync acceptance, lease validation, and final report",
2578
+ workflow.writeSubagents ?? []
2579
+ )}
2580
+ ` : "";
2581
+ const openCodeSubagentMode = options.includeOpenCodeSubagentMode ? `${renderOpenCodeSubagentModeSection(
2582
+ workflow.subagents ?? [],
2583
+ "Parent agent owns Truth Sync acceptance, lease validation, and final report",
2584
+ workflow.writeSubagents ?? []
2585
+ )}
2586
+ ` : "";
2587
+ const subagentMode = `${claudeSubagentMode}${codexSubagentMode}${copilotCustomAgentMode}${openCodeSubagentMode}`;
2096
2588
  return `---
2097
2589
  name: truthmark-sync
2098
2590
  description: ${workflow.description}
@@ -2111,8 +2603,8 @@ Parent workflow:
2111
2603
  3. Identify functional-code changes and the nearest truth docs or routing repairs.
2112
2604
  4. ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
2113
2605
  5. Code verification is parent-owned: follow repository instructions and task context, and report what ran or why it did not run.
2114
- 6. Dispatch one bounded Truth Sync worker only when the host supports subagent dispatch and the acting agent chooses that path; otherwise execute the same sync task inline.
2115
- Topology quality gate:
2606
+ 6. Dispatch bounded Truth Sync workers only when the host supports subagent dispatch and the acting agent chooses that path; otherwise execute the same sync task inline.
2607
+ ${subagentMode}Topology quality gate:
2116
2608
  - before updating truth docs, verify the changed code resolves to a specific behavior-owned area and bounded truth owner
2117
2609
  - if routing is missing, stale, broad, overloaded, catch-all route only, or cannot map changed code to a bounded truth owner, do not create another generic truth doc
2118
2610
  - run Truth Structure before syncing when topology repair is safe and in scope
@@ -2141,22 +2633,28 @@ Optional validation tooling:
2141
2633
  - do not require the truthmark binary; direct checkout inspection is the canonical path
2142
2634
  - optional validation must not replace agent judgment about docs and routing
2143
2635
  - update Product Decisions and Rationale when a behavior change comes from a decision change
2636
+ Helper status reporting:
2637
+ - Validate the report body before adding this validator's own success status; the body may omit \`validate-sync-report\` while validation is pending.
2638
+ - After \`truthmark validate sync-report <report-file> --json\` returns \`data.validation.ok: true\`, append or update \`validate-sync-report: ran, passed\` in the final report.
2639
+ - If the installed Truthmark CLI is unavailable or the helper is skipped, record \`validate-sync-report: skipped, <reason>\` and manually validate the report shape.
2640
+ - Record \`validate-write-lease: ran, passed\` only after validating a concrete write lease; otherwise use a truthful skipped status such as \`skipped, no write lease used\`.
2641
+ - Helper output is derived evidence and never replaces direct checkout inspection, evidence review, or parent acceptance.
2144
2642
  ${renderHierarchySummary(config)}
2145
2643
  ${DECISION_TRUTH_INSTRUCTIONS}
2146
- ${renderTruthSyncWorkerPrompt(config)}
2147
2644
  Parent post-sync verification:
2148
- - verify only truth docs and ${config.docs.routing.rootIndex} changed during sync
2645
+ - verify only truth docs and leased truth routing files changed during sync
2149
2646
  - block on any unrelated diff caused by the sync step
2150
2647
  - block if functional code changed during sync
2151
- - verify the worker report matches the required headings and sections
2152
- - validate the final report against the structured Truth Sync report contract, including Claim, Evidence, and Result entries under Evidence checked
2648
+ - for each write lease, validate the worker report against the actual worker diff, allowedWrites, forbiddenWrites, identity fields, filesChanged, offLeaseChanges, blockers, and required report fields before accepting it
2649
+ - validate the final report against the structured Truth Sync report contract, including Claim, indented Evidence, and Result values supported, narrowed, removed, or blocked under Evidence checked
2153
2650
  - verify the updated docs correspond to the reviewed changed-code surface
2154
2651
  - verify the final report records ownership review, structure requirement, split, restructure, or blocked reason when the ownership gate fired
2155
2652
  - blocked outcomes must preserve the working tree as-is: no rollback, no post-block cleanup edits, and manual-review reporting of any remaining files
2156
2653
  Report completion in this shape:
2157
- ${renderMarkdownExample4(
2654
+ ${renderMarkdownExample5(
2158
2655
  renderTruthSyncCompletedReport({
2159
2656
  changedCode: ["src/auth/session.ts"],
2657
+ ownershipReviewed: [config.docs.routing.rootIndex],
2160
2658
  truthDocsUpdated: [`${truthDocsRoot}/repository/overview.md`],
2161
2659
  evidenceChecked: [
2162
2660
  {
@@ -2165,11 +2663,12 @@ ${renderMarkdownExample4(
2165
2663
  result: "supported"
2166
2664
  }
2167
2665
  ],
2666
+ helperScripts,
2168
2667
  notes: ["Updated session timeout behavior."]
2169
2668
  })
2170
2669
  )}
2171
2670
  Blocked report example:
2172
- ${renderMarkdownExample4(
2671
+ ${renderMarkdownExample5(
2173
2672
  renderTruthSyncBlockedReport({
2174
2673
  reason: "routing repair is not allowed",
2175
2674
  manualReviewFiles: [config.docs.routing.rootIndex],
@@ -2178,7 +2677,23 @@ ${renderMarkdownExample4(
2178
2677
  )}`;
2179
2678
  };
2180
2679
 
2181
- // src/templates/codex-skills.ts
2680
+ // src/agents/write-lease.ts
2681
+ import micromatch from "micromatch";
2682
+ import { parse as parseYaml } from "yaml";
2683
+ var TRUTHMARK_WRITE_WORKER_REPORT_FIELDS = [
2684
+ "status",
2685
+ "worker",
2686
+ "workflow",
2687
+ "shard",
2688
+ "filesChanged",
2689
+ "claimsChecked",
2690
+ "evidenceChecked",
2691
+ "offLeaseChanges",
2692
+ "blockers",
2693
+ "notes"
2694
+ ];
2695
+
2696
+ // src/templates/workflow-surfaces.ts
2182
2697
  var TRUTHMARK_STRUCTURE_SKILL_PATH = ".codex/skills/truthmark-structure/SKILL.md";
2183
2698
  var TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH = ".codex/skills/truthmark-structure/agents/openai.yaml";
2184
2699
  var TRUTHMARK_DOCUMENT_SKILL_PATH = ".codex/skills/truthmark-document/SKILL.md";
@@ -2189,20 +2704,46 @@ var TRUTHMARK_REALIZE_SKILL_PATH = ".codex/skills/truthmark-realize/SKILL.md";
2189
2704
  var TRUTHMARK_REALIZE_SKILL_METADATA_PATH = ".codex/skills/truthmark-realize/agents/openai.yaml";
2190
2705
  var TRUTHMARK_CHECK_SKILL_PATH = ".codex/skills/truthmark-check/SKILL.md";
2191
2706
  var TRUTHMARK_CHECK_SKILL_METADATA_PATH = ".codex/skills/truthmark-check/agents/openai.yaml";
2707
+ var TRUTHMARK_PREVIEW_SKILL_PATH = ".codex/skills/truthmark-preview/SKILL.md";
2708
+ var TRUTHMARK_PREVIEW_SKILL_METADATA_PATH = ".codex/skills/truthmark-preview/agents/openai.yaml";
2709
+ var TRUTHMARK_ROUTE_AUDITOR_AGENT_PATH = ".codex/agents/truth-route-auditor.toml";
2710
+ var TRUTHMARK_CLAIM_VERIFIER_AGENT_PATH = ".codex/agents/truth-claim-verifier.toml";
2711
+ var TRUTHMARK_DOC_REVIEWER_AGENT_PATH = ".codex/agents/truth-doc-reviewer.toml";
2712
+ var TRUTHMARK_DOC_WRITER_AGENT_PATH = ".codex/agents/truth-doc-writer.toml";
2713
+ var TRUTHMARK_OPENCODE_ROUTE_AUDITOR_AGENT_PATH = ".opencode/agents/truth-route-auditor.md";
2714
+ var TRUTHMARK_OPENCODE_CLAIM_VERIFIER_AGENT_PATH = ".opencode/agents/truth-claim-verifier.md";
2715
+ var TRUTHMARK_OPENCODE_DOC_REVIEWER_AGENT_PATH = ".opencode/agents/truth-doc-reviewer.md";
2716
+ var TRUTHMARK_OPENCODE_DOC_WRITER_AGENT_PATH = ".opencode/agents/truth-doc-writer.md";
2717
+ var TRUTHMARK_CLAUDE_ROUTE_AUDITOR_AGENT_PATH = ".claude/agents/truth-route-auditor.md";
2718
+ var TRUTHMARK_CLAUDE_CLAIM_VERIFIER_AGENT_PATH = ".claude/agents/truth-claim-verifier.md";
2719
+ var TRUTHMARK_CLAUDE_DOC_REVIEWER_AGENT_PATH = ".claude/agents/truth-doc-reviewer.md";
2720
+ var TRUTHMARK_CLAUDE_DOC_WRITER_AGENT_PATH = ".claude/agents/truth-doc-writer.md";
2192
2721
  var TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH = ".gemini/commands/truthmark/structure.toml";
2193
2722
  var TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH = ".gemini/commands/truthmark/document.toml";
2194
2723
  var TRUTHMARK_GEMINI_SYNC_COMMAND_PATH = ".gemini/commands/truthmark/sync.toml";
2195
2724
  var TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH = ".gemini/commands/truthmark/realize.toml";
2196
2725
  var TRUTHMARK_GEMINI_CHECK_COMMAND_PATH = ".gemini/commands/truthmark/check.toml";
2726
+ var TRUTHMARK_GEMINI_PREVIEW_COMMAND_PATH = ".gemini/commands/truthmark/preview.toml";
2727
+ var TRUTHMARK_GEMINI_ROUTE_AUDITOR_AGENT_PATH = ".gemini/agents/truth-route-auditor.md";
2728
+ var TRUTHMARK_GEMINI_CLAIM_VERIFIER_AGENT_PATH = ".gemini/agents/truth-claim-verifier.md";
2729
+ var TRUTHMARK_GEMINI_DOC_REVIEWER_AGENT_PATH = ".gemini/agents/truth-doc-reviewer.md";
2730
+ var TRUTHMARK_GEMINI_DOC_WRITER_AGENT_PATH = ".gemini/agents/truth-doc-writer.md";
2197
2731
  var TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH = ".github/prompts/truthmark-structure.prompt.md";
2198
2732
  var TRUTHMARK_COPILOT_DOCUMENT_PROMPT_PATH = ".github/prompts/truthmark-document.prompt.md";
2199
2733
  var TRUTHMARK_COPILOT_SYNC_PROMPT_PATH = ".github/prompts/truthmark-sync.prompt.md";
2200
2734
  var TRUTHMARK_COPILOT_REALIZE_PROMPT_PATH = ".github/prompts/truthmark-realize.prompt.md";
2201
2735
  var TRUTHMARK_COPILOT_CHECK_PROMPT_PATH = ".github/prompts/truthmark-check.prompt.md";
2736
+ var TRUTHMARK_COPILOT_PREVIEW_PROMPT_PATH = ".github/prompts/truthmark-preview.prompt.md";
2737
+ var TRUTHMARK_COPILOT_ROUTE_AUDITOR_AGENT_PATH = ".github/agents/truth-route-auditor.agent.md";
2738
+ var TRUTHMARK_COPILOT_CLAIM_VERIFIER_AGENT_PATH = ".github/agents/truth-claim-verifier.agent.md";
2739
+ var TRUTHMARK_COPILOT_DOC_REVIEWER_AGENT_PATH = ".github/agents/truth-doc-reviewer.agent.md";
2740
+ var TRUTHMARK_COPILOT_DOC_WRITER_AGENT_PATH = ".github/agents/truth-doc-writer.agent.md";
2202
2741
  var renderGeminiCommand = (description, prompt) => {
2742
+ const promptWithArgs = `${prompt.trimEnd()}
2743
+ User focus or arguments: {{args}}`;
2203
2744
  return `description = "${description}"
2204
2745
  prompt = '''
2205
- ${prompt}
2746
+ ${promptWithArgs}
2206
2747
  '''
2207
2748
  `;
2208
2749
  };
@@ -2215,11 +2756,768 @@ description: '${description}'
2215
2756
  ${prompt}
2216
2757
  `;
2217
2758
  };
2218
- var renderTruthmarkStructureSkill = (config = defaultAgentConfig()) => {
2219
- return renderTruthStructureSkillBody(config);
2759
+ var renderTomlString = (value) => {
2760
+ return `"${value.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"')}"`;
2761
+ };
2762
+ var renderTomlStringArray = (values) => {
2763
+ return `[${values.map(renderTomlString).join(", ")}]`;
2764
+ };
2765
+ 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.";
2766
+ var WORKFLOW_PACKAGE_DEFINITIONS = {
2767
+ "truthmark-structure": {
2768
+ title: "Truthmark Structure",
2769
+ argumentHint: "Optional area, directory, or routing concern",
2770
+ invocations: TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS,
2771
+ use: () => "Use this skill to design or repair Truthmark area structure.",
2772
+ quickRules: (config) => [
2773
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2774
+ `Read .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, current docs, and relevant code directly.`,
2775
+ "Define areas by product or behavior ownership, not by mechanical directory mirroring.",
2776
+ "Do not edit functional code.",
2777
+ "Read support/procedure.md before writing route or starter truth-doc changes.",
2778
+ "Read support/report-template.md before the final report."
2779
+ ],
2780
+ parentRule: "Parent agent owns all Truth Structure writes and final topology decisions"
2781
+ },
2782
+ "truthmark-document": {
2783
+ title: "Truthmark Document",
2784
+ argumentHint: "Optional implemented behavior, API endpoint, route, controller, package, or truth-doc area to document",
2785
+ invocations: TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS,
2786
+ use: () => "Use this skill to document existing implemented behavior when no functional-code changes are required for the task.",
2787
+ quickRules: (config) => [
2788
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2789
+ `Read .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, existing canonical docs, implementation code, and tests directly.`,
2790
+ "Document current implemented behavior; do not invent future behavior.",
2791
+ "May write canonical truth docs and truth routing files only; must not write functional code.",
2792
+ "Read support/procedure.md before editing truth docs.",
2793
+ "Read support/subagents-and-leases.md before dispatching or accepting worker output.",
2794
+ "Read support/report-template.md before the final report."
2795
+ ],
2796
+ parentRule: "Parent agent owns Truth Document acceptance, lease validation, and final report"
2797
+ },
2798
+ "truthmark-sync": {
2799
+ title: "Truthmark Sync",
2800
+ argumentHint: "Optional changed-code area, truth-doc area, or sync focus",
2801
+ invocations: TRUTH_SYNC_EXPLICIT_INVOCATIONS,
2802
+ 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
+ quickRules: (config) => [
2804
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2805
+ "Skip docs-only, formatting-only, behavior-preserving renames with no truth impact, missing config, and no-code changes.",
2806
+ `Read .truthmark/config.yml, the configured root route index at ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, and relevant canonical docs.`,
2807
+ "direct checkout inspection is the canonical path; do not require the truthmark binary.",
2808
+ "May write canonical truth docs and truth routing files only; must not rewrite functional code.",
2809
+ "Read support/procedure.md before editing truth docs.",
2810
+ "Read support/subagents-and-leases.md before dispatching or accepting worker output.",
2811
+ "Read support/report-template.md before the final report."
2812
+ ],
2813
+ parentRule: "Parent agent owns Truth Sync acceptance, lease validation, and final report"
2814
+ },
2815
+ "truthmark-preview": {
2816
+ title: "Truthmark Preview",
2817
+ argumentHint: "Optional requested outcome, code area, doc path, or routing question",
2818
+ invocations: TRUTH_PREVIEW_EXPLICIT_INVOCATIONS,
2819
+ use: () => "Use this skill only when the user explicitly asks to preview Truthmark routing or workflow choice before edits.",
2820
+ quickRules: (config) => [
2821
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2822
+ `Read .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, and only the truth docs or implementation files needed to preview ownership.`,
2823
+ "Truth Preview is read-only; this report is intended, not authorized.",
2824
+ "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
+ "Use optional read-only route-auditor evidence only when it reduces context or clarifies ownership.",
2826
+ "Hand off to the selected workflow after user approval."
2827
+ ],
2828
+ parentRule: "Parent agent owns the final Truth Preview report"
2829
+ },
2830
+ "truthmark-realize": {
2831
+ title: "Truthmark Realize",
2832
+ argumentHint: "Optional truth doc path, area, or desired code behavior to realize",
2833
+ invocations: TRUTH_REALIZE_EXPLICIT_INVOCATIONS,
2834
+ use: () => "Use this skill only when the user explicitly asks to realize truth docs into code.",
2835
+ quickRules: (config) => [
2836
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2837
+ `Read the source truth docs, .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files, tests, and relevant functional code directly.`,
2838
+ "Truth docs lead; code follows.",
2839
+ "may write functional code only; must not edit truth docs or truth routing while realizing those docs.",
2840
+ "Read support/procedure.md before changing code.",
2841
+ "Read support/report-template.md before the final report."
2842
+ ]
2843
+ },
2844
+ "truthmark-check": {
2845
+ title: "Truthmark Check",
2846
+ argumentHint: "Optional area, doc path, or audit focus",
2847
+ invocations: TRUTH_CHECK_EXPLICIT_INVOCATIONS,
2848
+ use: () => "Use this skill to audit repository truth health.",
2849
+ quickRules: (config) => [
2850
+ "Follow docs/ai/repo-rules.md as the repository instruction authority.",
2851
+ `Read .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, canonical docs, and relevant implementation directly.`,
2852
+ "Report issues and suggested fixes; do not silently rewrite unrelated files.",
2853
+ "Direct checkout inspection is valid even when local tooling is unavailable.",
2854
+ "Read support/procedure.md before auditing details.",
2855
+ "Read support/subagents-and-leases.md before dispatching verifier subagents.",
2856
+ "Read support/report-template.md before the final report."
2857
+ ],
2858
+ parentRule: "Parent agent owns the final Truth Check report"
2859
+ }
2860
+ };
2861
+ var stripWorkflowSkillFrontmatter = (body) => {
2862
+ return body.replace(/^---\n[\s\S]*?\n---\n\n?/u, "").trim();
2863
+ };
2864
+ var splitWorkflowSupport = (body) => {
2865
+ const stripped = stripWorkflowSkillFrontmatter(body);
2866
+ const marker = "Report completion in this shape:";
2867
+ const markerIndex = stripped.indexOf(marker);
2868
+ if (markerIndex === -1) {
2869
+ return {
2870
+ procedure: stripped,
2871
+ reportTemplate: "Report completion in the workflow-specific shape."
2872
+ };
2873
+ }
2874
+ return {
2875
+ procedure: stripped.slice(0, markerIndex).trim(),
2876
+ reportTemplate: stripped.slice(markerIndex).trim()
2877
+ };
2878
+ };
2879
+ var renderSkillSupportFile = (title, body) => {
2880
+ return `# ${title}
2881
+
2882
+ Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
2883
+
2884
+ ${body}
2885
+ `;
2886
+ };
2887
+ var renderHelperManifest = (helpers) => {
2888
+ const manifest = {
2889
+ helpers: Object.fromEntries(
2890
+ helpers.map((helper) => [
2891
+ helper.id,
2892
+ {
2893
+ optional: helper.optional,
2894
+ runner: helper.runner,
2895
+ command: helper.command,
2896
+ inputs: helper.inputs,
2897
+ output: helper.output,
2898
+ writes: helper.writes,
2899
+ ...helper.allowedWrites === void 0 ? {} : { allowedWrites: helper.allowedWrites },
2900
+ fallback: helper.fallback
2901
+ }
2902
+ ])
2903
+ )
2904
+ };
2905
+ return [
2906
+ `# Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.`,
2907
+ stringify2(manifest, { lineWidth: 0 })
2908
+ ].join("\n");
2909
+ };
2910
+ var renderHelperPolicySupport = (helpers) => {
2911
+ const reportHelperId = helpers.find((helper) => helper.id.endsWith("-report"))?.id ?? helpers[0]?.id;
2912
+ const helperLines = helpers.map(
2913
+ (helper) => `- ${helper.id}: optional ${helper.runner}; manual fallback: ${helper.fallback}`
2914
+ ).join("\n");
2915
+ return renderSkillSupportFile(
2916
+ "Optional Helper CLI Policy",
2917
+ `Optional helper CLI commands may collect deterministic checkout facts or validate artifacts. If the Truthmark CLI is unavailable or too old for a declared helper, continue manually using this procedure and report which helper was skipped. Helper output is derived evidence; it does not override direct checkout inspection, workflow write boundaries, or parent acceptance.
2918
+
2919
+ Runner detection:
2920
+ - Check the declared Truthmark CLI runner before invoking a helper.
2921
+ - Invoke helpers through the installed \`truthmark validate ... --json\` CLI command using argv-style arguments from helper-manifest.yml.
2922
+ - If unavailable or version-mismatched, treat the helper as skipped and use the manual fallback.
2923
+ - Do not fail the workflow solely because a helper cannot run.
2924
+
2925
+ Available helpers:
2926
+ ${helperLines}
2927
+
2928
+ Final reports should include helper status when helpers are declared for this workflow:
2929
+
2930
+ \`\`\`md
2931
+ Helper scripts:
2932
+ - ${reportHelperId}: ran, passed
2933
+ - validate-write-lease: skipped, no write lease used
2934
+ \`\`\``
2935
+ );
2936
+ };
2937
+ var renderStandaloneWorkflowSkillBody = (workflowId, config) => {
2938
+ switch (workflowId) {
2939
+ case "truthmark-structure":
2940
+ return renderTruthStructureSkillBody(config);
2941
+ case "truthmark-document":
2942
+ return renderTruthDocumentSkillBody(config);
2943
+ case "truthmark-sync":
2944
+ return renderTruthSyncSkillBody(config);
2945
+ case "truthmark-preview":
2946
+ return renderTruthPreviewSkillBody(config);
2947
+ case "truthmark-realize":
2948
+ return renderTruthmarkRealizeSkillBody(config);
2949
+ case "truthmark-check":
2950
+ return renderTruthCheckSkillBody(config);
2951
+ }
2952
+ };
2953
+ var renderWorkflowEntrypoint = (workflowId, config, supportFiles, host) => {
2954
+ const workflow = getTruthmarkWorkflow(workflowId);
2955
+ const definition = WORKFLOW_PACKAGE_DEFINITIONS[workflowId];
2956
+ const supportFileList = supportFiles.map((supportFile) => `- ${supportFile}`).join("\n");
2957
+ const hostUsage = host === "github-copilot" ? "Use as a Copilot agent skill. Prompt files remain available under `.github/prompts/` for command-style invocation in supported Copilot IDEs." : host === "gemini-cli" ? "Use as a Gemini CLI Agent Skill; commands remain available under `/truthmark:*` for command-first invocation." : void 0;
2958
+ return `---
2959
+ name: ${workflowId}
2960
+ description: ${workflow.description}
2961
+ argument-hint: ${definition.argumentHint}
2962
+ user-invocable: true
2963
+ truthmark-version: ${TRUTHMARK_VERSION}
2964
+ ---
2965
+
2966
+ # ${definition.title}
2967
+
2968
+ ${definition.use(config)}
2969
+ ${hostUsage === void 0 ? "" : `
2970
+ ${hostUsage}
2971
+ `}
2972
+
2973
+ Invocations: ${definition.invocations}
2974
+
2975
+ Quick procedure:
2976
+ ${definition.quickRules(config).map((rule) => `- ${rule}`).join("\n")}
2977
+
2978
+ Progressive disclosure:
2979
+ ${supportFileList}
2980
+ `;
2981
+ };
2982
+ var renderWorkflowSubagentSupport = (workflowId, host) => {
2983
+ const workflow = getTruthmarkWorkflow(workflowId);
2984
+ const definition = WORKFLOW_PACKAGE_DEFINITIONS[workflowId];
2985
+ const readAgents = workflow.subagents ?? [];
2986
+ const writeAgents = workflow.writeSubagents ?? [];
2987
+ if (readAgents.length === 0 && writeAgents.length === 0) {
2988
+ return void 0;
2989
+ }
2990
+ if (definition.parentRule === void 0) {
2991
+ return void 0;
2992
+ }
2993
+ switch (host) {
2994
+ case "codex":
2995
+ return renderCodexSubagentModeSection(
2996
+ readAgents,
2997
+ definition.parentRule,
2998
+ writeAgents
2999
+ );
3000
+ case "opencode":
3001
+ return renderOpenCodeSubagentModeSection(
3002
+ readAgents,
3003
+ definition.parentRule,
3004
+ writeAgents
3005
+ );
3006
+ case "claude-code":
3007
+ return renderClaudeSubagentModeSection(
3008
+ readAgents,
3009
+ definition.parentRule,
3010
+ writeAgents
3011
+ );
3012
+ case "github-copilot":
3013
+ return renderCopilotCustomAgentModeSection(
3014
+ readAgents,
3015
+ definition.parentRule,
3016
+ writeAgents
3017
+ );
3018
+ case "gemini-cli":
3019
+ return renderGeminiSubagentModeSection(
3020
+ readAgents,
3021
+ definition.parentRule,
3022
+ writeAgents
3023
+ );
3024
+ }
3025
+ };
3026
+ var renderTruthmarkSkillPackage = ({
3027
+ skillPath,
3028
+ workflowId,
3029
+ host,
3030
+ config = defaultAgentConfig()
3031
+ }) => {
3032
+ const skillDirectory = skillPath.replace(/\/SKILL\.md$/u, "");
3033
+ const supportDirectory = `${skillDirectory}/support`;
3034
+ const { procedure, reportTemplate } = splitWorkflowSupport(
3035
+ renderStandaloneWorkflowSkillBody(workflowId, config)
3036
+ );
3037
+ const subagents = renderWorkflowSubagentSupport(workflowId, host);
3038
+ const helpers = getTruthmarkWorkflow(workflowId).helpers ?? [];
3039
+ const supportFiles = [
3040
+ "support/procedure.md",
3041
+ "support/report-template.md",
3042
+ ...subagents === void 0 ? [] : ["support/subagents-and-leases.md"],
3043
+ ...helpers.length === 0 ? [] : ["helper-manifest.yml", "support/helper-policy.md"]
3044
+ ];
3045
+ const definition = WORKFLOW_PACKAGE_DEFINITIONS[workflowId];
3046
+ const files = [
3047
+ {
3048
+ path: skillPath,
3049
+ content: renderWorkflowEntrypoint(workflowId, config, supportFiles, host)
3050
+ },
3051
+ {
3052
+ path: `${supportDirectory}/procedure.md`,
3053
+ content: renderSkillSupportFile(
3054
+ `${definition.title} Procedure`,
3055
+ procedure
3056
+ )
3057
+ },
3058
+ {
3059
+ path: `${supportDirectory}/report-template.md`,
3060
+ content: renderSkillSupportFile(
3061
+ `${definition.title} Report Template`,
3062
+ reportTemplate
3063
+ )
3064
+ }
3065
+ ];
3066
+ if (subagents !== void 0) {
3067
+ files.push({
3068
+ path: `${supportDirectory}/subagents-and-leases.md`,
3069
+ content: renderSkillSupportFile(
3070
+ `${definition.title} Subagents And Leases`,
3071
+ subagents
3072
+ )
3073
+ });
3074
+ }
3075
+ if (helpers.length > 0) {
3076
+ files.push(
3077
+ {
3078
+ path: `${skillDirectory}/helper-manifest.yml`,
3079
+ content: renderHelperManifest(helpers)
3080
+ },
3081
+ {
3082
+ path: `${supportDirectory}/helper-policy.md`,
3083
+ content: renderHelperPolicySupport(helpers)
3084
+ }
3085
+ );
3086
+ }
3087
+ return files;
3088
+ };
3089
+ var normalizeOpenCodePermissionPath = (path12) => {
3090
+ const normalized = path12.replace(/\\/gu, "/").replace(/^\.\//u, "").replace(/\/+$/u, "");
3091
+ return normalized === "" ? "." : normalized;
3092
+ };
3093
+ var appendOpenCodePermissionGlob = (root, glob) => {
3094
+ return root === "." ? glob.replace(/^\//u, "") : `${root}${glob}`;
3095
+ };
3096
+ var renderOpenCodeWriterEditAllowRules = (config) => {
3097
+ const truthDocsRoot = normalizeOpenCodePermissionPath(
3098
+ resolveTruthDocsRoot(config)
3099
+ );
3100
+ const rootRouteIndex = normalizeOpenCodePermissionPath(
3101
+ config.docs.routing.rootIndex
3102
+ );
3103
+ const areaFilesRoot = normalizeOpenCodePermissionPath(
3104
+ config.docs.routing.areaFilesRoot
3105
+ );
3106
+ const allowedPatterns = [
3107
+ appendOpenCodePermissionGlob(truthDocsRoot, "/**"),
3108
+ rootRouteIndex,
3109
+ appendOpenCodePermissionGlob(areaFilesRoot, "/**/*.md")
3110
+ ];
3111
+ return [...new Set(allowedPatterns)].map((pattern) => ` ${JSON.stringify(pattern)}: allow`).join("\n");
3112
+ };
3113
+ var READ_ONLY_SUBAGENT_CONTEXT_BOUNDARY = `Context boundary:
3114
+ Do not preload AGENTS.md, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, or repo-wide policy docs unless the parent explicitly assigns them as evidence.
3115
+ Use only the parent-assigned shard plus required checkout evidence files.
3116
+ Return findings only; the parent workflow owns repository-policy interpretation, final decisions, and all writes.`;
3117
+ var renderReadOnlySubagentInstructions = (instructions) => {
3118
+ return `${instructions}
3119
+ ${READ_ONLY_SUBAGENT_CONTEXT_BOUNDARY}`;
3120
+ };
3121
+ var TRUTHMARK_SUBAGENT_PROFILES = {
3122
+ truth_route_auditor: {
3123
+ codexName: "truth_route_auditor",
3124
+ copilotName: "truth-route-auditor",
3125
+ description: "Read-only Truthmark route auditor for bounded routing and ownership verification.",
3126
+ nicknameCandidates: ["Route Audit", "Route Trace", "Route Check"],
3127
+ instructions: `Stay read-only.
3128
+ Audit one bounded Truthmark route, area, or doc shard assigned by the parent.
3129
+ Read .truthmark/config.yml, the root route index, relevant child route files, mapped truth docs, and relevant implementation files directly.
3130
+ Find missing, stale, broad, overloaded, catch-all, mixed-owner, or unrouteable ownership.
3131
+ Do not edit files, stage changes, or propose broad rewrites.
3132
+ Return JSON only with keys: scope, filesReviewed, findings, evidence, confidence, recommendedWorkflow, notes.
3133
+ recommendedWorkflow must be one of: none, truthmark-document, truthmark-structure.`
3134
+ },
3135
+ truth_claim_verifier: {
3136
+ codexName: "truth_claim_verifier",
3137
+ copilotName: "truth-claim-verifier",
3138
+ description: "Read-only Truthmark claim verifier for checking canonical truth against checkout evidence.",
3139
+ nicknameCandidates: ["Claim Audit", "Claim Trace", "Claim Check"],
3140
+ instructions: `Stay read-only.
3141
+ Verify the behavior-bearing truth claims assigned by the parent against primary checkout evidence.
3142
+ Use implementation, tests, config, routing, generated templates, schemas, or explicit evidence blocks as primary evidence.
3143
+ Canonical docs and examples can corroborate but are not sole proof when implementation conflicts.
3144
+ For every checked claim, classify the result as supported | narrowed | removed | blocked.
3145
+ Do not edit files, stage changes, or invent missing behavior.
3146
+ Return JSON only with keys: scope, filesReviewed, claimsChecked, evidence, unsupportedClaims, confidence, recommendedWorkflow, notes.`
3147
+ },
3148
+ truth_doc_reviewer: {
3149
+ codexName: "truth_doc_reviewer",
3150
+ copilotName: "truth-doc-reviewer",
3151
+ description: "Read-only Truthmark doc reviewer for shape, decision, rationale, and evidence hygiene.",
3152
+ nicknameCandidates: ["Doc Audit", "Doc Shape", "Doc Check"],
3153
+ instructions: `Stay read-only.
3154
+ Review assigned canonical truth docs for frontmatter, source_of_truth, required template sections, Evidence checked entries, Product Decisions, and Rationale.
3155
+ Flag README.md files used as behavior truth targets, mixed-owner docs, and shape repairs that should move to Truth Structure.
3156
+ Do not edit files, stage changes, or rewrite docs.
3157
+ Return JSON only with keys: scope, filesReviewed, findings, evidence, confidence, recommendedWorkflow, notes.
3158
+ recommendedWorkflow must be one of: none, truthmark-document, truthmark-structure.`
3159
+ }
3160
+ };
3161
+ var TRUTHMARK_WRITE_SUBAGENT_PROFILES = {
3162
+ truth_doc_writer: {
3163
+ codexName: "truth_doc_writer",
3164
+ copilotName: "truth-doc-writer",
3165
+ description: "Write-capable Truthmark doc worker for one parent-leased truth-document shard.",
3166
+ nicknameCandidates: ["Doc Writer", "Truth Writer", "Doc Sync"],
3167
+ instructions: `Write one leased Truthmark truth-document shard assigned by the parent.
3168
+ Require an explicit write lease before editing. The lease must name workflow, worker, shard, objective, requiredReads, allowedWrites, forbiddenWrites, evidenceRequired, verification, and reportFields.
3169
+ Read every requiredReads entry directly before editing.
3170
+ Edit only leased canonical truth docs or leased truth routing files. Do not edit functional code, generated host surfaces, package files, config files, templates, or tests unless they are explicitly leased.
3171
+ Do not expand your own write scope. If the task needs an off-lease file, stop and report blocked.
3172
+ Block when ownership is missing or ambiguous, evidence does not support the requested claim, another worker changed the leased file, generated surfaces appear stale, or a required edit is outside the lease.
3173
+ Return YAML only with keys: ${TRUTHMARK_WRITE_WORKER_REPORT_FIELDS.join(", ")}.
3174
+ status must be completed or blocked.
3175
+ filesChanged must list only files you actually changed.
3176
+ offLeaseChanges must be empty for completed reports.
3177
+ The parent must validate the actual checkout diff before accepting your report.`
3178
+ }
3179
+ };
3180
+ var renderCodexReadOnlyAgent = ({
3181
+ name,
3182
+ description,
3183
+ nicknameCandidates,
3184
+ developerInstructions
3185
+ }) => {
3186
+ return `# Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3187
+ name = ${renderTomlString(name)}
3188
+ description = ${renderTomlString(description)}
3189
+ sandbox_mode = "read-only"
3190
+ nickname_candidates = ${renderTomlStringArray(nicknameCandidates)}
3191
+ developer_instructions = """
3192
+ ${developerInstructions}
3193
+ """
3194
+ `;
3195
+ };
3196
+ var renderCodexWriteAgent = ({
3197
+ name,
3198
+ description,
3199
+ nicknameCandidates,
3200
+ developerInstructions
3201
+ }) => {
3202
+ return `# Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3203
+ name = ${renderTomlString(name)}
3204
+ description = ${renderTomlString(description)}
3205
+ sandbox_mode = "workspace-write"
3206
+ nickname_candidates = ${renderTomlStringArray(nicknameCandidates)}
3207
+ developer_instructions = """
3208
+ ${developerInstructions}
3209
+ """
3210
+ `;
3211
+ };
3212
+ var renderCopilotReadOnlyAgent = ({
3213
+ copilotName,
3214
+ description,
3215
+ instructions
3216
+ }) => {
3217
+ const agentInstructions = renderReadOnlySubagentInstructions(instructions);
3218
+ return `---
3219
+ name: ${copilotName}
3220
+ description: ${description}
3221
+ tools: [read, search]
3222
+ ---
3223
+
3224
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3225
+
3226
+ ${agentInstructions}
3227
+ `;
3228
+ };
3229
+ var renderCopilotWriteAgent = ({
3230
+ copilotName,
3231
+ description,
3232
+ instructions
3233
+ }) => {
3234
+ return `---
3235
+ name: ${copilotName}
3236
+ description: ${description}
3237
+ tools: [read, search, edit]
3238
+ ---
3239
+
3240
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3241
+
3242
+ ${instructions}
3243
+ `;
3244
+ };
3245
+ var renderGeminiReadOnlyAgent = ({
3246
+ copilotName,
3247
+ description,
3248
+ instructions
3249
+ }) => {
3250
+ const agentInstructions = renderReadOnlySubagentInstructions(instructions);
3251
+ return `---
3252
+ name: ${copilotName}
3253
+ description: ${description}
3254
+ kind: local
3255
+ tools: [read_file, grep_search]
3256
+ ---
3257
+
3258
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3259
+
3260
+ Manual invocation: @${copilotName}
3261
+
3262
+ ${agentInstructions}
3263
+ `;
3264
+ };
3265
+ var renderGeminiWriteAgent = ({
3266
+ copilotName,
3267
+ description,
3268
+ instructions
3269
+ }) => {
3270
+ return `---
3271
+ name: ${copilotName}
3272
+ description: ${description}
3273
+ kind: local
3274
+ tools: [read_file, grep_search, write_file]
3275
+ ---
3276
+
3277
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3278
+
3279
+ Manual invocation: @${copilotName} with an explicit parent write lease.
3280
+
3281
+ ${instructions}
3282
+ `;
3283
+ };
3284
+ var renderClaudeReadOnlyAgent = ({
3285
+ copilotName,
3286
+ description,
3287
+ instructions
3288
+ }) => {
3289
+ const agentInstructions = renderReadOnlySubagentInstructions(instructions);
3290
+ return `---
3291
+ name: ${copilotName}
3292
+ description: ${description}
3293
+ tools: Read, Grep, Glob, LS
3294
+ ---
3295
+
3296
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3297
+
3298
+ Manual invocation: use the ${copilotName} subagent.
3299
+
3300
+ ${agentInstructions}
3301
+ `;
3302
+ };
3303
+ var renderClaudeWriteAgent = ({
3304
+ copilotName,
3305
+ description,
3306
+ instructions
3307
+ }) => {
3308
+ return `---
3309
+ name: ${copilotName}
3310
+ description: ${description}
3311
+ tools: Read, Grep, Glob, LS, Edit, MultiEdit
3312
+ ---
3313
+
3314
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3315
+
3316
+ Manual invocation: use the ${copilotName} subagent with an explicit parent write lease.
3317
+
3318
+ ${instructions}
3319
+ `;
3320
+ };
3321
+ var renderTruthmarkRouteAuditorAgent = () => {
3322
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor;
3323
+ return renderCodexReadOnlyAgent({
3324
+ name: profile.codexName,
3325
+ description: profile.description,
3326
+ nicknameCandidates: profile.nicknameCandidates,
3327
+ developerInstructions: renderReadOnlySubagentInstructions(
3328
+ profile.instructions
3329
+ )
3330
+ });
3331
+ };
3332
+ var renderTruthmarkClaimVerifierAgent = () => {
3333
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_claim_verifier;
3334
+ return renderCodexReadOnlyAgent({
3335
+ name: profile.codexName,
3336
+ description: profile.description,
3337
+ nicknameCandidates: profile.nicknameCandidates,
3338
+ developerInstructions: renderReadOnlySubagentInstructions(
3339
+ profile.instructions
3340
+ )
3341
+ });
3342
+ };
3343
+ var renderTruthmarkDocReviewerAgent = () => {
3344
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_doc_reviewer;
3345
+ return renderCodexReadOnlyAgent({
3346
+ name: profile.codexName,
3347
+ description: profile.description,
3348
+ nicknameCandidates: profile.nicknameCandidates,
3349
+ developerInstructions: renderReadOnlySubagentInstructions(
3350
+ profile.instructions
3351
+ )
3352
+ });
3353
+ };
3354
+ var renderTruthmarkDocWriterAgent = () => {
3355
+ const profile = TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer;
3356
+ return renderCodexWriteAgent({
3357
+ name: profile.codexName,
3358
+ description: profile.description,
3359
+ nicknameCandidates: profile.nicknameCandidates,
3360
+ developerInstructions: profile.instructions
3361
+ });
3362
+ };
3363
+ var renderTruthmarkCopilotRouteAuditorAgent = () => {
3364
+ return renderCopilotReadOnlyAgent(
3365
+ TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor
3366
+ );
3367
+ };
3368
+ var renderTruthmarkCopilotClaimVerifierAgent = () => {
3369
+ return renderCopilotReadOnlyAgent(
3370
+ TRUTHMARK_SUBAGENT_PROFILES.truth_claim_verifier
3371
+ );
3372
+ };
3373
+ var renderTruthmarkCopilotDocReviewerAgent = () => {
3374
+ return renderCopilotReadOnlyAgent(
3375
+ TRUTHMARK_SUBAGENT_PROFILES.truth_doc_reviewer
3376
+ );
3377
+ };
3378
+ var renderTruthmarkCopilotDocWriterAgent = () => {
3379
+ return renderCopilotWriteAgent(
3380
+ TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer
3381
+ );
3382
+ };
3383
+ var renderTruthmarkGeminiRouteAuditorAgent = () => {
3384
+ return renderGeminiReadOnlyAgent(
3385
+ TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor
3386
+ );
3387
+ };
3388
+ var renderTruthmarkGeminiClaimVerifierAgent = () => {
3389
+ return renderGeminiReadOnlyAgent(
3390
+ TRUTHMARK_SUBAGENT_PROFILES.truth_claim_verifier
3391
+ );
3392
+ };
3393
+ var renderTruthmarkGeminiDocReviewerAgent = () => {
3394
+ return renderGeminiReadOnlyAgent(
3395
+ TRUTHMARK_SUBAGENT_PROFILES.truth_doc_reviewer
3396
+ );
3397
+ };
3398
+ var renderTruthmarkGeminiDocWriterAgent = () => {
3399
+ return renderGeminiWriteAgent(
3400
+ TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer
3401
+ );
3402
+ };
3403
+ var renderTruthmarkClaudeRouteAuditorAgent = () => {
3404
+ return renderClaudeReadOnlyAgent(
3405
+ TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor
3406
+ );
3407
+ };
3408
+ var renderTruthmarkClaudeClaimVerifierAgent = () => {
3409
+ return renderClaudeReadOnlyAgent(
3410
+ TRUTHMARK_SUBAGENT_PROFILES.truth_claim_verifier
3411
+ );
2220
3412
  };
2221
- var renderTruthmarkStructureLocalSkill = (config = defaultAgentConfig()) => {
2222
- return renderTruthStructureSkillBody(config);
3413
+ var renderTruthmarkClaudeDocReviewerAgent = () => {
3414
+ return renderClaudeReadOnlyAgent(
3415
+ TRUTHMARK_SUBAGENT_PROFILES.truth_doc_reviewer
3416
+ );
3417
+ };
3418
+ var renderTruthmarkClaudeDocWriterAgent = () => {
3419
+ return renderClaudeWriteAgent(
3420
+ TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer
3421
+ );
3422
+ };
3423
+ var renderOpenCodeReadOnlyAgent = ({
3424
+ invocation,
3425
+ description,
3426
+ instructions
3427
+ }) => {
3428
+ const agentInstructions = renderReadOnlySubagentInstructions(instructions);
3429
+ return `---
3430
+ description: ${description}
3431
+ mode: subagent
3432
+ permission:
3433
+ edit: deny
3434
+ task: deny
3435
+ webfetch: deny
3436
+ websearch: deny
3437
+ external_directory: deny
3438
+ bash:
3439
+ "*": ask
3440
+ "git status*": allow
3441
+ "git diff*": allow
3442
+ "git log*": allow
3443
+ "rg *": allow
3444
+ "grep *": allow
3445
+ ---
3446
+
3447
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3448
+
3449
+ Manual invocation: @${invocation}
3450
+
3451
+ ${agentInstructions}
3452
+ `;
3453
+ };
3454
+ var renderOpenCodeWriteAgent = ({
3455
+ invocation,
3456
+ description,
3457
+ instructions,
3458
+ config
3459
+ }) => {
3460
+ const editAllowRules = renderOpenCodeWriterEditAllowRules(config);
3461
+ return `---
3462
+ description: ${description}
3463
+ mode: subagent
3464
+ permission:
3465
+ read: allow
3466
+ list: allow
3467
+ grep: allow
3468
+ glob: allow
3469
+ edit:
3470
+ "*": deny
3471
+ ${editAllowRules}
3472
+ task: deny
3473
+ webfetch: deny
3474
+ websearch: deny
3475
+ external_directory: deny
3476
+ bash:
3477
+ "*": ask
3478
+ "git status*": allow
3479
+ "git diff*": allow
3480
+ ---
3481
+
3482
+ # Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
3483
+
3484
+ Manual invocation: @${invocation}
3485
+
3486
+ ${instructions}
3487
+ `;
3488
+ };
3489
+ var renderTruthmarkOpenCodeRouteAuditorAgent = () => {
3490
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor;
3491
+ return renderOpenCodeReadOnlyAgent({
3492
+ invocation: profile.copilotName,
3493
+ description: profile.description,
3494
+ instructions: profile.instructions
3495
+ });
3496
+ };
3497
+ var renderTruthmarkOpenCodeClaimVerifierAgent = () => {
3498
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_claim_verifier;
3499
+ return renderOpenCodeReadOnlyAgent({
3500
+ invocation: profile.copilotName,
3501
+ description: profile.description,
3502
+ instructions: profile.instructions
3503
+ });
3504
+ };
3505
+ var renderTruthmarkOpenCodeDocReviewerAgent = () => {
3506
+ const profile = TRUTHMARK_SUBAGENT_PROFILES.truth_doc_reviewer;
3507
+ return renderOpenCodeReadOnlyAgent({
3508
+ invocation: profile.copilotName,
3509
+ description: profile.description,
3510
+ instructions: profile.instructions
3511
+ });
3512
+ };
3513
+ var renderTruthmarkOpenCodeDocWriterAgent = (config = defaultAgentConfig()) => {
3514
+ const profile = TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer;
3515
+ return renderOpenCodeWriteAgent({
3516
+ invocation: profile.copilotName,
3517
+ description: profile.description,
3518
+ instructions: profile.instructions,
3519
+ config
3520
+ });
2223
3521
  };
2224
3522
  var renderTruthmarkStructureSkillMetadata = () => {
2225
3523
  const workflow = getTruthmarkWorkflow("truthmark-structure");
@@ -2236,12 +3534,6 @@ truthmark:
2236
3534
  refresh_command: "truthmark init"
2237
3535
  `;
2238
3536
  };
2239
- var renderTruthmarkDocumentSkill = (config = defaultAgentConfig()) => {
2240
- return renderTruthDocumentSkillBody(config);
2241
- };
2242
- var renderTruthmarkDocumentLocalSkill = (config = defaultAgentConfig()) => {
2243
- return renderTruthDocumentSkillBody(config);
2244
- };
2245
3537
  var renderTruthmarkDocumentSkillMetadata = () => {
2246
3538
  const workflow = getTruthmarkWorkflow("truthmark-document");
2247
3539
  return `interface:
@@ -2257,12 +3549,6 @@ truthmark:
2257
3549
  refresh_command: "truthmark init"
2258
3550
  `;
2259
3551
  };
2260
- var renderTruthmarkSyncSkill = (config = defaultAgentConfig()) => {
2261
- return renderTruthSyncSkillBody(config);
2262
- };
2263
- var renderTruthmarkSyncLocalSkill = (config = defaultAgentConfig()) => {
2264
- return renderTruthSyncSkillBody(config);
2265
- };
2266
3552
  var renderTruthmarkSyncSkillMetadata = () => {
2267
3553
  const workflow = getTruthmarkWorkflow("truthmark-sync");
2268
3554
  return `interface:
@@ -2338,14 +3624,23 @@ Verification:
2338
3624
  \`\`\`
2339
3625
  `;
2340
3626
  };
2341
- var renderTruthmarkRealizeSkill = (config = defaultAgentConfig()) => {
2342
- return renderTruthmarkRealizeSkillBody(config);
2343
- };
2344
- var renderTruthmarkRealizeLocalSkill = (config = defaultAgentConfig()) => {
2345
- return renderTruthmarkRealizeSkillBody(config);
3627
+ var renderTruthmarkRealizeSkillMetadata = () => {
3628
+ const workflow = getTruthmarkWorkflow("truthmark-realize");
3629
+ return `interface:
3630
+ display_name: "${workflow.displayName}"
3631
+ short_description: "${workflow.shortDescription}"
3632
+ default_prompt: "${workflow.defaultPrompt}"
3633
+
3634
+ policy:
3635
+ allow_implicit_invocation: ${workflow.allowImplicitInvocation}
3636
+
3637
+ truthmark:
3638
+ version: "${TRUTHMARK_VERSION}"
3639
+ refresh_command: "truthmark init"
3640
+ `;
2346
3641
  };
2347
- var renderTruthmarkRealizeSkillMetadata = () => {
2348
- const workflow = getTruthmarkWorkflow("truthmark-realize");
3642
+ var renderTruthmarkPreviewSkillMetadata = () => {
3643
+ const workflow = getTruthmarkWorkflow("truthmark-preview");
2349
3644
  return `interface:
2350
3645
  display_name: "${workflow.displayName}"
2351
3646
  short_description: "${workflow.shortDescription}"
@@ -2359,12 +3654,6 @@ truthmark:
2359
3654
  refresh_command: "truthmark init"
2360
3655
  `;
2361
3656
  };
2362
- var renderTruthmarkCheckSkill = (config = defaultAgentConfig()) => {
2363
- return renderTruthCheckSkillBody(config);
2364
- };
2365
- var renderTruthmarkCheckLocalSkill = (config = defaultAgentConfig()) => {
2366
- return renderTruthCheckSkillBody(config);
2367
- };
2368
3657
  var renderTruthmarkCheckSkillMetadata = () => {
2369
3658
  const workflow = getTruthmarkWorkflow("truthmark-check");
2370
3659
  return `interface:
@@ -2415,25 +3704,38 @@ var renderTruthmarkGeminiCheckCommand = (config = defaultAgentConfig()) => {
2415
3704
  renderTruthCheckSkillBody(config)
2416
3705
  );
2417
3706
  };
3707
+ var renderTruthmarkGeminiPreviewCommand = (config = defaultAgentConfig()) => {
3708
+ const workflow = getTruthmarkWorkflow("truthmark-preview");
3709
+ return renderGeminiCommand(
3710
+ workflow.description,
3711
+ renderTruthPreviewSkillBody(config)
3712
+ );
3713
+ };
2418
3714
  var renderTruthmarkCopilotStructurePrompt = (config = defaultAgentConfig()) => {
2419
3715
  const workflow = getTruthmarkWorkflow("truthmark-structure");
2420
3716
  return renderCopilotPromptFile(
2421
3717
  workflow.description,
2422
- renderTruthStructureSkillBody(config)
3718
+ renderTruthStructureSkillBody(config, {
3719
+ includeCopilotCustomAgentMode: true
3720
+ })
2423
3721
  );
2424
3722
  };
2425
3723
  var renderTruthmarkCopilotDocumentPrompt = (config = defaultAgentConfig()) => {
2426
3724
  const workflow = getTruthmarkWorkflow("truthmark-document");
2427
3725
  return renderCopilotPromptFile(
2428
3726
  workflow.description,
2429
- renderTruthDocumentSkillBody(config)
3727
+ renderTruthDocumentSkillBody(config, {
3728
+ includeCopilotCustomAgentMode: true
3729
+ })
2430
3730
  );
2431
3731
  };
2432
3732
  var renderTruthmarkCopilotSyncPrompt = (config = defaultAgentConfig()) => {
2433
3733
  const workflow = getTruthmarkWorkflow("truthmark-sync");
2434
3734
  return renderCopilotPromptFile(
2435
3735
  workflow.description,
2436
- renderTruthSyncSkillBody(config)
3736
+ renderTruthSyncSkillBody(config, {
3737
+ includeCopilotCustomAgentMode: true
3738
+ })
2437
3739
  );
2438
3740
  };
2439
3741
  var renderTruthmarkCopilotRealizePrompt = (config = defaultAgentConfig()) => {
@@ -2447,84 +3749,253 @@ var renderTruthmarkCopilotCheckPrompt = (config = defaultAgentConfig()) => {
2447
3749
  const workflow = getTruthmarkWorkflow("truthmark-check");
2448
3750
  return renderCopilotPromptFile(
2449
3751
  workflow.description,
2450
- renderTruthCheckSkillBody(config)
3752
+ renderTruthCheckSkillBody(config, {
3753
+ includeCopilotCustomAgentMode: true
3754
+ })
3755
+ );
3756
+ };
3757
+ var renderTruthmarkCopilotPreviewPrompt = (config = defaultAgentConfig()) => {
3758
+ const workflow = getTruthmarkWorkflow("truthmark-preview");
3759
+ return renderCopilotPromptFile(
3760
+ workflow.description,
3761
+ renderTruthPreviewSkillBody(config)
2451
3762
  );
2452
3763
  };
2453
3764
 
2454
3765
  // src/templates/generated-surfaces.ts
2455
- var workflowSkillFiles = (basePath, config) => {
3766
+ var codexFiles = (config) => {
2456
3767
  const files = [
3768
+ ...renderTruthmarkSkillPackage({
3769
+ skillPath: TRUTHMARK_STRUCTURE_SKILL_PATH,
3770
+ workflowId: "truthmark-structure",
3771
+ host: "codex",
3772
+ config
3773
+ }),
2457
3774
  {
2458
- path: `${basePath}/truthmark-structure/SKILL.md`,
2459
- content: renderTruthmarkStructureLocalSkill(config)
3775
+ path: TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH,
3776
+ content: renderTruthmarkStructureSkillMetadata()
2460
3777
  },
3778
+ ...renderTruthmarkSkillPackage({
3779
+ skillPath: TRUTHMARK_DOCUMENT_SKILL_PATH,
3780
+ workflowId: "truthmark-document",
3781
+ host: "codex",
3782
+ config
3783
+ }),
2461
3784
  {
2462
- path: `${basePath}/truthmark-document/SKILL.md`,
2463
- content: renderTruthmarkDocumentLocalSkill(config)
3785
+ path: TRUTHMARK_DOCUMENT_SKILL_METADATA_PATH,
3786
+ content: renderTruthmarkDocumentSkillMetadata()
2464
3787
  },
3788
+ ...renderTruthmarkSkillPackage({
3789
+ skillPath: TRUTHMARK_SYNC_SKILL_PATH,
3790
+ workflowId: "truthmark-sync",
3791
+ host: "codex",
3792
+ config
3793
+ }),
2465
3794
  {
2466
- path: `${basePath}/truthmark-sync/SKILL.md`,
2467
- content: renderTruthmarkSyncLocalSkill(config)
3795
+ path: TRUTHMARK_SYNC_SKILL_METADATA_PATH,
3796
+ content: renderTruthmarkSyncSkillMetadata()
2468
3797
  },
3798
+ ...renderTruthmarkSkillPackage({
3799
+ skillPath: TRUTHMARK_PREVIEW_SKILL_PATH,
3800
+ workflowId: "truthmark-preview",
3801
+ host: "codex",
3802
+ config
3803
+ }),
2469
3804
  {
2470
- path: `${basePath}/truthmark-check/SKILL.md`,
2471
- content: renderTruthmarkCheckLocalSkill(config)
3805
+ path: TRUTHMARK_PREVIEW_SKILL_METADATA_PATH,
3806
+ content: renderTruthmarkPreviewSkillMetadata()
2472
3807
  },
3808
+ ...renderTruthmarkSkillPackage({
3809
+ skillPath: TRUTHMARK_CHECK_SKILL_PATH,
3810
+ workflowId: "truthmark-check",
3811
+ host: "codex",
3812
+ config
3813
+ }),
2473
3814
  {
2474
- path: `${basePath}/truthmark-realize/SKILL.md`,
2475
- content: renderTruthmarkRealizeLocalSkill(config)
2476
- }
2477
- ];
2478
- return files;
2479
- };
2480
- var codexFiles = (config) => {
2481
- const files = [
3815
+ path: TRUTHMARK_CHECK_SKILL_METADATA_PATH,
3816
+ content: renderTruthmarkCheckSkillMetadata()
3817
+ },
3818
+ ...renderTruthmarkSkillPackage({
3819
+ skillPath: TRUTHMARK_REALIZE_SKILL_PATH,
3820
+ workflowId: "truthmark-realize",
3821
+ host: "codex",
3822
+ config
3823
+ }),
2482
3824
  {
2483
- path: TRUTHMARK_STRUCTURE_SKILL_PATH,
2484
- content: renderTruthmarkStructureSkill(config)
3825
+ path: TRUTHMARK_REALIZE_SKILL_METADATA_PATH,
3826
+ content: renderTruthmarkRealizeSkillMetadata()
2485
3827
  },
2486
3828
  {
2487
- path: TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH,
2488
- content: renderTruthmarkStructureSkillMetadata()
3829
+ path: TRUTHMARK_ROUTE_AUDITOR_AGENT_PATH,
3830
+ content: renderTruthmarkRouteAuditorAgent()
2489
3831
  },
2490
3832
  {
2491
- path: TRUTHMARK_DOCUMENT_SKILL_PATH,
2492
- content: renderTruthmarkDocumentSkill(config)
3833
+ path: TRUTHMARK_CLAIM_VERIFIER_AGENT_PATH,
3834
+ content: renderTruthmarkClaimVerifierAgent()
2493
3835
  },
2494
3836
  {
2495
- path: TRUTHMARK_DOCUMENT_SKILL_METADATA_PATH,
2496
- content: renderTruthmarkDocumentSkillMetadata()
3837
+ path: TRUTHMARK_DOC_REVIEWER_AGENT_PATH,
3838
+ content: renderTruthmarkDocReviewerAgent()
3839
+ },
3840
+ {
3841
+ path: TRUTHMARK_DOC_WRITER_AGENT_PATH,
3842
+ content: renderTruthmarkDocWriterAgent()
3843
+ }
3844
+ ];
3845
+ return files;
3846
+ };
3847
+ var opencodeFiles = (config) => {
3848
+ return [
3849
+ ...renderTruthmarkSkillPackage({
3850
+ skillPath: ".opencode/skills/truthmark-structure/SKILL.md",
3851
+ workflowId: "truthmark-structure",
3852
+ host: "opencode",
3853
+ config
3854
+ }),
3855
+ ...renderTruthmarkSkillPackage({
3856
+ skillPath: ".opencode/skills/truthmark-document/SKILL.md",
3857
+ workflowId: "truthmark-document",
3858
+ host: "opencode",
3859
+ config
3860
+ }),
3861
+ ...renderTruthmarkSkillPackage({
3862
+ skillPath: ".opencode/skills/truthmark-sync/SKILL.md",
3863
+ workflowId: "truthmark-sync",
3864
+ host: "opencode",
3865
+ config
3866
+ }),
3867
+ ...renderTruthmarkSkillPackage({
3868
+ skillPath: ".opencode/skills/truthmark-preview/SKILL.md",
3869
+ workflowId: "truthmark-preview",
3870
+ host: "opencode",
3871
+ config
3872
+ }),
3873
+ ...renderTruthmarkSkillPackage({
3874
+ skillPath: ".opencode/skills/truthmark-check/SKILL.md",
3875
+ workflowId: "truthmark-check",
3876
+ host: "opencode",
3877
+ config
3878
+ }),
3879
+ ...renderTruthmarkSkillPackage({
3880
+ skillPath: ".opencode/skills/truthmark-realize/SKILL.md",
3881
+ workflowId: "truthmark-realize",
3882
+ host: "opencode",
3883
+ config
3884
+ }),
3885
+ {
3886
+ path: TRUTHMARK_OPENCODE_ROUTE_AUDITOR_AGENT_PATH,
3887
+ content: renderTruthmarkOpenCodeRouteAuditorAgent()
2497
3888
  },
2498
3889
  {
2499
- path: TRUTHMARK_SYNC_SKILL_PATH,
2500
- content: renderTruthmarkSyncSkill(config)
3890
+ path: TRUTHMARK_OPENCODE_CLAIM_VERIFIER_AGENT_PATH,
3891
+ content: renderTruthmarkOpenCodeClaimVerifierAgent()
2501
3892
  },
2502
3893
  {
2503
- path: TRUTHMARK_SYNC_SKILL_METADATA_PATH,
2504
- content: renderTruthmarkSyncSkillMetadata()
3894
+ path: TRUTHMARK_OPENCODE_DOC_REVIEWER_AGENT_PATH,
3895
+ content: renderTruthmarkOpenCodeDocReviewerAgent()
2505
3896
  },
2506
3897
  {
2507
- path: TRUTHMARK_CHECK_SKILL_PATH,
2508
- content: renderTruthmarkCheckSkill(config)
3898
+ path: TRUTHMARK_OPENCODE_DOC_WRITER_AGENT_PATH,
3899
+ content: renderTruthmarkOpenCodeDocWriterAgent(config)
3900
+ }
3901
+ ];
3902
+ };
3903
+ var claudeFiles = (config, block) => {
3904
+ return [
3905
+ ...instructionBlockFiles(["CLAUDE.md"], block),
3906
+ ...renderTruthmarkSkillPackage({
3907
+ skillPath: ".claude/skills/truthmark-structure/SKILL.md",
3908
+ workflowId: "truthmark-structure",
3909
+ host: "claude-code",
3910
+ config
3911
+ }),
3912
+ ...renderTruthmarkSkillPackage({
3913
+ skillPath: ".claude/skills/truthmark-document/SKILL.md",
3914
+ workflowId: "truthmark-document",
3915
+ host: "claude-code",
3916
+ config
3917
+ }),
3918
+ ...renderTruthmarkSkillPackage({
3919
+ skillPath: ".claude/skills/truthmark-sync/SKILL.md",
3920
+ workflowId: "truthmark-sync",
3921
+ host: "claude-code",
3922
+ config
3923
+ }),
3924
+ ...renderTruthmarkSkillPackage({
3925
+ skillPath: ".claude/skills/truthmark-preview/SKILL.md",
3926
+ workflowId: "truthmark-preview",
3927
+ host: "claude-code",
3928
+ config
3929
+ }),
3930
+ ...renderTruthmarkSkillPackage({
3931
+ skillPath: ".claude/skills/truthmark-check/SKILL.md",
3932
+ workflowId: "truthmark-check",
3933
+ host: "claude-code",
3934
+ config
3935
+ }),
3936
+ ...renderTruthmarkSkillPackage({
3937
+ skillPath: ".claude/skills/truthmark-realize/SKILL.md",
3938
+ workflowId: "truthmark-realize",
3939
+ host: "claude-code",
3940
+ config
3941
+ }),
3942
+ {
3943
+ path: TRUTHMARK_CLAUDE_ROUTE_AUDITOR_AGENT_PATH,
3944
+ content: renderTruthmarkClaudeRouteAuditorAgent()
2509
3945
  },
2510
3946
  {
2511
- path: TRUTHMARK_CHECK_SKILL_METADATA_PATH,
2512
- content: renderTruthmarkCheckSkillMetadata()
3947
+ path: TRUTHMARK_CLAUDE_CLAIM_VERIFIER_AGENT_PATH,
3948
+ content: renderTruthmarkClaudeClaimVerifierAgent()
2513
3949
  },
2514
3950
  {
2515
- path: TRUTHMARK_REALIZE_SKILL_PATH,
2516
- content: renderTruthmarkRealizeSkill(config)
3951
+ path: TRUTHMARK_CLAUDE_DOC_REVIEWER_AGENT_PATH,
3952
+ content: renderTruthmarkClaudeDocReviewerAgent()
2517
3953
  },
2518
3954
  {
2519
- path: TRUTHMARK_REALIZE_SKILL_METADATA_PATH,
2520
- content: renderTruthmarkRealizeSkillMetadata()
3955
+ path: TRUTHMARK_CLAUDE_DOC_WRITER_AGENT_PATH,
3956
+ content: renderTruthmarkClaudeDocWriterAgent()
2521
3957
  }
2522
3958
  ];
2523
- return files;
2524
3959
  };
2525
3960
  var copilotFiles = (config, block) => {
2526
3961
  const files = [
2527
3962
  ...instructionBlockFiles([".github/copilot-instructions.md"], block),
3963
+ ...renderTruthmarkSkillPackage({
3964
+ skillPath: ".github/skills/truthmark-structure/SKILL.md",
3965
+ workflowId: "truthmark-structure",
3966
+ host: "github-copilot",
3967
+ config
3968
+ }),
3969
+ ...renderTruthmarkSkillPackage({
3970
+ skillPath: ".github/skills/truthmark-document/SKILL.md",
3971
+ workflowId: "truthmark-document",
3972
+ host: "github-copilot",
3973
+ config
3974
+ }),
3975
+ ...renderTruthmarkSkillPackage({
3976
+ skillPath: ".github/skills/truthmark-sync/SKILL.md",
3977
+ workflowId: "truthmark-sync",
3978
+ host: "github-copilot",
3979
+ config
3980
+ }),
3981
+ ...renderTruthmarkSkillPackage({
3982
+ skillPath: ".github/skills/truthmark-preview/SKILL.md",
3983
+ workflowId: "truthmark-preview",
3984
+ host: "github-copilot",
3985
+ config
3986
+ }),
3987
+ ...renderTruthmarkSkillPackage({
3988
+ skillPath: ".github/skills/truthmark-check/SKILL.md",
3989
+ workflowId: "truthmark-check",
3990
+ host: "github-copilot",
3991
+ config
3992
+ }),
3993
+ ...renderTruthmarkSkillPackage({
3994
+ skillPath: ".github/skills/truthmark-realize/SKILL.md",
3995
+ workflowId: "truthmark-realize",
3996
+ host: "github-copilot",
3997
+ config
3998
+ }),
2528
3999
  {
2529
4000
  path: TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH,
2530
4001
  content: renderTruthmarkCopilotStructurePrompt(config)
@@ -2537,6 +4008,10 @@ var copilotFiles = (config, block) => {
2537
4008
  path: TRUTHMARK_COPILOT_SYNC_PROMPT_PATH,
2538
4009
  content: renderTruthmarkCopilotSyncPrompt(config)
2539
4010
  },
4011
+ {
4012
+ path: TRUTHMARK_COPILOT_PREVIEW_PROMPT_PATH,
4013
+ content: renderTruthmarkCopilotPreviewPrompt(config)
4014
+ },
2540
4015
  {
2541
4016
  path: TRUTHMARK_COPILOT_CHECK_PROMPT_PATH,
2542
4017
  content: renderTruthmarkCopilotCheckPrompt(config)
@@ -2544,10 +4019,107 @@ var copilotFiles = (config, block) => {
2544
4019
  {
2545
4020
  path: TRUTHMARK_COPILOT_REALIZE_PROMPT_PATH,
2546
4021
  content: renderTruthmarkCopilotRealizePrompt(config)
4022
+ },
4023
+ {
4024
+ path: TRUTHMARK_COPILOT_ROUTE_AUDITOR_AGENT_PATH,
4025
+ content: renderTruthmarkCopilotRouteAuditorAgent()
4026
+ },
4027
+ {
4028
+ path: TRUTHMARK_COPILOT_CLAIM_VERIFIER_AGENT_PATH,
4029
+ content: renderTruthmarkCopilotClaimVerifierAgent()
4030
+ },
4031
+ {
4032
+ path: TRUTHMARK_COPILOT_DOC_REVIEWER_AGENT_PATH,
4033
+ content: renderTruthmarkCopilotDocReviewerAgent()
4034
+ },
4035
+ {
4036
+ path: TRUTHMARK_COPILOT_DOC_WRITER_AGENT_PATH,
4037
+ content: renderTruthmarkCopilotDocWriterAgent()
2547
4038
  }
2548
4039
  ];
2549
4040
  return files;
2550
4041
  };
4042
+ var geminiFiles = (config, block) => {
4043
+ return [
4044
+ ...instructionBlockFiles(["GEMINI.md"], block),
4045
+ ...renderTruthmarkSkillPackage({
4046
+ skillPath: ".gemini/skills/truthmark-structure/SKILL.md",
4047
+ workflowId: "truthmark-structure",
4048
+ host: "gemini-cli",
4049
+ config
4050
+ }),
4051
+ ...renderTruthmarkSkillPackage({
4052
+ skillPath: ".gemini/skills/truthmark-document/SKILL.md",
4053
+ workflowId: "truthmark-document",
4054
+ host: "gemini-cli",
4055
+ config
4056
+ }),
4057
+ ...renderTruthmarkSkillPackage({
4058
+ skillPath: ".gemini/skills/truthmark-sync/SKILL.md",
4059
+ workflowId: "truthmark-sync",
4060
+ host: "gemini-cli",
4061
+ config
4062
+ }),
4063
+ ...renderTruthmarkSkillPackage({
4064
+ skillPath: ".gemini/skills/truthmark-preview/SKILL.md",
4065
+ workflowId: "truthmark-preview",
4066
+ host: "gemini-cli",
4067
+ config
4068
+ }),
4069
+ ...renderTruthmarkSkillPackage({
4070
+ skillPath: ".gemini/skills/truthmark-check/SKILL.md",
4071
+ workflowId: "truthmark-check",
4072
+ host: "gemini-cli",
4073
+ config
4074
+ }),
4075
+ ...renderTruthmarkSkillPackage({
4076
+ skillPath: ".gemini/skills/truthmark-realize/SKILL.md",
4077
+ workflowId: "truthmark-realize",
4078
+ host: "gemini-cli",
4079
+ config
4080
+ }),
4081
+ {
4082
+ path: TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH,
4083
+ content: renderTruthmarkGeminiStructureCommand(config)
4084
+ },
4085
+ {
4086
+ path: TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH,
4087
+ content: renderTruthmarkGeminiDocumentCommand(config)
4088
+ },
4089
+ {
4090
+ path: TRUTHMARK_GEMINI_SYNC_COMMAND_PATH,
4091
+ content: renderTruthmarkGeminiSyncCommand(config)
4092
+ },
4093
+ {
4094
+ path: TRUTHMARK_GEMINI_PREVIEW_COMMAND_PATH,
4095
+ content: renderTruthmarkGeminiPreviewCommand(config)
4096
+ },
4097
+ {
4098
+ path: TRUTHMARK_GEMINI_CHECK_COMMAND_PATH,
4099
+ content: renderTruthmarkGeminiCheckCommand(config)
4100
+ },
4101
+ {
4102
+ path: TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH,
4103
+ content: renderTruthmarkGeminiRealizeCommand(config)
4104
+ },
4105
+ {
4106
+ path: TRUTHMARK_GEMINI_ROUTE_AUDITOR_AGENT_PATH,
4107
+ content: renderTruthmarkGeminiRouteAuditorAgent()
4108
+ },
4109
+ {
4110
+ path: TRUTHMARK_GEMINI_CLAIM_VERIFIER_AGENT_PATH,
4111
+ content: renderTruthmarkGeminiClaimVerifierAgent()
4112
+ },
4113
+ {
4114
+ path: TRUTHMARK_GEMINI_DOC_REVIEWER_AGENT_PATH,
4115
+ content: renderTruthmarkGeminiDocReviewerAgent()
4116
+ },
4117
+ {
4118
+ path: TRUTHMARK_GEMINI_DOC_WRITER_AGENT_PATH,
4119
+ content: renderTruthmarkGeminiDocWriterAgent()
4120
+ }
4121
+ ];
4122
+ };
2551
4123
  var instructionBlockFiles = (paths, block) => {
2552
4124
  return paths.map((path12) => ({
2553
4125
  path: path12,
@@ -2560,48 +4132,25 @@ var filesForPlatform = (platform, config, block) => {
2560
4132
  case "codex":
2561
4133
  return codexFiles(config);
2562
4134
  case "opencode":
2563
- return workflowSkillFiles(".opencode/skills", config);
4135
+ return opencodeFiles(config);
2564
4136
  case "claude-code":
2565
- return [
2566
- ...instructionBlockFiles(["CLAUDE.md"], block),
2567
- ...workflowSkillFiles(".claude/skills", config)
2568
- ];
4137
+ return claudeFiles(config, block);
2569
4138
  case "github-copilot":
2570
4139
  return copilotFiles(config, block);
2571
4140
  case "gemini-cli":
2572
- return [
2573
- ...instructionBlockFiles(["GEMINI.md"], block),
2574
- {
2575
- path: TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH,
2576
- content: renderTruthmarkGeminiStructureCommand(config)
2577
- },
2578
- {
2579
- path: TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH,
2580
- content: renderTruthmarkGeminiDocumentCommand(config)
2581
- },
2582
- {
2583
- path: TRUTHMARK_GEMINI_SYNC_COMMAND_PATH,
2584
- content: renderTruthmarkGeminiSyncCommand(config)
2585
- },
2586
- {
2587
- path: TRUTHMARK_GEMINI_CHECK_COMMAND_PATH,
2588
- content: renderTruthmarkGeminiCheckCommand(config)
2589
- },
2590
- {
2591
- path: TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH,
2592
- content: renderTruthmarkGeminiRealizeCommand(config)
2593
- }
2594
- ];
4141
+ return geminiFiles(config, block);
2595
4142
  }
2596
4143
  };
2597
4144
  var renderGeneratedSurfaces = (config, block = renderAgentsBlock(config)) => {
2598
4145
  const files = [
2599
4146
  ...instructionBlockFiles(config.instructionTargets, block),
2600
- ...config.platforms.flatMap((platform) => filesForPlatform(platform, config, block))
4147
+ ...config.platforms.flatMap(
4148
+ (platform) => filesForPlatform(platform, config, block)
4149
+ )
2601
4150
  ];
2602
- return Array.from(new Map(files.map((file) => [file.path, file])).values()).sort(
2603
- (left, right) => left.path.localeCompare(right.path)
2604
- );
4151
+ return Array.from(
4152
+ new Map(files.map((file) => [file.path, file])).values()
4153
+ ).sort((left, right) => left.path.localeCompare(right.path));
2605
4154
  };
2606
4155
 
2607
4156
  // src/init/init.ts
@@ -2733,7 +4282,7 @@ var diagnosticCategoryForPath = (filePath, config) => {
2733
4282
  if (filePath === "AGENTS.md") {
2734
4283
  return "truth-sync";
2735
4284
  }
2736
- if (filePath === "CLAUDE.md" || filePath === "GEMINI.md" || filePath === ".github/copilot-instructions.md" || filePath.startsWith(".github/prompts/truthmark-") || filePath.startsWith(".claude/skills/truthmark-") || filePath.startsWith(".opencode/skills/truthmark-")) {
4285
+ if (filePath === "CLAUDE.md" || filePath === "GEMINI.md" || filePath === ".github/copilot-instructions.md" || filePath.startsWith(".github/prompts/truthmark-") || filePath.startsWith(".github/agents/truth-") || filePath.startsWith(".claude/agents/truth-") || filePath.startsWith(".claude/skills/truthmark-") || filePath.startsWith(".opencode/skills/truthmark-") || filePath.startsWith(".opencode/agents/") || filePath.startsWith(".codex/agents/")) {
2737
4286
  return "truth-sync";
2738
4287
  }
2739
4288
  if (filePath.startsWith(".codex/skills/truthmark-structure/")) {
@@ -2745,6 +4294,9 @@ var diagnosticCategoryForPath = (filePath, config) => {
2745
4294
  if (filePath.startsWith(".codex/skills/truthmark-sync/")) {
2746
4295
  return "truth-sync";
2747
4296
  }
4297
+ if (filePath.startsWith(".codex/skills/truthmark-preview/")) {
4298
+ return "truth-sync";
4299
+ }
2748
4300
  if (filePath.startsWith(".codex/skills/truthmark-realize/")) {
2749
4301
  return "realization";
2750
4302
  }
@@ -3176,12 +4728,12 @@ var checkLinks = async (rootDir, markdownPaths) => {
3176
4728
  // src/checks/areas.ts
3177
4729
  import fs13 from "fs/promises";
3178
4730
  import fg5 from "fast-glob";
3179
- import micromatch3 from "micromatch";
4731
+ import micromatch4 from "micromatch";
3180
4732
 
3181
4733
  // src/routing/area-resolver.ts
3182
4734
  import fs12 from "fs/promises";
3183
4735
  import fg4 from "fast-glob";
3184
- import micromatch from "micromatch";
4736
+ import micromatch2 from "micromatch";
3185
4737
  var unique = (values) => {
3186
4738
  return [...new Set(values)];
3187
4739
  };
@@ -3200,7 +4752,7 @@ var isCodeSurfaceWithinParent = (childPattern, parentPatterns) => {
3200
4752
  return false;
3201
4753
  }
3202
4754
  return parentPatterns.some((parentPattern) => {
3203
- return micromatch.isMatch(childPrefix, parentPattern) || micromatch.isMatch(childPattern, parentPattern);
4755
+ return micromatch2.isMatch(childPrefix, parentPattern) || micromatch2.isMatch(childPattern, parentPattern);
3204
4756
  });
3205
4757
  };
3206
4758
  var ensureChildPath = async (rootDir, areaFilesRoot, filePath) => {
@@ -3387,7 +4939,7 @@ var resolveAreaRouting = async (rootDir, config) => {
3387
4939
  };
3388
4940
 
3389
4941
  // src/sync/classify.ts
3390
- import micromatch2 from "micromatch";
4942
+ import micromatch3 from "micromatch";
3391
4943
  var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
3392
4944
  ".c",
3393
4945
  ".cc",
@@ -3507,10 +5059,10 @@ var classifyPath = (filePath, ignorePatterns) => {
3507
5059
  if (normalizedPath.startsWith(".truthmark/")) {
3508
5060
  return "derived";
3509
5061
  }
3510
- if (normalizedPath.startsWith(".claude/") || normalizedPath.startsWith(".codex/") || normalizedPath.startsWith(".gemini/commands/") || normalizedPath.startsWith(".opencode/") || normalizedPath === ".github/copilot-instructions.md" || normalizedPath.startsWith(".github/prompts/truthmark-") || normalizedPath === "AGENTS.md" || normalizedPath === "CLAUDE.md" || normalizedPath === "GEMINI.md" || normalizedPath.startsWith(".gemini/commands/truthmark/")) {
5062
+ if (normalizedPath.startsWith(".claude/") || normalizedPath.startsWith(".codex/") || normalizedPath.startsWith(".gemini/commands/") || normalizedPath.startsWith(".opencode/") || normalizedPath === ".github/copilot-instructions.md" || normalizedPath.startsWith(".github/agents/truth-") || normalizedPath.startsWith(".github/prompts/truthmark-") || normalizedPath === "AGENTS.md" || normalizedPath === "CLAUDE.md" || normalizedPath === "GEMINI.md" || normalizedPath.startsWith(".gemini/commands/truthmark/")) {
3511
5063
  return "derived";
3512
5064
  }
3513
- if (ignorePatterns.length > 0 && micromatch2.isMatch(normalizedPath, ignorePatterns)) {
5065
+ if (ignorePatterns.length > 0 && micromatch3.isMatch(normalizedPath, ignorePatterns)) {
3514
5066
  return "ignored";
3515
5067
  }
3516
5068
  if (normalizedPath.toLowerCase().endsWith(".md")) {
@@ -3806,7 +5358,7 @@ var checkAreas = async (rootDir, config) => {
3806
5358
  }
3807
5359
  for (const codeFile of codeFiles.sort()) {
3808
5360
  const matched = areaCoverage.some(
3809
- (entry) => entry.valid && entry.patterns.some((pattern) => micromatch3.isMatch(codeFile, pattern))
5361
+ (entry) => entry.valid && entry.patterns.some((pattern) => micromatch4.isMatch(codeFile, pattern))
3810
5362
  );
3811
5363
  if (!matched) {
3812
5364
  diagnostics.push({
@@ -3837,7 +5389,7 @@ var checkAreas = async (rootDir, config) => {
3837
5389
 
3838
5390
  // src/checks/decisions.ts
3839
5391
  import fs14 from "fs/promises";
3840
- import micromatch4 from "micromatch";
5392
+ import micromatch5 from "micromatch";
3841
5393
  var REQUIRED_DECISION_HEADINGS = ["Scope", "Product Decisions", "Rationale"];
3842
5394
  var isTruthDocumentKind3 = (value) => {
3843
5395
  return TRUTH_DOCUMENT_KINDS.includes(value);
@@ -3901,7 +5453,7 @@ var decisionTruthGlobs = (config) => {
3901
5453
  ].filter((root) => Boolean(root)).map((root) => `${root}/**/*.md`);
3902
5454
  };
3903
5455
  var isDecisionTruthCandidate = (config, filePath) => {
3904
- return !filePath.endsWith("/README.md") && micromatch4.isMatch(filePath, decisionTruthGlobs(config));
5456
+ return !filePath.endsWith("/README.md") && micromatch5.isMatch(filePath, decisionTruthGlobs(config));
3905
5457
  };
3906
5458
  var checkDecisionSections = async (rootDir, config, markdownPaths, truthDocumentEntries = []) => {
3907
5459
  const diagnostics = [];
@@ -4020,7 +5572,7 @@ var checkGeneratedSurfaces = async (rootDir, config) => {
4020
5572
 
4021
5573
  // src/impact/build.ts
4022
5574
  import path9 from "path";
4023
- import micromatch6 from "micromatch";
5575
+ import micromatch7 from "micromatch";
4024
5576
 
4025
5577
  // src/repo-index/build.ts
4026
5578
  import fs18 from "fs/promises";
@@ -4032,7 +5584,7 @@ import path5 from "path";
4032
5584
  import { execa as execa2 } from "execa";
4033
5585
  import fg6 from "fast-glob";
4034
5586
  import matter2 from "gray-matter";
4035
- import micromatch5 from "micromatch";
5587
+ import micromatch6 from "micromatch";
4036
5588
  var languageByExtension = /* @__PURE__ */ new Map([
4037
5589
  [".ts", "typescript"],
4038
5590
  [".tsx", "typescript"],
@@ -4109,7 +5661,7 @@ var gitDiscoverableFiles = async (rootDir) => {
4109
5661
  return result.stdout.split("\n").map((line) => normalizePath2(line.trim())).filter((line) => line.length > 0);
4110
5662
  };
4111
5663
  var isIgnoredPath = (filePath, ignore) => {
4112
- return micromatch5.isMatch(filePath, [...defaultIgnore, ...ignore]);
5664
+ return micromatch6.isMatch(filePath, [...defaultIgnore, ...ignore]);
4113
5665
  };
4114
5666
  var discoverRepoFiles = async (rootDir, ignore) => {
4115
5667
  const discoveredFiles = await gitDiscoverableFiles(rootDir) ?? await fg6(["**/*"], {
@@ -4123,6 +5675,18 @@ var discoverRepoFiles = async (rootDir, ignore) => {
4123
5675
  const docs = [];
4124
5676
  const tests = [];
4125
5677
  for (const filePath of discoveredFiles.filter((entry) => !isIgnoredPath(entry, ignore)).sort()) {
5678
+ let stat;
5679
+ try {
5680
+ stat = await fs16.stat(path5.join(rootDir, filePath));
5681
+ } catch (error) {
5682
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
5683
+ continue;
5684
+ }
5685
+ throw error;
5686
+ }
5687
+ if (!stat.isFile()) {
5688
+ continue;
5689
+ }
4126
5690
  const extension = path5.posix.extname(filePath);
4127
5691
  const kind = fileKind(filePath, ignore);
4128
5692
  files.push({
@@ -4528,7 +6092,7 @@ var readBaseFile = async (cwd, base, filePath) => {
4528
6092
  // src/impact/build.ts
4529
6093
  var uniqueSorted = (values) => [...new Set(values)].sort();
4530
6094
  var routeMatchesFile = (route, filePath) => {
4531
- return route.codeSurface.some((pattern) => micromatch6.isMatch(filePath, pattern));
6095
+ return route.codeSurface.some((pattern) => micromatch7.isMatch(filePath, pattern));
4532
6096
  };
4533
6097
  var routeOwnsTruthDoc = (route, filePath) => {
4534
6098
  return route.truthDocs.includes(filePath);
@@ -5149,6 +6713,319 @@ var renderContextPackMarkdown = (pack) => {
5149
6713
  `;
5150
6714
  };
5151
6715
 
6716
+ // src/cli/handlers.ts
6717
+ import fs23 from "fs/promises";
6718
+
6719
+ // src/agents/workflow-helper-validation.ts
6720
+ import { parse as parseYaml2 } from "yaml";
6721
+ var escapeRegex = (value) => value.split("").map((char) => ".+*?^$()[]{}|\\".includes(char) ? `\\${char}` : char).join("");
6722
+ var hasLabel = (text, label) => {
6723
+ const escaped = escapeRegex(label);
6724
+ return new RegExp(String.raw`(^|\n)\s*(?:#{1,6}\s*)?${escaped}\s*:?\s*(\n|$)`, "iu").test(
6725
+ text
6726
+ );
6727
+ };
6728
+ var getSection = (text, label) => {
6729
+ const lines = text.split(/\r?\n/u);
6730
+ const labelPattern = new RegExp(String.raw`^(?:#{1,6}\s*)?${escapeRegex(label)}\s*:?\s*$`, "iu");
6731
+ const sectionHeaderPattern = /^(?:#{1,6}\s*)?[A-Z][A-Za-z0-9 ]+:\s*$/u;
6732
+ const startIndex = lines.findIndex((line) => labelPattern.test(line));
6733
+ if (startIndex === -1) {
6734
+ return null;
6735
+ }
6736
+ const nextSectionOffset = lines.slice(startIndex + 1).findIndex((line) => sectionHeaderPattern.test(line));
6737
+ const endIndex = nextSectionOffset === -1 ? lines.length : startIndex + 1 + nextSectionOffset;
6738
+ return lines.slice(startIndex + 1, endIndex).join("\n").trim();
6739
+ };
6740
+ var requireBulletSection = (text, label, errors, checks) => {
6741
+ const section = getSection(text, label);
6742
+ if (section === null) {
6743
+ errors.push(`missing required section: ${label}`);
6744
+ return;
6745
+ }
6746
+ if (!/^-\s+\S/mu.test(section)) {
6747
+ errors.push(`${label} must include at least one bullet`);
6748
+ return;
6749
+ }
6750
+ checks.push(label);
6751
+ };
6752
+ var validateEvidenceChecked = (text, errors, checks) => {
6753
+ const section = getSection(text, "Evidence checked");
6754
+ if (section === null || section === "") {
6755
+ errors.push("Evidence checked must include at least one structured entry");
6756
+ return;
6757
+ }
6758
+ const entries = section.split(/\n(?=-\s+)/u).map((entry) => entry.trim()).filter(Boolean);
6759
+ if (entries.length === 0) {
6760
+ errors.push("Evidence checked must include at least one structured entry");
6761
+ return;
6762
+ }
6763
+ const entryPattern = /^- Claim:\s*\S[^\n]*\n {2,}Evidence:\s*\S[^\n]*\n {2,}Result:\s*(supported|narrowed|removed|blocked)\s*$/iu;
6764
+ for (const [index, entry] of entries.entries()) {
6765
+ if (!entryPattern.test(entry)) {
6766
+ errors.push(
6767
+ `Evidence checked entry ${index + 1} must match '- Claim: ...' followed by indented 'Evidence: ...' and 'Result: supported | narrowed | removed | blocked'`
6768
+ );
6769
+ }
6770
+ }
6771
+ if (errors.length === 0) {
6772
+ checks.push(
6773
+ "Evidence checked entries include Claim:, Evidence:, and Result: supported | narrowed | removed | blocked"
6774
+ );
6775
+ }
6776
+ };
6777
+ var validateHelperScriptEntries = (entries, requiredHelpers, errors, checks) => {
6778
+ if (entries === void 0 || entries.length === 0) {
6779
+ errors.push("Helper scripts must include status for optional helpers");
6780
+ return;
6781
+ }
6782
+ const statusPattern = /^(?:-\s*)?([a-z0-9-]+):\s*(?:ran,\s*passed|skipped,\s*\S.*)$/iu;
6783
+ const validHelperIds = /* @__PURE__ */ new Set();
6784
+ for (const entry of entries) {
6785
+ const match = entry.trim().match(statusPattern);
6786
+ if (match === null) {
6787
+ errors.push(
6788
+ "Helper scripts entries must match '- helper-id: ran, passed' or '- helper-id: skipped, reason'; ran, failed is not valid for completed reports"
6789
+ );
6790
+ continue;
6791
+ }
6792
+ validHelperIds.add(match[1].toLowerCase());
6793
+ }
6794
+ for (const helperId of requiredHelpers) {
6795
+ if (!validHelperIds.has(helperId.toLowerCase())) {
6796
+ errors.push(`missing Helper scripts status: ${helperId}`);
6797
+ }
6798
+ }
6799
+ if (errors.length === 0) {
6800
+ checks.push(`Helper scripts statuses include ${requiredHelpers.join(", ")}`);
6801
+ }
6802
+ };
6803
+ var validateHelperScripts = (text, requiredHelpers, errors, checks) => {
6804
+ const section = getSection(text, "Helper scripts");
6805
+ const entries = section?.split(/\n/u).map((entry) => entry.trim()).filter(Boolean);
6806
+ validateHelperScriptEntries(entries, requiredHelpers, errors, checks);
6807
+ };
6808
+ var validateTruthSyncReportText = (text) => {
6809
+ const helper = "validate-sync-report";
6810
+ const statusMatch = text.match(/^\s*Truth Sync:\s*(completed|blocked|skipped)\b/imu);
6811
+ if (statusMatch === null) {
6812
+ return {
6813
+ ok: false,
6814
+ helper,
6815
+ errors: ["missing Truth Sync status: expected completed, blocked, or skipped"]
6816
+ };
6817
+ }
6818
+ const status = statusMatch[1].toLowerCase();
6819
+ const checks = [`status: ${status}`];
6820
+ const errors = [];
6821
+ if (status === "completed") {
6822
+ try {
6823
+ const report = parseTruthSyncReport(text.trimStart());
6824
+ for (const [label, items] of [
6825
+ ["Changed code reviewed", report.changedCode],
6826
+ ["Ownership reviewed", report.ownershipReviewed],
6827
+ ["Truth docs updated", report.truthDocsUpdated],
6828
+ ["Notes", report.notes]
6829
+ ]) {
6830
+ if (items.length === 0) {
6831
+ errors.push(`${label} must include at least one bullet`);
6832
+ } else {
6833
+ checks.push(label);
6834
+ }
6835
+ }
6836
+ if (report.evidenceChecked.length === 0) {
6837
+ errors.push("Evidence checked must include at least one structured entry");
6838
+ } else {
6839
+ checks.push(
6840
+ "Evidence checked entries include Claim:, Evidence:, and Result: supported | narrowed | removed | blocked"
6841
+ );
6842
+ }
6843
+ validateHelperScriptEntries(
6844
+ report.helperScripts,
6845
+ ["validate-write-lease"],
6846
+ errors,
6847
+ checks
6848
+ );
6849
+ } catch (error) {
6850
+ errors.push(error instanceof Error ? error.message : "invalid Truth Sync report");
6851
+ }
6852
+ } else if (status === "skipped") {
6853
+ requireBulletSection(text, "Reason", errors, checks);
6854
+ } else if (status === "blocked") {
6855
+ requireBulletSection(text, "Reason", errors, checks);
6856
+ requireBulletSection(text, "Files requiring manual review", errors, checks);
6857
+ requireBulletSection(text, "Next action", errors, checks);
6858
+ }
6859
+ return errors.length > 0 ? { ok: false, helper, errors } : { ok: true, helper, checks };
6860
+ };
6861
+ var validateTruthDocumentReportText = (text) => {
6862
+ const helper = "validate-document-report";
6863
+ const statusMatch = text.match(/^\s*Truth Document:\s*(completed|blocked)\b/imu);
6864
+ if (statusMatch === null) {
6865
+ return {
6866
+ ok: false,
6867
+ helper,
6868
+ errors: ["missing Truth Document status: expected completed or blocked"]
6869
+ };
6870
+ }
6871
+ const status = statusMatch[1].toLowerCase();
6872
+ const checks = [`status: ${status}`];
6873
+ const errors = [];
6874
+ if (status === "completed") {
6875
+ for (const label of ["Implementation reviewed", "Ownership reviewed", "Notes"]) {
6876
+ requireBulletSection(text, label, errors, checks);
6877
+ }
6878
+ if (hasLabel(text, "Evidence checked")) {
6879
+ checks.push("Evidence checked");
6880
+ } else {
6881
+ errors.push("missing required section: Evidence checked");
6882
+ }
6883
+ if (hasLabel(text, "Helper scripts")) {
6884
+ checks.push("Helper scripts");
6885
+ } else {
6886
+ errors.push("missing required section: Helper scripts");
6887
+ }
6888
+ const truthDocsUpdated = getSection(text, "Truth docs updated");
6889
+ const truthDocsCreated = getSection(text, "Truth docs created");
6890
+ if (truthDocsUpdated === null && truthDocsCreated === null) {
6891
+ errors.push("missing required section: Truth docs updated or Truth docs created");
6892
+ } else if (![truthDocsUpdated, truthDocsCreated].some(
6893
+ (section) => section !== null && /^-\s+\S/mu.test(section)
6894
+ )) {
6895
+ errors.push("Truth docs updated or Truth docs created must include at least one bullet");
6896
+ } else {
6897
+ checks.push("Truth docs updated or created");
6898
+ }
6899
+ validateEvidenceChecked(text, errors, checks);
6900
+ validateHelperScripts(text, ["validate-write-lease"], errors, checks);
6901
+ } else if (status === "blocked") {
6902
+ requireBulletSection(text, "Reason", errors, checks);
6903
+ }
6904
+ return errors.length > 0 ? { ok: false, helper, errors } : { ok: true, helper, checks };
6905
+ };
6906
+ var cleanPathValue = (value) => value.trim().replace(/^["']|["']$/gu, "");
6907
+ var normalizePath5 = (value) => cleanPathValue(value).replace(/^\.\//u, "");
6908
+ var windowsDriveAbsolutePattern = /^[A-Za-z]:[\\/]/u;
6909
+ var uncPathPattern = /^[/\\]{2}[^/\\]+[/\\]+[^/\\]+/u;
6910
+ var isUnsafePathValue = (value) => {
6911
+ const cleanValue = cleanPathValue(value);
6912
+ const pathValue = cleanValue.endsWith("/**") ? cleanValue.slice(0, -3) : cleanValue;
6913
+ return pathValue.startsWith("/") || pathValue.startsWith("\\") || windowsDriveAbsolutePattern.test(pathValue) || uncPathPattern.test(pathValue) || pathValue.split(/[\\/]+/u).includes("..");
6914
+ };
6915
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6916
+ var findWriteLeaseRecord = (value) => {
6917
+ if (!isRecord(value)) {
6918
+ return null;
6919
+ }
6920
+ if (Object.prototype.hasOwnProperty.call(value, "allowedWrites") || Object.prototype.hasOwnProperty.call(value, "forbiddenWrites")) {
6921
+ return value;
6922
+ }
6923
+ for (const nestedKey of ["writeLease", "lease"]) {
6924
+ const nested = value[nestedKey];
6925
+ if (isRecord(nested)) {
6926
+ return nested;
6927
+ }
6928
+ }
6929
+ return value;
6930
+ };
6931
+ var readStringArray = (record, field, errors) => {
6932
+ const value = record[field];
6933
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
6934
+ errors.push(`${field} must be an array of strings`);
6935
+ return [];
6936
+ }
6937
+ return value;
6938
+ };
6939
+ var parseListFields = (text) => {
6940
+ const errors = [];
6941
+ let parsed;
6942
+ try {
6943
+ parsed = parseYaml2(text);
6944
+ } catch (error) {
6945
+ return {
6946
+ allowedWrites: [],
6947
+ forbiddenWrites: [],
6948
+ errors: [
6949
+ `manual-validation required: invalid write lease YAML${error instanceof Error ? `: ${error.message}` : ""}`
6950
+ ]
6951
+ };
6952
+ }
6953
+ const record = findWriteLeaseRecord(parsed);
6954
+ if (record === null) {
6955
+ return {
6956
+ allowedWrites: [],
6957
+ forbiddenWrites: [],
6958
+ errors: ["write lease YAML must be an object"]
6959
+ };
6960
+ }
6961
+ return {
6962
+ allowedWrites: readStringArray(record, "allowedWrites", errors),
6963
+ forbiddenWrites: readStringArray(record, "forbiddenWrites", errors),
6964
+ errors
6965
+ };
6966
+ };
6967
+ var isSupportedPattern = (pattern) => {
6968
+ const withoutTrailingGlob = pattern.endsWith("/**") ? pattern.slice(0, -3) : pattern;
6969
+ return !/[?*[\]{}]/u.test(withoutTrailingGlob);
6970
+ };
6971
+ var matchesPattern = (filePath, pattern) => {
6972
+ if (pattern.endsWith("/**")) {
6973
+ const prefix = pattern.slice(0, -3).replace(/\/+$/u, "");
6974
+ return filePath === prefix || filePath.startsWith(`${prefix}/`);
6975
+ }
6976
+ return filePath === pattern;
6977
+ };
6978
+ var validateWriteLeaseText = (leaseText, changedText) => {
6979
+ const helper = "validate-write-lease";
6980
+ const parsed = parseListFields(leaseText);
6981
+ const rawAllowedWrites = parsed.allowedWrites.map(cleanPathValue).filter(Boolean);
6982
+ const rawForbiddenWrites = parsed.forbiddenWrites.map(cleanPathValue).filter(Boolean);
6983
+ const rawChangedFiles = changedText.split(/\r?\n/u).map(cleanPathValue).filter(Boolean);
6984
+ const allowedWrites = rawAllowedWrites.map(normalizePath5).filter(Boolean);
6985
+ const forbiddenWrites = rawForbiddenWrites.map(normalizePath5).filter(Boolean);
6986
+ const changedFiles = rawChangedFiles.map(normalizePath5).filter(Boolean);
6987
+ const checks = [];
6988
+ const errors = [...parsed.errors];
6989
+ for (const pattern of rawAllowedWrites) {
6990
+ if (isUnsafePathValue(pattern)) {
6991
+ errors.push(`invalid allowedWrites path: ${pattern}`);
6992
+ }
6993
+ }
6994
+ for (const pattern of rawForbiddenWrites) {
6995
+ if (isUnsafePathValue(pattern)) {
6996
+ errors.push(`invalid forbiddenWrites path: ${pattern}`);
6997
+ }
6998
+ }
6999
+ for (const filePath of rawChangedFiles) {
7000
+ if (isUnsafePathValue(filePath)) {
7001
+ errors.push(`invalid changed file path: ${filePath}`);
7002
+ }
7003
+ }
7004
+ for (const pattern of [...allowedWrites, ...forbiddenWrites]) {
7005
+ if (!isSupportedPattern(pattern)) {
7006
+ errors.push(`manual-validation required: unsupported write pattern ${pattern}`);
7007
+ }
7008
+ }
7009
+ if (allowedWrites.length === 0) {
7010
+ errors.push("manual-validation required: no allowedWrites entries found");
7011
+ }
7012
+ if (errors.length === 0) {
7013
+ for (const filePath of changedFiles) {
7014
+ if (!allowedWrites.some((pattern) => matchesPattern(filePath, pattern))) {
7015
+ errors.push(`${filePath} is outside allowedWrites`);
7016
+ continue;
7017
+ }
7018
+ const forbiddenPattern = forbiddenWrites.find((pattern) => matchesPattern(filePath, pattern));
7019
+ if (forbiddenPattern !== void 0) {
7020
+ errors.push(`${filePath} matches forbiddenWrites pattern ${forbiddenPattern}`);
7021
+ continue;
7022
+ }
7023
+ checks.push(filePath);
7024
+ }
7025
+ }
7026
+ return errors.length > 0 ? { ok: false, helper, errors } : { ok: true, helper, checks };
7027
+ };
7028
+
5152
7029
  // src/cli/handlers.ts
5153
7030
  var runConfig2 = async (options) => {
5154
7031
  return runConfig(process.cwd(), options);
@@ -5205,6 +7082,33 @@ var isContextPackWorkflow = (value) => {
5205
7082
  var isContextPackFormat = (value) => {
5206
7083
  return value === void 0 || value === "json" || value === "markdown";
5207
7084
  };
7085
+ var readHelperFile = async (filePath, helper) => {
7086
+ try {
7087
+ return await fs23.readFile(filePath, "utf8");
7088
+ } catch (error) {
7089
+ const message = error instanceof Error ? error.message : String(error);
7090
+ return { ok: false, helper, errors: [`could not read file: ${message}`] };
7091
+ }
7092
+ };
7093
+ var runValidateSyncReport = async (reportFile) => {
7094
+ const text = await readHelperFile(reportFile, "validate-sync-report");
7095
+ return typeof text === "string" ? validateTruthSyncReportText(text) : text;
7096
+ };
7097
+ var runValidateDocumentReport = async (reportFile) => {
7098
+ const text = await readHelperFile(reportFile, "validate-document-report");
7099
+ return typeof text === "string" ? validateTruthDocumentReportText(text) : text;
7100
+ };
7101
+ var runValidateWriteLease = async (leaseFile, changedFilesFile) => {
7102
+ const leaseText = await readHelperFile(leaseFile, "validate-write-lease");
7103
+ if (typeof leaseText !== "string") {
7104
+ return leaseText;
7105
+ }
7106
+ const changedText = await readHelperFile(changedFilesFile, "validate-write-lease");
7107
+ if (typeof changedText !== "string") {
7108
+ return changedText;
7109
+ }
7110
+ return validateWriteLeaseText(leaseText, changedText);
7111
+ };
5208
7112
  var runContext = async (options) => {
5209
7113
  if (!isContextPackWorkflow(options.workflow)) {
5210
7114
  return {
@@ -5261,6 +7165,28 @@ var writeContextResult = (result, options) => {
5261
7165
  }
5262
7166
  writeResult(result, options);
5263
7167
  };
7168
+ var renderValidationHuman = (result) => {
7169
+ if (result.ok === true) {
7170
+ return [`${result.helper}: ok`, ...result.checks.map((check) => `- ${check}`)].join("\n");
7171
+ }
7172
+ return [`${result.helper}: failed`, ...result.errors.map((error) => `- ${error}`)].join("\n");
7173
+ };
7174
+ var toValidationCommandResult = (command, result) => ({
7175
+ command,
7176
+ summary: result.ok ? "Validation passed" : "Validation failed",
7177
+ diagnostics: [],
7178
+ data: {
7179
+ validation: result
7180
+ }
7181
+ });
7182
+ var writeValidationResult = (command, result, options) => {
7183
+ const output = options.json ? renderJson(toValidationCommandResult(command, result)) : renderValidationHuman(result);
7184
+ process.stdout.write(`${output}
7185
+ `);
7186
+ if (!result.ok) {
7187
+ process.exitCode = 1;
7188
+ }
7189
+ };
5264
7190
  var addJsonOption = (command) => {
5265
7191
  return command.option("--json", "Render command output as JSON");
5266
7192
  };
@@ -5304,6 +7230,32 @@ var buildProgram = () => {
5304
7230
  options
5305
7231
  );
5306
7232
  });
7233
+ const validate = program.command("validate").description("Run optional Truthmark workflow helper validators from the installed CLI.");
7234
+ addJsonOption(
7235
+ validate.command("sync-report").description("Validate a Truth Sync report file.").argument("<report-file>", "Truth Sync report file")
7236
+ ).action(async (reportFile, options) => {
7237
+ writeValidationResult("validate sync-report", await runValidateSyncReport(reportFile), options);
7238
+ });
7239
+ addJsonOption(
7240
+ validate.command("document-report").description("Validate a Truth Document report file.").argument("<report-file>", "Truth Document report file")
7241
+ ).action(async (reportFile, options) => {
7242
+ writeValidationResult(
7243
+ "validate document-report",
7244
+ await runValidateDocumentReport(reportFile),
7245
+ options
7246
+ );
7247
+ });
7248
+ addJsonOption(
7249
+ validate.command("write-lease").description("Validate a workflow write lease or worker report against changed files.").argument("<lease-or-report-file>", "Lease or worker report file").argument("<changed-files-file>", "Newline-separated changed file list")
7250
+ ).action(
7251
+ async (leaseOrReportFile, changedFilesFile, options) => {
7252
+ writeValidationResult(
7253
+ "validate write-lease",
7254
+ await runValidateWriteLease(leaseOrReportFile, changedFilesFile),
7255
+ options
7256
+ );
7257
+ }
7258
+ );
5307
7259
  return program;
5308
7260
  };
5309
7261