forge-cc 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/package.json +3 -2
  2. package/dist/gates/codex-gate.d.ts +0 -51
  3. package/dist/gates/codex-gate.js +0 -121
  4. package/dist/gates/codex-gate.js.map +0 -1
  5. package/dist/gates/prd-gate.d.ts +0 -7
  6. package/dist/gates/prd-gate.js +0 -193
  7. package/dist/gates/prd-gate.js.map +0 -1
  8. package/dist/gates/remediation.d.ts +0 -46
  9. package/dist/gates/remediation.js +0 -423
  10. package/dist/gates/remediation.js.map +0 -1
  11. package/dist/gates/review-gate.d.ts +0 -16
  12. package/dist/gates/review-gate.js +0 -479
  13. package/dist/gates/review-gate.js.map +0 -1
  14. package/dist/gates/runtime-gate.d.ts +0 -5
  15. package/dist/gates/runtime-gate.js +0 -99
  16. package/dist/gates/runtime-gate.js.map +0 -1
  17. package/dist/gates/test-analysis.d.ts +0 -21
  18. package/dist/gates/test-analysis.js +0 -394
  19. package/dist/gates/test-analysis.js.map +0 -1
  20. package/dist/gates/visual-capture.d.ts +0 -24
  21. package/dist/gates/visual-capture.js +0 -144
  22. package/dist/gates/visual-capture.js.map +0 -1
  23. package/dist/gates/visual-gate.d.ts +0 -18
  24. package/dist/gates/visual-gate.js +0 -234
  25. package/dist/gates/visual-gate.js.map +0 -1
  26. package/dist/gates/visual-reviewer.d.ts +0 -11
  27. package/dist/gates/visual-reviewer.js +0 -211
  28. package/dist/gates/visual-reviewer.js.map +0 -1
  29. package/dist/go/auto-chain.d.ts +0 -136
  30. package/dist/go/auto-chain.js +0 -389
  31. package/dist/go/auto-chain.js.map +0 -1
  32. package/dist/go/executor.d.ts +0 -137
  33. package/dist/go/executor.js +0 -447
  34. package/dist/go/executor.js.map +0 -1
  35. package/dist/go/finalize.d.ts +0 -108
  36. package/dist/go/finalize.js +0 -331
  37. package/dist/go/finalize.js.map +0 -1
  38. package/dist/go/linear-sync-cli.d.ts +0 -55
  39. package/dist/go/linear-sync-cli.js +0 -192
  40. package/dist/go/linear-sync-cli.js.map +0 -1
  41. package/dist/go/linear-sync.d.ts +0 -112
  42. package/dist/go/linear-sync.js +0 -375
  43. package/dist/go/linear-sync.js.map +0 -1
  44. package/dist/go/prd-queue.d.ts +0 -43
  45. package/dist/go/prd-queue.js +0 -67
  46. package/dist/go/prd-queue.js.map +0 -1
  47. package/dist/go/prd-selector.d.ts +0 -57
  48. package/dist/go/prd-selector.js +0 -101
  49. package/dist/go/prd-selector.js.map +0 -1
  50. package/dist/go/verify-loop.d.ts +0 -64
  51. package/dist/go/verify-loop.js +0 -327
  52. package/dist/go/verify-loop.js.map +0 -1
  53. package/dist/hooks/pre-commit.d.ts +0 -5
  54. package/dist/hooks/pre-commit.js +0 -75
  55. package/dist/hooks/pre-commit.js.map +0 -1
  56. package/dist/linear/issues.d.ts +0 -22
  57. package/dist/linear/issues.js +0 -51
  58. package/dist/linear/issues.js.map +0 -1
  59. package/dist/linear/milestones.d.ts +0 -11
  60. package/dist/linear/milestones.js +0 -32
  61. package/dist/linear/milestones.js.map +0 -1
  62. package/dist/linear/projects.d.ts +0 -16
  63. package/dist/linear/projects.js +0 -51
  64. package/dist/linear/projects.js.map +0 -1
  65. package/dist/reporter/human.d.ts +0 -7
  66. package/dist/reporter/human.js +0 -93
  67. package/dist/reporter/human.js.map +0 -1
  68. package/dist/reporter/json.d.ts +0 -2
  69. package/dist/reporter/json.js +0 -4
  70. package/dist/reporter/json.js.map +0 -1
  71. package/dist/setup/structural-templates.d.ts +0 -12
  72. package/dist/setup/structural-templates.js +0 -288
  73. package/dist/setup/structural-templates.js.map +0 -1
  74. package/dist/setup/templates.d.ts +0 -17
  75. package/dist/setup/templates.js +0 -109
  76. package/dist/setup/templates.js.map +0 -1
  77. package/dist/setup/test-planner.d.ts +0 -38
  78. package/dist/setup/test-planner.js +0 -91
  79. package/dist/setup/test-planner.js.map +0 -1
  80. package/dist/setup/test-scaffold.d.ts +0 -31
  81. package/dist/setup/test-scaffold.js +0 -209
  82. package/dist/setup/test-scaffold.js.map +0 -1
  83. package/dist/setup/test-templates.d.ts +0 -37
  84. package/dist/setup/test-templates.js +0 -313
  85. package/dist/setup/test-templates.js.map +0 -1
  86. package/dist/spec/generator.d.ts +0 -34
  87. package/dist/spec/generator.js +0 -227
  88. package/dist/spec/generator.js.map +0 -1
  89. package/dist/spec/interview.d.ts +0 -142
  90. package/dist/spec/interview.js +0 -287
  91. package/dist/spec/interview.js.map +0 -1
  92. package/dist/spec/linear-sync.d.ts +0 -48
  93. package/dist/spec/linear-sync.js +0 -125
  94. package/dist/spec/linear-sync.js.map +0 -1
  95. package/dist/spec/scanner.d.ts +0 -79
  96. package/dist/spec/scanner.js +0 -566
  97. package/dist/spec/scanner.js.map +0 -1
  98. package/dist/spec/templates.d.ts +0 -375
  99. package/dist/spec/templates.js +0 -95
  100. package/dist/spec/templates.js.map +0 -1
  101. package/dist/state/prd-status.d.ts +0 -62
  102. package/dist/state/prd-status.js +0 -122
  103. package/dist/state/prd-status.js.map +0 -1
  104. package/dist/state/reader.d.ts +0 -7
  105. package/dist/state/reader.js +0 -43
  106. package/dist/state/reader.js.map +0 -1
  107. package/dist/state/writer.d.ts +0 -21
  108. package/dist/state/writer.js +0 -106
  109. package/dist/state/writer.js.map +0 -1
  110. package/dist/team/consensus.d.ts +0 -28
  111. package/dist/team/consensus.js +0 -130
  112. package/dist/team/consensus.js.map +0 -1
  113. package/dist/team/index.d.ts +0 -4
  114. package/dist/team/index.js +0 -5
  115. package/dist/team/index.js.map +0 -1
  116. package/dist/team/lifecycle.d.ts +0 -37
  117. package/dist/team/lifecycle.js +0 -92
  118. package/dist/team/lifecycle.js.map +0 -1
  119. package/dist/team/reviewer.d.ts +0 -10
  120. package/dist/team/reviewer.js +0 -345
  121. package/dist/team/reviewer.js.map +0 -1
  122. package/dist/team/types.d.ts +0 -269
  123. package/dist/team/types.js +0 -70
  124. package/dist/team/types.js.map +0 -1
  125. package/dist/utils/browser.d.ts +0 -10
  126. package/dist/utils/browser.js +0 -96
  127. package/dist/utils/browser.js.map +0 -1
  128. package/dist/utils/platform.d.ts +0 -29
  129. package/dist/utils/platform.js +0 -90
  130. package/dist/utils/platform.js.map +0 -1
  131. package/dist/worktree/identity.d.ts +0 -9
  132. package/dist/worktree/identity.js +0 -32
  133. package/dist/worktree/identity.js.map +0 -1
  134. package/dist/worktree/parallel.d.ts +0 -87
  135. package/dist/worktree/parallel.js +0 -328
  136. package/dist/worktree/parallel.js.map +0 -1
  137. package/dist/worktree/session.d.ts +0 -67
  138. package/dist/worktree/session.js +0 -194
  139. package/dist/worktree/session.js.map +0 -1
  140. package/dist/worktree/state-merge.d.ts +0 -43
  141. package/dist/worktree/state-merge.js +0 -162
  142. package/dist/worktree/state-merge.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-cc",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Forge — verification harness for Claude Code agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,7 +40,8 @@
