@vijaypjavvadi/bdd2pw 1.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +308 -0
  2. package/LICENSE +21 -0
  3. package/README.md +254 -0
  4. package/dist/cli.d.ts +6 -0
  5. package/dist/cli.js +176 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/discovery/mcpClient.d.ts +53 -0
  8. package/dist/discovery/mcpClient.js +326 -0
  9. package/dist/discovery/mcpClient.js.map +1 -0
  10. package/dist/discovery/snapshotParser.d.ts +13 -0
  11. package/dist/discovery/snapshotParser.js +51 -0
  12. package/dist/discovery/snapshotParser.js.map +1 -0
  13. package/dist/emitters/facade.d.ts +52 -0
  14. package/dist/emitters/facade.js +125 -0
  15. package/dist/emitters/facade.js.map +1 -0
  16. package/dist/http/artifacts.d.ts +14 -0
  17. package/dist/http/artifacts.js +36 -0
  18. package/dist/http/artifacts.js.map +1 -0
  19. package/dist/http/jobs.d.ts +26 -0
  20. package/dist/http/jobs.js +59 -0
  21. package/dist/http/jobs.js.map +1 -0
  22. package/dist/http/routes.d.ts +11 -0
  23. package/dist/http/routes.js +267 -0
  24. package/dist/http/routes.js.map +1 -0
  25. package/dist/http/schemas.d.ts +167 -0
  26. package/dist/http/schemas.js +57 -0
  27. package/dist/http/schemas.js.map +1 -0
  28. package/dist/index.d.ts +49 -0
  29. package/dist/index.js +507 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/llm/governanceClient.d.ts +24 -0
  32. package/dist/llm/governanceClient.js +22 -0
  33. package/dist/llm/governanceClient.js.map +1 -0
  34. package/dist/llm/providers/anthropic.d.ts +8 -0
  35. package/dist/llm/providers/anthropic.js +12 -0
  36. package/dist/llm/providers/anthropic.js.map +1 -0
  37. package/dist/llm/providers/gemini.d.ts +5 -0
  38. package/dist/llm/providers/gemini.js +9 -0
  39. package/dist/llm/providers/gemini.js.map +1 -0
  40. package/dist/llm/providers/openai.d.ts +5 -0
  41. package/dist/llm/providers/openai.js +9 -0
  42. package/dist/llm/providers/openai.js.map +1 -0
  43. package/dist/parser/gherkinParser.d.ts +17 -0
  44. package/dist/parser/gherkinParser.js +143 -0
  45. package/dist/parser/gherkinParser.js.map +1 -0
  46. package/dist/repo/projectScaffolder.d.ts +24 -0
  47. package/dist/repo/projectScaffolder.js +64 -0
  48. package/dist/repo/projectScaffolder.js.map +1 -0
  49. package/dist/repo/repoScanner.d.ts +21 -0
  50. package/dist/repo/repoScanner.js +132 -0
  51. package/dist/repo/repoScanner.js.map +1 -0
  52. package/dist/reports/reviewReport.d.ts +19 -0
  53. package/dist/reports/reviewReport.js +96 -0
  54. package/dist/reports/reviewReport.js.map +1 -0
  55. package/dist/server.d.ts +10 -0
  56. package/dist/server.js +40 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/transformers/locatorPicker.d.ts +40 -0
  59. package/dist/transformers/locatorPicker.js +283 -0
  60. package/dist/transformers/locatorPicker.js.map +1 -0
  61. package/dist/transformers/pomResolver.d.ts +28 -0
  62. package/dist/transformers/pomResolver.js +35 -0
  63. package/dist/transformers/pomResolver.js.map +1 -0
  64. package/dist/transformers/stepMatcher.d.ts +36 -0
  65. package/dist/transformers/stepMatcher.js +461 -0
  66. package/dist/transformers/stepMatcher.js.map +1 -0
  67. package/dist/types.d.ts +166 -0
  68. package/dist/types.js +7 -0
  69. package/dist/types.js.map +1 -0
  70. package/dist/utils/logger.d.ts +6 -0
  71. package/dist/utils/logger.js +25 -0
  72. package/dist/utils/logger.js.map +1 -0
  73. package/dist/utils/naming.d.ts +23 -0
  74. package/dist/utils/naming.js +58 -0
  75. package/dist/utils/naming.js.map +1 -0
  76. package/dist/validate/tscRunner.d.ts +17 -0
  77. package/dist/validate/tscRunner.js +98 -0
  78. package/dist/validate/tscRunner.js.map +1 -0
  79. package/package.json +69 -0
  80. package/templates/gitignore.tmpl +10 -0
  81. package/templates/package.json.tmpl +16 -0
  82. package/templates/playwright.config.ts.tmpl +24 -0
  83. package/templates/tsconfig.json.tmpl +15 -0
