truthmark 1.4.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/README.de.md +623 -193
- package/README.es.md +624 -194
- package/README.md +614 -191
- package/README.ru.md +631 -201
- package/README.zh.md +630 -198
- package/dist/main.js +846 -39
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1567,6 +1567,27 @@ var renderCopilotCustomAgentModeSection = (agents, parentRule, writeAgents = [])
|
|
|
1567
1567
|
`- ${parentRule}`
|
|
1568
1568
|
].join("\n");
|
|
1569
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
|
+
};
|
|
1570
1591
|
var defaultAgentConfig = () => {
|
|
1571
1592
|
return createDefaultConfig();
|
|
1572
1593
|
};
|
|
@@ -1678,7 +1699,50 @@ var renderDefaultStandards = (documents) => {
|
|
|
1678
1699
|
return DEFAULT_STANDARDS.filter((template) => !existingPaths.has(template.path));
|
|
1679
1700
|
};
|
|
1680
1701
|
|
|
1702
|
+
// src/templates/workflow-surfaces.ts
|
|
1703
|
+
import { stringify as stringify2 } from "yaml";
|
|
1704
|
+
|
|
1681
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
|
+
};
|
|
1682
1746
|
var TRUTHMARK_WORKFLOW_MANIFEST = {
|
|
1683
1747
|
"truthmark-sync": {
|
|
1684
1748
|
id: "truthmark-sync",
|
|
@@ -1717,10 +1781,12 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
|
|
|
1717
1781
|
"Truth docs updated",
|
|
1718
1782
|
"Truth docs split",
|
|
1719
1783
|
"Evidence checked",
|
|
1784
|
+
"Helper scripts",
|
|
1720
1785
|
"Notes"
|
|
1721
1786
|
],
|
|
1722
1787
|
subagents: ["truth_route_auditor", "truth_claim_verifier"],
|
|
1723
|
-
writeSubagents: ["truth_doc_writer"]
|
|
1788
|
+
writeSubagents: ["truth_doc_writer"],
|
|
1789
|
+
helpers: [VALIDATE_SYNC_REPORT_HELPER, VALIDATE_WRITE_LEASE_HELPER]
|
|
1724
1790
|
},
|
|
1725
1791
|
"truthmark-structure": {
|
|
1726
1792
|
id: "truthmark-structure",
|
|
@@ -1801,10 +1867,12 @@ var TRUTHMARK_WORKFLOW_MANIFEST = {
|
|
|
1801
1867
|
"Truth docs restructured",
|
|
1802
1868
|
"Routing updated",
|
|
1803
1869
|
"Evidence checked",
|
|
1870
|
+
"Helper scripts",
|
|
1804
1871
|
"Notes"
|
|
1805
1872
|
],
|
|
1806
1873
|
subagents: ["truth_route_auditor", "truth_claim_verifier"],
|
|
1807
|
-
writeSubagents: ["truth_doc_writer"]
|
|
1874
|
+
writeSubagents: ["truth_doc_writer"],
|
|
1875
|
+
helpers: [VALIDATE_DOCUMENT_REPORT_HELPER, VALIDATE_WRITE_LEASE_HELPER]
|
|
1808
1876
|
},
|
|
1809
1877
|
"truthmark-realize": {
|
|
1810
1878
|
id: "truthmark-realize",
|
|
@@ -2012,11 +2080,15 @@ var renderMarkdownExample2 = (content) => {
|
|
|
2012
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.";
|
|
2013
2081
|
var renderTruthDocumentReportExample = (config = defaultAgentConfig()) => {
|
|
2014
2082
|
const truthDocsRoot = resolveTruthDocsRoot(config);
|
|
2083
|
+
const helperScripts = ["validate-write-lease: skipped, no write lease used"];
|
|
2015
2084
|
return `Truth Document: completed
|
|
2016
2085
|
|
|
2017
2086
|
Implementation reviewed:
|
|
2018
2087
|
- src/routing/area-resolver.ts
|
|
2019
2088
|
|
|
2089
|
+
Ownership reviewed:
|
|
2090
|
+
- ${config.docs.routing.rootIndex}
|
|
2091
|
+
|
|
2020
2092
|
Truth docs created:
|
|
2021
2093
|
- ${truthDocsRoot}/contracts.md
|
|
2022
2094
|
|
|
@@ -2040,6 +2112,9 @@ ${renderClaimEvidenceCheckedSection([
|
|
|
2040
2112
|
}
|
|
2041
2113
|
])}
|
|
2042
2114
|
|
|
2115
|
+
Helper scripts:
|
|
2116
|
+
${helperScripts.map((helperScript) => `- ${helperScript}`).join("\n")}
|
|
2117
|
+
|
|
2043
2118
|
Notes:
|
|
2044
2119
|
- Documented routing and behavior from route handlers and tests.`;
|
|
2045
2120
|
};
|
|
@@ -2115,6 +2190,12 @@ ${renderTruthDocRestructureGateSection(
|
|
|
2115
2190
|
${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
|
|
2116
2191
|
${renderHierarchySummary(config)}
|
|
2117
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.
|
|
2118
2199
|
Parent post-document verification:
|
|
2119
2200
|
- verify only truth docs and leased truth routing files changed during document work
|
|
2120
2201
|
- block on functional code, generated host surfaces, or unrelated diffs caused by document work
|
|
@@ -2366,24 +2447,105 @@ var renderBulletSection = (title, items) => {
|
|
|
2366
2447
|
return `${title}:
|
|
2367
2448
|
${items.map((item) => `- ${item}`).join("\n")}`;
|
|
2368
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
|
+
};
|
|
2369
2512
|
var renderTruthSyncCompletedReport = (input) => {
|
|
2370
2513
|
return [
|
|
2371
2514
|
"Truth Sync: completed",
|
|
2372
2515
|
renderBulletSection("Changed code reviewed", input.changedCode),
|
|
2516
|
+
renderBulletSection("Ownership reviewed", input.ownershipReviewed),
|
|
2373
2517
|
renderBulletSection("Truth docs updated", input.truthDocsUpdated),
|
|
2374
2518
|
renderClaimEvidenceCheckedSection(input.evidenceChecked),
|
|
2519
|
+
...input.helperScripts === void 0 ? [] : [renderBulletSection("Helper scripts", input.helperScripts)],
|
|
2375
2520
|
renderBulletSection("Notes", input.notes)
|
|
2376
2521
|
].join("\n\n");
|
|
2377
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
|
+
};
|
|
2378
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
|
+
}
|
|
2379
2543
|
const sections = [
|
|
2380
2544
|
"Truth Sync: blocked",
|
|
2381
|
-
renderBulletSection("Reason", [input.reason])
|
|
2545
|
+
renderBulletSection("Reason", [input.reason]),
|
|
2546
|
+
renderBulletSection("Files requiring manual review", manualReviewFiles),
|
|
2547
|
+
renderBulletSection("Next action", [input.nextAction])
|
|
2382
2548
|
];
|
|
2383
|
-
if ((input.manualReviewFiles?.length ?? 0) > 0) {
|
|
2384
|
-
sections.push(renderBulletSection("Files requiring manual review", input.manualReviewFiles));
|
|
2385
|
-
}
|
|
2386
|
-
sections.push(renderBulletSection("Next action", [input.nextAction]));
|
|
2387
2549
|
return [
|
|
2388
2550
|
...sections
|
|
2389
2551
|
].join("\n\n");
|
|
@@ -2397,6 +2559,7 @@ var renderMarkdownExample5 = (content) => {
|
|
|
2397
2559
|
var renderTruthSyncSkillBody = (config = defaultAgentConfig(), options = {}) => {
|
|
2398
2560
|
const truthDocsRoot = resolveTruthDocsRoot(config);
|
|
2399
2561
|
const workflow = getTruthmarkWorkflow("truthmark-sync");
|
|
2562
|
+
const helperScripts = ["validate-write-lease: skipped, no write lease used"];
|
|
2400
2563
|
const claudeSubagentMode = options.includeClaudeSubagentMode ? `${renderClaudeSubagentModeSection(
|
|
2401
2564
|
workflow.subagents ?? [],
|
|
2402
2565
|
"Parent agent owns Truth Sync acceptance, lease validation, and final report",
|
|
@@ -2470,6 +2633,12 @@ Optional validation tooling:
|
|
|
2470
2633
|
- do not require the truthmark binary; direct checkout inspection is the canonical path
|
|
2471
2634
|
- optional validation must not replace agent judgment about docs and routing
|
|
2472
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.
|
|
2473
2642
|
${renderHierarchySummary(config)}
|
|
2474
2643
|
${DECISION_TRUTH_INSTRUCTIONS}
|
|
2475
2644
|
Parent post-sync verification:
|
|
@@ -2477,7 +2646,7 @@ Parent post-sync verification:
|
|
|
2477
2646
|
- block on any unrelated diff caused by the sync step
|
|
2478
2647
|
- block if functional code changed during sync
|
|
2479
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
|
|
2480
|
-
- validate the final report against the structured Truth Sync report contract, including Claim, Evidence, and Result
|
|
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
|
|
2481
2650
|
- verify the updated docs correspond to the reviewed changed-code surface
|
|
2482
2651
|
- verify the final report records ownership review, structure requirement, split, restructure, or blocked reason when the ownership gate fired
|
|
2483
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
|
|
@@ -2485,6 +2654,7 @@ Report completion in this shape:
|
|
|
2485
2654
|
${renderMarkdownExample5(
|
|
2486
2655
|
renderTruthSyncCompletedReport({
|
|
2487
2656
|
changedCode: ["src/auth/session.ts"],
|
|
2657
|
+
ownershipReviewed: [config.docs.routing.rootIndex],
|
|
2488
2658
|
truthDocsUpdated: [`${truthDocsRoot}/repository/overview.md`],
|
|
2489
2659
|
evidenceChecked: [
|
|
2490
2660
|
{
|
|
@@ -2493,6 +2663,7 @@ ${renderMarkdownExample5(
|
|
|
2493
2663
|
result: "supported"
|
|
2494
2664
|
}
|
|
2495
2665
|
],
|
|
2666
|
+
helperScripts,
|
|
2496
2667
|
notes: ["Updated session timeout behavior."]
|
|
2497
2668
|
})
|
|
2498
2669
|
)}
|
|
@@ -2553,6 +2724,10 @@ var TRUTHMARK_GEMINI_SYNC_COMMAND_PATH = ".gemini/commands/truthmark/sync.toml";
|
|
|
2553
2724
|
var TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH = ".gemini/commands/truthmark/realize.toml";
|
|
2554
2725
|
var TRUTHMARK_GEMINI_CHECK_COMMAND_PATH = ".gemini/commands/truthmark/check.toml";
|
|
2555
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";
|
|
2556
2731
|
var TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH = ".github/prompts/truthmark-structure.prompt.md";
|
|
2557
2732
|
var TRUTHMARK_COPILOT_DOCUMENT_PROMPT_PATH = ".github/prompts/truthmark-document.prompt.md";
|
|
2558
2733
|
var TRUTHMARK_COPILOT_SYNC_PROMPT_PATH = ".github/prompts/truthmark-sync.prompt.md";
|
|
@@ -2564,9 +2739,11 @@ var TRUTHMARK_COPILOT_CLAIM_VERIFIER_AGENT_PATH = ".github/agents/truth-claim-ve
|
|
|
2564
2739
|
var TRUTHMARK_COPILOT_DOC_REVIEWER_AGENT_PATH = ".github/agents/truth-doc-reviewer.agent.md";
|
|
2565
2740
|
var TRUTHMARK_COPILOT_DOC_WRITER_AGENT_PATH = ".github/agents/truth-doc-writer.agent.md";
|
|
2566
2741
|
var renderGeminiCommand = (description, prompt) => {
|
|
2742
|
+
const promptWithArgs = `${prompt.trimEnd()}
|
|
2743
|
+
User focus or arguments: {{args}}`;
|
|
2567
2744
|
return `description = "${description}"
|
|
2568
2745
|
prompt = '''
|
|
2569
|
-
${
|
|
2746
|
+
${promptWithArgs}
|
|
2570
2747
|
'''
|
|
2571
2748
|
`;
|
|
2572
2749
|
};
|
|
@@ -2707,6 +2884,56 @@ Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades
|
|
|
2707
2884
|
${body}
|
|
2708
2885
|
`;
|
|
2709
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
|
+
};
|
|
2710
2937
|
var renderStandaloneWorkflowSkillBody = (workflowId, config) => {
|
|
2711
2938
|
switch (workflowId) {
|
|
2712
2939
|
case "truthmark-structure":
|
|
@@ -2723,10 +2950,11 @@ var renderStandaloneWorkflowSkillBody = (workflowId, config) => {
|
|
|
2723
2950
|
return renderTruthCheckSkillBody(config);
|
|
2724
2951
|
}
|
|
2725
2952
|
};
|
|
2726
|
-
var renderWorkflowEntrypoint = (workflowId, config, supportFiles) => {
|
|
2953
|
+
var renderWorkflowEntrypoint = (workflowId, config, supportFiles, host) => {
|
|
2727
2954
|
const workflow = getTruthmarkWorkflow(workflowId);
|
|
2728
2955
|
const definition = WORKFLOW_PACKAGE_DEFINITIONS[workflowId];
|
|
2729
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;
|
|
2730
2958
|
return `---
|
|
2731
2959
|
name: ${workflowId}
|
|
2732
2960
|
description: ${workflow.description}
|
|
@@ -2738,6 +2966,9 @@ truthmark-version: ${TRUTHMARK_VERSION}
|
|
|
2738
2966
|
# ${definition.title}
|
|
2739
2967
|
|
|
2740
2968
|
${definition.use(config)}
|
|
2969
|
+
${hostUsage === void 0 ? "" : `
|
|
2970
|
+
${hostUsage}
|
|
2971
|
+
`}
|
|
2741
2972
|
|
|
2742
2973
|
Invocations: ${definition.invocations}
|
|
2743
2974
|
|
|
@@ -2778,6 +3009,18 @@ var renderWorkflowSubagentSupport = (workflowId, host) => {
|
|
|
2778
3009
|
definition.parentRule,
|
|
2779
3010
|
writeAgents
|
|
2780
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
|
+
);
|
|
2781
3024
|
}
|
|
2782
3025
|
};
|
|
2783
3026
|
var renderTruthmarkSkillPackage = ({
|
|
@@ -2792,16 +3035,18 @@ var renderTruthmarkSkillPackage = ({
|
|
|
2792
3035
|
renderStandaloneWorkflowSkillBody(workflowId, config)
|
|
2793
3036
|
);
|
|
2794
3037
|
const subagents = renderWorkflowSubagentSupport(workflowId, host);
|
|
3038
|
+
const helpers = getTruthmarkWorkflow(workflowId).helpers ?? [];
|
|
2795
3039
|
const supportFiles = [
|
|
2796
3040
|
"support/procedure.md",
|
|
2797
3041
|
"support/report-template.md",
|
|
2798
|
-
...subagents === void 0 ? [] : ["support/subagents-and-leases.md"]
|
|
3042
|
+
...subagents === void 0 ? [] : ["support/subagents-and-leases.md"],
|
|
3043
|
+
...helpers.length === 0 ? [] : ["helper-manifest.yml", "support/helper-policy.md"]
|
|
2799
3044
|
];
|
|
2800
3045
|
const definition = WORKFLOW_PACKAGE_DEFINITIONS[workflowId];
|
|
2801
3046
|
const files = [
|
|
2802
3047
|
{
|
|
2803
3048
|
path: skillPath,
|
|
2804
|
-
content: renderWorkflowEntrypoint(workflowId, config, supportFiles)
|
|
3049
|
+
content: renderWorkflowEntrypoint(workflowId, config, supportFiles, host)
|
|
2805
3050
|
},
|
|
2806
3051
|
{
|
|
2807
3052
|
path: `${supportDirectory}/procedure.md`,
|
|
@@ -2827,6 +3072,18 @@ var renderTruthmarkSkillPackage = ({
|
|
|
2827
3072
|
)
|
|
2828
3073
|
});
|
|
2829
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
|
+
}
|
|
2830
3087
|
return files;
|
|
2831
3088
|
};
|
|
2832
3089
|
var normalizeOpenCodePermissionPath = (path12) => {
|
|
@@ -2982,6 +3239,45 @@ tools: [read, search, edit]
|
|
|
2982
3239
|
|
|
2983
3240
|
# Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun truthmark init after upgrades.
|
|
2984
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
|
+
|
|
2985
3281
|
${instructions}
|
|
2986
3282
|
`;
|
|
2987
3283
|
};
|
|
@@ -3084,6 +3380,26 @@ var renderTruthmarkCopilotDocWriterAgent = () => {
|
|
|
3084
3380
|
TRUTHMARK_WRITE_SUBAGENT_PROFILES.truth_doc_writer
|
|
3085
3381
|
);
|
|
3086
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
|
+
};
|
|
3087
3403
|
var renderTruthmarkClaudeRouteAuditorAgent = () => {
|
|
3088
3404
|
return renderClaudeReadOnlyAgent(
|
|
3089
3405
|
TRUTHMARK_SUBAGENT_PROFILES.truth_route_auditor
|
|
@@ -3644,6 +3960,42 @@ var claudeFiles = (config, block) => {
|
|
|
3644
3960
|
var copilotFiles = (config, block) => {
|
|
3645
3961
|
const files = [
|
|
3646
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
|
+
}),
|
|
3647
3999
|
{
|
|
3648
4000
|
path: TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH,
|
|
3649
4001
|
content: renderTruthmarkCopilotStructurePrompt(config)
|
|
@@ -3687,6 +4039,87 @@ var copilotFiles = (config, block) => {
|
|
|
3687
4039
|
];
|
|
3688
4040
|
return files;
|
|
3689
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
|
+
};
|
|
3690
4123
|
var instructionBlockFiles = (paths, block) => {
|
|
3691
4124
|
return paths.map((path12) => ({
|
|
3692
4125
|
path: path12,
|
|
@@ -3705,33 +4138,7 @@ var filesForPlatform = (platform, config, block) => {
|
|
|
3705
4138
|
case "github-copilot":
|
|
3706
4139
|
return copilotFiles(config, block);
|
|
3707
4140
|
case "gemini-cli":
|
|
3708
|
-
return
|
|
3709
|
-
...instructionBlockFiles(["GEMINI.md"], block),
|
|
3710
|
-
{
|
|
3711
|
-
path: TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH,
|
|
3712
|
-
content: renderTruthmarkGeminiStructureCommand(config)
|
|
3713
|
-
},
|
|
3714
|
-
{
|
|
3715
|
-
path: TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH,
|
|
3716
|
-
content: renderTruthmarkGeminiDocumentCommand(config)
|
|
3717
|
-
},
|
|
3718
|
-
{
|
|
3719
|
-
path: TRUTHMARK_GEMINI_SYNC_COMMAND_PATH,
|
|
3720
|
-
content: renderTruthmarkGeminiSyncCommand(config)
|
|
3721
|
-
},
|
|
3722
|
-
{
|
|
3723
|
-
path: TRUTHMARK_GEMINI_PREVIEW_COMMAND_PATH,
|
|
3724
|
-
content: renderTruthmarkGeminiPreviewCommand(config)
|
|
3725
|
-
},
|
|
3726
|
-
{
|
|
3727
|
-
path: TRUTHMARK_GEMINI_CHECK_COMMAND_PATH,
|
|
3728
|
-
content: renderTruthmarkGeminiCheckCommand(config)
|
|
3729
|
-
},
|
|
3730
|
-
{
|
|
3731
|
-
path: TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH,
|
|
3732
|
-
content: renderTruthmarkGeminiRealizeCommand(config)
|
|
3733
|
-
}
|
|
3734
|
-
];
|
|
4141
|
+
return geminiFiles(config, block);
|
|
3735
4142
|
}
|
|
3736
4143
|
};
|
|
3737
4144
|
var renderGeneratedSurfaces = (config, block = renderAgentsBlock(config)) => {
|
|
@@ -5268,6 +5675,18 @@ var discoverRepoFiles = async (rootDir, ignore) => {
|
|
|
5268
5675
|
const docs = [];
|
|
5269
5676
|
const tests = [];
|
|
5270
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
|
+
}
|
|
5271
5690
|
const extension = path5.posix.extname(filePath);
|
|
5272
5691
|
const kind = fileKind(filePath, ignore);
|
|
5273
5692
|
files.push({
|
|
@@ -6294,6 +6713,319 @@ var renderContextPackMarkdown = (pack) => {
|
|
|
6294
6713
|
`;
|
|
6295
6714
|
};
|
|
6296
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
|
+
|
|
6297
7029
|
// src/cli/handlers.ts
|
|
6298
7030
|
var runConfig2 = async (options) => {
|
|
6299
7031
|
return runConfig(process.cwd(), options);
|
|
@@ -6350,6 +7082,33 @@ var isContextPackWorkflow = (value) => {
|
|
|
6350
7082
|
var isContextPackFormat = (value) => {
|
|
6351
7083
|
return value === void 0 || value === "json" || value === "markdown";
|
|
6352
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
|
+
};
|
|
6353
7112
|
var runContext = async (options) => {
|
|
6354
7113
|
if (!isContextPackWorkflow(options.workflow)) {
|
|
6355
7114
|
return {
|
|
@@ -6406,6 +7165,28 @@ var writeContextResult = (result, options) => {
|
|
|
6406
7165
|
}
|
|
6407
7166
|
writeResult(result, options);
|
|
6408
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
|
+
};
|
|
6409
7190
|
var addJsonOption = (command) => {
|
|
6410
7191
|
return command.option("--json", "Render command output as JSON");
|
|
6411
7192
|
};
|
|
@@ -6449,6 +7230,32 @@ var buildProgram = () => {
|
|
|
6449
7230
|
options
|
|
6450
7231
|
);
|
|
6451
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
|
+
);
|
|
6452
7259
|
return program;
|
|
6453
7260
|
};
|
|
6454
7261
|
|