@yasserkhanorg/e2e-agents 0.3.8 → 0.5.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.
- package/dist/agent/config.d.ts +12 -0
- package/dist/agent/config.d.ts.map +1 -1
- package/dist/agent/config.js +32 -0
- package/dist/cli.js +103 -0
- package/dist/esm/agent/config.js +32 -0
- package/dist/esm/cli.js +103 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/knowledge/api_surface.js +177 -0
- package/dist/esm/knowledge/context_loader.js +85 -0
- package/dist/esm/knowledge/route_families.js +211 -0
- package/dist/esm/knowledge/spec_index.js +122 -0
- package/dist/esm/pipeline/orchestrator.js +219 -0
- package/dist/esm/pipeline/stage0_preprocess.js +109 -0
- package/dist/esm/pipeline/stage1_impact.js +124 -0
- package/dist/esm/pipeline/stage2_coverage.js +131 -0
- package/dist/esm/pipeline/stage3_generation.js +146 -0
- package/dist/esm/pipeline/stage4_heal.js +145 -0
- package/dist/esm/prompts/coverage.js +64 -0
- package/dist/esm/prompts/generation.js +141 -0
- package/dist/esm/prompts/heal.js +69 -0
- package/dist/esm/prompts/impact.js +82 -0
- package/dist/esm/validation/guardrails.js +95 -0
- package/dist/esm/validation/output_schema.js +80 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/knowledge/api_surface.d.ts +25 -0
- package/dist/knowledge/api_surface.d.ts.map +1 -0
- package/dist/knowledge/api_surface.js +184 -0
- package/dist/knowledge/context_loader.d.ts +13 -0
- package/dist/knowledge/context_loader.d.ts.map +1 -0
- package/dist/knowledge/context_loader.js +90 -0
- package/dist/knowledge/route_families.d.ts +48 -0
- package/dist/knowledge/route_families.d.ts.map +1 -0
- package/dist/knowledge/route_families.js +220 -0
- package/dist/knowledge/spec_index.d.ts +18 -0
- package/dist/knowledge/spec_index.d.ts.map +1 -0
- package/dist/knowledge/spec_index.js +128 -0
- package/dist/pipeline/orchestrator.d.ts +31 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.js +222 -0
- package/dist/pipeline/stage0_preprocess.d.ts +31 -0
- package/dist/pipeline/stage0_preprocess.d.ts.map +1 -0
- package/dist/pipeline/stage0_preprocess.js +112 -0
- package/dist/pipeline/stage1_impact.d.ts +19 -0
- package/dist/pipeline/stage1_impact.d.ts.map +1 -0
- package/dist/pipeline/stage1_impact.js +127 -0
- package/dist/pipeline/stage2_coverage.d.ts +17 -0
- package/dist/pipeline/stage2_coverage.d.ts.map +1 -0
- package/dist/pipeline/stage2_coverage.js +134 -0
- package/dist/pipeline/stage3_generation.d.ts +31 -0
- package/dist/pipeline/stage3_generation.d.ts.map +1 -0
- package/dist/pipeline/stage3_generation.js +149 -0
- package/dist/pipeline/stage4_heal.d.ts +56 -0
- package/dist/pipeline/stage4_heal.d.ts.map +1 -0
- package/dist/pipeline/stage4_heal.js +151 -0
- package/dist/prompts/coverage.d.ts +37 -0
- package/dist/prompts/coverage.d.ts.map +1 -0
- package/dist/prompts/coverage.js +68 -0
- package/dist/prompts/generation.d.ts +23 -0
- package/dist/prompts/generation.d.ts.map +1 -0
- package/dist/prompts/generation.js +146 -0
- package/dist/prompts/heal.d.ts +19 -0
- package/dist/prompts/heal.d.ts.map +1 -0
- package/dist/prompts/heal.js +73 -0
- package/dist/prompts/impact.d.ts +30 -0
- package/dist/prompts/impact.d.ts.map +1 -0
- package/dist/prompts/impact.js +86 -0
- package/dist/validation/guardrails.d.ts +27 -0
- package/dist/validation/guardrails.d.ts.map +1 -0
- package/dist/validation/guardrails.js +104 -0
- package/dist/validation/output_schema.d.ts +64 -0
- package/dist/validation/output_schema.d.ts.map +1 -0
- package/dist/validation/output_schema.js +84 -0
- package/package.json +3 -1
- package/schemas/flow-decision.schema.json +83 -0
- package/schemas/route-families.schema.json +107 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
export function buildCoveragePrompt(ctx) {
|
|
4
|
+
const flowsBlock = ctx.flows
|
|
5
|
+
.map((f) => {
|
|
6
|
+
const actions = f.userActions.length > 0 ? f.userActions.join('; ') : 'unknown';
|
|
7
|
+
return `- ${f.flowId} (${f.priority}): ${f.flowName}\n Route: ${f.route}\n User actions: ${actions}\n Evidence: ${f.evidence}`;
|
|
8
|
+
})
|
|
9
|
+
.join('\n\n');
|
|
10
|
+
const specsBlock = ctx.specs
|
|
11
|
+
.map((s) => {
|
|
12
|
+
return `### ${s.relativePath}\nTest titles: ${s.testTitles.join(', ')}\n\`\`\`typescript\n${s.content}\n\`\`\``;
|
|
13
|
+
})
|
|
14
|
+
.join('\n\n');
|
|
15
|
+
return [
|
|
16
|
+
'You are evaluating whether existing Mattermost Playwright E2E tests cover the impacted flows.',
|
|
17
|
+
'',
|
|
18
|
+
`IMPACTED FLOWS (${ctx.flows.length}):`,
|
|
19
|
+
flowsBlock,
|
|
20
|
+
'',
|
|
21
|
+
`EXISTING SPEC FILES (${ctx.specs.length}):`,
|
|
22
|
+
specsBlock,
|
|
23
|
+
'',
|
|
24
|
+
ctx.contextBlock,
|
|
25
|
+
'',
|
|
26
|
+
'For each flow, determine coverage.',
|
|
27
|
+
'',
|
|
28
|
+
'Return strict JSON only with this shape:',
|
|
29
|
+
'{"coverage":[{"flowId":"<flow_id>","action":"run_existing|add_scenarios|create_spec|cannot_determine","existingSpecs":[{"path":"<relative path>","testTitles":["<exact test title>"],"coverageLevel":"full|partial|none","missingScenarios":["<specific scenario>"]}],"scenariosToAdd":["<scenario description>"],"targetSpec":"<path to extend>","newSpecPath":"<path for new spec>","blockingReason":"<why cannot_determine>","confidence":0-100}]}',
|
|
30
|
+
'',
|
|
31
|
+
'Rules:',
|
|
32
|
+
'- When claiming coverage exists, you MUST quote the exact test title from the spec file.',
|
|
33
|
+
'- If a spec tests a related but different flow, mark as "partial" not "full".',
|
|
34
|
+
'- Do NOT claim coverage exists if you cannot cite the exact test.',
|
|
35
|
+
'- Scenario gaps must be stated as user actions, not code changes.',
|
|
36
|
+
' Wrong: "test the new isEditing state"',
|
|
37
|
+
' Right: "test editing a scheduled message while it is in pending state"',
|
|
38
|
+
'- For add_scenarios, specify which existing spec file to extend in targetSpec.',
|
|
39
|
+
'- For create_spec, suggest a path following Mattermost conventions.',
|
|
40
|
+
'- Prefer adding scenarios to existing specs over creating new spec files.',
|
|
41
|
+
].join('\n');
|
|
42
|
+
}
|
|
43
|
+
export function parseCoverageResponse(text) {
|
|
44
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
45
|
+
const candidates = fenced ? [fenced[1], text] : [text];
|
|
46
|
+
for (const candidate of candidates) {
|
|
47
|
+
const start = candidate.indexOf('{');
|
|
48
|
+
const end = candidate.lastIndexOf('}');
|
|
49
|
+
if (start < 0 || end <= start) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const raw = candidate.slice(start, end + 1);
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(raw);
|
|
55
|
+
if (parsed && Array.isArray(parsed.coverage)) {
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { formatApiSurfaceForPrompt } from '../knowledge/api_surface.js';
|
|
4
|
+
function resolveRelevantPageObjects(apiSurface, decision) {
|
|
5
|
+
const relevant = [];
|
|
6
|
+
const familyHints = [
|
|
7
|
+
decision.routeFamily,
|
|
8
|
+
decision.featureId,
|
|
9
|
+
...decision.userActions.join(' ').toLowerCase().split(/\s+/),
|
|
10
|
+
]
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.map((s) => s.toLowerCase().replace(/[^a-z]/g, ''));
|
|
13
|
+
for (const po of apiSurface.pageObjects) {
|
|
14
|
+
const nameLower = po.className.toLowerCase();
|
|
15
|
+
if (nameLower.includes('channels') ||
|
|
16
|
+
nameLower.includes('page') ||
|
|
17
|
+
familyHints.some((hint) => hint.length > 3 && nameLower.includes(hint))) {
|
|
18
|
+
relevant.push(po.className);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return [...new Set(relevant)].slice(0, 10);
|
|
22
|
+
}
|
|
23
|
+
export function buildGenerationPrompt(ctx) {
|
|
24
|
+
const relevantClasses = resolveRelevantPageObjects(ctx.apiSurface, ctx.decision);
|
|
25
|
+
const apiBlock = relevantClasses.length > 0
|
|
26
|
+
? formatApiSurfaceForPrompt(ctx.apiSurface, relevantClasses)
|
|
27
|
+
: 'No page objects available. Use raw Playwright selectors via page.getByRole/getByTestId.';
|
|
28
|
+
const scenariosBlock = (ctx.decision.scenariosToAdd || [])
|
|
29
|
+
.map((s, i) => ` ${i + 1}. ${s}`)
|
|
30
|
+
.join('\n');
|
|
31
|
+
const existingBlock = ctx.existingSpecContent
|
|
32
|
+
? `\nEXISTING SPEC (extend this file):\n\`\`\`typescript\n${ctx.existingSpecContent}\n\`\`\``
|
|
33
|
+
: '';
|
|
34
|
+
const modeInstruction = ctx.mode === 'create_spec'
|
|
35
|
+
? `Create a NEW spec file at: ${ctx.specPath}`
|
|
36
|
+
: `ADD scenarios to the EXISTING spec at: ${ctx.specPath}`;
|
|
37
|
+
const routeFamilyTag = ctx.decision.routeFamily;
|
|
38
|
+
return [
|
|
39
|
+
'You are generating Mattermost Playwright E2E test code.',
|
|
40
|
+
'',
|
|
41
|
+
`TASK: ${modeInstruction}`,
|
|
42
|
+
'',
|
|
43
|
+
`FLOW: ${ctx.decision.flowName}`,
|
|
44
|
+
`Route Family: ${ctx.decision.routeFamily}${ctx.decision.featureId ? ` / ${ctx.decision.featureId}` : ''}`,
|
|
45
|
+
`Route: ${ctx.decision.specificRoute || '(not specified)'}`,
|
|
46
|
+
`Priority: ${ctx.decision.priority}`,
|
|
47
|
+
`Evidence: ${ctx.decision.evidence}`,
|
|
48
|
+
'',
|
|
49
|
+
'SCENARIOS TO IMPLEMENT:',
|
|
50
|
+
scenariosBlock || ' (implement core user actions for this flow)',
|
|
51
|
+
'',
|
|
52
|
+
'USER ACTIONS:',
|
|
53
|
+
ctx.decision.userActions.map((a) => ` - ${a}`).join('\n') || ' (none specified)',
|
|
54
|
+
'',
|
|
55
|
+
'AVAILABLE PAGE OBJECTS AND METHODS:',
|
|
56
|
+
apiBlock,
|
|
57
|
+
existingBlock,
|
|
58
|
+
'',
|
|
59
|
+
'MANDATORY RULES:',
|
|
60
|
+
'1. Import ONLY from "@mattermost/playwright-lib" — no other test framework imports.',
|
|
61
|
+
'2. Every test must call `await pw.initSetup()` first.',
|
|
62
|
+
'3. Use `await pw.testBrowser.login(user)` to log in — never hardcode credentials.',
|
|
63
|
+
'4. Use ONLY page object methods listed above. Do NOT invent methods that are not listed.',
|
|
64
|
+
'5. If a method is not available, use `page.getByRole()` or `page.getByTestId()`.',
|
|
65
|
+
`6. Tag every test: {tag: '@${routeFamilyTag}'}`,
|
|
66
|
+
'7. Write one test per scenario with a descriptive name of what the user does and what is verified.',
|
|
67
|
+
'8. Use `expect` from "@mattermost/playwright-lib" — do NOT import from "@playwright/test".',
|
|
68
|
+
'9. Include the copyright header for new files.',
|
|
69
|
+
'10. NEVER fabricate test IDs (MM-TXXXX). Use descriptive names only.',
|
|
70
|
+
'',
|
|
71
|
+
'EXAMPLE SPEC STRUCTURE:',
|
|
72
|
+
'```typescript',
|
|
73
|
+
'// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.',
|
|
74
|
+
'// See LICENSE.txt for license information.',
|
|
75
|
+
'',
|
|
76
|
+
"import {expect, test} from '@mattermost/playwright-lib';",
|
|
77
|
+
'',
|
|
78
|
+
'test(',
|
|
79
|
+
" 'descriptive name of what is tested',",
|
|
80
|
+
` {tag: '@${routeFamilyTag}'},`,
|
|
81
|
+
' async ({pw}) => {',
|
|
82
|
+
' const {user} = await pw.initSetup();',
|
|
83
|
+
' const {channelsPage} = await pw.testBrowser.login(user);',
|
|
84
|
+
' await channelsPage.goto();',
|
|
85
|
+
' await channelsPage.toBeVisible();',
|
|
86
|
+
' // test steps...',
|
|
87
|
+
' },',
|
|
88
|
+
');',
|
|
89
|
+
'```',
|
|
90
|
+
'',
|
|
91
|
+
'Return ONLY the TypeScript code. No explanations, no markdown fences.',
|
|
92
|
+
].join('\n');
|
|
93
|
+
}
|
|
94
|
+
export function parseGenerationResponse(text, expectedPath, mode, flowId) {
|
|
95
|
+
let code = text.trim();
|
|
96
|
+
const fenced = code.match(/^```(?:typescript|ts)?\s*([\s\S]*?)```\s*$/i);
|
|
97
|
+
if (fenced) {
|
|
98
|
+
code = fenced[1].trim();
|
|
99
|
+
}
|
|
100
|
+
if (!code.includes('test(')) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (!code.includes('@mattermost/playwright-lib')) {
|
|
104
|
+
code = `import {expect, test} from '@mattermost/playwright-lib';\n\n${code}`;
|
|
105
|
+
}
|
|
106
|
+
return { specPath: expectedPath, code, mode, flowId };
|
|
107
|
+
}
|
|
108
|
+
const BUILT_IN_METHODS = new Set([
|
|
109
|
+
'click', 'fill', 'focus', 'hover', 'press', 'type', 'check', 'uncheck',
|
|
110
|
+
'selectOption', 'waitFor', 'waitForLoadState', 'evaluate', 'dispatchEvent',
|
|
111
|
+
'getAttribute', 'textContent', 'innerText', 'innerHTML',
|
|
112
|
+
'isVisible', 'isEnabled', 'isChecked', 'isHidden',
|
|
113
|
+
'toBeVisible', 'toBeEnabled', 'toBeChecked', 'toBeHidden',
|
|
114
|
+
'toContainText', 'toHaveText', 'toHaveURL', 'toHaveValue',
|
|
115
|
+
'not', 'nth', 'first', 'last', 'all',
|
|
116
|
+
'getByRole', 'getByText', 'getByLabel', 'getByPlaceholder',
|
|
117
|
+
'getByTestId', 'getByTitle', 'getByAltText',
|
|
118
|
+
'locator', 'frame', 'page', 'expect',
|
|
119
|
+
'goBack', 'goForward', 'reload', 'goto',
|
|
120
|
+
'keyboard', 'mouse', 'touchscreen', 'close', 'bringToFront',
|
|
121
|
+
'initSetup', 'login', 'waitUntil', 'skipIfNoLicense', 'ensureLicense',
|
|
122
|
+
'random', 'duration', 'isOutsideRemoteUserHour', 'setTimeout',
|
|
123
|
+
'skip', 'fixme', 'slow', 'fail',
|
|
124
|
+
]);
|
|
125
|
+
/**
|
|
126
|
+
* Returns method names that appear in generated code but do not exist in the API surface.
|
|
127
|
+
* Used for logging; does not block generation.
|
|
128
|
+
*/
|
|
129
|
+
export function detectHallucinatedMethods(code, apiSurface) {
|
|
130
|
+
const allMethods = new Set(apiSurface.pageObjects.flatMap((po) => po.methods.map((m) => m.name)));
|
|
131
|
+
const suspected = [];
|
|
132
|
+
const callRe = /\bawait\s+\w+\.([a-zA-Z_]\w*)\s*\(/g;
|
|
133
|
+
let match;
|
|
134
|
+
while ((match = callRe.exec(code)) !== null) {
|
|
135
|
+
const methodName = match[1];
|
|
136
|
+
if (!BUILT_IN_METHODS.has(methodName) && !allMethods.has(methodName) && methodName.length > 3) {
|
|
137
|
+
suspected.push(methodName);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return [...new Set(suspected)];
|
|
141
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Builds a route-family-aware heal prompt for the playwright-test-healer agent.
|
|
5
|
+
* Enriches the base healer constraints with flow context so the agent understands
|
|
6
|
+
* what the test is supposed to verify, reducing hallucination during selector repair.
|
|
7
|
+
*/
|
|
8
|
+
export function buildHealPrompt(ctx) {
|
|
9
|
+
const flowBlock = ctx.decision
|
|
10
|
+
? [
|
|
11
|
+
'',
|
|
12
|
+
'FLOW CONTEXT (use to understand test intent — do not change test objectives):',
|
|
13
|
+
` Flow: ${ctx.decision.flowName}`,
|
|
14
|
+
` Route Family: ${ctx.decision.routeFamily}${ctx.decision.featureId ? ` / ${ctx.decision.featureId}` : ''}`,
|
|
15
|
+
` Route: ${ctx.decision.specificRoute || '(family-level)'}`,
|
|
16
|
+
` User Actions: ${ctx.decision.userActions.join('; ') || 'not specified'}`,
|
|
17
|
+
` Evidence: ${ctx.decision.evidence}`,
|
|
18
|
+
].join('\n')
|
|
19
|
+
: '';
|
|
20
|
+
const statusNote = ctx.status === 'flaky'
|
|
21
|
+
? 'This test is FLAKY (passes sometimes, fails other times). Look for race conditions, missing waits, or order-dependent state.'
|
|
22
|
+
: 'This test is FAILING consistently. The selector, URL, or API call is likely broken.';
|
|
23
|
+
const failureBlock = ctx.failureDetail
|
|
24
|
+
? `\nFailure detail:\n${ctx.failureDetail}`
|
|
25
|
+
: '';
|
|
26
|
+
return [
|
|
27
|
+
'Heal this specific Playwright test file and keep edits minimal.',
|
|
28
|
+
'',
|
|
29
|
+
`Target test file: ${ctx.specPath}`,
|
|
30
|
+
`Status: ${ctx.status.toUpperCase()} — ${statusNote}`,
|
|
31
|
+
failureBlock,
|
|
32
|
+
flowBlock,
|
|
33
|
+
'',
|
|
34
|
+
'Healing constraints (must follow):',
|
|
35
|
+
'- Import ONLY from "@mattermost/playwright-lib". Do not use "@playwright/test" directly.',
|
|
36
|
+
'- Do not use test.describe or test.only.',
|
|
37
|
+
'- Keep a single tag string matching the route family (e.g. "@channels", "@scheduled_posts").',
|
|
38
|
+
'- Use only existing Mattermost Playwright fixture and page-object APIs.',
|
|
39
|
+
'- Do NOT invent new pw.* clients or page object methods that do not exist.',
|
|
40
|
+
'- Avoid brittle class selectors (.backstage-navbar, .admin-console__wrapper, .left-panel, .panel-card).',
|
|
41
|
+
'- Prefer stable assertions using URL patterns, data-testid attributes, ARIA roles, and page-object methods.',
|
|
42
|
+
'- For flaky tests: add explicit waits (waitFor, expect().toBeVisible()) before interactions.',
|
|
43
|
+
'- Keep the test intent and scenario unchanged — only fix what is broken.',
|
|
44
|
+
'- If behavior is genuinely broken server-side, mark test.fixme with a clear comment explaining why.',
|
|
45
|
+
'',
|
|
46
|
+
'Run and fix this test until it compiles and passes, or mark test.fixme when the behavior is truly broken.',
|
|
47
|
+
].filter((line) => line !== null).join('\n');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Builds a minimal quality-fix prompt for spec files that fail content validation
|
|
51
|
+
* (e.g. contain test.describe, test.only, wrong imports).
|
|
52
|
+
*/
|
|
53
|
+
export function buildQualityFixPrompt(specPath, qualityIssues) {
|
|
54
|
+
return [
|
|
55
|
+
'Fix quality issues in this Playwright spec file. Make minimal edits only.',
|
|
56
|
+
'',
|
|
57
|
+
`Target file: ${specPath}`,
|
|
58
|
+
'',
|
|
59
|
+
'Issues to fix:',
|
|
60
|
+
...qualityIssues.map((issue) => ` - ${issue}`),
|
|
61
|
+
'',
|
|
62
|
+
'Rules:',
|
|
63
|
+
'- Import only from "@mattermost/playwright-lib".',
|
|
64
|
+
'- Remove test.describe wrappers (flatten to top-level test() calls).',
|
|
65
|
+
'- Remove test.only calls.',
|
|
66
|
+
'- Ensure each test has exactly one tag string.',
|
|
67
|
+
'- Do not change test logic — only fix structural quality issues.',
|
|
68
|
+
].join('\n');
|
|
69
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { formatSpecsForPrompt } from '../knowledge/spec_index.js';
|
|
4
|
+
import { formatApiSurfaceForPrompt } from '../knowledge/api_surface.js';
|
|
5
|
+
export function buildImpactPrompt(ctx) {
|
|
6
|
+
const familyRoutes = ctx.family.routes.join(', ');
|
|
7
|
+
const featureNote = ctx.featureId ? `\nFEATURE: ${ctx.featureId}` : '';
|
|
8
|
+
const pageObjectNames = ctx.family.pageObjects || [];
|
|
9
|
+
const componentNames = ctx.family.components || [];
|
|
10
|
+
const allClassNames = [...pageObjectNames, ...componentNames];
|
|
11
|
+
const apiSurfaceBlock = allClassNames.length > 0
|
|
12
|
+
? formatApiSurfaceForPrompt(ctx.apiSurface, allClassNames)
|
|
13
|
+
: 'No page objects or components mapped for this family.';
|
|
14
|
+
const specsBlock = ctx.existingSpecs.length > 0
|
|
15
|
+
? formatSpecsForPrompt(ctx.existingSpecs)
|
|
16
|
+
: 'No existing specs found for this route family.';
|
|
17
|
+
const changedFilesBlock = ctx.changedFiles
|
|
18
|
+
.map((f) => {
|
|
19
|
+
if (f.snippet) {
|
|
20
|
+
return `${f.path}:\n\`\`\`\n${f.snippet}\n\`\`\``;
|
|
21
|
+
}
|
|
22
|
+
return f.path;
|
|
23
|
+
})
|
|
24
|
+
.join('\n\n');
|
|
25
|
+
return [
|
|
26
|
+
'You are analyzing code changes in Mattermost to identify impacted user-facing flows.',
|
|
27
|
+
'',
|
|
28
|
+
`ROUTE FAMILY: ${ctx.family.id}`,
|
|
29
|
+
`ROUTES: ${familyRoutes}`,
|
|
30
|
+
featureNote,
|
|
31
|
+
'',
|
|
32
|
+
`PAGE OBJECTS AND COMPONENTS:`,
|
|
33
|
+
apiSurfaceBlock,
|
|
34
|
+
'',
|
|
35
|
+
`EXISTING SPECS FOR THIS FAMILY (${ctx.existingSpecs.length}):`,
|
|
36
|
+
specsBlock,
|
|
37
|
+
'',
|
|
38
|
+
`CHANGED FILES (${ctx.changedFiles.length}):`,
|
|
39
|
+
changedFilesBlock,
|
|
40
|
+
'',
|
|
41
|
+
ctx.contextBlock,
|
|
42
|
+
'',
|
|
43
|
+
'For each changed file, identify impacted user-facing flows.',
|
|
44
|
+
'',
|
|
45
|
+
'Return strict JSON only with this shape:',
|
|
46
|
+
'{"flows":[{"id":"<flow_id>","name":"<human readable name>","route":"<specific route from ROUTES>","userActions":["<what the user does>"],"priority":"P0|P1|P2","confidence":0-100,"evidence":"<why this flow is impacted>","pageObjects":["<page object used>"],"changedFiles":["<files>"]}]}',
|
|
47
|
+
'',
|
|
48
|
+
'Rules:',
|
|
49
|
+
'- ONLY use routes listed in ROUTES above.',
|
|
50
|
+
'- ONLY reference page objects and components listed above.',
|
|
51
|
+
'- Each flow must describe a specific user action, not a generic category.',
|
|
52
|
+
'- If you cannot determine the impacted flow with high confidence, return:',
|
|
53
|
+
' {"id":"unknown","name":"cannot determine","confidence":0,"evidence":"<reason>","userActions":[],"changedFiles":["<files>"]}',
|
|
54
|
+
'- Do NOT default to /admin_console/reporting/system_analytics unless the changed files are literally analytics code.',
|
|
55
|
+
'- Do NOT invent routes, page objects, or methods that are not listed above.',
|
|
56
|
+
'- Keep at most 8 flows.',
|
|
57
|
+
'- Prioritize true user-impacting flows; avoid low-value internal buckets.',
|
|
58
|
+
].filter(Boolean).join('\n');
|
|
59
|
+
}
|
|
60
|
+
export function parseImpactResponse(text) {
|
|
61
|
+
// Try to extract JSON from the response
|
|
62
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
63
|
+
const candidates = fenced ? [fenced[1], text] : [text];
|
|
64
|
+
for (const candidate of candidates) {
|
|
65
|
+
const start = candidate.indexOf('{');
|
|
66
|
+
const end = candidate.lastIndexOf('}');
|
|
67
|
+
if (start < 0 || end <= start) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const raw = candidate.slice(start, end + 1);
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(raw);
|
|
73
|
+
if (parsed && Array.isArray(parsed.flows)) {
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
export const EVIDENCE_THRESHOLDS = {
|
|
4
|
+
minConfidenceForAction: 40,
|
|
5
|
+
minConfidenceForGeneration: 60,
|
|
6
|
+
cannotDetermineBelow: 30,
|
|
7
|
+
highConfidenceAbove: 75,
|
|
8
|
+
};
|
|
9
|
+
export function computeConfidence(check) {
|
|
10
|
+
let score = 0;
|
|
11
|
+
if (check.hasRouteFamily) {
|
|
12
|
+
score += 25;
|
|
13
|
+
}
|
|
14
|
+
if (check.hasSpecificRoute) {
|
|
15
|
+
score += 15;
|
|
16
|
+
}
|
|
17
|
+
if (check.hasPageObject) {
|
|
18
|
+
score += 20;
|
|
19
|
+
}
|
|
20
|
+
if (check.hasUserAction) {
|
|
21
|
+
score += 25;
|
|
22
|
+
}
|
|
23
|
+
if (check.hasExistingSpecCited) {
|
|
24
|
+
score += 15;
|
|
25
|
+
}
|
|
26
|
+
return Math.min(100, score);
|
|
27
|
+
}
|
|
28
|
+
export function classifyConfidence(confidence) {
|
|
29
|
+
if (confidence >= EVIDENCE_THRESHOLDS.highConfidenceAbove) {
|
|
30
|
+
return 'high';
|
|
31
|
+
}
|
|
32
|
+
if (confidence >= EVIDENCE_THRESHOLDS.minConfidenceForAction) {
|
|
33
|
+
return 'medium';
|
|
34
|
+
}
|
|
35
|
+
return 'low';
|
|
36
|
+
}
|
|
37
|
+
export function shouldForceCannotDetermine(confidence) {
|
|
38
|
+
return confidence < EVIDENCE_THRESHOLDS.cannotDetermineBelow;
|
|
39
|
+
}
|
|
40
|
+
export function validateRouteAgainstManifest(route, familyId, manifest) {
|
|
41
|
+
const family = manifest.families.find((f) => f.id === familyId);
|
|
42
|
+
if (!family) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
// Check family-level routes
|
|
46
|
+
for (const pattern of family.routes) {
|
|
47
|
+
if (routeMatchesPattern(route, pattern)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Check feature-level routes
|
|
52
|
+
if (family.features) {
|
|
53
|
+
for (const feature of family.features) {
|
|
54
|
+
if (feature.routes) {
|
|
55
|
+
for (const pattern of feature.routes) {
|
|
56
|
+
if (routeMatchesPattern(route, pattern)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
function routeMatchesPattern(route, pattern) {
|
|
66
|
+
// Convert route pattern like /{team}/channels/{channel} to regex
|
|
67
|
+
const regexStr = pattern
|
|
68
|
+
.replace(/\{[^}]+\}/g, '[^/]+')
|
|
69
|
+
.replace(/\//g, '\\/');
|
|
70
|
+
try {
|
|
71
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
72
|
+
return regex.test(route);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return route === pattern || route.startsWith(pattern);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function computeCannotDetermineRatio(decisions) {
|
|
79
|
+
if (decisions.length === 0) {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const cannotDetermineCount = decisions.filter((d) => d.action === 'cannot_determine').length;
|
|
83
|
+
return cannotDetermineCount / decisions.length;
|
|
84
|
+
}
|
|
85
|
+
export function computeOverallConfidence(decisions) {
|
|
86
|
+
if (decisions.length === 0) {
|
|
87
|
+
return 'low';
|
|
88
|
+
}
|
|
89
|
+
const actionable = decisions.filter((d) => d.action !== 'cannot_determine');
|
|
90
|
+
if (actionable.length === 0) {
|
|
91
|
+
return 'low';
|
|
92
|
+
}
|
|
93
|
+
const avgConfidence = actionable.reduce((sum, d) => sum + d.confidence, 0) / actionable.length;
|
|
94
|
+
return classifyConfidence(avgConfidence);
|
|
95
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
const VALID_ACTIONS = ['run_existing', 'add_scenarios', 'create_spec', 'cannot_determine'];
|
|
4
|
+
const VALID_PRIORITIES = ['P0', 'P1', 'P2'];
|
|
5
|
+
const VALID_SOURCES = ['ai', 'catalog', 'traceability', 'deterministic'];
|
|
6
|
+
export function validateFlowDecision(decision) {
|
|
7
|
+
const errors = [];
|
|
8
|
+
if (!decision || typeof decision !== 'object') {
|
|
9
|
+
return { valid: false, errors: ['Decision must be a non-null object'] };
|
|
10
|
+
}
|
|
11
|
+
const d = decision;
|
|
12
|
+
if (typeof d.flowId !== 'string' || !d.flowId) {
|
|
13
|
+
errors.push('flowId is required');
|
|
14
|
+
}
|
|
15
|
+
if (typeof d.flowName !== 'string' || !d.flowName) {
|
|
16
|
+
errors.push('flowName is required');
|
|
17
|
+
}
|
|
18
|
+
if (typeof d.routeFamily !== 'string' || !d.routeFamily) {
|
|
19
|
+
errors.push('routeFamily is required');
|
|
20
|
+
}
|
|
21
|
+
if (!Array.isArray(d.changedFiles)) {
|
|
22
|
+
errors.push('changedFiles must be an array');
|
|
23
|
+
}
|
|
24
|
+
if (typeof d.evidence !== 'string') {
|
|
25
|
+
errors.push('evidence is required');
|
|
26
|
+
}
|
|
27
|
+
if (!VALID_SOURCES.includes(d.evidenceSource)) {
|
|
28
|
+
errors.push(`evidenceSource must be one of: ${VALID_SOURCES.join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
if (typeof d.confidence !== 'number' || d.confidence < 0 || d.confidence > 100) {
|
|
31
|
+
errors.push('confidence must be a number between 0 and 100');
|
|
32
|
+
}
|
|
33
|
+
if (!VALID_ACTIONS.includes(d.action)) {
|
|
34
|
+
errors.push(`action must be one of: ${VALID_ACTIONS.join(', ')}`);
|
|
35
|
+
}
|
|
36
|
+
if (!VALID_PRIORITIES.includes(d.priority)) {
|
|
37
|
+
errors.push(`priority must be one of: ${VALID_PRIORITIES.join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
if (d.action === 'cannot_determine' && (typeof d.blockingReason !== 'string' || !d.blockingReason)) {
|
|
40
|
+
errors.push('blockingReason is required when action is cannot_determine');
|
|
41
|
+
}
|
|
42
|
+
if (d.action === 'add_scenarios' && (!Array.isArray(d.scenariosToAdd) || d.scenariosToAdd.length === 0)) {
|
|
43
|
+
errors.push('scenariosToAdd is required when action is add_scenarios');
|
|
44
|
+
}
|
|
45
|
+
return { valid: errors.length === 0, errors };
|
|
46
|
+
}
|
|
47
|
+
export function buildSummary(decisions) {
|
|
48
|
+
const families = new Set();
|
|
49
|
+
const actions = { run_existing: 0, add_scenarios: 0, create_spec: 0, cannot_determine: 0 };
|
|
50
|
+
let covered = 0;
|
|
51
|
+
let partial = 0;
|
|
52
|
+
let uncovered = 0;
|
|
53
|
+
for (const d of decisions) {
|
|
54
|
+
families.add(d.routeFamily);
|
|
55
|
+
actions[d.action]++;
|
|
56
|
+
if (d.action === 'run_existing') {
|
|
57
|
+
covered++;
|
|
58
|
+
}
|
|
59
|
+
else if (d.action === 'add_scenarios') {
|
|
60
|
+
partial++;
|
|
61
|
+
}
|
|
62
|
+
else if (d.action === 'create_spec') {
|
|
63
|
+
uncovered++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const actionable = decisions.filter((d) => d.action !== 'cannot_determine');
|
|
67
|
+
const avgConfidence = actionable.length > 0
|
|
68
|
+
? actionable.reduce((sum, d) => sum + d.confidence, 0) / actionable.length
|
|
69
|
+
: 0;
|
|
70
|
+
return {
|
|
71
|
+
changedFiles: new Set(decisions.flatMap((d) => d.changedFiles)).size,
|
|
72
|
+
routeFamiliesImpacted: Array.from(families).sort(),
|
|
73
|
+
flowsIdentified: decisions.length,
|
|
74
|
+
flowsCovered: covered,
|
|
75
|
+
flowsPartial: partial,
|
|
76
|
+
flowsUncovered: uncovered,
|
|
77
|
+
actionsRequired: actions,
|
|
78
|
+
overallConfidence: avgConfidence >= 75 ? 'high' : avgConfidence >= 40 ? 'medium' : 'low',
|
|
79
|
+
};
|
|
80
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,4 +28,21 @@ export { ingestTraceabilityInput } from './agent/traceability_ingest.js';
|
|
|
28
28
|
export type { TraceabilityIngestOptions, TraceabilityIngestResult, TraceabilityIngestEntry } from './agent/traceability_ingest.js';
|
|
29
29
|
export { captureTraceabilityInput } from './agent/traceability_capture.js';
|
|
30
30
|
export type { TraceabilityCaptureOptions, TraceabilityCaptureResult } from './agent/traceability_capture.js';
|
|
31
|
+
export { runPipeline } from './pipeline/orchestrator.js';
|
|
32
|
+
export type { PipelineConfig, PipelineResult } from './pipeline/orchestrator.js';
|
|
33
|
+
export type { FlowDecision, FlowDecisionReport, FlowDecisionSummary, FlowAction, EvidenceSource } from './validation/output_schema.js';
|
|
34
|
+
export { runGenerationStage } from './pipeline/stage3_generation.js';
|
|
35
|
+
export type { GenerationConfig, GenerationResult, GeneratedSpec } from './pipeline/stage3_generation.js';
|
|
36
|
+
export { buildGenerationPrompt, parseGenerationResponse, detectHallucinatedMethods } from './prompts/generation.js';
|
|
37
|
+
export type { GenerationPromptContext, GenerationAgentResponse } from './prompts/generation.js';
|
|
38
|
+
export { runHealStage, healFromReport, resolveHealTargets, renderHealMarkdown } from './pipeline/stage4_heal.js';
|
|
39
|
+
export type { HealConfig, HealTarget, HealResult } from './pipeline/stage4_heal.js';
|
|
40
|
+
export { buildHealPrompt, buildQualityFixPrompt } from './prompts/heal.js';
|
|
41
|
+
export type { HealPromptContext } from './prompts/heal.js';
|
|
42
|
+
export { loadRouteFamilyManifest, bindFilesToFamilies } from './knowledge/route_families.js';
|
|
43
|
+
export type { RouteFamily, RouteFeature, RouteFamilyManifest, FileBinding } from './knowledge/route_families.js';
|
|
44
|
+
export { buildApiSurface, loadOrBuildApiSurface } from './knowledge/api_surface.js';
|
|
45
|
+
export type { ApiSurfaceCatalog, PageObjectSurface } from './knowledge/api_surface.js';
|
|
46
|
+
export { buildSpecIndex, getSpecsForFamily } from './knowledge/spec_index.js';
|
|
47
|
+
export type { SpecIndex, SpecEntry } from './knowledge/spec_index.js';
|
|
31
48
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAGH,YAAY,EACR,WAAW,EACX,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,GACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,gBAAgB,EAAE,0BAA0B,EAAC,MAAM,yBAAyB,CAAC;AAGrF,OAAO,EAAC,iBAAiB,EAAE,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAC,kBAAkB,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAChF,YAAY,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,UAAU,CAAC;AACjI,YAAY,EACR,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,4BAA4B,EAC5B,6BAA6B,GAChC,MAAM,UAAU,CAAC;AAClB,OAAO,EAAC,0BAA0B,EAAE,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAChF,YAAY,EAAC,2BAA2B,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAC,6BAA6B,EAAE,4BAA4B,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAC,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACvE,YAAY,EAAC,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACjI,OAAO,EAAC,wBAAwB,EAAC,MAAM,iCAAiC,CAAC;AACzE,YAAY,EAAC,0BAA0B,EAAE,yBAAyB,EAAC,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.captureTraceability = exports.ingestTraceability = exports.handoffGeneratedTests = exports.recommendTests = exports.findGaps = exports.analyzeImpact = exports.validateProviderSetup = exports.LLMProviderFactory = exports.CustomProvider = exports.checkOpenAISetup = exports.OpenAIProvider = exports.checkOllamaSetup = exports.OllamaProvider = exports.checkAnthropicSetup = exports.AnthropicProvider = exports.UnsupportedCapabilityError = exports.LLMProviderError = void 0;
|
|
5
|
+
exports.getSpecsForFamily = exports.buildSpecIndex = exports.loadOrBuildApiSurface = exports.buildApiSurface = exports.bindFilesToFamilies = exports.loadRouteFamilyManifest = exports.buildQualityFixPrompt = exports.buildHealPrompt = exports.renderHealMarkdown = exports.resolveHealTargets = exports.healFromReport = exports.runHealStage = exports.detectHallucinatedMethods = exports.parseGenerationResponse = exports.buildGenerationPrompt = exports.runGenerationStage = exports.runPipeline = exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.captureTraceability = exports.ingestTraceability = exports.handoffGeneratedTests = exports.recommendTests = exports.findGaps = exports.analyzeImpact = exports.validateProviderSetup = exports.LLMProviderFactory = exports.CustomProvider = exports.checkOpenAISetup = exports.OpenAIProvider = exports.checkOllamaSetup = exports.OllamaProvider = exports.checkAnthropicSetup = exports.AnthropicProvider = exports.UnsupportedCapabilityError = exports.LLMProviderError = void 0;
|
|
6
6
|
var provider_interface_js_1 = require("./provider_interface.js");
|
|
7
7
|
Object.defineProperty(exports, "LLMProviderError", { enumerable: true, get: function () { return provider_interface_js_1.LLMProviderError; } });
|
|
8
8
|
Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return provider_interface_js_1.UnsupportedCapabilityError; } });
|
|
@@ -39,3 +39,30 @@ var traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
|
39
39
|
Object.defineProperty(exports, "ingestTraceabilityInput", { enumerable: true, get: function () { return traceability_ingest_js_1.ingestTraceabilityInput; } });
|
|
40
40
|
var traceability_capture_js_1 = require("./agent/traceability_capture.js");
|
|
41
41
|
Object.defineProperty(exports, "captureTraceabilityInput", { enumerable: true, get: function () { return traceability_capture_js_1.captureTraceabilityInput; } });
|
|
42
|
+
// Pipeline API (route-family-bound impact analysis)
|
|
43
|
+
var orchestrator_js_1 = require("./pipeline/orchestrator.js");
|
|
44
|
+
Object.defineProperty(exports, "runPipeline", { enumerable: true, get: function () { return orchestrator_js_1.runPipeline; } });
|
|
45
|
+
var stage3_generation_js_1 = require("./pipeline/stage3_generation.js");
|
|
46
|
+
Object.defineProperty(exports, "runGenerationStage", { enumerable: true, get: function () { return stage3_generation_js_1.runGenerationStage; } });
|
|
47
|
+
var generation_js_1 = require("./prompts/generation.js");
|
|
48
|
+
Object.defineProperty(exports, "buildGenerationPrompt", { enumerable: true, get: function () { return generation_js_1.buildGenerationPrompt; } });
|
|
49
|
+
Object.defineProperty(exports, "parseGenerationResponse", { enumerable: true, get: function () { return generation_js_1.parseGenerationResponse; } });
|
|
50
|
+
Object.defineProperty(exports, "detectHallucinatedMethods", { enumerable: true, get: function () { return generation_js_1.detectHallucinatedMethods; } });
|
|
51
|
+
var stage4_heal_js_1 = require("./pipeline/stage4_heal.js");
|
|
52
|
+
Object.defineProperty(exports, "runHealStage", { enumerable: true, get: function () { return stage4_heal_js_1.runHealStage; } });
|
|
53
|
+
Object.defineProperty(exports, "healFromReport", { enumerable: true, get: function () { return stage4_heal_js_1.healFromReport; } });
|
|
54
|
+
Object.defineProperty(exports, "resolveHealTargets", { enumerable: true, get: function () { return stage4_heal_js_1.resolveHealTargets; } });
|
|
55
|
+
Object.defineProperty(exports, "renderHealMarkdown", { enumerable: true, get: function () { return stage4_heal_js_1.renderHealMarkdown; } });
|
|
56
|
+
var heal_js_1 = require("./prompts/heal.js");
|
|
57
|
+
Object.defineProperty(exports, "buildHealPrompt", { enumerable: true, get: function () { return heal_js_1.buildHealPrompt; } });
|
|
58
|
+
Object.defineProperty(exports, "buildQualityFixPrompt", { enumerable: true, get: function () { return heal_js_1.buildQualityFixPrompt; } });
|
|
59
|
+
// Knowledge modules
|
|
60
|
+
var route_families_js_1 = require("./knowledge/route_families.js");
|
|
61
|
+
Object.defineProperty(exports, "loadRouteFamilyManifest", { enumerable: true, get: function () { return route_families_js_1.loadRouteFamilyManifest; } });
|
|
62
|
+
Object.defineProperty(exports, "bindFilesToFamilies", { enumerable: true, get: function () { return route_families_js_1.bindFilesToFamilies; } });
|
|
63
|
+
var api_surface_js_1 = require("./knowledge/api_surface.js");
|
|
64
|
+
Object.defineProperty(exports, "buildApiSurface", { enumerable: true, get: function () { return api_surface_js_1.buildApiSurface; } });
|
|
65
|
+
Object.defineProperty(exports, "loadOrBuildApiSurface", { enumerable: true, get: function () { return api_surface_js_1.loadOrBuildApiSurface; } });
|
|
66
|
+
var spec_index_js_1 = require("./knowledge/spec_index.js");
|
|
67
|
+
Object.defineProperty(exports, "buildSpecIndex", { enumerable: true, get: function () { return spec_index_js_1.buildSpecIndex; } });
|
|
68
|
+
Object.defineProperty(exports, "getSpecsForFamily", { enumerable: true, get: function () { return spec_index_js_1.getSpecsForFamily; } });
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface MethodSignature {
|
|
2
|
+
name: string;
|
|
3
|
+
kind: 'method' | 'property' | 'getter';
|
|
4
|
+
}
|
|
5
|
+
export interface PageObjectSurface {
|
|
6
|
+
className: string;
|
|
7
|
+
file: string;
|
|
8
|
+
methods: MethodSignature[];
|
|
9
|
+
}
|
|
10
|
+
export interface ApiSurfaceCatalog {
|
|
11
|
+
pageObjects: PageObjectSurface[];
|
|
12
|
+
generatedAt: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiSurfaceConfig {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
pageObjectsDir?: string;
|
|
17
|
+
componentsDir?: string;
|
|
18
|
+
cachePath?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildApiSurface(testsRoot: string, config?: ApiSurfaceConfig): ApiSurfaceCatalog;
|
|
21
|
+
export declare function loadOrBuildApiSurface(testsRoot: string, config?: ApiSurfaceConfig): ApiSurfaceCatalog;
|
|
22
|
+
export declare function getMethodsForPageObject(catalog: ApiSurfaceCatalog, className: string): MethodSignature[];
|
|
23
|
+
export declare function validateMethodCall(catalog: ApiSurfaceCatalog, className: string, methodName: string): boolean;
|
|
24
|
+
export declare function formatApiSurfaceForPrompt(catalog: ApiSurfaceCatalog, classNames: string[]): string;
|
|
25
|
+
//# sourceMappingURL=api_surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api_surface.d.ts","sourceRoot":"","sources":["../../src/knowledge/api_surface.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AA4GD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAiB/F;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAgCrG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CAGxG;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAG7G;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAqBlG"}
|