package/dist/index.js ADDED
@@ -0,0 +1,507 @@
1
+ "use strict";
2
+ /**
3
+ * Public programmatic API for `@vijaypjavvadi/bdd2pw`.
4
+ *
5
+ * The CLI (`src/cli.ts`) and HTTP service (`src/server.ts`) are thin shells
6
+ * over these three functions. See docs/ARCHITECTURE.md §1.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.scaffold = scaffold;
43
+ exports.analyze = analyze;
44
+ exports.updatePom = updatePom;
45
+ const fs = __importStar(require("fs-extra"));
46
+ const path = __importStar(require("path"));
47
+ const gherkinParser_1 = require("./parser/gherkinParser");
48
+ const repoScanner_1 = require("./repo/repoScanner");
49
+ const projectScaffolder_1 = require("./repo/projectScaffolder");
50
+ const mcpClient_1 = require("./discovery/mcpClient");
51
+ const snapshotParser_1 = require("./discovery/snapshotParser");
52
+ const locatorPicker_1 = require("./transformers/locatorPicker");
53
+ const pomResolver_1 = require("./transformers/pomResolver");
54
+ const stepMatcher_1 = require("./transformers/stepMatcher");
55
+ const facade_1 = require("./emitters/facade");
56
+ const tscRunner_1 = require("./validate/tscRunner");
57
+ const reviewReport_1 = require("./reports/reviewReport");
58
+ const naming_1 = require("./utils/naming");
59
+ const pw_emit_1 = require("@vijaypjavvadi/pw-emit");
60
+ const logger_1 = require("./utils/logger");
61
+ /**
62
+ * Field names we never count as "missing" on a POM, because they're
63
+ * synthetic (provided by the Playwright test fixture or by the POM base
64
+ * class) rather than discovered locators.
65
+ */
66
+ const RESERVED_FIELD_NAMES = new Set(["page", "context", "browser"]);
67
+ class NotImplementedError extends Error {
68
+ constructor(fn, phase) {
69
+ super(`bdd2pw.${fn}() is not implemented yet — landing in ${phase}. ` +
70
+ `See docs/SCOPE.md §16 (Phasing) for the rollout plan.`);
71
+ this.name = "NotImplementedError";
72
+ }
73
+ }
74
+ /**
75
+ * Scaffold a Playwright TS test repo from a Gherkin .feature file.
76
+ *
77
+ * Pipeline (see docs/ARCHITECTURE.md §2):
78
+ * gherkin parse → repo scan → POM resolve → MCP discover →
79
+ * locator pick → step match → emit → tsc validate → review report.
80
+ *
81
+ * Phase 1a: MCP page discovery uses the file-snapshot fallback. Pass
82
+ * `opts.snapshotFile` to bypass the (not-yet-implemented) real browser
83
+ * scan. Real `@playwright/mcp` integration lands in Phase 1b.
84
+ */
85
+ async function scaffold(opts) {
86
+ const reviewItems = [];
87
+ logger_1.logger.info({ feature: opts.feature, page: opts.page, repo: opts.repo }, "scaffold start");
88
+ // 1) Parse Gherkin
89
+ const feature = await (0, gherkinParser_1.parseFeature)(opts.feature);
90
+ reviewItems.push({
91
+ severity: "info",
92
+ message: `Parsed feature "${feature.name}" — ${feature.scenarios.length} scenario(s)${feature.background ? " + Background" : ""}`,
93
+ });
94
+ // 2) Scaffold target repo if missing playwright.config.ts
95
+ const scaffoldResult = await (0, projectScaffolder_1.scaffoldProject)({
96
+ repoRoot: opts.repo,
97
+ templatesDir: opts.templates,
98
+ baseUrl: opts.url,
99
+ projectName: feature.name.toLowerCase().replace(/\s+/g, "-"),
100
+ });
101
+ reviewItems.push(...scaffoldResult.warnings);
102
+ // 3) Scan target repo for existing POMs
103
+ const repoState = await (0, repoScanner_1.scanRepo)(opts.repo);
104
+ // 4) Discover page elements
105
+ // Three modes:
106
+ // - --no-discovery → skip the scan, use empty list (rule-only probing)
107
+ // - --snapshot-file → read from disk (CI / regression test path)
108
+ // - default → real Chromium via @playwright/mcp / playwright
109
+ // Navigation errors are SOFT-FAILED — they get logged as a warning and
110
+ // we proceed with an empty element list. This way `BDD_REVIEW.md` still
111
+ // lands and rule-only steps (`I am on the page`, `should be redirected`)
112
+ // still produce useful output even when the URL isn't reachable.
113
+ let elements = [];
114
+ if (opts.noDiscovery) {
115
+ reviewItems.push({
116
+ severity: "info",
117
+ message: "Page discovery skipped (--no-discovery). Field-referencing rules will fall to TODO.",
118
+ });
119
+ }
120
+ else {
121
+ try {
122
+ const snapshot = await (0, mcpClient_1.scanPage)({
123
+ url: opts.url,
124
+ storageState: opts.storageState,
125
+ headed: opts.headed,
126
+ snapshotFile: opts.snapshotFile,
127
+ });
128
+ elements = (0, snapshotParser_1.parseSnapshot)(snapshot);
129
+ }
130
+ catch (err) {
131
+ reviewItems.push({
132
+ severity: "warn",
133
+ message: `Page discovery failed: ${err.message.split("\n")[0]}. Continuing with empty element list — POM will be created with the synthesised goto() only, and field-referencing steps will fall to TODO.`,
134
+ suggestion: "Pass --snapshot-file <path.json> to use a captured snapshot, or --no-discovery to skip discovery silently.",
135
+ });
136
+ }
137
+ }
138
+ const candidateChoices = (0, locatorPicker_1.dedupeLocators)(elements.map((e) => (0, locatorPicker_1.pickLocator)(e, elements)));
139
+ reviewItems.push({
140
+ severity: "info",
141
+ message: `Discovered ${elements.length} element(s); picked ${candidateChoices.length} unique locator(s)`,
142
+ });
143
+ // 5) Resolve POM decision
144
+ // Predict referenced fields by matching steps against a "POM with all candidates"
145
+ const pageVar = (0, naming_1.camelCase)(opts.page);
146
+ const pomFileName = (0, pw_emit_1.pageObjectFileName)(opts.page); // "LoginPage" → "login.page.ts"
147
+ const candidatePom = {
148
+ className: opts.page,
149
+ filePath: path.join(opts.repo, "pages", pomFileName),
150
+ fields: candidateChoices,
151
+ methods: [],
152
+ exists: false,
153
+ };
154
+ const provisionalBindings = [];
155
+ for (const scenario of feature.scenarios) {
156
+ for (const step of scenario.steps) {
157
+ provisionalBindings.push((0, stepMatcher_1.matchStep)(step, candidatePom, pageVar));
158
+ }
159
+ }
160
+ if (feature.background) {
161
+ for (const step of feature.background) {
162
+ provisionalBindings.push((0, stepMatcher_1.matchStep)(step, candidatePom, pageVar));
163
+ }
164
+ }
165
+ const referencedFields = new Set();
166
+ for (const b of provisionalBindings) {
167
+ if (b.pomCall) {
168
+ const m = b.pomCall.method.match(/^(\w+)\./);
169
+ if (m && !RESERVED_FIELD_NAMES.has(m[1]))
170
+ referencedFields.add(m[1]);
171
+ }
172
+ if (b.assertion) {
173
+ const m = b.assertion.locator.match(/^[a-zA-Z_$][\w$]*\.(\w+)/);
174
+ if (m && !RESERVED_FIELD_NAMES.has(m[1]))
175
+ referencedFields.add(m[1]);
176
+ }
177
+ }
178
+ const decision = (0, pomResolver_1.resolvePom)({
179
+ requestedName: opts.page,
180
+ existing: repoState.pageObjects,
181
+ referencedFields: [...referencedFields],
182
+ });
183
+ reviewItems.push({
184
+ severity: "info",
185
+ message: `POM decision for ${opts.page}: ${decision.decision}${decision.missingFields.length ? ` (missing fields: ${decision.missingFields.join(", ")})` : ""}`,
186
+ });
187
+ // 6) Build the final POM IR (existing fields + only the new ones we need)
188
+ const finalPom = buildFinalPom(decision, opts.page, candidatePom, candidateChoices);
189
+ // 6.5) Synthesise a `goto()` method so the spec's `await loginPage.goto()`
190
+ // actually navigates. Skipped if the POM already has one (e.g. on AUGMENT)
191
+ // or if no URL was provided.
192
+ if (opts.url && !finalPom.methods.some((m) => m.name === "goto")) {
193
+ finalPom.methods.push({
194
+ name: "goto",
195
+ params: [],
196
+ body: `await this.page.goto(${JSON.stringify(opts.url)});`,
197
+ origin: "generated",
198
+ });
199
+ }
200
+ // 7) Re-match steps now that the final POM is known
201
+ const finalBindingsByScenario = [];
202
+ for (const scenario of feature.scenarios) {
203
+ const bindings = scenario.steps.map((s) => (0, stepMatcher_1.matchStep)(s, finalPom, pageVar));
204
+ finalBindingsByScenario.push({ name: scenario.name, bindings });
205
+ }
206
+ const beforeEachBindings = (feature.background ?? []).map((s) => (0, stepMatcher_1.matchStep)(s, finalPom, pageVar));
207
+ // Outline scenarios — flatten Examples into one test per row
208
+ const flattened = [];
209
+ for (const scenario of feature.scenarios) {
210
+ if (scenario.examples && scenario.examples.length > 0) {
211
+ for (const row of scenario.examples) {
212
+ const expanded = scenario.steps.map((step) => {
213
+ const text = (0, gherkinParser_1.substituteOutlinePlaceholders)(step.text, row);
214
+ return (0, stepMatcher_1.matchStep)({ ...step, text }, finalPom, pageVar);
215
+ });
216
+ const labels = Object.entries(row).map(([k, v]) => `${k}=${v}`).join(", ");
217
+ flattened.push({ name: `${scenario.name} [${labels}]`, bindings: expanded });
218
+ }
219
+ }
220
+ else {
221
+ flattened.push(finalBindingsByScenario.find((s) => s.name === scenario.name));
222
+ }
223
+ }
224
+ for (const sc of flattened) {
225
+ for (const b of sc.bindings) {
226
+ if (b.warning) {
227
+ reviewItems.push({
228
+ severity: "warn",
229
+ message: `[${sc.name}] ${b.warning}`,
230
+ suggestion: "Add a custom step rule, enable --llm fallback, or hand-edit the spec.",
231
+ });
232
+ }
233
+ }
234
+ }
235
+ // Background bindings emit into beforeEach but their warnings were being
236
+ // dropped from the review report. Surface them with a [Background] tag.
237
+ for (const b of beforeEachBindings) {
238
+ if (b.warning) {
239
+ reviewItems.push({
240
+ severity: "warn",
241
+ message: `[Background] ${b.warning}`,
242
+ suggestion: "Add a custom step rule, enable --llm fallback, or hand-edit the spec.",
243
+ });
244
+ }
245
+ }
246
+ const filesWritten = [...scaffoldResult.filesWritten];
247
+ if (!opts.dryRun) {
248
+ // 8) Emit Page Object
249
+ const pomEmitMode = decision.decision === "CREATE" ? "create" : "augment";
250
+ const pomEmit = (0, facade_1.emitPageObject)({
251
+ pom: finalPom,
252
+ mode: pomEmitMode,
253
+ existing: decision.existing
254
+ ? await fs.readFile(decision.existing.filePath, "utf8").catch(() => undefined)
255
+ : undefined,
256
+ });
257
+ reviewItems.push(...pomEmit.warnings.map((w) => ({ ...w, file: finalPom.filePath })));
258
+ await fs.ensureDir(path.dirname(finalPom.filePath));
259
+ await fs.writeFile(finalPom.filePath, pomEmit.contents, "utf8");
260
+ filesWritten.push(finalPom.filePath);
261
+ // 9) Emit spec file. pageObjectFileName returns "login.page.ts"; strip
262
+ // the trailing ".ts" for both the spec file stem and the import path.
263
+ const pomStem = pomFileName.replace(/\.ts$/, ""); // "login.page"
264
+ const specStem = pomStem.replace(/\.page$/, ""); // "login"
265
+ const specPath = path.join(opts.repo, "tests", `${specStem}.spec.ts`);
266
+ const specEmit = (0, facade_1.emitTestFile)({
267
+ describeName: feature.name,
268
+ beforeEach: beforeEachBindings.length ? beforeEachBindings : undefined,
269
+ scenarios: flattened,
270
+ pomImports: [
271
+ {
272
+ className: opts.page,
273
+ fromPath: `../pages/${pomStem}`,
274
+ },
275
+ ],
276
+ });
277
+ reviewItems.push(...specEmit.warnings.map((w) => ({ ...w, file: specPath })));
278
+ await fs.ensureDir(path.dirname(specPath));
279
+ await fs.writeFile(specPath, specEmit.contents, "utf8");
280
+ filesWritten.push(specPath);
281
+ }
282
+ // 10) Validate
283
+ let tscErrorCount = 0;
284
+ if (!opts.dryRun && !opts.noValidate) {
285
+ const tscResult = await (0, tscRunner_1.tscValidate)(opts.repo);
286
+ tscErrorCount = tscResult.errorCount;
287
+ reviewItems.push(...tscResult.items);
288
+ }
289
+ // 11) Review report
290
+ const reviewReportPath = await (0, reviewReport_1.writeReviewReport)({
291
+ repoRoot: opts.repo,
292
+ items: reviewItems,
293
+ feature: opts.feature,
294
+ url: opts.url,
295
+ });
296
+ filesWritten.push(reviewReportPath);
297
+ logger_1.logger.info({ filesWritten: filesWritten.length, reviewItems: reviewItems.length, tscErrorCount }, "scaffold complete");
298
+ return { filesWritten, reviewItems, tscErrorCount, reviewReportPath };
299
+ }
300
+ /**
301
+ * Construct the final POM IR based on the resolver decision.
302
+ *
303
+ * CREATE → the candidate POM as-is
304
+ * REUSE → the existing POM as-is (no new fields)
305
+ * AUGMENT → existing fields + missing fields appended (existing kept verbatim)
306
+ */
307
+ function buildFinalPom(decision, className, candidatePom, candidateChoices) {
308
+ if (decision.decision === "CREATE" || !decision.existing) {
309
+ return { ...candidatePom, className };
310
+ }
311
+ if (decision.decision === "REUSE") {
312
+ return decision.existing;
313
+ }
314
+ // AUGMENT: existing fields + only the new ones we need
315
+ const presentNames = new Set(decision.existing.fields.map((f) => f.fieldName));
316
+ const newFields = candidateChoices.filter((c) => !presentNames.has(c.fieldName));
317
+ return {
318
+ ...decision.existing,
319
+ fields: [...decision.existing.fields, ...newFields],
320
+ };
321
+ }
322
+ /**
323
+ * Dry-run analyser. Parses the .feature, scans the URL (or snapshot file),
324
+ * picks locators, matches steps — but writes nothing.
325
+ */
326
+ async function analyze(opts) {
327
+ const feature = await (0, gherkinParser_1.parseFeature)(opts.feature);
328
+ const snapshotFile = opts.snapshotFile;
329
+ const snapshot = await (0, mcpClient_1.scanPage)({
330
+ url: opts.url,
331
+ storageState: opts.storageState,
332
+ headed: opts.headed,
333
+ snapshotFile,
334
+ });
335
+ const elements = (0, snapshotParser_1.parseSnapshot)(snapshot);
336
+ const discoveredLocators = (0, locatorPicker_1.dedupeLocators)(elements.map((e) => (0, locatorPicker_1.pickLocator)(e, elements)));
337
+ const provisionalPom = {
338
+ className: "AnalyzedPage",
339
+ filePath: "",
340
+ fields: discoveredLocators,
341
+ methods: [],
342
+ exists: false,
343
+ };
344
+ const bindings = [];
345
+ for (const scenario of feature.scenarios) {
346
+ for (const step of scenario.steps) {
347
+ bindings.push((0, stepMatcher_1.matchStep)(step, provisionalPom, "analyzedPage"));
348
+ }
349
+ }
350
+ const warnings = bindings
351
+ .filter((b) => b.warning)
352
+ .map((b) => ({ severity: "warn", message: b.warning }));
353
+ return { feature, discoveredLocators, bindings, warnings };
354
+ }
355
+ /**
356
+ * Re-scan a URL and merge any newly-discovered locators into an existing
357
+ * Page Object. **Append-only by construction:**
358
+ *
359
+ * - Never deletes any property, method, or import.
360
+ * - Never renames anything.
361
+ * - Never modifies any existing method body — hand-edits are preserved
362
+ * byte-identical.
363
+ * - Skips field-name collisions (existing field wins).
364
+ * - Adds new locator fields + their constructor assignments only.
365
+ * - Method synthesis is opt-in and deferred to v1.1.
366
+ *
367
+ * Implementation: AST surgery via `ts-morph`. We read the existing file,
368
+ * compute a diff against the freshly-scanned IR, and use `ts-morph`'s
369
+ * `addProperty` / `addStatements` APIs to splice new content into the
370
+ * existing class. Then `save()` writes back. No re-emit, no overwrite.
371
+ *
372
+ * Hard fails:
373
+ * - The POM file at `pages/<name>.page.ts` does not exist.
374
+ * - The class declared in the file doesn't match `--page <Name>`.
375
+ *
376
+ * See docs/ARCHITECTURE.md §4.
377
+ */
378
+ async function updatePom(opts) {
379
+ const reviewItems = [];
380
+ logger_1.logger.info({ page: opts.page, repo: opts.repo, url: opts.url }, "updatePom start");
381
+ // 1) Find the existing POM file.
382
+ const repoState = await (0, repoScanner_1.scanRepo)(opts.repo);
383
+ const existing = repoState.pageObjects.get(opts.page);
384
+ if (!existing) {
385
+ throw new Error(`Page Object "${opts.page}" not found in ${path.join(opts.repo, "pages")}. ` +
386
+ `Use \`bdd2pw scaffold\` to create it first.`);
387
+ }
388
+ // 2) Discover live elements.
389
+ const noDiscovery = opts.noDiscovery;
390
+ const snapshotFile = opts.snapshotFile;
391
+ let elements = [];
392
+ if (noDiscovery) {
393
+ reviewItems.push({
394
+ severity: "info",
395
+ message: "Page discovery skipped (--no-discovery). updatePom will be a no-op.",
396
+ });
397
+ }
398
+ else {
399
+ try {
400
+ const snapshot = await (0, mcpClient_1.scanPage)({
401
+ url: opts.url,
402
+ storageState: opts.storageState,
403
+ headed: opts.headed,
404
+ snapshotFile,
405
+ });
406
+ elements = (0, snapshotParser_1.parseSnapshot)(snapshot);
407
+ }
408
+ catch (err) {
409
+ reviewItems.push({
410
+ severity: "warn",
411
+ message: `Page discovery failed: ${err.message.split("\n")[0]}. updatePom is a no-op.`,
412
+ suggestion: "Pass --snapshot-file <path.json> for offline merging.",
413
+ });
414
+ }
415
+ }
416
+ const allChoices = (0, locatorPicker_1.dedupeLocators)(elements.map((e) => (0, locatorPicker_1.pickLocator)(e, elements)));
417
+ // 3) Diff against the existing POM. New = not present by fieldName.
418
+ const existingFieldNames = new Set(existing.fields.map((f) => f.fieldName));
419
+ const newChoices = allChoices.filter((c) => !existingFieldNames.has(c.fieldName));
420
+ reviewItems.push({
421
+ severity: "info",
422
+ message: `Existing fields: ${existing.fields.length}. ` +
423
+ `Discovered: ${allChoices.length}. ` +
424
+ `New (to append): ${newChoices.length}. ` +
425
+ `Skipped collisions: ${allChoices.length - newChoices.length}.`,
426
+ });
427
+ // 4) If nothing new, no-op.
428
+ if (newChoices.length === 0) {
429
+ const reviewReportPath = await (0, reviewReport_1.writeReviewReport)({
430
+ repoRoot: opts.repo,
431
+ items: reviewItems,
432
+ feature: "(updatePom — no feature file)",
433
+ url: opts.url,
434
+ });
435
+ logger_1.logger.info({ reviewReportPath }, "updatePom complete (no-op)");
436
+ return {
437
+ added: { fields: 0, methods: 0 },
438
+ preserved: {
439
+ fields: existing.fields.length,
440
+ methods: existing.methods.length,
441
+ },
442
+ filePath: existing.filePath,
443
+ reviewItems,
444
+ };
445
+ }
446
+ // 5) AST surgery — append new properties + constructor lines.
447
+ // Using ts-morph against the same file the repoScanner already loaded
448
+ // would re-parse, but the API surface is fluent so this is fine.
449
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
450
+ const { Project } = require("ts-morph");
451
+ const project = new Project({
452
+ skipAddingFilesFromTsConfig: true,
453
+ compilerOptions: { allowJs: false, noEmit: true, target: 99 },
454
+ });
455
+ const sourceFile = project.addSourceFileAtPath(existing.filePath);
456
+ const cls = sourceFile.getClass(opts.page);
457
+ if (!cls) {
458
+ throw new Error(`File ${existing.filePath} exists but does not declare class "${opts.page}". ` +
459
+ `Found classes: ${sourceFile
460
+ .getClasses()
461
+ .map((c) => c.getName() ?? "(anonymous)")
462
+ .join(", ") || "(none)"}.`);
463
+ }
464
+ // Append a new readonly Locator property per new choice.
465
+ for (const choice of newChoices) {
466
+ cls.addProperty({
467
+ name: choice.fieldName,
468
+ type: "Locator",
469
+ isReadonly: true,
470
+ });
471
+ }
472
+ // Append a constructor assignment per new choice.
473
+ const ctor = cls.getConstructors()[0];
474
+ if (ctor) {
475
+ for (const choice of newChoices) {
476
+ const expr = (0, pw_emit_1.renderLocatorExpr)(choice);
477
+ ctor.addStatements(`this.${choice.fieldName} = ${expr};`);
478
+ }
479
+ }
480
+ else {
481
+ reviewItems.push({
482
+ severity: "warn",
483
+ message: `Class "${opts.page}" has no constructor. New properties were declared ` +
484
+ `but their initialisers were skipped. Add the constructor manually.`,
485
+ });
486
+ }
487
+ await sourceFile.save();
488
+ logger_1.logger.info({ filePath: existing.filePath, added: newChoices.length }, "updatePom: AST surgery complete");
489
+ // 6) Review report.
490
+ const reviewReportPath = await (0, reviewReport_1.writeReviewReport)({
491
+ repoRoot: opts.repo,
492
+ items: reviewItems,
493
+ feature: "(updatePom — no feature file)",
494
+ url: opts.url,
495
+ });
496
+ logger_1.logger.info({ reviewReportPath }, "updatePom complete");
497
+ return {
498
+ added: { fields: newChoices.length, methods: 0 },
499
+ preserved: {
500
+ fields: existing.fields.length,
501
+ methods: existing.methods.length,
502
+ },
503
+ filePath: existing.filePath,
504
+ reviewItems,
505
+ };
506
+ }
507
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Routes every LLM call through the `ai-governance` sidecar (default :8004).
3
+ * No direct calls to provider SDKs — providers are plugins inside the sidecar.
4
+ *
5
+ * Phase 4 work item.
6
+ */
7
+ export declare class GovernanceError extends Error {
8
+ readonly cause?: unknown | undefined;
9
+ constructor(message: string, cause?: unknown | undefined);
10
+ }
11
+ export interface GovernanceCallInput {
12
+ provider: "anthropic" | "openai" | "gemini";
13
+ model?: string;
14
+ prompt: string;
15
+ context?: Record<string, unknown>;
16
+ governanceUrl?: string;
17
+ }
18
+ export interface GovernanceCallResult {
19
+ text: string;
20
+ redactions: number;
21
+ provider: string;
22
+ model: string;
23
+ }
24
+ export declare function callViaGovernance(_input: GovernanceCallInput): Promise<GovernanceCallResult>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * Routes every LLM call through the `ai-governance` sidecar (default :8004).
4
+ * No direct calls to provider SDKs — providers are plugins inside the sidecar.
5
+ *
6
+ * Phase 4 work item.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.GovernanceError = void 0;
10
+ exports.callViaGovernance = callViaGovernance;
11
+ class GovernanceError extends Error {
12
+ constructor(message, cause) {
13
+ super(message);
14
+ this.cause = cause;
15
+ this.name = "GovernanceError";
16
+ }
17
+ }
18
+ exports.GovernanceError = GovernanceError;
19
+ async function callViaGovernance(_input) {
20
+ throw new GovernanceError("callViaGovernance() — Phase 4");
21
+ }
22
+ //# sourceMappingURL=governanceClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governanceClient.js","sourceRoot":"","sources":["../../src/llm/governanceClient.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAwBH,8CAIC;AA1BD,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe,EAAkB,KAAe;QAC1D,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,UAAK,GAAL,KAAK,CAAU;QAE1D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AALD,0CAKC;AAiBM,KAAK,UAAU,iBAAiB,CACrC,MAA2B;IAE3B,MAAM,IAAI,eAAe,CAAC,+BAA+B,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Anthropic provider plugin — invoked indirectly via the governance sidecar.
3
+ * This file is a placeholder; concrete provider logic lives in the sidecar
4
+ * in production. The local stub is kept only for unit tests.
5
+ *
6
+ * Phase 4 work item.
7
+ */
8
+ export declare const provider: "anthropic";
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Anthropic provider plugin — invoked indirectly via the governance sidecar.
4
+ * This file is a placeholder; concrete provider logic lives in the sidecar
5
+ * in production. The local stub is kept only for unit tests.
6
+ *
7
+ * Phase 4 work item.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.provider = void 0;
11
+ exports.provider = "anthropic";
12
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/llm/providers/anthropic.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEU,QAAA,QAAQ,GAAG,WAAoB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Gemini provider plugin — see anthropic.ts for the rationale.
3
+ * Phase 4 work item.
4
+ */
5
+ export declare const provider: "gemini";
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * Gemini provider plugin — see anthropic.ts for the rationale.
4
+ * Phase 4 work item.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.provider = void 0;
8
+ exports.provider = "gemini";
9
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/llm/providers/gemini.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEU,QAAA,QAAQ,GAAG,QAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * OpenAI provider plugin — see anthropic.ts for the rationale.
3
+ * Phase 4 work item.
4
+ */
5
+ export declare const provider: "openai";
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * OpenAI provider plugin — see anthropic.ts for the rationale.
4
+ * Phase 4 work item.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.provider = void 0;
8
+ exports.provider = "openai";
9
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/llm/providers/openai.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEU,QAAA,QAAQ,GAAG,QAAiB,CAAC"}