@taodigital/agents 0.0.0-stage → 1.2.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 (76) hide show
  1. package/README.md +99 -2
  2. package/dist/api-test-agent.d.ts +126 -0
  3. package/dist/api-test-agent.js +267 -0
  4. package/dist/artifact-intel-agent.d.ts +11 -0
  5. package/dist/artifact-intel-agent.js +152 -0
  6. package/dist/coverage-gap-agent.d.ts +25 -0
  7. package/dist/coverage-gap-agent.js +269 -0
  8. package/dist/coverage-map-agent.d.ts +15 -0
  9. package/dist/coverage-map-agent.js +255 -0
  10. package/dist/crawl-diff-agent.d.ts +27 -0
  11. package/dist/crawl-diff-agent.js +412 -0
  12. package/dist/data-agent.d.ts +101 -0
  13. package/dist/data-agent.js +2284 -0
  14. package/dist/document-agent.d.ts +10 -0
  15. package/dist/document-agent.js +32 -0
  16. package/dist/enhancement-agent.d.ts +48 -0
  17. package/dist/enhancement-agent.js +342 -0
  18. package/dist/field-detector-agent.d.ts +35 -0
  19. package/dist/field-detector-agent.js +220 -0
  20. package/dist/flow-agent.d.ts +130 -0
  21. package/dist/flow-agent.js +169 -0
  22. package/dist/github-agent.d.ts +18 -0
  23. package/dist/github-agent.js +39 -0
  24. package/dist/github-write-agent.d.ts +67 -0
  25. package/dist/github-write-agent.js +249 -0
  26. package/dist/grouping-agent.d.ts +18 -0
  27. package/dist/grouping-agent.js +338 -0
  28. package/dist/healing-agent.d.ts +73 -0
  29. package/dist/healing-agent.js +137 -0
  30. package/dist/index.d.ts +36 -0
  31. package/dist/index.js +67 -0
  32. package/dist/integration-test-agent.d.ts +118 -0
  33. package/dist/integration-test-agent.js +165 -0
  34. package/dist/label-assignment-agent.d.ts +15 -0
  35. package/dist/label-assignment-agent.js +97 -0
  36. package/dist/llm-config.d.ts +38 -0
  37. package/dist/llm-config.js +287 -0
  38. package/dist/llm-mock.d.ts +77 -0
  39. package/dist/llm-mock.js +192 -0
  40. package/dist/llm.d.ts +58 -0
  41. package/dist/llm.js +438 -0
  42. package/dist/nlp-agent.d.ts +208 -0
  43. package/dist/nlp-agent.js +340 -0
  44. package/dist/orchestrator.d.ts +285 -0
  45. package/dist/orchestrator.js +141 -0
  46. package/dist/plan-agent.d.ts +4 -0
  47. package/dist/plan-agent.js +200 -0
  48. package/dist/repo-scan-agent.d.ts +189 -0
  49. package/dist/repo-scan-agent.js +2032 -0
  50. package/dist/requirements-agent.d.ts +59 -0
  51. package/dist/requirements-agent.js +641 -0
  52. package/dist/scenario-agent.d.ts +20 -0
  53. package/dist/scenario-agent.js +123 -0
  54. package/dist/script-agent.d.ts +447 -0
  55. package/dist/script-agent.js +11813 -0
  56. package/dist/security-test-agent.d.ts +111 -0
  57. package/dist/security-test-agent.js +141 -0
  58. package/dist/skill-file-agent.d.ts +264 -0
  59. package/dist/skill-file-agent.js +3470 -0
  60. package/dist/step-coverage.d.ts +46 -0
  61. package/dist/step-coverage.js +288 -0
  62. package/dist/step-utils.d.ts +2 -0
  63. package/dist/step-utils.js +62 -0
  64. package/dist/test-case-agent.d.ts +206 -0
  65. package/dist/test-case-agent.js +2141 -0
  66. package/dist/test-import-agent.d.ts +148 -0
  67. package/dist/test-import-agent.js +3235 -0
  68. package/dist/test-script-agent.d.ts +16 -0
  69. package/dist/test-script-agent.js +48 -0
  70. package/dist/token-pricing.d.ts +14 -0
  71. package/dist/token-pricing.js +62 -0
  72. package/dist/types.d.ts +232 -0
  73. package/dist/types.js +7 -0
  74. package/dist/visual-agent.d.ts +114 -0
  75. package/dist/visual-agent.js +261 -0
  76. package/package.json +26 -4
