@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
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Thin facade over `@vijaypjavvadi/pw-emit`. All POM/spec rendering happens
3
+ * in `pw-emit`; bdd2pw only owns:
4
+ * - the orchestration (which IRs to feed in, in what order)
5
+ * - the IR→pw-emit adaptation (bdd2pw's IR carries scaffolder-only fields
6
+ * like `filePath` and `exists` that pw-emit doesn't need)
7
+ *
8
+ * See docs/PHASE_0_PLAN.md and docs/ARCHITECTURE.md §5.
9
+ */
10
+ import { type EmitResult } from "@vijaypjavvadi/pw-emit";
11
+ import type { PageObjectIR, StepBinding } from "../types";
12
+ export declare class EmitterConsistencyError extends Error {
13
+ constructor(message: string);
14
+ }
15
+ export interface EmitPageObjectInput {
16
+ pom: PageObjectIR;
17
+ /** When `'augment'`, an existing file is being updated — caller must
18
+ * ensure the IR already contains both existing and new fields/methods.
19
+ * See FR-19 in docs/SCOPE.md. */
20
+ mode: "create" | "augment";
21
+ existing?: string;
22
+ /** Wrap locator initialisers in `healOrThrow(...)` for runtime healing. */
23
+ selfHealingShim?: boolean;
24
+ }
25
+ export interface EmitTestFileInput {
26
+ describeName: string;
27
+ beforeEach?: StepBinding[];
28
+ scenarios: {
29
+ name: string;
30
+ bindings: StepBinding[];
31
+ }[];
32
+ pomImports: {
33
+ className: string;
34
+ fromPath: string;
35
+ }[];
36
+ }
37
+ export type { EmitResult };
38
+ export declare function emitPageObject(input: EmitPageObjectInput): EmitResult;
39
+ /**
40
+ * Render a Gherkin-derived test spec via pw-emit.
41
+ *
42
+ * The bdd2pw caller passes `StepBinding[]` per scenario (still tied to
43
+ * Gherkin step text + POM method calls); the facade renders them into TS
44
+ * body strings and hands the resulting `TestSpecIR` to pw-emit.
45
+ *
46
+ * **POM instantiation:** every test body and every hook body is prefixed
47
+ * with `const <pageVar> = new <ClassName>(page);` for each imported POM.
48
+ * Without this, `await loginPage.goto()` references an undeclared variable.
49
+ * Each scope gets its own fresh instance — POM construction is just
50
+ * Locator creation, which is cheap.
51
+ */
52
+ export declare function emitTestFile(input: EmitTestFileInput): EmitResult;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * Thin facade over `@vijaypjavvadi/pw-emit`. All POM/spec rendering happens
4
+ * in `pw-emit`; bdd2pw only owns:
5
+ * - the orchestration (which IRs to feed in, in what order)
6
+ * - the IR→pw-emit adaptation (bdd2pw's IR carries scaffolder-only fields
7
+ * like `filePath` and `exists` that pw-emit doesn't need)
8
+ *
9
+ * See docs/PHASE_0_PLAN.md and docs/ARCHITECTURE.md §5.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.EmitterConsistencyError = void 0;
13
+ exports.emitPageObject = emitPageObject;
14
+ exports.emitTestFile = emitTestFile;
15
+ const pw_emit_1 = require("@vijaypjavvadi/pw-emit");
16
+ const naming_1 = require("../utils/naming");
17
+ class EmitterConsistencyError extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = "EmitterConsistencyError";
21
+ }
22
+ }
23
+ exports.EmitterConsistencyError = EmitterConsistencyError;
24
+ /**
25
+ * Adapt a bdd2pw `LocatorChoice` to a pw-emit `LocatorChoice`.
26
+ * Drops scaffolder-only fields (`source`, `confidence`).
27
+ */
28
+ function toPwLocatorChoice(c) {
29
+ return { api: c.api, args: c.args, fieldName: c.fieldName };
30
+ }
31
+ /**
32
+ * Adapt a bdd2pw `PageObjectIR` to a pw-emit `PageObjectIR`.
33
+ * Drops scaffolder-only fields (`filePath`, `url`, `exists`); converts
34
+ * methods (which already carry pre-rendered TS bodies in bdd2pw).
35
+ */
36
+ function toPwPageObjectIR(pom) {
37
+ return {
38
+ className: pom.className,
39
+ fields: pom.fields.map(toPwLocatorChoice),
40
+ methods: pom.methods.map((m) => ({
41
+ name: m.name,
42
+ params: m.params,
43
+ body: m.body,
44
+ })),
45
+ };
46
+ }
47
+ function emitPageObject(input) {
48
+ if (input.mode === "augment" && !input.existing) {
49
+ throw new EmitterConsistencyError(`emitPageObject(mode: 'augment') requires the existing file contents — caller must read the file first.`);
50
+ }
51
+ const opts = { selfHealingShim: input.selfHealingShim };
52
+ return (0, pw_emit_1.emitPageObject)(toPwPageObjectIR(input.pom), opts);
53
+ }
54
+ /**
55
+ * Render a Gherkin-derived test spec via pw-emit.
56
+ *
57
+ * The bdd2pw caller passes `StepBinding[]` per scenario (still tied to
58
+ * Gherkin step text + POM method calls); the facade renders them into TS
59
+ * body strings and hands the resulting `TestSpecIR` to pw-emit.
60
+ *
61
+ * **POM instantiation:** every test body and every hook body is prefixed
62
+ * with `const <pageVar> = new <ClassName>(page);` for each imported POM.
63
+ * Without this, `await loginPage.goto()` references an undeclared variable.
64
+ * Each scope gets its own fresh instance — POM construction is just
65
+ * Locator creation, which is cheap.
66
+ */
67
+ function emitTestFile(input) {
68
+ const prelude = input.pomImports.map((p) => `const ${(0, naming_1.camelCase)(p.className)} = new ${p.className}(page);`);
69
+ const ir = {
70
+ describeName: input.describeName,
71
+ pomImports: input.pomImports,
72
+ beforeEach: input.beforeEach && input.beforeEach.length
73
+ ? [{ body: bindingsToBody(input.beforeEach, prelude) }]
74
+ : undefined,
75
+ tests: input.scenarios.map((s) => ({
76
+ name: s.name,
77
+ body: bindingsToBody(s.bindings, prelude),
78
+ })),
79
+ };
80
+ return (0, pw_emit_1.emitTestSpec)(ir);
81
+ }
82
+ /**
83
+ * Render a list of step bindings into a sequence of TS statements + comments.
84
+ *
85
+ * Each binding becomes either:
86
+ * - `await <pageVar>.<method>(<args>);` for POM calls
87
+ * - `await expect(<locator>).<matcher>(<expected>);` for assertions
88
+ * - `// TODO: <step text> — <warning>` when no clean mapping was found
89
+ *
90
+ * One blank line between bindings to keep the rendered spec readable.
91
+ * `prelude` lines (POM instantiation) are emitted first, followed by a
92
+ * blank line, then the bindings.
93
+ */
94
+ function bindingsToBody(bindings, prelude = []) {
95
+ const lines = [];
96
+ if (prelude.length > 0) {
97
+ lines.push(...prelude);
98
+ lines.push("");
99
+ }
100
+ for (const b of bindings) {
101
+ lines.push(`// ${b.step.keyword} ${b.step.text}`);
102
+ if (b.customBody) {
103
+ // Compound step — body has multiple statements pre-rendered.
104
+ for (const line of b.customBody.split("\n"))
105
+ lines.push(line);
106
+ }
107
+ else if (b.pomCall) {
108
+ const args = b.pomCall.args.join(", ");
109
+ lines.push(`await ${b.pomCall.page}.${b.pomCall.method}(${args});`);
110
+ }
111
+ else if (b.assertion) {
112
+ const expected = b.assertion.expected !== undefined ? b.assertion.expected : "";
113
+ lines.push(`await expect(${b.assertion.locator}).${b.assertion.matcher}(${expected});`);
114
+ }
115
+ else {
116
+ lines.push(`// TODO: ${b.warning ?? "no rule matched this step"}`);
117
+ }
118
+ lines.push("");
119
+ }
120
+ // Trim trailing blank
121
+ while (lines.length && lines[lines.length - 1] === "")
122
+ lines.pop();
123
+ return lines.join("\n");
124
+ }
125
+ //# sourceMappingURL=facade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facade.js","sourceRoot":"","sources":["../../src/emitters/facade.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAwEH,wCAQC;AAeD,oCAkBC;AA/GD,oDAQgC;AAQhC,4CAA4C;AAE5C,MAAa,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AALD,0DAKC;AAsBD;;;GAGG;AACH,SAAS,iBAAiB,CAAC,CAAgB;IACzC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,GAAiB;IACzC,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;QACzC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,KAA0B;IACvD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,uBAAuB,CAC/B,wGAAwG,CACzG,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAA0B,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC;IAC/E,OAAO,IAAA,wBAAgB,EAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,YAAY,CAAC,KAAwB;IACnD,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,IAAA,kBAAS,EAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,SAAS,SAAS,CACrE,CAAC;IAEF,MAAM,EAAE,GAAe;QACrB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,UAAU,EACR,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM;YACzC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;YACvD,CAAC,CAAC,SAAS;QACf,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC1C,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,IAAA,sBAAc,EAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,cAAc,CAAC,QAAuB,EAAE,UAAoB,EAAE;IACrE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YACjB,6DAA6D;YAC7D,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;YACvB,MAAM,QAAQ,GACZ,CAAC,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,KAAK,CAAC,IAAI,CACR,gBAAgB,CAAC,CAAC,SAAS,CAAC,OAAO,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,IAAI,QAAQ,IAAI,CAC5E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,IAAI,2BAA2B,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,sBAAsB;IACtB,OAAO,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IACnE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Zip + stream a job's artefact directory to the client via `archiver`.
3
+ * Excludes `node_modules`, `.git`, `test-results`, `playwright-report`.
4
+ *
5
+ * Headers set:
6
+ * Content-Type: application/zip
7
+ * Content-Disposition: attachment; filename="bdd2pw-<jobId>.zip"
8
+ *
9
+ * Streamed (not buffered), so very large outputs don't blow worker memory.
10
+ * Caller is responsible for catching errors and falling back gracefully
11
+ * if headers haven't been sent yet.
12
+ */
13
+ import type { Response } from "express";
14
+ export declare function streamArtifactZip(res: Response, artifactDir: string, jobId: string): Promise<void>;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Zip + stream a job's artefact directory to the client via `archiver`.
4
+ * Excludes `node_modules`, `.git`, `test-results`, `playwright-report`.
5
+ *
6
+ * Headers set:
7
+ * Content-Type: application/zip
8
+ * Content-Disposition: attachment; filename="bdd2pw-<jobId>.zip"
9
+ *
10
+ * Streamed (not buffered), so very large outputs don't blow worker memory.
11
+ * Caller is responsible for catching errors and falling back gracefully
12
+ * if headers haven't been sent yet.
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.streamArtifactZip = streamArtifactZip;
19
+ const archiver_1 = __importDefault(require("archiver"));
20
+ async function streamArtifactZip(res, artifactDir, jobId) {
21
+ res.setHeader("Content-Type", "application/zip");
22
+ res.setHeader("Content-Disposition", `attachment; filename="bdd2pw-${jobId}.zip"`);
23
+ return new Promise((resolve, reject) => {
24
+ const archive = (0, archiver_1.default)("zip", { zlib: { level: 6 } });
25
+ archive.on("error", (err) => reject(err));
26
+ archive.on("end", () => resolve());
27
+ archive.pipe(res);
28
+ archive.glob("**/*", {
29
+ cwd: artifactDir,
30
+ dot: true,
31
+ ignore: ["node_modules/**", ".git/**", "test-results/**", "playwright-report/**"],
32
+ });
33
+ void archive.finalize();
34
+ });
35
+ }
36
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/http/artifacts.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;AAKH,8CAuBC;AAzBD,wDAAgC;AAEzB,KAAK,UAAU,iBAAiB,CACrC,GAAa,EACb,WAAmB,EACnB,KAAa;IAEb,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACjD,GAAG,CAAC,SAAS,CACX,qBAAqB,EACrB,gCAAgC,KAAK,OAAO,CAC7C,CAAC;IAEF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,IAAA,kBAAQ,EAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;YACnB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,IAAI;YACT,MAAM,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,iBAAiB,EAAE,sBAAsB,CAAC;SAClF,CAAC,CAAC;QACH,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * In-memory job store. v1.0 only. v1.1 promotes to SQLite-backed.
3
+ * See docs/ARCHITECTURE.md §8.
4
+ */
5
+ import type { ReviewItem } from "../types";
6
+ export type JobStage = "queued" | "parsing" | "scanning_repo" | "discovering_page" | "picking_locators" | "matching_steps" | "emitting" | "validating" | "completed" | "failed";
7
+ export interface JobRecord {
8
+ id: string;
9
+ status: "queued" | "running" | "completed" | "failed";
10
+ stage: JobStage;
11
+ progress: number;
12
+ warnings: ReviewItem[];
13
+ errors: ReviewItem[];
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ /** Path to the on-disk artefact directory once available. */
17
+ artifactDir?: string;
18
+ /** Final result payload after `completed`. */
19
+ result?: unknown;
20
+ }
21
+ export declare function createJob(): JobRecord;
22
+ export declare function getJob(id: string): JobRecord | undefined;
23
+ export declare function updateJob(id: string, patch: Partial<JobRecord>): JobRecord | undefined;
24
+ /** Sweep jobs older than `maxAgeMs`. Default: 24h. */
25
+ export declare function sweepJobs(maxAgeMs?: number): number;
26
+ export declare function _resetForTests(): void;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /**
3
+ * In-memory job store. v1.0 only. v1.1 promotes to SQLite-backed.
4
+ * See docs/ARCHITECTURE.md §8.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createJob = createJob;
8
+ exports.getJob = getJob;
9
+ exports.updateJob = updateJob;
10
+ exports.sweepJobs = sweepJobs;
11
+ exports._resetForTests = _resetForTests;
12
+ const ulid_1 = require("ulid");
13
+ const store = new Map();
14
+ function createJob() {
15
+ const now = new Date().toISOString();
16
+ const job = {
17
+ id: (0, ulid_1.ulid)(),
18
+ status: "queued",
19
+ stage: "queued",
20
+ progress: 0,
21
+ warnings: [],
22
+ errors: [],
23
+ createdAt: now,
24
+ updatedAt: now,
25
+ };
26
+ store.set(job.id, job);
27
+ return job;
28
+ }
29
+ function getJob(id) {
30
+ return store.get(id);
31
+ }
32
+ function updateJob(id, patch) {
33
+ const current = store.get(id);
34
+ if (!current)
35
+ return undefined;
36
+ const updated = {
37
+ ...current,
38
+ ...patch,
39
+ updatedAt: new Date().toISOString(),
40
+ };
41
+ store.set(id, updated);
42
+ return updated;
43
+ }
44
+ /** Sweep jobs older than `maxAgeMs`. Default: 24h. */
45
+ function sweepJobs(maxAgeMs = 24 * 60 * 60 * 1000) {
46
+ const cutoff = Date.now() - maxAgeMs;
47
+ let removed = 0;
48
+ for (const [id, job] of store) {
49
+ if (Date.parse(job.updatedAt) < cutoff) {
50
+ store.delete(id);
51
+ removed++;
52
+ }
53
+ }
54
+ return removed;
55
+ }
56
+ function _resetForTests() {
57
+ store.clear();
58
+ }
59
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/http/jobs.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAkCH,8BAcC;AAED,wBAEC;AAED,8BAUC;AAGD,8BAUC;AAED,wCAEC;AA/ED,+BAA4B;AA8B5B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE3C,SAAgB,SAAS;IACvB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,GAAG,GAAc;QACrB,EAAE,EAAE,IAAA,WAAI,GAAE;QACV,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACf,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,MAAM,CAAC,EAAU;IAC/B,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,SAAgB,SAAS,CAAC,EAAU,EAAE,KAAyB;IAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,OAAO,GAAc;QACzB,GAAG,OAAO;QACV,GAAG,KAAK;QACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sDAAsD;AACtD,SAAgB,SAAS,CAAC,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;IACrC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAAC;YACvC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,cAAc;IAC5B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Express route registrations for the HTTP API.
3
+ * See docs/SCOPE.md §8b and docs/ARCHITECTURE.md §3 + §6.
4
+ *
5
+ * Phase 3: workers are wired. Each `POST` accepts → 202 + jobId, then a
6
+ * Promise worker calls the real `scaffold()` / `analyze()` / `updatePom()`
7
+ * and updates the job state. `GET /jobs/:id/artifact` streams a zip of
8
+ * the output dir for `scaffold` jobs.
9
+ */
10
+ import type { Application } from "express";
11
+ export declare function mountRoutes(app: Application): void;
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ /**
3
+ * Express route registrations for the HTTP API.
4
+ * See docs/SCOPE.md §8b and docs/ARCHITECTURE.md §3 + §6.
5
+ *
6
+ * Phase 3: workers are wired. Each `POST` accepts → 202 + jobId, then a
7
+ * Promise worker calls the real `scaffold()` / `analyze()` / `updatePom()`
8
+ * and updates the job state. `GET /jobs/:id/artifact` streams a zip of
9
+ * the output dir for `scaffold` jobs.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.mountRoutes = mountRoutes;
46
+ const os = __importStar(require("os"));
47
+ const path = __importStar(require("path"));
48
+ const fs = __importStar(require("fs-extra"));
49
+ const schemas_1 = require("./schemas");
50
+ const jobs_1 = require("./jobs");
51
+ const artifacts_1 = require("./artifacts");
52
+ const index_1 = require("../index");
53
+ const logger_1 = require("../utils/logger");
54
+ function mountRoutes(app) {
55
+ app.get("/readyz", (_req, res) => {
56
+ res.json({ ok: true, mcp: "unknown", governance: "unknown" });
57
+ });
58
+ app.post("/scaffold", (req, res) => {
59
+ const parsed = schemas_1.ScaffoldRequestSchema.safeParse(req.body);
60
+ if (!parsed.success) {
61
+ return res
62
+ .status(400)
63
+ .json({ error: "ValidationError", details: parsed.error.errors });
64
+ }
65
+ const job = (0, jobs_1.createJob)();
66
+ logger_1.logger.info({ jobId: job.id, kind: "scaffold" }, "job accepted");
67
+ // Per-job artifact directory under tmpdir.
68
+ const artifactDir = path.join(os.tmpdir(), "bdd2pw-jobs", job.id);
69
+ (0, jobs_1.updateJob)(job.id, { status: "running", stage: "queued", artifactDir });
70
+ void runScaffoldWorker(job.id, parsed.data, artifactDir);
71
+ return res.status(202).json({
72
+ jobId: job.id,
73
+ links: {
74
+ self: `/jobs/${job.id}`,
75
+ artifact: `/jobs/${job.id}/artifact`,
76
+ },
77
+ });
78
+ });
79
+ app.post("/analyze", (req, res) => {
80
+ const parsed = schemas_1.AnalyzeRequestSchema.safeParse(req.body);
81
+ if (!parsed.success) {
82
+ return res
83
+ .status(400)
84
+ .json({ error: "ValidationError", details: parsed.error.errors });
85
+ }
86
+ const job = (0, jobs_1.createJob)();
87
+ logger_1.logger.info({ jobId: job.id, kind: "analyze" }, "job accepted");
88
+ (0, jobs_1.updateJob)(job.id, { status: "running", stage: "parsing" });
89
+ void runAnalyzeWorker(job.id, parsed.data);
90
+ return res.status(202).json({
91
+ jobId: job.id,
92
+ links: { self: `/jobs/${job.id}`, artifact: `/jobs/${job.id}/artifact` },
93
+ });
94
+ });
95
+ app.post("/update-pom", (req, res) => {
96
+ const parsed = schemas_1.UpdatePomRequestSchema.safeParse(req.body);
97
+ if (!parsed.success) {
98
+ return res
99
+ .status(400)
100
+ .json({ error: "ValidationError", details: parsed.error.errors });
101
+ }
102
+ const job = (0, jobs_1.createJob)();
103
+ logger_1.logger.info({ jobId: job.id, kind: "update-pom" }, "job accepted");
104
+ (0, jobs_1.updateJob)(job.id, { status: "running", stage: "scanning_repo" });
105
+ void runUpdatePomWorker(job.id, parsed.data);
106
+ return res.status(202).json({
107
+ jobId: job.id,
108
+ links: { self: `/jobs/${job.id}`, artifact: `/jobs/${job.id}/artifact` },
109
+ });
110
+ });
111
+ app.get("/jobs/:id", (req, res) => {
112
+ const job = (0, jobs_1.getJob)(req.params.id);
113
+ if (!job)
114
+ return res.status(404).json({ error: "JobNotFound" });
115
+ return res.json(job);
116
+ });
117
+ app.get("/jobs/:id/artifact", async (req, res) => {
118
+ const job = (0, jobs_1.getJob)(req.params.id);
119
+ if (!job)
120
+ return res.status(404).json({ error: "JobNotFound" });
121
+ if (job.status !== "completed" || !job.artifactDir) {
122
+ return res
123
+ .status(409)
124
+ .json({ error: "ArtifactNotReady", status: job.status });
125
+ }
126
+ if (!(await fs.pathExists(job.artifactDir))) {
127
+ return res
128
+ .status(410)
129
+ .json({ error: "ArtifactExpired", message: "Artifact directory no longer exists." });
130
+ }
131
+ try {
132
+ await (0, artifacts_1.streamArtifactZip)(res, job.artifactDir, job.id);
133
+ }
134
+ catch (err) {
135
+ logger_1.logger.error({ jobId: job.id, err }, "artifact stream failed");
136
+ // Headers may already be flushed; best we can do is end the response.
137
+ if (!res.headersSent) {
138
+ res.status(500).json({ error: "StreamFailed", message: err.message });
139
+ }
140
+ else {
141
+ res.end();
142
+ }
143
+ }
144
+ });
145
+ app.get("/jobs/:id/log", (req, res) => {
146
+ const job = (0, jobs_1.getJob)(req.params.id);
147
+ if (!job)
148
+ return res.status(404).json({ error: "JobNotFound" });
149
+ // v1.0 returns the in-memory job record's warnings + errors as a flat
150
+ // text dump. Real per-job log file tailing is a v1.1 enhancement once
151
+ // pino multi-stream routing is wired.
152
+ res.type("text/plain");
153
+ const lines = [];
154
+ lines.push(`# Job ${job.id} — status=${job.status} stage=${job.stage}`);
155
+ lines.push(`# created=${job.createdAt} updated=${job.updatedAt}`);
156
+ lines.push("");
157
+ for (const w of job.warnings)
158
+ lines.push(`[warn] ${w.message}`);
159
+ for (const e of job.errors)
160
+ lines.push(`[error] ${e.message}`);
161
+ res.send(lines.join("\n"));
162
+ });
163
+ }
164
+ // ─── Workers ───────────────────────────────────────────────────────────────
165
+ async function runScaffoldWorker(jobId, body, artifactDir) {
166
+ try {
167
+ (0, jobs_1.updateJob)(jobId, { stage: "parsing", progress: 0.1 });
168
+ // Override the caller-provided repo with our per-job artifact dir so we
169
+ // don't write outside the sandbox. The caller can still download the
170
+ // result via GET /jobs/:id/artifact.
171
+ const opts = {
172
+ feature: body.feature,
173
+ url: body.url,
174
+ page: body.page,
175
+ repo: artifactDir,
176
+ pages: body.options?.pages,
177
+ storageState: body.options?.storageState,
178
+ headed: body.options?.headed,
179
+ llm: body.options?.llm,
180
+ governanceUrl: body.options?.governanceUrl,
181
+ templates: body.options?.templates,
182
+ noValidate: body.options?.noValidate,
183
+ telemetry: body.options?.telemetry,
184
+ force: body.options?.force,
185
+ snapshotFile: body.options?.snapshotFile,
186
+ noDiscovery: body.options?.noDiscovery,
187
+ };
188
+ (0, jobs_1.updateJob)(jobId, { stage: "emitting", progress: 0.5 });
189
+ const result = await (0, index_1.scaffold)(opts);
190
+ (0, jobs_1.updateJob)(jobId, {
191
+ status: "completed",
192
+ stage: "completed",
193
+ progress: 1,
194
+ result,
195
+ warnings: result.reviewItems.filter((i) => i.severity === "warn"),
196
+ errors: result.reviewItems.filter((i) => i.severity === "error"),
197
+ });
198
+ logger_1.logger.info({ jobId, files: result.filesWritten.length }, "scaffold worker complete");
199
+ }
200
+ catch (err) {
201
+ logger_1.logger.error({ jobId, err }, "scaffold worker failed");
202
+ (0, jobs_1.updateJob)(jobId, {
203
+ status: "failed",
204
+ stage: "failed",
205
+ errors: [{ severity: "error", message: err.message }],
206
+ });
207
+ }
208
+ }
209
+ async function runAnalyzeWorker(jobId, body) {
210
+ try {
211
+ (0, jobs_1.updateJob)(jobId, { stage: "parsing", progress: 0.2 });
212
+ const result = await (0, index_1.analyze)({
213
+ feature: body.feature,
214
+ url: body.url,
215
+ storageState: body.options?.storageState,
216
+ headed: body.options?.headed,
217
+ });
218
+ (0, jobs_1.updateJob)(jobId, {
219
+ status: "completed",
220
+ stage: "completed",
221
+ progress: 1,
222
+ result,
223
+ warnings: result.warnings,
224
+ });
225
+ logger_1.logger.info({ jobId }, "analyze worker complete");
226
+ }
227
+ catch (err) {
228
+ logger_1.logger.error({ jobId, err }, "analyze worker failed");
229
+ (0, jobs_1.updateJob)(jobId, {
230
+ status: "failed",
231
+ stage: "failed",
232
+ errors: [{ severity: "error", message: err.message }],
233
+ });
234
+ }
235
+ }
236
+ async function runUpdatePomWorker(jobId, body) {
237
+ try {
238
+ (0, jobs_1.updateJob)(jobId, { stage: "scanning_repo", progress: 0.2 });
239
+ const result = await (0, index_1.updatePom)({
240
+ page: body.page,
241
+ url: body.url,
242
+ repo: body.repo,
243
+ storageState: body.options?.storageState,
244
+ headed: body.options?.headed,
245
+ templates: body.options?.templates,
246
+ });
247
+ (0, jobs_1.updateJob)(jobId, {
248
+ status: "completed",
249
+ stage: "completed",
250
+ progress: 1,
251
+ result,
252
+ warnings: result.reviewItems.filter((i) => i.severity === "warn"),
253
+ // updatePom modifies the user's repo directly; no artifact dir for download
254
+ artifactDir: undefined,
255
+ });
256
+ logger_1.logger.info({ jobId, addedFields: result.added.fields }, "update-pom worker complete");
257
+ }
258
+ catch (err) {
259
+ logger_1.logger.error({ jobId, err }, "update-pom worker failed");
260
+ (0, jobs_1.updateJob)(jobId, {
261
+ status: "failed",
262
+ stage: "failed",
263
+ errors: [{ severity: "error", message: err.message }],
264
+ });
265
+ }
266
+ }
267
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/http/routes.ts"],"names":[],"mappings":"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"}