forgecraft-mcp 1.7.0 → 1.8.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.
Files changed (52) hide show
  1. package/README.md +79 -0
  2. package/dist/registry/remote-gates.d.ts +16 -0
  3. package/dist/registry/remote-gates.d.ts.map +1 -1
  4. package/dist/registry/remote-gates.js +56 -0
  5. package/dist/registry/remote-gates.js.map +1 -1
  6. package/dist/registry/sentinel-domain-map.d.ts.map +1 -1
  7. package/dist/registry/sentinel-domain-map.js +16 -9
  8. package/dist/registry/sentinel-domain-map.js.map +1 -1
  9. package/dist/registry/sentinel-renderer.d.ts +13 -8
  10. package/dist/registry/sentinel-renderer.d.ts.map +1 -1
  11. package/dist/registry/sentinel-renderer.js +440 -162
  12. package/dist/registry/sentinel-renderer.js.map +1 -1
  13. package/dist/shared/harness-budget.d.ts +49 -0
  14. package/dist/shared/harness-budget.d.ts.map +1 -0
  15. package/dist/shared/harness-budget.js +123 -0
  16. package/dist/shared/harness-budget.js.map +1 -0
  17. package/dist/shared/hook-installer.d.ts.map +1 -1
  18. package/dist/shared/hook-installer.js +2 -1
  19. package/dist/shared/hook-installer.js.map +1 -1
  20. package/dist/tools/close-cycle-helpers.d.ts +9 -0
  21. package/dist/tools/close-cycle-helpers.d.ts.map +1 -1
  22. package/dist/tools/close-cycle-helpers.js.map +1 -1
  23. package/dist/tools/close-cycle.d.ts.map +1 -1
  24. package/dist/tools/close-cycle.js +29 -0
  25. package/dist/tools/close-cycle.js.map +1 -1
  26. package/dist/tools/contribute-gate.d.ts +30 -4
  27. package/dist/tools/contribute-gate.d.ts.map +1 -1
  28. package/dist/tools/contribute-gate.js +180 -66
  29. package/dist/tools/contribute-gate.js.map +1 -1
  30. package/dist/tools/gate-genesis.d.ts +47 -0
  31. package/dist/tools/gate-genesis.d.ts.map +1 -0
  32. package/dist/tools/gate-genesis.js +241 -0
  33. package/dist/tools/gate-genesis.js.map +1 -0
  34. package/dist/tools/learning-graph.d.ts +31 -0
  35. package/dist/tools/learning-graph.d.ts.map +1 -0
  36. package/dist/tools/learning-graph.js +266 -0
  37. package/dist/tools/learning-graph.js.map +1 -0
  38. package/dist/tools/setup-artifact-writers.d.ts +15 -3
  39. package/dist/tools/setup-artifact-writers.d.ts.map +1 -1
  40. package/dist/tools/setup-artifact-writers.js +149 -13
  41. package/dist/tools/setup-artifact-writers.js.map +1 -1
  42. package/dist/tools/setup-phase2.d.ts +9 -0
  43. package/dist/tools/setup-phase2.d.ts.map +1 -1
  44. package/dist/tools/setup-phase2.js +13 -0
  45. package/dist/tools/setup-phase2.js.map +1 -1
  46. package/dist/tools/setup-project.d.ts +6 -0
  47. package/dist/tools/setup-project.d.ts.map +1 -1
  48. package/dist/tools/setup-project.js +21 -4
  49. package/dist/tools/setup-project.js.map +1 -1
  50. package/package.json +99 -98
  51. package/templates/api/instructions.yaml +50 -188
  52. package/templates/universal/instructions.yaml +194 -1003
