forge-cc 0.1.41 → 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 (203) hide show
  1. package/README.md +454 -338
  2. package/dist/cli.js +194 -935
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config/loader.d.ts +1 -1
  5. package/dist/config/loader.js +49 -56
  6. package/dist/config/loader.js.map +1 -1
  7. package/dist/config/schema.d.ts +37 -125
  8. package/dist/config/schema.js +13 -28
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/doctor.d.ts +10 -0
  11. package/dist/doctor.js +148 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/gates/index.d.ts +14 -12
  14. package/dist/gates/index.js +53 -105
  15. package/dist/gates/index.js.map +1 -1
  16. package/dist/gates/lint-gate.d.ts +2 -2
  17. package/dist/gates/lint-gate.js +60 -66
  18. package/dist/gates/lint-gate.js.map +1 -1
  19. package/dist/gates/tests-gate.d.ts +2 -4
  20. package/dist/gates/tests-gate.js +75 -203
  21. package/dist/gates/tests-gate.js.map +1 -1
  22. package/dist/gates/types-gate.d.ts +2 -2
  23. package/dist/gates/types-gate.js +53 -59
  24. package/dist/gates/types-gate.js.map +1 -1
  25. package/dist/linear/client.d.ts +31 -108
  26. package/dist/linear/client.js +88 -388
  27. package/dist/linear/client.js.map +1 -1
  28. package/dist/linear/sync.d.ts +15 -0
  29. package/dist/linear/sync.js +102 -0
  30. package/dist/linear/sync.js.map +1 -0
  31. package/dist/runner/loop.d.ts +4 -0
  32. package/dist/runner/loop.js +168 -0
  33. package/dist/runner/loop.js.map +1 -0
  34. package/dist/runner/prompt.d.ts +14 -0
  35. package/dist/runner/prompt.js +59 -0
  36. package/dist/runner/prompt.js.map +1 -0
  37. package/dist/runner/update.d.ts +1 -0
  38. package/dist/runner/update.js +72 -0
  39. package/dist/runner/update.js.map +1 -0
  40. package/dist/server.d.ts +6 -2
  41. package/dist/server.js +43 -101
  42. package/dist/server.js.map +1 -1
  43. package/dist/setup.d.ts +5 -0
  44. package/dist/setup.js +208 -0
  45. package/dist/setup.js.map +1 -0
  46. package/dist/state/cache.d.ts +3 -0
  47. package/dist/state/cache.js +23 -0
  48. package/dist/state/cache.js.map +1 -0
  49. package/dist/state/status.d.ts +66 -0
  50. package/dist/state/status.js +96 -0
  51. package/dist/state/status.js.map +1 -0
  52. package/dist/types.d.ts +46 -114
  53. package/dist/worktree/manager.d.ts +6 -103
  54. package/dist/worktree/manager.js +25 -296
  55. package/dist/worktree/manager.js.map +1 -1
  56. package/hooks/pre-commit-verify.js +109 -109
  57. package/package.json +5 -3
  58. package/skills/forge-go.md +20 -13
  59. package/skills/forge-setup.md +149 -388
  60. package/skills/forge-spec.md +367 -342
  61. package/skills/forge-triage.md +179 -133
  62. package/skills/forge-update.md +87 -93
  63. package/dist/gates/codex-gate.d.ts +0 -51
  64. package/dist/gates/codex-gate.js +0 -121
  65. package/dist/gates/codex-gate.js.map +0 -1
  66. package/dist/gates/prd-gate.d.ts +0 -7
  67. package/dist/gates/prd-gate.js +0 -193
  68. package/dist/gates/prd-gate.js.map +0 -1
  69. package/dist/gates/remediation.d.ts +0 -46
  70. package/dist/gates/remediation.js +0 -423
  71. package/dist/gates/remediation.js.map +0 -1
  72. package/dist/gates/review-gate.d.ts +0 -16
  73. package/dist/gates/review-gate.js +0 -479
  74. package/dist/gates/review-gate.js.map +0 -1
  75. package/dist/gates/runtime-gate.d.ts +0 -5
  76. package/dist/gates/runtime-gate.js +0 -99
  77. package/dist/gates/runtime-gate.js.map +0 -1
  78. package/dist/gates/test-analysis.d.ts +0 -21
  79. package/dist/gates/test-analysis.js +0 -394
  80. package/dist/gates/test-analysis.js.map +0 -1
  81. package/dist/gates/visual-capture.d.ts +0 -24
  82. package/dist/gates/visual-capture.js +0 -144
  83. package/dist/gates/visual-capture.js.map +0 -1
  84. package/dist/gates/visual-gate.d.ts +0 -18
  85. package/dist/gates/visual-gate.js +0 -234
  86. package/dist/gates/visual-gate.js.map +0 -1
  87. package/dist/gates/visual-reviewer.d.ts +0 -11
  88. package/dist/gates/visual-reviewer.js +0 -211
  89. package/dist/gates/visual-reviewer.js.map +0 -1
  90. package/dist/go/auto-chain.d.ts +0 -136
  91. package/dist/go/auto-chain.js +0 -389
  92. package/dist/go/auto-chain.js.map +0 -1
  93. package/dist/go/executor.d.ts +0 -137
  94. package/dist/go/executor.js +0 -447
  95. package/dist/go/executor.js.map +0 -1
  96. package/dist/go/finalize.d.ts +0 -108
  97. package/dist/go/finalize.js +0 -331
  98. package/dist/go/finalize.js.map +0 -1
  99. package/dist/go/linear-sync-cli.d.ts +0 -55
  100. package/dist/go/linear-sync-cli.js +0 -192
  101. package/dist/go/linear-sync-cli.js.map +0 -1
  102. package/dist/go/linear-sync.d.ts +0 -112
  103. package/dist/go/linear-sync.js +0 -375
  104. package/dist/go/linear-sync.js.map +0 -1
  105. package/dist/go/prd-queue.d.ts +0 -43
  106. package/dist/go/prd-queue.js +0 -67
  107. package/dist/go/prd-queue.js.map +0 -1
  108. package/dist/go/prd-selector.d.ts +0 -57
  109. package/dist/go/prd-selector.js +0 -101
  110. package/dist/go/prd-selector.js.map +0 -1
  111. package/dist/go/verify-loop.d.ts +0 -64
  112. package/dist/go/verify-loop.js +0 -327
  113. package/dist/go/verify-loop.js.map +0 -1
  114. package/dist/hooks/pre-commit.d.ts +0 -5
  115. package/dist/hooks/pre-commit.js +0 -75
  116. package/dist/hooks/pre-commit.js.map +0 -1
  117. package/dist/linear/issues.d.ts +0 -22
  118. package/dist/linear/issues.js +0 -51
  119. package/dist/linear/issues.js.map +0 -1
  120. package/dist/linear/milestones.d.ts +0 -11
  121. package/dist/linear/milestones.js +0 -32
  122. package/dist/linear/milestones.js.map +0 -1
  123. package/dist/linear/projects.d.ts +0 -16
  124. package/dist/linear/projects.js +0 -51
  125. package/dist/linear/projects.js.map +0 -1
  126. package/dist/reporter/human.d.ts +0 -7
  127. package/dist/reporter/human.js +0 -93
  128. package/dist/reporter/human.js.map +0 -1
  129. package/dist/reporter/json.d.ts +0 -2
  130. package/dist/reporter/json.js +0 -4
  131. package/dist/reporter/json.js.map +0 -1
  132. package/dist/setup/structural-templates.d.ts +0 -12
  133. package/dist/setup/structural-templates.js +0 -288
  134. package/dist/setup/structural-templates.js.map +0 -1
  135. package/dist/setup/templates.d.ts +0 -17
  136. package/dist/setup/templates.js +0 -109
  137. package/dist/setup/templates.js.map +0 -1
  138. package/dist/setup/test-planner.d.ts +0 -38
  139. package/dist/setup/test-planner.js +0 -91
  140. package/dist/setup/test-planner.js.map +0 -1
  141. package/dist/setup/test-scaffold.d.ts +0 -31
  142. package/dist/setup/test-scaffold.js +0 -209
  143. package/dist/setup/test-scaffold.js.map +0 -1
  144. package/dist/setup/test-templates.d.ts +0 -37
  145. package/dist/setup/test-templates.js +0 -313
  146. package/dist/setup/test-templates.js.map +0 -1
  147. package/dist/spec/generator.d.ts +0 -34
  148. package/dist/spec/generator.js +0 -227
  149. package/dist/spec/generator.js.map +0 -1
  150. package/dist/spec/interview.d.ts +0 -142
  151. package/dist/spec/interview.js +0 -287
  152. package/dist/spec/interview.js.map +0 -1
  153. package/dist/spec/linear-sync.d.ts +0 -48
  154. package/dist/spec/linear-sync.js +0 -125
  155. package/dist/spec/linear-sync.js.map +0 -1
  156. package/dist/spec/scanner.d.ts +0 -79
  157. package/dist/spec/scanner.js +0 -566
  158. package/dist/spec/scanner.js.map +0 -1
  159. package/dist/spec/templates.d.ts +0 -375
  160. package/dist/spec/templates.js +0 -95
  161. package/dist/spec/templates.js.map +0 -1
  162. package/dist/state/prd-status.d.ts +0 -62
  163. package/dist/state/prd-status.js +0 -122
  164. package/dist/state/prd-status.js.map +0 -1
  165. package/dist/state/reader.d.ts +0 -7
  166. package/dist/state/reader.js +0 -43
  167. package/dist/state/reader.js.map +0 -1
  168. package/dist/state/writer.d.ts +0 -21
  169. package/dist/state/writer.js +0 -106
  170. package/dist/state/writer.js.map +0 -1
  171. package/dist/team/consensus.d.ts +0 -28
  172. package/dist/team/consensus.js +0 -130
  173. package/dist/team/consensus.js.map +0 -1
  174. package/dist/team/index.d.ts +0 -4
  175. package/dist/team/index.js +0 -5
  176. package/dist/team/index.js.map +0 -1
  177. package/dist/team/lifecycle.d.ts +0 -37
  178. package/dist/team/lifecycle.js +0 -92
  179. package/dist/team/lifecycle.js.map +0 -1
  180. package/dist/team/reviewer.d.ts +0 -10
  181. package/dist/team/reviewer.js +0 -345
  182. package/dist/team/reviewer.js.map +0 -1
  183. package/dist/team/types.d.ts +0 -269
  184. package/dist/team/types.js +0 -70
  185. package/dist/team/types.js.map +0 -1
  186. package/dist/utils/browser.d.ts +0 -10
  187. package/dist/utils/browser.js +0 -96
  188. package/dist/utils/browser.js.map +0 -1
  189. package/dist/utils/platform.d.ts +0 -29
  190. package/dist/utils/platform.js +0 -90
  191. package/dist/utils/platform.js.map +0 -1
  192. package/dist/worktree/identity.d.ts +0 -9
  193. package/dist/worktree/identity.js +0 -32
  194. package/dist/worktree/identity.js.map +0 -1
  195. package/dist/worktree/parallel.d.ts +0 -87
  196. package/dist/worktree/parallel.js +0 -328
  197. package/dist/worktree/parallel.js.map +0 -1
  198. package/dist/worktree/session.d.ts +0 -67
  199. package/dist/worktree/session.js +0 -194
  200. package/dist/worktree/session.js.map +0 -1
  201. package/dist/worktree/state-merge.d.ts +0 -43
  202. package/dist/worktree/state-merge.js +0 -162
  203. package/dist/worktree/state-merge.js.map +0 -1
@@ -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;