@vijaypjavvadi/bdd2pw 1.1.6 → 2.0.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.
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ /**
3
+ * Anthropic-backed LLMClient.
4
+ *
5
+ * Flow per generateBinding():
6
+ * 1. Cache lookup — if hit, return immediately, no provider call.
7
+ * 2. Build prompt (system + user) via `src/llm/prompt.ts`.
8
+ * 3. Sanitise user prompt via the governance sidecar (kind="code").
9
+ * Fail-closed if the sidecar is unreachable.
10
+ * 4. Call Anthropic API with temperature=0, JSON response, the model
11
+ * from options (default claude-sonnet-4-6).
12
+ * 5. Parse the response as JSON. Validate it as a StepBinding
13
+ * (echoes step text, has at most one of pomCall/assertion/customBody).
14
+ * 6. Cache the result, return.
15
+ *
16
+ * Soft-fail: any error in steps 3–5 returns `{ error: "<reason>" }`. The
17
+ * caller (matchStep wrapper) falls through to the existing TODO + warning
18
+ * binding. The scaffold still completes; just the affected step lands as
19
+ * a TODO instead of LLM-generated code.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.AnthropicLLMClient = void 0;
23
+ exports.parseBindingJson = parseBindingJson;
24
+ const prompt_1 = require("./prompt");
25
+ const governanceClient_1 = require("./governanceClient");
26
+ const cache_1 = require("./cache");
27
+ const DEFAULT_MODEL = "claude-sonnet-4-6";
28
+ const DEFAULT_GOVERNANCE_URL = "http://localhost:4900";
29
+ const DEFAULT_MAX_CALLS = 50;
30
+ class AnthropicLLMClient {
31
+ constructor(opts, cachePathDefault) {
32
+ this.cache = null;
33
+ this.callsCounter = 0;
34
+ this.anthropic = null; // lazy-loaded SDK instance
35
+ this.model = opts.model ?? DEFAULT_MODEL;
36
+ this.apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
37
+ this.maxCalls = opts.maxCalls ?? DEFAULT_MAX_CALLS;
38
+ this.skipGovernance = opts.skipGovernance ?? false;
39
+ this.log = opts.log ?? (() => { });
40
+ this.governance = new governanceClient_1.GovernanceClient(opts.governanceUrl ?? DEFAULT_GOVERNANCE_URL);
41
+ this.cachePath = opts.cachePath ?? cachePathDefault;
42
+ }
43
+ async ensureCache() {
44
+ if (!this.cache) {
45
+ this.cache = await (0, cache_1.openSqliteCache)(this.cachePath);
46
+ }
47
+ return this.cache;
48
+ }
49
+ budgetExhausted() {
50
+ return this.callsCounter >= this.maxCalls;
51
+ }
52
+ callsMade() {
53
+ return this.callsCounter;
54
+ }
55
+ async generateBinding(input) {
56
+ const start = Date.now();
57
+ const key = (0, prompt_1.cacheKey)(input, this.model);
58
+ const cache = await this.ensureCache();
59
+ // 1) Cache lookup
60
+ const hit = await cache.get(key);
61
+ if (hit) {
62
+ this.log({ kind: "cache_hit", key });
63
+ return {
64
+ binding: hit.binding,
65
+ fromCache: true,
66
+ model: hit.model,
67
+ latencyMs: Date.now() - start,
68
+ };
69
+ }
70
+ this.log({ kind: "cache_miss", key });
71
+ // Budget check — refuse if exhausted (caller will fall back to TODO).
72
+ if (this.budgetExhausted()) {
73
+ return {
74
+ error: `LLM budget exhausted (${this.callsCounter}/${this.maxCalls} calls). Increase via --llm-max-calls.`,
75
+ fromCache: false,
76
+ };
77
+ }
78
+ // 2) Build prompt
79
+ const userPrompt = (0, prompt_1.buildUserPrompt)(input);
80
+ // 3) Sanitise via governance sidecar (unless skipped for tests).
81
+ let sanitisedUserPrompt = userPrompt;
82
+ if (!this.skipGovernance) {
83
+ try {
84
+ this.log({ kind: "sanitise_start", bytes: userPrompt.length });
85
+ const result = await this.governance.sanitiseCode(userPrompt);
86
+ sanitisedUserPrompt = result.sanitised;
87
+ this.log({
88
+ kind: "sanitise_done",
89
+ bytes: sanitisedUserPrompt.length,
90
+ findings: result.findings.length,
91
+ });
92
+ }
93
+ catch (err) {
94
+ const isUnreachable = err instanceof governanceClient_1.GovernanceUnreachableError;
95
+ const message = err instanceof Error ? err.message : String(err);
96
+ this.log({
97
+ kind: "error",
98
+ phase: "governance",
99
+ message,
100
+ });
101
+ return {
102
+ error: isUnreachable
103
+ ? `Governance sidecar unreachable; refusing to call LLM (fail-closed). ${message}`
104
+ : `Governance sanitise failed: ${message}`,
105
+ fromCache: false,
106
+ };
107
+ }
108
+ }
109
+ // 4) Anthropic call
110
+ if (!this.apiKey) {
111
+ return {
112
+ error: "ANTHROPIC_API_KEY is not set; pass apiKey or set the env var.",
113
+ fromCache: false,
114
+ };
115
+ }
116
+ const anthropic = await this.lazyClient();
117
+ if (!anthropic) {
118
+ return {
119
+ error: "@anthropic-ai/sdk not installed. Run: npm install @anthropic-ai/sdk",
120
+ fromCache: false,
121
+ };
122
+ }
123
+ let responseText = "";
124
+ let inputTokens = 0;
125
+ let outputTokens = 0;
126
+ try {
127
+ this.log({
128
+ kind: "provider_call_start",
129
+ model: this.model,
130
+ promptBytes: sanitisedUserPrompt.length,
131
+ });
132
+ const callStart = Date.now();
133
+ const resp = await anthropic.messages.create({
134
+ model: this.model,
135
+ max_tokens: 1024,
136
+ temperature: 0,
137
+ system: prompt_1.SYSTEM_PROMPT,
138
+ messages: [{ role: "user", content: sanitisedUserPrompt }],
139
+ });
140
+ this.callsCounter += 1;
141
+ const callLatency = Date.now() - callStart;
142
+ // The SDK returns content as an array of blocks; first block is text.
143
+ const firstBlock = (resp.content ?? [])[0];
144
+ if (firstBlock && firstBlock.type === "text") {
145
+ responseText = firstBlock.text;
146
+ }
147
+ inputTokens = resp.usage?.input_tokens ?? 0;
148
+ outputTokens = resp.usage?.output_tokens ?? 0;
149
+ this.log({
150
+ kind: "provider_call_done",
151
+ model: this.model,
152
+ latencyMs: callLatency,
153
+ inputTokens,
154
+ outputTokens,
155
+ });
156
+ }
157
+ catch (err) {
158
+ const message = err instanceof Error ? err.message : String(err);
159
+ this.log({ kind: "error", phase: "anthropic", message });
160
+ return {
161
+ error: `Anthropic API call failed: ${message}`,
162
+ fromCache: false,
163
+ };
164
+ }
165
+ // 5) Parse + validate
166
+ const binding = parseBindingJson(responseText, input);
167
+ if (!binding) {
168
+ this.log({
169
+ kind: "error",
170
+ phase: "parse",
171
+ message: `Could not parse JSON binding from LLM output: ${responseText.slice(0, 200)}`,
172
+ });
173
+ return {
174
+ error: `Could not parse JSON binding from LLM output (first 200 chars): ${responseText.slice(0, 200)}`,
175
+ fromCache: false,
176
+ };
177
+ }
178
+ this.log({ kind: "binding_parsed", binding });
179
+ // 6) Cache + return
180
+ await cache.set(key, {
181
+ binding,
182
+ model: this.model,
183
+ createdAt: new Date().toISOString(),
184
+ });
185
+ return {
186
+ binding,
187
+ fromCache: false,
188
+ model: this.model,
189
+ latencyMs: Date.now() - start,
190
+ };
191
+ }
192
+ async lazyClient() {
193
+ if (this.anthropic)
194
+ return this.anthropic;
195
+ try {
196
+ // @anthropic-ai/sdk is in optionalDependencies. require() defensively.
197
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
198
+ const mod = require("@anthropic-ai/sdk");
199
+ const Anthropic = mod.Anthropic ?? mod.default ?? mod;
200
+ this.anthropic = new Anthropic({ apiKey: this.apiKey });
201
+ return this.anthropic;
202
+ }
203
+ catch {
204
+ return null;
205
+ }
206
+ }
207
+ async close() {
208
+ if (this.cache) {
209
+ await this.cache.close().catch(() => undefined);
210
+ this.cache = null;
211
+ }
212
+ }
213
+ }
214
+ exports.AnthropicLLMClient = AnthropicLLMClient;
215
+ /**
216
+ * Parse the LLM's text response as JSON and validate it has the expected
217
+ * StepBinding shape. Returns undefined on any failure (caller soft-fails).
218
+ *
219
+ * The LLM occasionally wraps JSON in ```json ... ``` fences despite the
220
+ * system prompt — strip those before parsing.
221
+ */
222
+ function parseBindingJson(text, input) {
223
+ let trimmed = text.trim();
224
+ // Strip ```json ... ``` fences if present.
225
+ const fenceMatch = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/);
226
+ if (fenceMatch)
227
+ trimmed = fenceMatch[1].trim();
228
+ let parsed;
229
+ try {
230
+ parsed = JSON.parse(trimmed);
231
+ }
232
+ catch {
233
+ return undefined;
234
+ }
235
+ if (!parsed || typeof parsed !== "object")
236
+ return undefined;
237
+ // Echo the step from the input — the LLM's "step" field is sometimes
238
+ // slightly different (it normalises whitespace, capitalises, etc.). Use
239
+ // ours so downstream comments stay consistent.
240
+ const out = {
241
+ step: { ...input.step },
242
+ };
243
+ if (parsed.pomCall && typeof parsed.pomCall === "object") {
244
+ const pc = parsed.pomCall;
245
+ if (typeof pc.page === "string" && typeof pc.method === "string") {
246
+ out.pomCall = {
247
+ page: pc.page,
248
+ method: pc.method,
249
+ args: Array.isArray(pc.args) ? pc.args.map(String) : [],
250
+ };
251
+ }
252
+ }
253
+ if (parsed.assertion && typeof parsed.assertion === "object") {
254
+ const a = parsed.assertion;
255
+ if (typeof a.locator === "string" && typeof a.matcher === "string") {
256
+ out.assertion = {
257
+ locator: a.locator,
258
+ matcher: a.matcher,
259
+ expected: typeof a.expected === "string" ? a.expected : undefined,
260
+ };
261
+ }
262
+ }
263
+ if (typeof parsed.customBody === "string") {
264
+ out.customBody = parsed.customBody;
265
+ }
266
+ if (typeof parsed.warning === "string") {
267
+ out.warning = parsed.warning;
268
+ }
269
+ // At least one of the four must be set; otherwise the LLM produced an
270
+ // empty binding which we reject.
271
+ if (!out.pomCall &&
272
+ !out.assertion &&
273
+ !out.customBody &&
274
+ !out.warning) {
275
+ return undefined;
276
+ }
277
+ return out;
278
+ }
279
+ //# sourceMappingURL=anthropicClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropicClient.js","sourceRoot":"","sources":["../../src/llm/anthropicClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * SQLite-backed cache for LLM-generated step bindings.
3
+ *
4
+ * Why SQLite (not JSON file): better-sqlite3 already an optional dep,
5
+ * cheap concurrent reads, single-file, plays nicely with the .gitignore
6
+ * we already have for `.bdd2pw/`.
7
+ *
8
+ * Schema:
9
+ * llm_cache(
10
+ * key TEXT PRIMARY KEY, -- hash(model + step text + POM signature)
11
+ * value TEXT, -- JSON-stringified StepBinding
12
+ * model TEXT, -- LLM model identifier (audit only)
13
+ * created_at TEXT -- ISO-8601 timestamp
14
+ * )
15
+ *
16
+ * Cache invalidation: keys include the model name, so swapping models
17
+ * (e.g. claude-sonnet-4-6 → claude-opus-4-6) invalidates old entries
18
+ * automatically. To force a full reset, delete the file.
19
+ */
20
+ import type { StepBinding } from "../types";
21
+ export interface CacheEntry {
22
+ binding: StepBinding;
23
+ model: string;
24
+ createdAt: string;
25
+ }
26
+ export interface BindingCache {
27
+ get(key: string): Promise<CacheEntry | undefined>;
28
+ set(key: string, value: CacheEntry): Promise<void>;
29
+ size(): Promise<number>;
30
+ close(): Promise<void>;
31
+ }
32
+ /**
33
+ * In-memory cache — used when SQLite isn't available (better-sqlite3
34
+ * not installed) or when the caller passes :memory: as the path. Tests
35
+ * use this exclusively to avoid filesystem I/O.
36
+ */
37
+ export declare class InMemoryCache implements BindingCache {
38
+ private store;
39
+ get(key: string): Promise<CacheEntry | undefined>;
40
+ set(key: string, value: CacheEntry): Promise<void>;
41
+ size(): Promise<number>;
42
+ close(): Promise<void>;
43
+ }
44
+ /**
45
+ * Open a SQLite-backed cache at the given path. better-sqlite3 is an
46
+ * optional dep; if it's not installed (or load fails), fall back to an
47
+ * in-memory cache and warn. The caller can detect the fallback by checking
48
+ * if `cache instanceof InMemoryCache` (or just observe that bindings
49
+ * aren't reused across runs).
50
+ */
51
+ export declare function openSqliteCache(cachePath: string): Promise<BindingCache>;
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ /**
3
+ * SQLite-backed cache for LLM-generated step bindings.
4
+ *
5
+ * Why SQLite (not JSON file): better-sqlite3 already an optional dep,
6
+ * cheap concurrent reads, single-file, plays nicely with the .gitignore
7
+ * we already have for `.bdd2pw/`.
8
+ *
9
+ * Schema:
10
+ * llm_cache(
11
+ * key TEXT PRIMARY KEY, -- hash(model + step text + POM signature)
12
+ * value TEXT, -- JSON-stringified StepBinding
13
+ * model TEXT, -- LLM model identifier (audit only)
14
+ * created_at TEXT -- ISO-8601 timestamp
15
+ * )
16
+ *
17
+ * Cache invalidation: keys include the model name, so swapping models
18
+ * (e.g. claude-sonnet-4-6 → claude-opus-4-6) invalidates old entries
19
+ * automatically. To force a full reset, delete the file.
20
+ */
21
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ var desc = Object.getOwnPropertyDescriptor(m, k);
24
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
25
+ desc = { enumerable: true, get: function() { return m[k]; } };
26
+ }
27
+ Object.defineProperty(o, k2, desc);
28
+ }) : (function(o, m, k, k2) {
29
+ if (k2 === undefined) k2 = k;
30
+ o[k2] = m[k];
31
+ }));
32
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
33
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
34
+ }) : function(o, v) {
35
+ o["default"] = v;
36
+ });
37
+ var __importStar = (this && this.__importStar) || (function () {
38
+ var ownKeys = function(o) {
39
+ ownKeys = Object.getOwnPropertyNames || function (o) {
40
+ var ar = [];
41
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
42
+ return ar;
43
+ };
44
+ return ownKeys(o);
45
+ };
46
+ return function (mod) {
47
+ if (mod && mod.__esModule) return mod;
48
+ var result = {};
49
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
50
+ __setModuleDefault(result, mod);
51
+ return result;
52
+ };
53
+ })();
54
+ Object.defineProperty(exports, "__esModule", { value: true });
55
+ exports.InMemoryCache = void 0;
56
+ exports.openSqliteCache = openSqliteCache;
57
+ const fs = __importStar(require("fs-extra"));
58
+ const path = __importStar(require("path"));
59
+ /**
60
+ * In-memory cache — used when SQLite isn't available (better-sqlite3
61
+ * not installed) or when the caller passes :memory: as the path. Tests
62
+ * use this exclusively to avoid filesystem I/O.
63
+ */
64
+ class InMemoryCache {
65
+ constructor() {
66
+ this.store = new Map();
67
+ }
68
+ async get(key) {
69
+ return this.store.get(key);
70
+ }
71
+ async set(key, value) {
72
+ this.store.set(key, value);
73
+ }
74
+ async size() {
75
+ return this.store.size;
76
+ }
77
+ async close() {
78
+ /* nothing to close */
79
+ }
80
+ }
81
+ exports.InMemoryCache = InMemoryCache;
82
+ /**
83
+ * Open a SQLite-backed cache at the given path. better-sqlite3 is an
84
+ * optional dep; if it's not installed (or load fails), fall back to an
85
+ * in-memory cache and warn. The caller can detect the fallback by checking
86
+ * if `cache instanceof InMemoryCache` (or just observe that bindings
87
+ * aren't reused across runs).
88
+ */
89
+ async function openSqliteCache(cachePath) {
90
+ // Special case: ":memory:" → always in-memory, no disk.
91
+ if (cachePath === ":memory:") {
92
+ return new InMemoryCache();
93
+ }
94
+ let sqlite;
95
+ try {
96
+ // better-sqlite3 is in optionalDependencies. require() so a missing
97
+ // module doesn't break import-time of this file.
98
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
99
+ sqlite = require("better-sqlite3");
100
+ }
101
+ catch {
102
+ // Fall back to in-memory if the optional dep isn't installed. This
103
+ // means LLM bindings won't persist across runs — every call hits the
104
+ // provider — but the scaffolder still works.
105
+ return new InMemoryCache();
106
+ }
107
+ await fs.ensureDir(path.dirname(cachePath));
108
+ const db = sqlite(cachePath);
109
+ db.pragma("journal_mode = WAL");
110
+ db.exec(`
111
+ CREATE TABLE IF NOT EXISTS llm_cache (
112
+ key TEXT PRIMARY KEY,
113
+ value TEXT NOT NULL,
114
+ model TEXT NOT NULL,
115
+ created_at TEXT NOT NULL
116
+ )
117
+ `);
118
+ const getStmt = db.prepare("SELECT value, model, created_at FROM llm_cache WHERE key = ?");
119
+ const setStmt = db.prepare("INSERT OR REPLACE INTO llm_cache (key, value, model, created_at) VALUES (?, ?, ?, ?)");
120
+ const sizeStmt = db.prepare("SELECT COUNT(*) AS n FROM llm_cache");
121
+ return {
122
+ async get(key) {
123
+ const row = getStmt.get(key);
124
+ if (!row)
125
+ return undefined;
126
+ try {
127
+ return {
128
+ binding: JSON.parse(row.value),
129
+ model: row.model,
130
+ createdAt: row.created_at,
131
+ };
132
+ }
133
+ catch {
134
+ // Corrupted row — pretend it doesn't exist.
135
+ return undefined;
136
+ }
137
+ },
138
+ async set(key, entry) {
139
+ setStmt.run(key, JSON.stringify(entry.binding), entry.model, entry.createdAt);
140
+ },
141
+ async size() {
142
+ const row = sizeStmt.get();
143
+ return row.n;
144
+ },
145
+ async close() {
146
+ db.close();
147
+ },
148
+ };
149
+ }
150
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/llm/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Append every successful LLM-generated binding to
3
+ * `<repo>/artefacts/candidate-rules.jsonl`. The offline review pipeline
4
+ * reads this file to propose new deterministic rules — auto-write back
5
+ * into stepMatcher.ts is deferred to v2.1 (see docs/SCOPE.md §17).
6
+ *
7
+ * Why JSONL not a single JSON array: append-only writes are cheaper and
8
+ * safe under concurrent scaffold runs. Newline-delimited JSON also plays
9
+ * well with `jq`, `wc -l`, etc.
10
+ *
11
+ * Why `artefacts/` not `.bdd2pw/`: candidate rules are CONTENT users may
12
+ * commit to source control (the offline pipeline lives in their repo
13
+ * too). `.bdd2pw/` is for pure runtime cache (gitignored). We already
14
+ * use `artefacts/` for heal-events.jsonl from v1.1's self-healing
15
+ * scaffold, so the convention is established.
16
+ */
17
+ import type { CandidateRuleEntry } from "./types";
18
+ export declare class CandidateRulesWriter {
19
+ private filePath;
20
+ private initialised;
21
+ constructor(repoRoot: string, filename?: string);
22
+ /**
23
+ * Append one entry. Best-effort: if the directory can't be created or
24
+ * the file can't be written, swallow — generation already succeeded;
25
+ * we don't want to break the build for a logging failure.
26
+ */
27
+ append(entry: CandidateRuleEntry): Promise<void>;
28
+ /** For tests: return all entries written so far. */
29
+ readAll(): Promise<CandidateRuleEntry[]>;
30
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /**
3
+ * Append every successful LLM-generated binding to
4
+ * `<repo>/artefacts/candidate-rules.jsonl`. The offline review pipeline
5
+ * reads this file to propose new deterministic rules — auto-write back
6
+ * into stepMatcher.ts is deferred to v2.1 (see docs/SCOPE.md §17).
7
+ *
8
+ * Why JSONL not a single JSON array: append-only writes are cheaper and
9
+ * safe under concurrent scaffold runs. Newline-delimited JSON also plays
10
+ * well with `jq`, `wc -l`, etc.
11
+ *
12
+ * Why `artefacts/` not `.bdd2pw/`: candidate rules are CONTENT users may
13
+ * commit to source control (the offline pipeline lives in their repo
14
+ * too). `.bdd2pw/` is for pure runtime cache (gitignored). We already
15
+ * use `artefacts/` for heal-events.jsonl from v1.1's self-healing
16
+ * scaffold, so the convention is established.
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.CandidateRulesWriter = void 0;
53
+ const fs = __importStar(require("fs-extra"));
54
+ const path = __importStar(require("path"));
55
+ class CandidateRulesWriter {
56
+ constructor(repoRoot, filename = "candidate-rules.jsonl") {
57
+ this.initialised = false;
58
+ this.filePath = path.join(repoRoot, "artefacts", filename);
59
+ }
60
+ /**
61
+ * Append one entry. Best-effort: if the directory can't be created or
62
+ * the file can't be written, swallow — generation already succeeded;
63
+ * we don't want to break the build for a logging failure.
64
+ */
65
+ async append(entry) {
66
+ try {
67
+ if (!this.initialised) {
68
+ await fs.ensureDir(path.dirname(this.filePath));
69
+ this.initialised = true;
70
+ }
71
+ await fs.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
72
+ }
73
+ catch {
74
+ /* best-effort */
75
+ }
76
+ }
77
+ /** For tests: return all entries written so far. */
78
+ async readAll() {
79
+ if (!(await fs.pathExists(this.filePath)))
80
+ return [];
81
+ const raw = await fs.readFile(this.filePath, "utf8");
82
+ return raw
83
+ .split("\n")
84
+ .filter((l) => l.trim())
85
+ .map((l) => JSON.parse(l));
86
+ }
87
+ }
88
+ exports.CandidateRulesWriter = CandidateRulesWriter;
89
+ //# sourceMappingURL=candidateRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidateRules.js","sourceRoot":"","sources":["../../src/llm/candidateRules.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,6CAA+B;AAC/B,2CAA6B;AAG7B,MAAa,oBAAoB;IAI/B,YAAY,QAAgB,EAAE,QAAQ,GAAG,uBAAuB;QAFxD,gBAAW,GAAG,KAAK,CAAC;QAG1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,KAAyB;QACpC,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAChD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YAC1B,CAAC;YACD,MAAM,EAAE,CAAC,UAAU,CACjB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAC5B,MAAM,CACP,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACrD,OAAO,GAAG;aACP,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAuB,CAAC,CAAC;IACrD,CAAC;CACF;AAtCD,oDAsCC"}