@@ -1,5 +1,21 @@
1
- import { existsSync, readFileSync, writeFileSync } from "fs";
1
+ /**
2
+ * Gate contribution to the public quality-gates registry.
3
+ *
4
+ * Submission mechanism: GitHub issues on jghiringhelli/quality-gates
5
+ * (there is no ForgeCraft API server — by design).
6
+ *
7
+ * Primary: `gh issue create` — works when the dev has the GitHub CLI
8
+ * installed and authenticated (the common case).
9
+ * Fallback: a pre-filled GitHub issue URL written to the pending file —
10
+ * one click opens the proposal in the browser, body pre-populated.
11
+ *
12
+ * Issue format matches .github/ISSUE_TEMPLATE/quality-gate-proposal.md in
13
+ * the registry repo (labels: gate-proposal, status:pending-review).
14
+ */
15
+ import { existsSync, readFileSync, writeFileSync, mkdtempSync, rmSync, } from "fs";
2
16
  import { join } from "path";
17
+ import { tmpdir } from "os";
18
+ import { spawnSync } from "child_process";
3
19
  import { getContributableGates } from "../shared/project-gates.js";
4
20
  /**
5
21
  * Validate that a generalizable gate satisfies all five community convergence attributes.
@@ -36,21 +52,18 @@ function validateConvergenceAttributes(gate) {
36
52
  }
37
53
  const PENDING_CONTRIBUTIONS_FILE = ".forgecraft/pending-contributions.json";
38
54
  const SUBMITTED_CONTRIBUTIONS_FILE = ".forgecraft/contributions.json";
39
- /**
40
- * Reads the forgecraft.yaml config for contribution settings.
41
- */
42
- const DEFAULT_SERVER_URL = "https://api.forgecraft.tools";
55
+ const DEFAULT_REGISTRY_REPO = "jghiringhelli/quality-gates";
56
+ const ISSUE_LABELS = "gate-proposal,status:pending-review";
43
57
  function readContributionConfig(projectRoot) {
44
58
  const forgecraftPath = join(projectRoot, "forgecraft.yaml");
45
59
  if (!existsSync(forgecraftPath)) {
46
- return { contributeGates: false, serverUrl: DEFAULT_SERVER_URL };
60
+ return { contributeGates: false, registryRepo: DEFAULT_REGISTRY_REPO };
47
61
  }
48
62
  try {
49
63
  // Simple parse — avoid importing js-yaml to keep this lightweight
50
64
  const raw = readFileSync(forgecraftPath, "utf-8");
51
65
  const contributeMatch = raw.match(/contribute_gates:\s*(\S+)/);
52
- const serverMatch = raw.match(/server_url:\s*(\S+)/);
53
- const apiKeyMatch = raw.match(/api_key:\s*(\S+)/);
66
+ const repoMatch = raw.match(/registry_repo:\s*(\S+)/);
54
67
  const githubMatch = raw.match(/github_user:\s*(\S+)/);
55
68
  const val = contributeMatch?.[1];
56
69
  const contributeGates = val === "anonymous"
@@ -60,13 +73,12 @@ function readContributionConfig(projectRoot) {
60
73
  : false;
61
74
  return {
62
75
  contributeGates,
63
- serverUrl: serverMatch?.[1] ?? DEFAULT_SERVER_URL,
64
- apiKey: apiKeyMatch?.[1],
76
+ registryRepo: repoMatch?.[1] ?? DEFAULT_REGISTRY_REPO,
65
77
  githubUser: githubMatch?.[1],
66
78
  };
67
79
  }
68
80
  catch {
69
- return { contributeGates: false, serverUrl: DEFAULT_SERVER_URL };
81
+ return { contributeGates: false, registryRepo: DEFAULT_REGISTRY_REPO };
70
82
  }
71
83
  }
72
84
  /**
@@ -101,80 +113,182 @@ function recordSubmission(projectRoot, gate) {
101
113
  writeFileSync(filePath, JSON.stringify([...existing, gate], null, 2) + "\n", "utf-8");
102
114
  }
103
115
  /**
104
- * Submits a gate to the forgecraft-server API or queues it locally.
105
- *
106
- * @param gate - The project gate to submit.
107
- * @param mode - Contribution mode: anonymous or attributed.
108
- * @param serverUrl - Target API URL.
109
- * @param githubUser - GitHub username for attributed mode.
110
- * @param projectType - Optional project type context.
111
- * @param experimentId - Optional experiment identifier to tag the submission.
112
- * @returns Submission result with status and optional issue URL.
116
+ * Build the GitHub issue title for a gate proposal.
117
+ * Matches the registry's issue template: "[Gate Proposal] <gate-id>".
113
118
  */
114
- async function submitGate(gate, mode, serverUrl, apiKey, githubUser, projectType, experimentId) {
119
+ function buildIssueTitle(gate) {
120
+ return `[Gate Proposal] ${gate.id}`;
121
+ }
122
+ /**
123
+ * Build the GitHub issue body matching the registry's
124
+ * .github/ISSUE_TEMPLATE/quality-gate-proposal.md format.
125
+ */
126
+ function buildIssueBody(gate, mode, githubUser, experimentId) {
127
+ const contributor = mode === "attributed" && githubUser ? `@${githubUser}` : "anonymous";
128
+ const tags = Array.isArray(gate.tags) ? gate.tags.join(" | ") : "UNIVERSAL";
129
+ return [
130
+ `## Gate Proposal`,
131
+ ``,
132
+ `**Contributor**: ${contributor}`,
133
+ `**Project type**: ${gate.domain ?? "general"}`,
134
+ experimentId ? `**Experiment**: ${experimentId}` : ``,
135
+ ``,
136
+ `---`,
137
+ ``,
138
+ `### Gate Definition`,
139
+ ``,
140
+ `**ID**: \`${gate.id}\``,
141
+ `**Title**: ${gate.title}`,
142
+ `**Category**: ${gate.domain ?? "other"}`,
143
+ `**GS Property**: ${gate.gsProperty ?? ""}`,
144
+ `**Phase**: ${gate.phase ?? "development"}`,
145
+ `**Hook**: ${gate.hook ?? ""}`,
146
+ `**Tags**: ${tags}`,
147
+ ``,
148
+ `### Description`,
149
+ gate.description ?? "",
150
+ ``,
151
+ `### Check`,
152
+ "```",
153
+ gate.check ?? "",
154
+ "```",
155
+ ``,
156
+ `### Pass Criterion`,
157
+ gate.passCriterion ?? "",
158
+ ``,
159
+ `### Evidence`,
160
+ `> ${(gate.evidence ?? "").replace(/\n/g, "\n> ")}`,
161
+ ``,
162
+ `---`,
163
+ ``,
164
+ `*Submitted via \`forgecraft-mcp contribute_gate\`. By submitting this proposal,`,
165
+ `the contributor agrees the gate definition may be published under CC-BY-4.0`,
166
+ `in the quality-gates registry.*`,
167
+ ]
168
+ .filter((line) => line !== undefined)
169
+ .join("\n");
170
+ }
171
+ /**
172
+ * Build a pre-filled GitHub "new issue" URL — the no-auth fallback.
173
+ * One click opens the proposal in the browser with the body pre-populated.
174
+ * GitHub caps URLs around 8 KB; the body is truncated defensively.
175
+ */
176
+ function buildFallbackIssueUrl(registryRepo, title, body) {
177
+ const truncatedBody = body.length > 5500
178
+ ? body.slice(0, 5500) +
179
+ "\n\n<!-- truncated — full gate YAML in .forgecraft/gates/active/ -->"
180
+ : body;
181
+ const params = new URLSearchParams({
182
+ title,
183
+ labels: ISSUE_LABELS,
184
+ body: truncatedBody,
185
+ });
186
+ return `https://github.com/${registryRepo}/issues/new?${params.toString()}`;
187
+ }
188
+ /** Default GhRunner — invokes the real GitHub CLI. Exported for direct testing. */
189
+ export function runGhCli(args) {
190
+ // Safety net: never create real GitHub issues from a test run.
191
+ // Tests exercising the success path inject a mock ghRunner instead.
192
+ if (process.env["VITEST"] || process.env["NODE_ENV"] === "test") {
193
+ return { ok: false, stdout: "" };
194
+ }
115
195
  try {
116
- const headers = {
117
- "Content-Type": "application/json",
118
- };
119
- if (apiKey)
120
- headers["Authorization"] = `Bearer ${apiKey}`;
121
- const response = await fetch(`${serverUrl}/contribute/gate`, {
122
- method: "POST",
123
- headers,
124
- body: JSON.stringify({
125
- gate: {
126
- id: gate.id,
127
- title: gate.title,
128
- description: gate.description,
129
- domain: gate.domain,
130
- gsProperty: gate.gsProperty,
131
- phase: gate.phase,
132
- hook: gate.hook,
133
- check: gate.check,
134
- passCriterion: gate.passCriterion,
135
- tags: gate.tags,
136
- evidence: gate.evidence,
137
- convergenceAttributes: gate.convergenceAttributes,
138
- },
139
- mode,
140
- attribution: mode === "attributed"
141
- ? { github: githubUser, projectType }
142
- : undefined,
143
- ...(experimentId ? { experimentId } : {}),
144
- }),
145
- signal: AbortSignal.timeout(8000),
196
+ const result = spawnSync("gh", args, {
197
+ encoding: "utf-8",
198
+ timeout: 15_000,
199
+ windowsHide: true,
146
200
  });
147
- if (!response.ok)
148
- return { status: "pending" };
149
- const data = (await response.json());
150
- return {
151
- status: data.status === "submitted" ? "submitted" : "pending",
152
- issueUrl: data.issueUrl,
153
- };
201
+ if (result.error || result.status !== 0) {
202
+ return { ok: false, stdout: result.stdout ?? "" };
203
+ }
204
+ return { ok: true, stdout: (result.stdout ?? "").trim() };
205
+ }
206
+ catch {
207
+ return { ok: false, stdout: "" };
208
+ }
209
+ }
210
+ /**
211
+ * Submit a gate proposal as a GitHub issue on the registry repo.
212
+ *
213
+ * Tries `gh issue create` first (authenticated CLI). On any failure, returns
214
+ * status "pending" with a pre-filled issue URL the dev can open manually.
215
+ *
216
+ * @param gate - The project gate to submit
217
+ * @param mode - Contribution mode: anonymous or attributed
218
+ * @param registryRepo - Target repo ("owner/name")
219
+ * @param githubUser - GitHub username for attributed mode
220
+ * @param experimentId - Optional experiment identifier
221
+ * @param ghRunner - Injectable gh CLI runner (tests)
222
+ * @returns Submission result with status and issue URL
223
+ */
224
+ function submitGateAsIssue(gate, mode, registryRepo, githubUser, experimentId, ghRunner = runGhCli) {
225
+ const title = buildIssueTitle(gate);
226
+ const body = buildIssueBody(gate, mode, githubUser, experimentId);
227
+ // Primary: gh CLI. --body-file avoids all shell-escaping issues.
228
+ let bodyDir;
229
+ try {
230
+ bodyDir = mkdtempSync(join(tmpdir(), "fc-gate-"));
231
+ const bodyFile = join(bodyDir, "issue-body.md");
232
+ writeFileSync(bodyFile, body, "utf-8");
233
+ const result = ghRunner([
234
+ "issue",
235
+ "create",
236
+ "--repo",
237
+ registryRepo,
238
+ "--title",
239
+ title,
240
+ "--body-file",
241
+ bodyFile,
242
+ "--label",
243
+ ISSUE_LABELS,
244
+ ]);
245
+ if (result.ok) {
246
+ // gh prints the created issue URL as the last stdout line
247
+ const url = result.stdout
248
+ .split("\n")
249
+ .reverse()
250
+ .find((l) => l.startsWith("https://"));
251
+ return { status: "submitted", issueUrl: url };
252
+ }
154
253
  }
155
254
  catch {
156
- return { status: "pending" };
255
+ // fall through to URL fallback
256
+ }
257
+ finally {
258
+ if (bodyDir) {
259
+ try {
260
+ rmSync(bodyDir, { recursive: true, force: true });
261
+ }
262
+ catch {
263
+ /* temp cleanup is best-effort */
264
+ }
265
+ }
157
266
  }
267
+ // Fallback: pre-filled issue URL — dev opens it in the browser.
268
+ return {
269
+ status: "pending",
270
+ issueUrl: buildFallbackIssueUrl(registryRepo, title, body),
271
+ };
158
272
  }
159
273
  /**
160
274
  * Contributes all generalizable gates from .forgecraft/project-gates.yaml.
161
275
  * - Reads contribute_gates setting from forgecraft.yaml
162
276
  * - Skips gates already submitted (tracked in .forgecraft/contributions.json)
163
- * - Calls forgecraft-server API if reachable, otherwise queues locally
164
- * - Never throws all failures are recorded as skipped
277
+ * - Creates a GitHub issue on the registry repo via gh CLI when available,
278
+ * otherwise queues a pre-filled issue URL for one-click manual submission
279
+ * - Never throws — all failures are recorded as skipped or pending
165
280
  *
166
281
  * @param options - Contribution options including project root and optional overrides.
167
282
  * @returns Result containing submitted, skipped gates and optional pending file path.
168
283
  */
169
284
  export async function contributeGates(options) {
170
- const { projectRoot, dryRun = false, experimentId } = options;
285
+ const { projectRoot, dryRun = false, experimentId, ghRunner } = options;
171
286
  const config = readContributionConfig(projectRoot);
172
287
  if (!config.contributeGates) {
173
288
  return { submitted: [], skipped: [], pendingFile: undefined };
174
289
  }
175
290
  const mode = config.contributeGates;
176
- const serverUrl = options.serverUrl ?? config.serverUrl;
177
- const apiKey = options.apiKey ?? config.apiKey;
291
+ const registryRepo = options.registryRepo ?? config.registryRepo;
178
292
  const gates = getContributableGates(projectRoot);
179
293
  const alreadySubmitted = getAlreadySubmitted(projectRoot);
180
294
  const submitted = [];
@@ -200,12 +314,12 @@ export async function contributeGates(options) {
200
314
  submitted.push({ gateId: gate.id, mode, status: "pending" });
201
315
  continue;
202
316
  }
203
- const result = await submitGate(gate, mode, serverUrl, apiKey, config.githubUser, undefined, experimentId);
317
+ const result = submitGateAsIssue(gate, mode, registryRepo, config.githubUser, experimentId, ghRunner);
204
318
  const contributed = { gateId: gate.id, ...result, mode };
205
319
  submitted.push(contributed);
206
320
  recordSubmission(projectRoot, contributed);
207
321
  }
208
- // Write pending contributions to file for manual review/retry
322
+ // Write pending contributions (with their one-click issue URLs) for manual submission
209
323
  const pending = submitted.filter((s) => s.status === "pending");
210
324
  let pendingFile;
211
325
  if (pending.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"contribute-gate.js","sourceRoot":"","sources":["../../src/tools/contribute-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contribute-gate.js","sourceRoot":"","sources":["../../src/tools/contribute-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Gate genesis — propose new quality gates from observed development friction.
3
+ *
4
+ * Two signal sources:
5
+ * 1. `.forgecraft/gate-violations.jsonl` — the same hook violated repeatedly
6
+ * means the team keeps hitting a failure mode worth formalizing.
7
+ * 2. `.claude/corrections.md` — repeated AI corrections in the same category
8
+ * mean an unenforced convention; a gate makes it structural.
9
+ *
10
+ * Candidates become DRAFT YAML stubs in `.forgecraft/gates/drafts/` — never
11
+ * auto-activated (human judgment). When the dev fills in `evidence` and sets
12
+ * `generalizable: true`, the existing contribute flow takes the gate to the
13
+ * public registry as a GitHub issue. This completes the community flywheel:
14
+ * violations → drafts → active gates → registry → installed in other projects.
15
+ */
16
+ export interface GateCandidate {
17
+ /** Proposed gate id, e.g. "auto-gate-hardcoded-url". */
18
+ readonly id: string;
19
+ readonly source: "violations" | "corrections";
20
+ /** The hook name or correction category that triggered the proposal. */
21
+ readonly pattern: string;
22
+ readonly occurrences: number;
23
+ /** Up to MAX_EXAMPLES sample messages for the draft's context. */
24
+ readonly examples: readonly string[];
25
+ }
26
+ /**
27
+ * Scan violation log + corrections log and return gate candidates for
28
+ * patterns that repeat above threshold and aren't already covered by an
29
+ * active or draft gate.
30
+ *
31
+ * Never throws — missing or malformed files yield an empty list.
32
+ *
33
+ * @param projectRoot - Project root directory
34
+ * @returns Candidates sorted by occurrence count, highest first
35
+ */
36
+ export declare function proposeGateCandidates(projectRoot: string): GateCandidate[];
37
+ /**
38
+ * Write draft gate YAML stubs for the given candidates.
39
+ * Drafts land in `.forgecraft/gates/drafts/<id>.yaml` — idempotent, never
40
+ * overwrites, never auto-activates.
41
+ *
42
+ * @param projectRoot - Project root directory
43
+ * @param candidates - Candidates from proposeGateCandidates
44
+ * @returns Relative paths of draft files written
45
+ */
46
+ export declare function writeGateDrafts(projectRoot: string, candidates: readonly GateCandidate[]): string[];
47
+ //# sourceMappingURL=gate-genesis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-genesis.d.ts","sourceRoot":"","sources":["../../src/tools/gate-genesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmBH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAAC;IAC9C,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AASD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CAO1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,SAAS,aAAa,EAAE,GACnC,MAAM,EAAE,CAoBV"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Gate genesis — propose new quality gates from observed development friction.
3
+ *
4
+ * Two signal sources:
5
+ * 1. `.forgecraft/gate-violations.jsonl` — the same hook violated repeatedly
6
+ * means the team keeps hitting a failure mode worth formalizing.
7
+ * 2. `.claude/corrections.md` — repeated AI corrections in the same category
8
+ * mean an unenforced convention; a gate makes it structural.
9
+ *
10
+ * Candidates become DRAFT YAML stubs in `.forgecraft/gates/drafts/` — never
11
+ * auto-activated (human judgment). When the dev fills in `evidence` and sets
12
+ * `generalizable: true`, the existing contribute flow takes the gate to the
13
+ * public registry as a GitHub issue. This completes the community flywheel:
14
+ * violations → drafts → active gates → registry → installed in other projects.
15
+ */
16
+ import { existsSync, readFileSync, readdirSync, writeFileSync, mkdirSync, } from "fs";
17
+ import { join } from "path";
18
+ import { dump as yamlDump } from "js-yaml";
19
+ /** Minimum repeats before a violation pattern becomes a candidate. */
20
+ const VIOLATION_THRESHOLD = 3;
21
+ /** Minimum repeats before a correction category becomes a candidate. */
22
+ const CORRECTION_THRESHOLD = 2;
23
+ /** Max sample messages carried into the draft for context. */
24
+ const MAX_EXAMPLES = 3;
25
+ /**
26
+ * Scan violation log + corrections log and return gate candidates for
27
+ * patterns that repeat above threshold and aren't already covered by an
28
+ * active or draft gate.
29
+ *
30
+ * Never throws — missing or malformed files yield an empty list.
31
+ *
32
+ * @param projectRoot - Project root directory
33
+ * @returns Candidates sorted by occurrence count, highest first
34
+ */
35
+ export function proposeGateCandidates(projectRoot) {
36
+ const covered = collectCoveredPatterns(projectRoot);
37
+ const candidates = [
38
+ ...candidatesFromViolations(projectRoot, covered),
39
+ ...candidatesFromCorrections(projectRoot, covered),
40
+ ];
41
+ return candidates.sort((a, b) => b.occurrences - a.occurrences);
42
+ }
43
+ /**
44
+ * Write draft gate YAML stubs for the given candidates.
45
+ * Drafts land in `.forgecraft/gates/drafts/<id>.yaml` — idempotent, never
46
+ * overwrites, never auto-activates.
47
+ *
48
+ * @param projectRoot - Project root directory
49
+ * @param candidates - Candidates from proposeGateCandidates
50
+ * @returns Relative paths of draft files written
51
+ */
52
+ export function writeGateDrafts(projectRoot, candidates) {
53
+ const written = [];
54
+ if (candidates.length === 0)
55
+ return written;
56
+ const draftsDir = join(projectRoot, ".forgecraft", "gates", "drafts");
57
+ for (const candidate of candidates) {
58
+ const filePath = join(draftsDir, `${candidate.id}.yaml`);
59
+ if (existsSync(filePath))
60
+ continue;
61
+ try {
62
+ mkdirSync(draftsDir, { recursive: true });
63
+ writeFileSync(filePath, buildDraftYaml(candidate), "utf-8");
64
+ written.push(`.forgecraft/gates/drafts/${candidate.id}.yaml`);
65
+ }
66
+ catch {
67
+ // Single draft failure is non-fatal
68
+ }
69
+ }
70
+ return written;
71
+ }
72
+ // ── Signal extraction ─────────────────────────────────────────────────
73
+ function candidatesFromViolations(projectRoot, covered) {
74
+ const filePath = join(projectRoot, ".forgecraft", "gate-violations.jsonl");
75
+ if (!existsSync(filePath))
76
+ return [];
77
+ const byHook = new Map();
78
+ try {
79
+ for (const line of readFileSync(filePath, "utf-8").split("\n")) {
80
+ const trimmed = line.trim();
81
+ if (!trimmed)
82
+ continue;
83
+ let entry;
84
+ try {
85
+ entry = JSON.parse(trimmed);
86
+ }
87
+ catch {
88
+ continue; // skip malformed lines
89
+ }
90
+ if (!entry.hook)
91
+ continue;
92
+ const messages = byHook.get(entry.hook) ?? [];
93
+ messages.push(entry.message ?? "");
94
+ byHook.set(entry.hook, messages);
95
+ }
96
+ }
97
+ catch {
98
+ return [];
99
+ }
100
+ const candidates = [];
101
+ for (const [hook, messages] of byHook) {
102
+ if (messages.length < VIOLATION_THRESHOLD)
103
+ continue;
104
+ const pattern = normalizePattern(hook);
105
+ if (covered.has(pattern))
106
+ continue;
107
+ candidates.push({
108
+ id: `auto-gate-${pattern}`,
109
+ source: "violations",
110
+ pattern: hook,
111
+ occurrences: messages.length,
112
+ examples: dedupe(messages).slice(0, MAX_EXAMPLES),
113
+ });
114
+ }
115
+ return candidates;
116
+ }
117
+ function candidatesFromCorrections(projectRoot, covered) {
118
+ const filePath = join(projectRoot, ".claude", "corrections.md");
119
+ if (!existsSync(filePath))
120
+ return [];
121
+ // Entry format: YYYY-MM-DD | [category] description
122
+ const entryPattern = /^\d{4}-\d{2}-\d{2}\s*\|\s*\[([^\]]+)\]\s*(.+)$/;
123
+ const byCategory = new Map();
124
+ try {
125
+ let inComment = false;
126
+ for (const line of readFileSync(filePath, "utf-8").split("\n")) {
127
+ // Skip the commented-out examples in the stub
128
+ if (line.includes("<!--"))
129
+ inComment = true;
130
+ if (inComment) {
131
+ if (line.includes("-->"))
132
+ inComment = false;
133
+ continue;
134
+ }
135
+ const match = entryPattern.exec(line.trim());
136
+ if (!match)
137
+ continue;
138
+ const category = match[1].trim().toLowerCase();
139
+ const entries = byCategory.get(category) ?? [];
140
+ entries.push(match[2].trim());
141
+ byCategory.set(category, entries);
142
+ }
143
+ }
144
+ catch {
145
+ return [];
146
+ }
147
+ const candidates = [];
148
+ for (const [category, entries] of byCategory) {
149
+ if (entries.length < CORRECTION_THRESHOLD)
150
+ continue;
151
+ const pattern = normalizePattern(category);
152
+ if (covered.has(pattern))
153
+ continue;
154
+ candidates.push({
155
+ id: `auto-gate-${pattern}`,
156
+ source: "corrections",
157
+ pattern: category,
158
+ occurrences: entries.length,
159
+ examples: dedupe(entries).slice(0, MAX_EXAMPLES),
160
+ });
161
+ }
162
+ return candidates;
163
+ }
164
+ // ── Coverage check ────────────────────────────────────────────────────
165
+ /**
166
+ * Patterns already covered by an active or draft gate — don't re-propose.
167
+ * A gate covers a pattern when its id or hook field contains the normalized
168
+ * pattern string.
169
+ */
170
+ function collectCoveredPatterns(projectRoot) {
171
+ const covered = new Set();
172
+ for (const subdir of ["active", "drafts"]) {
173
+ const dir = join(projectRoot, ".forgecraft", "gates", subdir);
174
+ if (!existsSync(dir))
175
+ continue;
176
+ try {
177
+ for (const file of readdirSync(dir)) {
178
+ if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
179
+ continue;
180
+ // Gate id from filename: auto-gate-<pattern>.yaml or <pattern>.yaml
181
+ const base = file.replace(/\.(yaml|yml)$/, "");
182
+ covered.add(normalizePattern(base.replace(/^auto-gate-/, "")));
183
+ covered.add(normalizePattern(base));
184
+ }
185
+ }
186
+ catch {
187
+ // Unreadable dir — treat as no coverage
188
+ }
189
+ }
190
+ return covered;
191
+ }
192
+ // ── Draft rendering ───────────────────────────────────────────────────
193
+ function buildDraftYaml(candidate) {
194
+ const header = [
195
+ `# DRAFT gate — generated by gate genesis from repeated ${candidate.source}.`,
196
+ `# Pattern "${candidate.pattern}" occurred ${candidate.occurrences} times.`,
197
+ `#`,
198
+ `# To activate: fill in the FILL fields, move this file to`,
199
+ `# .forgecraft/gates/active/, and set generalizable: true if the gate`,
200
+ `# would help other projects (close_cycle will then propose it to the`,
201
+ `# community registry as a GitHub issue).`,
202
+ ``,
203
+ ].join("\n");
204
+ const body = yamlDump({
205
+ id: candidate.id,
206
+ title: `<FILL: human-readable title for the ${candidate.pattern} gate>`,
207
+ description: `Formalizes a repeated ${candidate.source === "violations" ? "hook violation" : "AI correction"}: ${candidate.pattern}`,
208
+ domain: "<FILL: security | test-quality | api-contract | environment-hygiene | other>",
209
+ gsProperty: "defended",
210
+ phase: "development",
211
+ hook: candidate.source === "violations" ? candidate.pattern : "pre-commit",
212
+ check: "<FILL: executable step-by-step check — no interpretation required>",
213
+ passCriterion: "<FILL: binary pass statement>",
214
+ implementation: "logic",
215
+ source: "project",
216
+ status: "draft",
217
+ // Provenance: "genesis" = the system detected the need from repeated
218
+ // friction. AI/dev-created gates use "organic" (see Gate Awareness in
219
+ // .claude/lifecycle.md). Tracked so the registry can distinguish gates
220
+ // born from observed failure vs. proactive judgment.
221
+ origin: "genesis",
222
+ detectedFrom: candidate.source,
223
+ generalizable: false,
224
+ evidence: `Observed ${candidate.occurrences}x in this project. Examples: ${candidate.examples.join(" | ")}`,
225
+ observedExamples: [...candidate.examples],
226
+ }, { lineWidth: 100, noRefs: true });
227
+ return header + body;
228
+ }
229
+ // ── Utilities ─────────────────────────────────────────────────────────
230
+ function normalizePattern(raw) {
231
+ return raw
232
+ .toLowerCase()
233
+ .replace(/^pre-commit-|^pre-push-|^post-commit-/, "")
234
+ .replace(/\.sh$/, "")
235
+ .replace(/[^a-z0-9]+/g, "-")
236
+ .replace(/^-+|-+$/g, "");
237
+ }
238
+ function dedupe(items) {
239
+ return [...new Set(items.filter((m) => m.trim()))];
240
+ }
241
+ //# sourceMappingURL=gate-genesis.js.map