40
40
  "AGENTS.md"
41
41
  ],
42
42
  "scripts": {
43
- "build": "tsc",
43
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
44
+ "build": "npm run clean && tsc",
44
45
  "dev": "tsc --watch",
45
46
  "start": "node dist/cli.js",
46
47
  "test": "vitest run",
@@ -1,51 +0,0 @@
1
- import type { GateResult } from "../types.js";
2
- import type { CodexComment } from "../team/types.js";
3
- export interface CodexGateOptions {
4
- owner: string;
5
- repo: string;
6
- prNumber: number;
7
- pollIntervalMs?: number;
8
- maxPolls?: number;
9
- projectDir?: string;
10
- }
11
- /**
12
- * Fetch PR review comments using the GitHub CLI.
13
- * Returns an empty array if the `gh` command fails.
14
- *
15
- * Uses `in_reply_to_id` to skip reply comments (only returns thread roots),
16
- * and accepts `knownIds` to exclude previously-addressed comments so the
17
- * polling loop can converge.
18
- */
19
- export declare function fetchPRComments(options: {
20
- owner: string;
21
- repo: string;
22
- prNumber: number;
23
- projectDir?: string;
24
- /** Comment IDs that have already been addressed (skip these) */
25
- knownIds?: Set<number>;
26
- }): CodexComment[];
27
- /**
28
- * Filter to only unresolved comments.
29
- */
30
- export declare function getUnresolvedComments(comments: CodexComment[]): CodexComment[];
31
- /**
32
- * Format a single comment for human-readable display.
33
- */
34
- export declare function formatCommentForFix(comment: CodexComment): string;
35
- /**
36
- * Poll for PR comments at a regular interval until new comments appear
37
- * or the maximum number of polls is reached.
38
- *
39
- * Accepts `knownIds` to exclude previously-addressed comments so re-polls
40
- * after a fix cycle only surface genuinely new feedback.
41
- */
42
- export declare function pollForCodexComments(options: CodexGateOptions & {
43
- knownIds?: Set<number>;
44
- }): Promise<CodexComment[]>;
45
- /**
46
- * Run the Codex post-PR review gate.
47
- *
48
- * This gate is NOT registered in the normal pipeline — it runs after a PR is
49
- * created and polls for Codex review comments.
50
- */
51
- export declare function runCodexGate(options: CodexGateOptions): Promise<GateResult>;
@@ -1,121 +0,0 @@
1
- import { execSync } from "node:child_process";
2
- /**
3
- * Fetch PR review comments using the GitHub CLI.
4
- * Returns an empty array if the `gh` command fails.
5
- *
6
- * Uses `in_reply_to_id` to skip reply comments (only returns thread roots),
7
- * and accepts `knownIds` to exclude previously-addressed comments so the
8
- * polling loop can converge.
9
- */
10
- export function fetchPRComments(options) {
11
- const { owner, repo, prNumber, projectDir, knownIds } = options;
12
- try {
13
- const raw = execSync(`gh api repos/${owner}/${repo}/pulls/${prNumber}/comments`, { cwd: projectDir, encoding: "utf-8", timeout: 30_000 });
14
- const parsed = JSON.parse(raw);
15
- if (!Array.isArray(parsed))
16
- return [];
17
- return parsed
18
- .filter((c) => {
19
- // Skip replies — only keep thread-root comments
20
- if (c.in_reply_to_id != null)
21
- return false;
22
- // Skip previously-addressed comments
23
- if (knownIds && knownIds.has(c.id))
24
- return false;
25
- return true;
26
- })
27
- .map((c) => ({
28
- id: c.id,
29
- body: c.body,
30
- path: c.path,
31
- line: c.line ??
32
- c.original_line ??
33
- undefined,
34
- resolved: false,
35
- }));
36
- }
37
- catch {
38
- return [];
39
- }
40
- }
41
- /**
42
- * Filter to only unresolved comments.
43
- */
44
- export function getUnresolvedComments(comments) {
45
- return comments.filter((c) => c.resolved === false);
46
- }
47
- /**
48
- * Format a single comment for human-readable display.
49
- */
50
- export function formatCommentForFix(comment) {
51
- const location = comment.line
52
- ? `${comment.path}:${comment.line}`
53
- : comment.path;
54
- return `**PR Comment #${comment.id}** (${location})\n${comment.body}`;
55
- }
56
- /**
57
- * Poll for PR comments at a regular interval until new comments appear
58
- * or the maximum number of polls is reached.
59
- *
60
- * Accepts `knownIds` to exclude previously-addressed comments so re-polls
61
- * after a fix cycle only surface genuinely new feedback.
62
- */
63
- export async function pollForCodexComments(options) {
64
- const intervalMs = options.pollIntervalMs ?? 60_000;
65
- const maxPolls = options.maxPolls ?? 8;
66
- for (let i = 0; i < maxPolls; i++) {
67
- // Wait before subsequent polls (first poll is immediate)
68
- if (i > 0) {
69
- await new Promise((r) => setTimeout(r, intervalMs));
70
- }
71
- const comments = fetchPRComments({
72
- owner: options.owner,
73
- repo: options.repo,
74
- prNumber: options.prNumber,
75
- projectDir: options.projectDir,
76
- knownIds: options.knownIds,
77
- });
78
- if (comments.length > 0) {
79
- return comments;
80
- }
81
- }
82
- return [];
83
- }
84
- /**
85
- * Run the Codex post-PR review gate.
86
- *
87
- * This gate is NOT registered in the normal pipeline — it runs after a PR is
88
- * created and polls for Codex review comments.
89
- */
90
- export async function runCodexGate(options) {
91
- const start = Date.now();
92
- const errors = [];
93
- const warnings = [];
94
- const unresolvedComments = await pollForCodexComments(options);
95
- if (unresolvedComments.length === 0) {
96
- warnings.push("No Codex review comments found (Codex may not be configured)");
97
- return {
98
- gate: "codex",
99
- passed: true,
100
- errors,
101
- warnings,
102
- duration_ms: Date.now() - start,
103
- };
104
- }
105
- for (const comment of unresolvedComments) {
106
- errors.push({
107
- file: comment.path,
108
- line: comment.line,
109
- message: comment.body,
110
- remediation: "Address the Codex review comment",
111
- });
112
- }
113
- return {
114
- gate: "codex",
115
- passed: false,
116
- errors,
117
- warnings,
118
- duration_ms: Date.now() - start,
119
- };
120
- }
121
- //# sourceMappingURL=codex-gate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex-gate.js","sourceRoot":"","sources":["../../src/gates/codex-gate.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import type { GateResult } from "../types.js";
2
- /**
3
- * Reads the git diff and compares against PRD acceptance criteria
4
- * to check coverage. This is a heuristic check -- it helps catch
5
- * obvious omissions but cannot verify behavior.
6
- */
7
- export declare function verifyPrd(projectDir: string, prdPath: string, baseBranch?: string): Promise<GateResult>;
@@ -1,193 +0,0 @@
1
- import { execSync } from "node:child_process";
2
- import { readFileSync } from "node:fs";
3
- /**
4
- * Reads the git diff and compares against PRD acceptance criteria
5
- * to check coverage. This is a heuristic check -- it helps catch
6
- * obvious omissions but cannot verify behavior.
7
- */
8
- export async function verifyPrd(projectDir, prdPath, baseBranch = "main") {
9
- const start = Date.now();
10
- const errors = [];
11
- const warnings = [];
12
- try {
13
- // Read PRD content
14
- const prdContent = readFileSync(prdPath, "utf-8");
15
- // Extract acceptance criteria
16
- const criteria = extractCriteria(prdContent);
17
- if (criteria.length === 0) {
18
- warnings.push("No acceptance criteria found in PRD (looked for checkboxes and criteria headings)");
19
- return {
20
- gate: "prd",
21
- passed: true,
22
- errors,
23
- warnings,
24
- duration_ms: Date.now() - start,
25
- };
26
- }
27
- // Get changed file names from diff
28
- let changedFiles;
29
- try {
30
- const nameOnly = execSync(`git diff ${baseBranch}...HEAD --name-only`, { cwd: projectDir, encoding: "utf-8", timeout: 30_000 });
31
- changedFiles = nameOnly
32
- .split("\n")
33
- .map((f) => f.trim())
34
- .filter(Boolean);
35
- }
36
- catch {
37
- changedFiles = [];
38
- warnings.push("Could not get git diff -- branch may not have diverged from base");
39
- }
40
- // Get stat summary for additional context
41
- let diffStat = "";
42
- try {
43
- diffStat = execSync(`git diff ${baseBranch}...HEAD --stat`, {
44
- cwd: projectDir,
45
- encoding: "utf-8",
46
- timeout: 30_000,
47
- });
48
- }
49
- catch {
50
- // Non-critical -- we still have changedFiles
51
- }
52
- if (changedFiles.length === 0 && diffStat === "") {
53
- warnings.push("No changes detected against base branch -- all criteria marked unclear");
54
- for (const criterion of criteria) {
55
- warnings.push(`? ${criterion} -- no changes to evaluate against`);
56
- }
57
- return {
58
- gate: "prd",
59
- passed: false,
60
- errors: [{ message: `No changes found to evaluate against ${criteria.length} criteria` }],
61
- warnings,
62
- duration_ms: Date.now() - start,
63
- };
64
- }
65
- // Evaluate each criterion against the diff
66
- for (const criterion of criteria) {
67
- const result = evaluateCriterion(criterion, changedFiles);
68
- if (result.status === "covered") {
69
- warnings.push(`\u2713 ${criterion} -- likely covered (matched: ${result.matchedFiles.join(", ")})`);
70
- }
71
- else if (result.status === "unclear") {
72
- warnings.push(`? ${criterion} -- could not determine coverage`);
73
- }
74
- else {
75
- errors.push({
76
- message: `\u2717 ${criterion} -- no matching changes found`,
77
- remediation: "Ensure the relevant code changes are committed and address this criterion",
78
- });
79
- }
80
- }
81
- }
82
- catch (err) {
83
- const message = err instanceof Error ? err.message : String(err);
84
- errors.push({ message: `PRD verification failed: ${message}` });
85
- }
86
- return {
87
- gate: "prd",
88
- passed: errors.length === 0,
89
- errors,
90
- warnings,
91
- duration_ms: Date.now() - start,
92
- };
93
- }
94
- /**
95
- * Extract acceptance criteria from PRD markdown content.
96
- * Looks for:
97
- * 1. Checkbox lines: `- [ ] ...` or `- [x] ...`
98
- * 2. Lines under "## Acceptance Criteria" or "## User Stories" headings
99
- */
100
- function extractCriteria(content) {
101
- const lines = content.split("\n");
102
- const criteria = [];
103
- const seen = new Set();
104
- let inCriteriaSection = false;
105
- for (const line of lines) {
106
- const trimmed = line.trim();
107
- // Check for criteria section headings
108
- if (/^#{1,3}\s+(acceptance\s+criteria|user\s+stories)/i.test(trimmed)) {
109
- inCriteriaSection = true;
110
- continue;
111
- }
112
- // End criteria section at next heading
113
- if (inCriteriaSection && /^#{1,3}\s+/.test(trimmed) && !/^#{1,3}\s+(acceptance\s+criteria|user\s+stories)/i.test(trimmed)) {
114
- inCriteriaSection = false;
115
- continue;
116
- }
117
- // Checkbox lines anywhere in the document
118
- const checkboxMatch = trimmed.match(/^-\s+\[[ x]\]\s+(.+)/i);
119
- if (checkboxMatch) {
120
- const text = checkboxMatch[1].trim();
121
- if (!seen.has(text)) {
122
- seen.add(text);
123
- criteria.push(text);
124
- }
125
- continue;
126
- }
127
- // Bullet points under a criteria section heading
128
- if (inCriteriaSection) {
129
- const bulletMatch = trimmed.match(/^[-*]\s+(.+)/);
130
- if (bulletMatch) {
131
- const text = bulletMatch[1].trim();
132
- if (!seen.has(text)) {
133
- seen.add(text);
134
- criteria.push(text);
135
- }
136
- }
137
- }
138
- }
139
- return criteria;
140
- }
141
- /**
142
- * Heuristic evaluation of whether a criterion is covered by the diff.
143
- * Extracts keywords from the criterion and matches against changed file paths.
144
- */
145
- function evaluateCriterion(criterion, changedFiles) {
146
- // Extract meaningful keywords (3+ chars, not common words)
147
- const stopWords = new Set([
148
- "the", "and", "for", "are", "but", "not", "you", "all", "can", "has",
149
- "her", "was", "one", "our", "out", "its", "his", "how", "its", "may",
150
- "who", "did", "get", "let", "say", "she", "too", "use", "way", "each",
151
- "which", "their", "will", "other", "about", "many", "then", "them",
152
- "been", "have", "from", "with", "they", "this", "that", "what", "when",
153
- "make", "like", "just", "over", "such", "take", "into", "than", "most",
154
- "also", "should", "would", "could", "must", "shall", "might", "does",
155
- "display", "show", "page", "user", "view", "click", "able", "ensure",
156
- "given", "when", "then",
157
- ]);
158
- const keywords = criterion
159
- .toLowerCase()
160
- .replace(/[^a-z0-9\s-]/g, " ")
161
- .split(/\s+/)
162
- .filter((w) => w.length >= 3 && !stopWords.has(w));
163
- if (keywords.length === 0) {
164
- return { status: "unclear", matchedFiles: [] };
165
- }
166
- // Match keywords against file paths
167
- const matchedFiles = [];
168
- for (const file of changedFiles) {
169
- const fileLower = file.toLowerCase();
170
- // Extract file name parts (split on /, ., -, _)
171
- const fileParts = fileLower.split(/[/.\-_]/).filter(Boolean);
172
- for (const keyword of keywords) {
173
- if (fileLower.includes(keyword) ||
174
- fileParts.some((part) => part.includes(keyword) || keyword.includes(part))) {
175
- matchedFiles.push(file);
176
- break;
177
- }
178
- }
179
- }
180
- if (matchedFiles.length > 0) {
181
- // Cap displayed files at 3 for readability
182
- const displayFiles = matchedFiles.length > 3
183
- ? [...matchedFiles.slice(0, 3), `+${matchedFiles.length - 3} more`]
184
- : matchedFiles;
185
- return { status: "covered", matchedFiles: displayFiles };
186
- }
187
- // If no files matched but there are very few keywords, mark as unclear
188
- if (keywords.length <= 2) {
189
- return { status: "unclear", matchedFiles: [] };
190
- }
191
- return { status: "not_covered", matchedFiles: [] };
192
- }
193
- //# sourceMappingURL=prd-gate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prd-gate.js","sourceRoot":"","sources":["../../src/gates/prd-gate.ts"],"names":[],"mappings":"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"}
@@ -1,46 +0,0 @@
1
- import type { GateError } from "../types.js";
2
- /**
3
- * Build actionable remediation text for a TypeScript compilation error.
4
- *
5
- * Parses the TS error code from the message and returns a targeted fix
6
- * instruction. Falls back to a generic hint when the code is unrecognized.
7
- */
8
- export declare function buildTypeRemediation(error: GateError): string;
9
- /**
10
- * Build actionable remediation text for a lint error (ESLint or Biome).
11
- *
12
- * Extracts the rule name from the error message and returns a targeted fix
13
- * instruction. Falls back to a generic hint when the rule is unrecognized.
14
- */
15
- export declare function buildLintRemediation(error: GateError): string;
16
- /**
17
- * Build actionable remediation text for a test failure.
18
- *
19
- * Scans the error message for common failure patterns (assertion mismatches,
20
- * runtime errors, timeouts) and returns targeted fix instructions. Falls
21
- * back to a generic test-fix hint when no patterns match.
22
- */
23
- export declare function buildTestRemediation(error: GateError): string;
24
- /**
25
- * Build actionable remediation text for a visual validation error.
26
- *
27
- * Scans the error message for viewport and layout keywords, then returns
28
- * CSS/layout-specific fix hints. Falls back to generic visual advice when
29
- * no patterns match.
30
- */
31
- export declare function buildVisualRemediation(error: GateError): string;
32
- /**
33
- * Build actionable remediation text for a code review finding.
34
- *
35
- * Adds PRD section references, CLAUDE.md rule citations, and concrete
36
- * next-step guidance so fix agents know exactly where to look.
37
- */
38
- export declare function buildReviewRemediation(error: GateError): string;
39
- /**
40
- * Build actionable remediation text for a test coverage error.
41
- *
42
- * Handles missing test files (enforcement mode) and zero-coverage baseline
43
- * failures. Returns file-specific instructions when a source file is
44
- * identified, or a general scaffolding instruction otherwise.
45
- */
46
- export declare function buildTestCoverageRemediation(error: GateError): string;