@@ -0,0 +1,16 @@
1
+ export interface ExecutionStep {
2
+ stepNumber: number;
3
+ description: string;
4
+ action: 'navigate' | 'click' | 'fill' | 'select' | 'assert_visible' | 'assert_text' | 'assert_url' | 'wait' | 'screenshot' | 'hover' | 'press_key' | 'script' | 'setVariable';
5
+ selector?: string;
6
+ selectorStrategy?: 'css' | 'text' | 'role' | 'label';
7
+ value?: string;
8
+ url?: string;
9
+ timeout?: number;
10
+ optional?: boolean;
11
+ }
12
+ export declare function generateExecutionPlan(tenantId: string, testCase: {
13
+ title: string;
14
+ steps: unknown;
15
+ preconditions?: string | null;
16
+ }, baseUrl: string): Promise<ExecutionStep[]>;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateExecutionPlan = generateExecutionPlan;
4
+ const core_1 = require("@taodigital/core");
5
+ const llm_js_1 = require("./llm.js");
6
+ const llm_config_js_1 = require("./llm-config.js");
7
+ const SYSTEM_DEFAULT = `You are a test execution planner. Convert human-readable test steps into a structured JSON array of ExecutionStep objects.
8
+
9
+ Rules:
10
+ - Map "click on X" / "click X" / "tap X" → action: "click", selectorStrategy: "text", selector: "X"
11
+ - Map ANY fill/type/enter/input step "enter X in Y" / "type X in Y" / "fill X in Y" / "enter X into Y" / "type X into Y" / "input X in Y" → action: "fill", selectorStrategy: "label", selector: "<core label of Y — strip 'the', strip trailing 'field/input/box/area'>", value: "X"
12
+ - Map "navigate to X" / "go to X" / "open X" → action: "navigate", url: "X"
13
+ - Map "assert X visible" / "verify X is shown" → action: "assert_visible", selectorStrategy: "text", selector: "X"
14
+ - Map "assert X contains Y" → action: "assert_text", selector: "X", value: "Y"
15
+ - Map "wait N seconds" → action: "wait", timeout: N*1000
16
+ - Map "Execute script (setVariable): X" or anything ending with "-> script:setVariable" → action: "setVariable", value: "X"
17
+ - Map "Execute script: X" or anything ending with "-> script" → action: "script", value: "X"
18
+ - Use selectorStrategy: "label" for ALL form field interactions (inputs, textareas, selects) — the selector must be the SHORT visible label, not the full phrase like "the Username input field"
19
+ - Use selectorStrategy: "role" for buttons, checkboxes, links by their accessible name
20
+ - Use selectorStrategy: "text" for text-matched elements or assertions
21
+ - Use selectorStrategy: "css" only when a specific CSS selector is evident
22
+ - Keep selector values SHORT: "Username" not "the Username input field", "Email" not "email address input"
23
+ - Return ONLY the JSON array, no explanation`;
24
+ async function generateExecutionPlan(tenantId, testCase, baseUrl) {
25
+ const llmCfg = await (0, llm_config_js_1.getTaskAgentLLMConfig)(tenantId, 'testRunner');
26
+ const steps = Array.isArray(testCase.steps) ? testCase.steps : [];
27
+ const preconditions = typeof testCase.preconditions === 'string' && testCase.preconditions
28
+ ? [testCase.preconditions]
29
+ : [];
30
+ const prompt = [
31
+ preconditions.length > 0 ? `Preconditions: ${preconditions.join('. ')}` : '',
32
+ `Base URL: ${baseUrl}`,
33
+ `Test: ${testCase.title}`,
34
+ `Steps:\n${steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`,
35
+ ].filter(Boolean).join('\n\n');
36
+ const seed = (0, llm_js_1.deterministicSeed)(`${tenantId}:${testCase.title}:${steps.join('|').slice(0, 300)}:${baseUrl}`);
37
+ const system = await (0, core_1.getAgentPrompt)('test-script-execution', undefined, tenantId) ?? SYSTEM_DEFAULT;
38
+ const { text } = await (0, llm_js_1.askTracked)(system, prompt, llmCfg, 8192, undefined, { temperature: 0, seed });
39
+ try {
40
+ // Strip markdown fences if the model wraps in ```json ... ```
41
+ const cleaned = text.trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/, '');
42
+ const parsed = JSON.parse(cleaned);
43
+ return Array.isArray(parsed) ? parsed.map((s, i) => ({ ...s, stepNumber: i })) : [];
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
@@ -0,0 +1,14 @@
1
+ import type { LLMUsage } from '@taodigital/core';
2
+ export interface ProviderPricing {
3
+ inputPer1M: number;
4
+ outputPer1M: number;
5
+ cacheReadPer1M?: number;
6
+ cacheWritePer1M?: number;
7
+ }
8
+ export declare const PRICING: Record<string, ProviderPricing>;
9
+ /**
10
+ * Load pricing overrides from the LlmPricing DB table into the in-process cache.
11
+ * Call once at agent worker startup — does not require making estimateCost() async.
12
+ */
13
+ export declare function loadPricingOverrides(): Promise<void>;
14
+ export declare function estimateCost(usage: Omit<LLMUsage, 'estimatedCostUsd'>, providerKey: string): number;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PRICING = void 0;
4
+ exports.loadPricingOverrides = loadPricingOverrides;
5
+ exports.estimateCost = estimateCost;
6
+ const database_1 = require("@taodigital/database");
7
+ exports.PRICING = {
8
+ // Anthropic (as of mid-2025)
9
+ 'anthropic/claude-sonnet-4-6': { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
10
+ 'anthropic/claude-haiku-4-5': { inputPer1M: 0.80, outputPer1M: 4.00, cacheReadPer1M: 0.08, cacheWritePer1M: 1.00 },
11
+ 'anthropic/claude-opus-4-8': { inputPer1M: 15.00, outputPer1M: 75.00, cacheReadPer1M: 1.50, cacheWritePer1M: 18.75 },
12
+ 'anthropic/claude-3-5-sonnet-20241022': { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
13
+ // OpenAI
14
+ 'openai/gpt-4o': { inputPer1M: 2.50, outputPer1M: 10.00 },
15
+ 'openai/gpt-4o-mini': { inputPer1M: 0.15, outputPer1M: 0.60 },
16
+ 'openai/o3-mini': { inputPer1M: 1.10, outputPer1M: 4.40 },
17
+ // Gemini
18
+ 'gemini/gemini-2.5-pro': { inputPer1M: 1.25, outputPer1M: 10.00 },
19
+ 'gemini/gemini-2.0-flash': { inputPer1M: 0.10, outputPer1M: 0.40 },
20
+ // Grok
21
+ 'grok/grok-3': { inputPer1M: 3.00, outputPer1M: 15.00 },
22
+ // OpenRouter (acts as a router — pricing varies per routed model)
23
+ // Estimate using the underlying model's price
24
+ 'openrouter/*': { inputPer1M: 3.00, outputPer1M: 15.00 },
25
+ // Ollama (local — zero cost)
26
+ 'ollama/*': { inputPer1M: 0, outputPer1M: 0 },
27
+ };
28
+ // In-process cache loaded by loadPricingOverrides() at agent startup.
29
+ // Keys are "provider/model"; values override the static PRICING table.
30
+ const _pricingOverrides = new Map();
31
+ /**
32
+ * Load pricing overrides from the LlmPricing DB table into the in-process cache.
33
+ * Call once at agent worker startup — does not require making estimateCost() async.
34
+ */
35
+ async function loadPricingOverrides() {
36
+ try {
37
+ const rows = await database_1.prismaAdmin.llmPricing.findMany({
38
+ select: { modelKey: true, inputPer1M: true, outputPer1M: true, cacheReadPer1M: true, cacheWritePer1M: true },
39
+ });
40
+ for (const row of rows) {
41
+ _pricingOverrides.set(row.modelKey, {
42
+ inputPer1M: row.inputPer1M,
43
+ outputPer1M: row.outputPer1M,
44
+ cacheReadPer1M: row.cacheReadPer1M,
45
+ cacheWritePer1M: row.cacheWritePer1M,
46
+ });
47
+ }
48
+ }
49
+ catch { /* DB unavailable — fall back to static PRICING */ }
50
+ }
51
+ function estimateCost(usage, providerKey) {
52
+ const pricing = _pricingOverrides.get(providerKey)
53
+ ?? _pricingOverrides.get(`${usage.provider}/*`)
54
+ ?? exports.PRICING[providerKey]
55
+ ?? exports.PRICING[`${usage.provider}/*`]
56
+ ?? { inputPer1M: 3, outputPer1M: 15 };
57
+ const inputCost = (usage.promptTokens / 1_000_000) * pricing.inputPer1M;
58
+ const outputCost = (usage.completionTokens / 1_000_000) * pricing.outputPer1M;
59
+ const cacheRead = ((usage.cacheReadTokens ?? 0) / 1_000_000) * (pricing.cacheReadPer1M ?? 0);
60
+ const cacheWrite = ((usage.cacheWriteTokens ?? 0) / 1_000_000) * (pricing.cacheWritePer1M ?? 0);
61
+ return parseFloat((inputCost + outputCost + cacheRead + cacheWrite).toFixed(6));
62
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Gap 1: Contract interfaces for @taodigital/agents.
3
+ * Routes should import from this file and depend on interfaces, not implementations.
4
+ * This enables swapping agent implementations without touching route code.
5
+ */
6
+ import type { LLMConfig } from './llm.js';
7
+ export interface GenerateTestCasesOpts {
8
+ tenantId: string;
9
+ projectId: string;
10
+ screenId: string;
11
+ jobId?: string;
12
+ oversized?: boolean;
13
+ viewport?: string;
14
+ apiEndpoints?: Array<{
15
+ method: string;
16
+ urlPattern: string;
17
+ }>;
18
+ suiteNameOverride?: string;
19
+ force?: boolean;
20
+ fullCoverage?: boolean;
21
+ suiteLastGenAt?: Date;
22
+ /**
23
+ * 'append' (default) — deduplicates by content hash + grounding hash + title Jaccard.
24
+ * 'replace' — deletes existing AI-generated cases for this screen before inserting.
25
+ * 'edit' — upserts: updates steps/gherkin/expectedResult on matched cases.
26
+ */
27
+ mode?: 'replace' | 'append' | 'edit';
28
+ repository?: {
29
+ getChangedScreenIds: (tenantId: string, projectId: string, sinceDate: Date) => Promise<string[]>;
30
+ };
31
+ llmCfg?: LLMConfig;
32
+ fastPassLlmCfg?: LLMConfig;
33
+ /** Override hardcoded GLOBAL_RULES_FALLBACK — load via agent-prompts.ts before calling. */
34
+ globalRules?: string;
35
+ }
36
+ export interface GenerateTestCasesResult {
37
+ skipped?: boolean;
38
+ reason?: string;
39
+ existingCaseCount?: number;
40
+ saved?: unknown[];
41
+ cases?: unknown[];
42
+ }
43
+ export interface RegenerateTestCaseTitleOpts {
44
+ tenantId: string;
45
+ testCaseId: string;
46
+ currentTitle: string;
47
+ screenName?: string;
48
+ steps?: string[];
49
+ expectedResult?: string;
50
+ kind?: string;
51
+ attempt?: number;
52
+ }
53
+ export interface TestGenerationAgent {
54
+ generateTestCases(opts: GenerateTestCasesOpts): Promise<GenerateTestCasesResult>;
55
+ regenerateTestCaseTitle(opts: RegenerateTestCaseTitleOpts): Promise<{
56
+ title: string;
57
+ }>;
58
+ }
59
+ export interface GenerateTestDataOpts {
60
+ tenantId: string;
61
+ projectId: string;
62
+ testCaseId: string;
63
+ jobId?: string;
64
+ targetCount?: number;
65
+ /** Called at key pipeline stages with real progress (0–95). */
66
+ onProgress?: (pct: number, step: string) => void;
67
+ }
68
+ export interface GenerateTestDataBatchCase {
69
+ id: string;
70
+ title: string;
71
+ steps: string[];
72
+ expectedResult: string;
73
+ preconditions?: string;
74
+ testDataInline?: object;
75
+ }
76
+ export interface GenerateTestDataBatchOpts {
77
+ llmCfg?: LLMConfig;
78
+ skillFile?: string;
79
+ tenantId?: string;
80
+ projectId?: string;
81
+ }
82
+ export interface GenerateTestDataResult {
83
+ dataSets: unknown[];
84
+ saved: unknown[];
85
+ skipped?: boolean;
86
+ reason?: string;
87
+ mode?: string;
88
+ source?: string;
89
+ }
90
+ export interface TestDataAgent {
91
+ generateTestData(opts: GenerateTestDataOpts): Promise<GenerateTestDataResult>;
92
+ generateTestDataBatch(cases: GenerateTestDataBatchCase[], options?: GenerateTestDataBatchOpts): Promise<Map<string, unknown>>;
93
+ }
94
+ export interface GenerateTestScriptOpts {
95
+ tenantId: string;
96
+ projectId: string;
97
+ testCaseId: string;
98
+ language?: string;
99
+ /** When true, derive and persist repoTargetPath on the test case for IDE push. */
100
+ useV2?: boolean;
101
+ jobId?: string;
102
+ /** Pre-extracted Playwright locators from the live page. */
103
+ extractedLocators?: Array<{
104
+ key: string;
105
+ expression: string;
106
+ description: string;
107
+ confidence: string;
108
+ }>;
109
+ /** Repo style profile — avoids internal re-query and ensures pomPaths() gets correct directories. */
110
+ styleProfile?: Record<string, unknown>;
111
+ /** Existing page-object inventory from the repo connection. */
112
+ pageObjectInventory?: Array<{
113
+ filePath: string;
114
+ className: string;
115
+ methods: Array<{
116
+ name: string;
117
+ params: string;
118
+ returnType: string;
119
+ }>;
120
+ importPath: string;
121
+ }>;
122
+ /** Optional user instruction to override or guide the LLM during regeneration. */
123
+ instructionOverride?: string;
124
+ }
125
+ export interface GenerateTestScriptResult {
126
+ language: string;
127
+ code: string;
128
+ files: Array<{
129
+ filename: string;
130
+ code: string;
131
+ path: string;
132
+ testCaseId: string;
133
+ role: string;
134
+ }>;
135
+ saved: unknown;
136
+ lintViolations: unknown[];
137
+ }
138
+ export interface GenerateSuiteScriptOpts {
139
+ tenantId: string;
140
+ projectId: string;
141
+ suiteId: string;
142
+ language?: string;
143
+ caseIds?: string[];
144
+ useV2?: boolean;
145
+ styleProfile?: Record<string, unknown>;
146
+ pageObjectInventory?: Array<{
147
+ filePath: string;
148
+ className: string;
149
+ methods: Array<{
150
+ name: string;
151
+ params: string;
152
+ returnType: string;
153
+ }>;
154
+ importPath: string;
155
+ }>;
156
+ onProgress?: (done: number, total: number) => void;
157
+ jobId?: string;
158
+ }
159
+ export interface GenerateSuiteScriptResult {
160
+ language: string;
161
+ files: Array<{
162
+ filename: string;
163
+ code: string;
164
+ path?: string;
165
+ testCaseId?: string;
166
+ role?: string;
167
+ }>;
168
+ basePage: string | null;
169
+ }
170
+ export interface ScriptAgent {
171
+ generateTestScript(opts: GenerateTestScriptOpts): Promise<GenerateTestScriptResult>;
172
+ generateSuiteScript(opts: GenerateSuiteScriptOpts): Promise<GenerateSuiteScriptResult>;
173
+ }
174
+ export interface GenerateScenariosOpts {
175
+ tenantId: string;
176
+ projectId: string;
177
+ requirement: {
178
+ reqId: string;
179
+ title: string;
180
+ actor?: string;
181
+ type?: string;
182
+ priority?: string;
183
+ acceptanceCriteria?: string[];
184
+ businessRules?: string[];
185
+ };
186
+ /** Number of scenarios to generate. Default 4, min 1, max 10. */
187
+ count?: number;
188
+ }
189
+ /** Mirrors the ScenarioOutput interface defined in scenario-agent.ts */
190
+ export interface ScenarioOutput {
191
+ title: string;
192
+ description?: string;
193
+ gherkin: string;
194
+ }
195
+ export interface ScenarioAgent {
196
+ generateScenarios(opts: GenerateScenariosOpts): Promise<ScenarioOutput[]>;
197
+ }
198
+ export interface ConvertNlpToTestOpts {
199
+ tenantId: string;
200
+ projectId: string;
201
+ description: string;
202
+ suiteId?: string;
203
+ }
204
+ export interface ConvertNlpToTestResult {
205
+ confidence?: number;
206
+ understoodIntent?: string;
207
+ unmatchedTerms?: string[];
208
+ testCase?: {
209
+ title: string;
210
+ kind: string;
211
+ steps: string[];
212
+ expectedResult: string;
213
+ groundedOn: string[];
214
+ };
215
+ saved?: unknown;
216
+ warning?: string;
217
+ error?: string;
218
+ description?: string;
219
+ }
220
+ export interface NlpAgent {
221
+ convertNlpToTest(opts: ConvertNlpToTestOpts): Promise<ConvertNlpToTestResult>;
222
+ }
223
+ export interface SkillFileAgent {
224
+ refreshTestCasesSkillFile(tenantId: string, projectId: string): Promise<void>;
225
+ refreshTestDataSkillFile(tenantId: string, projectId: string): Promise<void>;
226
+ refreshTestScriptSkillFile(tenantId: string, projectId: string): Promise<void>;
227
+ refreshRequirementsCoverageSkillFile(tenantId: string, projectId: string): Promise<void>;
228
+ refreshCoverageMatrix(tenantId: string, projectId: string): Promise<void>;
229
+ refreshTestCaseInventory(tenantId: string, projectId: string): Promise<void>;
230
+ refreshScriptInventory(tenantId: string, projectId: string): Promise<void>;
231
+ refreshFieldCatalogSkillFile(tenantId: string, projectId: string): Promise<void>;
232
+ }
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Gap 1: Contract interfaces for @taodigital/agents.
4
+ * Routes should import from this file and depend on interfaces, not implementations.
5
+ * This enables swapping agent implementations without touching route code.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,114 @@
1
+ /**
2
+ * ZeTa-AI Visual Intelligence Agent
3
+ *
4
+ * Handles visual regression testing:
5
+ * 1. On first crawl — save screenshots as baselines.
6
+ * 2. On subsequent crawls — compare new screenshots to baselines.
7
+ * 3. AI analyzes diffs: meaningful change vs. rendering noise.
8
+ * 4. Generates bug report drafts for critical visual changes.
9
+ *
10
+ * Phase 2: Vision AI integration (uses Claude's vision capability).
11
+ * Phase 1: Pixel-diff fallback (no vision AI needed yet).
12
+ */
13
+ export interface VisualComparisonResult {
14
+ screenId: string;
15
+ changeType: 'NONE' | 'MINOR' | 'SIGNIFICANT' | 'CRITICAL';
16
+ diffScore: number;
17
+ changes: Array<{
18
+ description: string;
19
+ location: string;
20
+ severity: string;
21
+ }>;
22
+ recommendation: 'APPROVE' | 'REVIEW' | 'FLAG' | 'BLOCK';
23
+ bugReportDraft?: {
24
+ title: string;
25
+ severity: string;
26
+ steps: string[];
27
+ expected: string;
28
+ actual: string;
29
+ };
30
+ }
31
+ /**
32
+ * Set or update the visual baseline for a screen.
33
+ * Called after the first successful crawl screenshot is stored.
34
+ */
35
+ export declare function setVisualBaseline(opts: {
36
+ tenantId: string;
37
+ projectId: string;
38
+ screenId: string;
39
+ screenshotPath: string;
40
+ viewport?: string;
41
+ approvedBy?: string;
42
+ }): Promise<void>;
43
+ /**
44
+ * Compare a new screenshot against the stored baseline.
45
+ * Phase 1: returns a structural diff (element count change).
46
+ * Phase 2: Vision AI reads both images and produces rich analysis.
47
+ */
48
+ export declare function compareToBaseline(opts: {
49
+ tenantId: string;
50
+ projectId: string;
51
+ screenId: string;
52
+ newScreenshotPath: string;
53
+ screenName: string;
54
+ viewport?: string;
55
+ }): Promise<VisualComparisonResult | null>;
56
+ /**
57
+ * Update the ignored regions for a visual baseline.
58
+ * Regions are excluded from AI visual comparison (PHI masking, dynamic content).
59
+ * Each region is a rectangle in original image coordinates (before compression).
60
+ */
61
+ export declare function updateIgnoredRegions(opts: {
62
+ tenantId: string;
63
+ projectId: string;
64
+ screenId: string;
65
+ viewport?: string;
66
+ regions: Array<{
67
+ x: number;
68
+ y: number;
69
+ width: number;
70
+ height: number;
71
+ label?: string;
72
+ }>;
73
+ }): Promise<void>;
74
+ /**
75
+ * Set visual baselines for all standard viewports from a map of viewport→screenshotPath.
76
+ * Call after crawl completes with screenshots at each breakpoint.
77
+ */
78
+ export declare function setAllViewportBaselines(opts: {
79
+ tenantId: string;
80
+ projectId: string;
81
+ screenId: string;
82
+ screenshots: Partial<Record<'DESKTOP' | 'TABLET' | 'MOBILE', string>>;
83
+ approvedBy?: string;
84
+ }): Promise<void>;
85
+ /**
86
+ * Compare a screen against baselines for ALL viewports that have baselines stored.
87
+ * Returns a map of viewport → comparison result. Null value = no baseline for that viewport.
88
+ */
89
+ export declare function compareAllViewports(opts: {
90
+ tenantId: string;
91
+ projectId: string;
92
+ screenId: string;
93
+ screenName: string;
94
+ screenshots: Partial<Record<'DESKTOP' | 'TABLET' | 'MOBILE', string>>;
95
+ }): Promise<Record<string, VisualComparisonResult | null>>;
96
+ /**
97
+ * Phase 2: AI-powered visual comparison using Claude vision.
98
+ * This replaces the file-size proxy with real image understanding.
99
+ */
100
+ export declare function aiVisualCompare(opts: {
101
+ baselineImageBase64: string;
102
+ newImageBase64: string;
103
+ imageMediaType?: 'image/png' | 'image/jpeg';
104
+ screenName: string;
105
+ screenPurpose: string;
106
+ tenantId?: string;
107
+ projectId?: string;
108
+ }): Promise<{
109
+ changeType: string;
110
+ changes: any[];
111
+ recommendation: string;
112
+ diffScore: number;
113
+ summary: string;
114
+ }>;