@hover-dev/core 0.16.0 → 0.18.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 (181) hide show
  1. package/README.md +26 -55
  2. package/dist/agentDirectives.d.ts +55 -0
  3. package/dist/agentDirectives.d.ts.map +1 -0
  4. package/dist/agentDirectives.js +276 -0
  5. package/dist/engine.d.ts +28 -0
  6. package/dist/engine.d.ts.map +1 -0
  7. package/dist/engine.js +27 -0
  8. package/dist/memory/businessMemory.d.ts +29 -0
  9. package/dist/memory/businessMemory.d.ts.map +1 -0
  10. package/dist/memory/businessMemory.js +125 -0
  11. package/dist/playwright/launchChrome.d.ts +18 -0
  12. package/dist/playwright/launchChrome.d.ts.map +1 -1
  13. package/dist/playwright/launchChrome.js +46 -3
  14. package/dist/qa/candidates.d.ts +32 -0
  15. package/dist/qa/candidates.d.ts.map +1 -0
  16. package/dist/qa/candidates.js +20 -0
  17. package/dist/qa/intensity.d.ts +33 -0
  18. package/dist/qa/intensity.d.ts.map +1 -0
  19. package/dist/qa/intensity.js +25 -0
  20. package/dist/qa/qaReport.d.ts +19 -0
  21. package/dist/qa/qaReport.d.ts.map +1 -0
  22. package/dist/qa/qaReport.js +50 -0
  23. package/dist/sessions/sessions.d.ts +125 -0
  24. package/dist/sessions/sessions.d.ts.map +1 -0
  25. package/dist/sessions/sessions.js +175 -0
  26. package/dist/specs/authFixture.d.ts +30 -0
  27. package/dist/specs/authFixture.d.ts.map +1 -0
  28. package/dist/specs/authFixture.js +145 -0
  29. package/dist/specs/detectSharedFlows.d.ts +1 -1
  30. package/dist/specs/detectSharedFlows.d.ts.map +1 -1
  31. package/dist/specs/detectSharedFlows.js +20 -21
  32. package/dist/specs/generatePageObject.d.ts +1 -1
  33. package/dist/specs/generatePageObject.d.ts.map +1 -1
  34. package/dist/specs/healPrompt.d.ts +19 -0
  35. package/dist/specs/healPrompt.d.ts.map +1 -0
  36. package/dist/specs/healPrompt.js +48 -0
  37. package/dist/specs/humanSteps.d.ts +4 -8
  38. package/dist/specs/humanSteps.d.ts.map +1 -1
  39. package/dist/specs/humanSteps.js +6 -1
  40. package/dist/specs/optimizeSpec.d.ts +15 -8
  41. package/dist/specs/optimizeSpec.d.ts.map +1 -1
  42. package/dist/specs/optimizeSpec.js +71 -41
  43. package/dist/specs/pageObjectManifest.d.ts +3 -1
  44. package/dist/specs/pageObjectManifest.d.ts.map +1 -1
  45. package/dist/specs/pageObjectManifest.js +24 -19
  46. package/dist/specs/replayGrounded.d.ts +45 -0
  47. package/dist/specs/replayGrounded.d.ts.map +1 -0
  48. package/dist/specs/replayGrounded.js +155 -0
  49. package/dist/specs/runFailures.d.ts +34 -0
  50. package/dist/specs/runFailures.d.ts.map +1 -0
  51. package/dist/specs/runFailures.js +93 -0
  52. package/dist/specs/seeds.d.ts +16 -15
  53. package/dist/specs/seeds.d.ts.map +1 -1
  54. package/dist/specs/seeds.js +86 -54
  55. package/dist/specs/sidecar.d.ts +34 -6
  56. package/dist/specs/sidecar.d.ts.map +1 -1
  57. package/dist/specs/sidecar.js +79 -9
  58. package/dist/specs/specStep.d.ts +21 -0
  59. package/dist/specs/specStep.d.ts.map +1 -0
  60. package/dist/specs/specStep.js +1 -0
  61. package/dist/specs/text.d.ts +8 -6
  62. package/dist/specs/text.d.ts.map +1 -1
  63. package/dist/specs/text.js +10 -7
  64. package/dist/specs/writeSpec.d.ts +62 -1
  65. package/dist/specs/writeSpec.d.ts.map +1 -1
  66. package/dist/specs/writeSpec.js +596 -21
  67. package/package.json +9 -29
  68. package/dist/agents/aider.d.ts +0 -16
  69. package/dist/agents/aider.d.ts.map +0 -1
  70. package/dist/agents/aider.js +0 -161
  71. package/dist/agents/argv.d.ts +0 -11
  72. package/dist/agents/argv.d.ts.map +0 -1
  73. package/dist/agents/argv.js +0 -23
  74. package/dist/agents/claude.d.ts +0 -3
  75. package/dist/agents/claude.d.ts.map +0 -1
  76. package/dist/agents/claude.js +0 -195
  77. package/dist/agents/codex.d.ts +0 -19
  78. package/dist/agents/codex.d.ts.map +0 -1
  79. package/dist/agents/codex.js +0 -216
  80. package/dist/agents/cursor.d.ts +0 -18
  81. package/dist/agents/cursor.d.ts.map +0 -1
  82. package/dist/agents/cursor.js +0 -220
  83. package/dist/agents/detect.d.ts +0 -46
  84. package/dist/agents/detect.d.ts.map +0 -1
  85. package/dist/agents/detect.js +0 -80
  86. package/dist/agents/gemini.d.ts +0 -17
  87. package/dist/agents/gemini.d.ts.map +0 -1
  88. package/dist/agents/gemini.js +0 -186
  89. package/dist/agents/index.d.ts +0 -6
  90. package/dist/agents/index.d.ts.map +0 -1
  91. package/dist/agents/index.js +0 -5
  92. package/dist/agents/invoke.d.ts +0 -12
  93. package/dist/agents/invoke.d.ts.map +0 -1
  94. package/dist/agents/invoke.js +0 -96
  95. package/dist/agents/qwen.d.ts +0 -17
  96. package/dist/agents/qwen.d.ts.map +0 -1
  97. package/dist/agents/qwen.js +0 -172
  98. package/dist/agents/registry.d.ts +0 -19
  99. package/dist/agents/registry.d.ts.map +0 -1
  100. package/dist/agents/registry.js +0 -34
  101. package/dist/agents/shared.d.ts +0 -28
  102. package/dist/agents/shared.d.ts.map +0 -1
  103. package/dist/agents/shared.js +0 -35
  104. package/dist/agents/types.d.ts +0 -186
  105. package/dist/agents/types.d.ts.map +0 -1
  106. package/dist/agents/types.js +0 -23
  107. package/dist/index.d.ts +0 -3
  108. package/dist/index.d.ts.map +0 -1
  109. package/dist/index.js +0 -2
  110. package/dist/mcp/sourceFence.d.ts +0 -23
  111. package/dist/mcp/sourceFence.d.ts.map +0 -1
  112. package/dist/mcp/sourceFence.js +0 -75
  113. package/dist/mcp/sourceServer.d.ts +0 -3
  114. package/dist/mcp/sourceServer.d.ts.map +0 -1
  115. package/dist/mcp/sourceServer.js +0 -116
  116. package/dist/playwright/cdpStatus.d.ts +0 -29
  117. package/dist/playwright/cdpStatus.d.ts.map +0 -1
  118. package/dist/playwright/cdpStatus.js +0 -119
  119. package/dist/playwright/preflight.d.ts +0 -31
  120. package/dist/playwright/preflight.d.ts.map +0 -1
  121. package/dist/playwright/preflight.js +0 -82
  122. package/dist/playwright/preflightCache.d.ts +0 -27
  123. package/dist/playwright/preflightCache.d.ts.map +0 -1
  124. package/dist/playwright/preflightCache.js +0 -21
  125. package/dist/playwright/raiseWindow.d.ts +0 -10
  126. package/dist/playwright/raiseWindow.d.ts.map +0 -1
  127. package/dist/playwright/raiseWindow.js +0 -158
  128. package/dist/playwright/resolveMcpConfig.d.ts +0 -55
  129. package/dist/playwright/resolveMcpConfig.d.ts.map +0 -1
  130. package/dist/playwright/resolveMcpConfig.js +0 -66
  131. package/dist/plugin-api.d.ts +0 -235
  132. package/dist/plugin-api.d.ts.map +0 -1
  133. package/dist/plugin-api.js +0 -52
  134. package/dist/runSession.d.ts +0 -42
  135. package/dist/runSession.d.ts.map +0 -1
  136. package/dist/runSession.js +0 -81
  137. package/dist/scripts/bench-multi-tab.d.ts +0 -2
  138. package/dist/scripts/bench-multi-tab.d.ts.map +0 -1
  139. package/dist/scripts/bench-multi-tab.js +0 -192
  140. package/dist/scripts/bench-ttfb.d.ts +0 -2
  141. package/dist/scripts/bench-ttfb.d.ts.map +0 -1
  142. package/dist/scripts/bench-ttfb.js +0 -127
  143. package/dist/scripts/start-chrome.d.ts +0 -3
  144. package/dist/scripts/start-chrome.d.ts.map +0 -1
  145. package/dist/scripts/start-chrome.js +0 -23
  146. package/dist/service/cdpHandlers.d.ts +0 -44
  147. package/dist/service/cdpHandlers.d.ts.map +0 -1
  148. package/dist/service/cdpHandlers.js +0 -85
  149. package/dist/service/cdpHint.d.ts +0 -48
  150. package/dist/service/cdpHint.d.ts.map +0 -1
  151. package/dist/service/cdpHint.js +0 -216
  152. package/dist/service/conventions.d.ts +0 -8
  153. package/dist/service/conventions.d.ts.map +0 -1
  154. package/dist/service/conventions.js +0 -42
  155. package/dist/service/saveHandlers.d.ts +0 -52
  156. package/dist/service/saveHandlers.d.ts.map +0 -1
  157. package/dist/service/saveHandlers.js +0 -75
  158. package/dist/service/types.d.ts +0 -58
  159. package/dist/service/types.d.ts.map +0 -1
  160. package/dist/service/types.js +0 -26
  161. package/dist/service.d.ts +0 -50
  162. package/dist/service.d.ts.map +0 -1
  163. package/dist/service.js +0 -1065
  164. package/dist/skills/writeSkill.d.ts +0 -27
  165. package/dist/skills/writeSkill.d.ts.map +0 -1
  166. package/dist/skills/writeSkill.js +0 -13
  167. package/dist/specs/extractPageObjects.d.ts +0 -18
  168. package/dist/specs/extractPageObjects.d.ts.map +0 -1
  169. package/dist/specs/extractPageObjects.js +0 -98
  170. package/dist/specs/listSpecs.d.ts +0 -52
  171. package/dist/specs/listSpecs.d.ts.map +0 -1
  172. package/dist/specs/listSpecs.js +0 -139
  173. package/dist/specs/optimizationSuggestion.d.ts +0 -26
  174. package/dist/specs/optimizationSuggestion.d.ts.map +0 -1
  175. package/dist/specs/optimizationSuggestion.js +0 -28
  176. package/dist/specs/optimizeSpecWithAgent.d.ts +0 -11
  177. package/dist/specs/optimizeSpecWithAgent.d.ts.map +0 -1
  178. package/dist/specs/optimizeSpecWithAgent.js +0 -40
  179. package/dist/specs/writeCaseCsv.d.ts +0 -28
  180. package/dist/specs/writeCaseCsv.d.ts.map +0 -1
  181. package/dist/specs/writeCaseCsv.js +0 -134
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Session ledger — one summary JSON per completed agent run, appended under
3
+ * `.hover/sessions/`. The local console (S3) reads these for run history +
4
+ * spend; Hover Cloud sync (S4) uploads them as-is.
5
+ *
6
+ * Deliberately summary-only: full `SkillStep[]` lives in the spec sidecar for
7
+ * saved sessions and is dropped for unsaved ones (persisting unsaved
8
+ * transcripts is a privacy decision deferred to a future opt-in).
9
+ *
10
+ * Writes are best-effort: a ledger failure must never break a run or a save.
11
+ */
12
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
13
+ import { join } from 'node:path';
14
+ import { runDir, conversationsDir } from '../specs/sidecar.js';
15
+ export const SESSION_RECORD_VERSION = 2;
16
+ /** Unescape literal "\n" / "\r\n" / "\t" sequences (e.g. an agent double-escaped
17
+ * its newlines) into real whitespace so markdown renders properly. */
18
+ function deEsc(s) {
19
+ return s.replace(/\\r\\n/g, '\n').replace(/\\n/g, '\n').replace(/\\t/g, ' ');
20
+ }
21
+ /** Defensive leak-guard, NOT a parse path. The agent is directed to emit a
22
+ * plain-markdown report (REPORTING_DIRECTIVE) — no JSON. A non-compliant agent
23
+ * that still wraps its report in a ```json block would otherwise leak raw JSON
24
+ * to the UI, so strip it: recover the `summary` field as prose when present
25
+ * (tolerating unescaped quotes by matching up to `","findings"`), else drop the
26
+ * block. Findings are NEVER extracted from JSON — they come only from the
27
+ * markdown `## Findings` section below. */
28
+ function stripJsonArtifact(summary) {
29
+ const block = summary.match(/```json\s*([\s\S]*?)```/i);
30
+ if (!block)
31
+ return summary;
32
+ const sm = block[1].match(/"summary"\s*:\s*"([\s\S]*?)"\s*,\s*"findings"/i);
33
+ if (sm)
34
+ return deEsc(sm[1].replace(/\\"/g, '"')).trim();
35
+ return summary.replace(block[0], '').replace(/\n{3,}/g, '\n\n').trim();
36
+ }
37
+ /**
38
+ * Strip leaked function-call syntax a model sometimes emits as TEXT instead of
39
+ * actually invoking the tool — e.g. a final summary that ends with
40
+ * `call\n<invoke name="mcp__playwright__browser_wait_for">…</invoke>`. The model
41
+ * "writes out" the call (a known tool-calling glitch, common at end-of-turn /
42
+ * budget cap) and the parser renders it verbatim into the report + Done card.
43
+ * This keeps user-facing prose about the APP, not Hover's tooling
44
+ * (REPORTING_DIRECTIVE). Defensive + total: any agent can trip this.
45
+ */
46
+ export function stripToolCallNoise(text) {
47
+ return text
48
+ .replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, '') // wrapper form
49
+ .replace(/<invoke\b[\s\S]*?<\/invoke>/gi, '') // closed call block
50
+ .replace(/<invoke\b[\s\S]*$/gi, '') // dangling (truncated) call
51
+ .replace(/<parameter\b[\s\S]*?<\/parameter>/gi, '') // stray parameter
52
+ .replace(/^[ \t]*call[ \t]*$/gim, '') // lone "call" lead-in line
53
+ .replace(/\n{3,}/g, '\n\n')
54
+ .trim();
55
+ }
56
+ /** Markdown-forced: the agent emits a plain-markdown report (REPORTING_DIRECTIVE)
57
+ * — ONE outcome line, `- ` bullets, and an optional `## Findings` section with
58
+ * `- **severity** — text` items. Parse the summary + findings from that markdown
59
+ * only; a stray ```json block (a non-compliant agent) is stripped, never parsed
60
+ * for findings and never leaked. Pure + total — no Findings block yields none. */
61
+ export function parseFindings(summary) {
62
+ const cleaned = stripToolCallNoise(stripJsonArtifact(summary));
63
+ const lines = cleaned.split('\n');
64
+ let hi = -1;
65
+ for (let i = 0; i < lines.length; i++) {
66
+ const t = lines[i].trim();
67
+ if (/^#{1,6}\s*(findings|bugs|issues)\b/i.test(t) || /^findings\s*:/i.test(t)) {
68
+ hi = i;
69
+ break;
70
+ }
71
+ }
72
+ if (hi < 0)
73
+ return { summary: cleaned.trim(), findings: [] };
74
+ let j = hi + 1;
75
+ while (j < lines.length && lines[j].trim() === '')
76
+ j++;
77
+ const start = j;
78
+ while (j < lines.length && /^\s*[-*]\s+/.test(lines[j]))
79
+ j++;
80
+ const bullets = lines.slice(start, j);
81
+ const findings = [];
82
+ for (const line of bullets) {
83
+ const m = line.match(/^\s*[-*]\s+(?:\*\*\s*([^*]+?)\s*\*\*\s*[—–:-]?\s*)?([\s\S]+)$/);
84
+ if (!m)
85
+ continue;
86
+ const text = (m[2] || '').trim();
87
+ if (!text)
88
+ continue;
89
+ findings.push({ severity: (m[1] || 'note').trim(), text });
90
+ }
91
+ const main = lines.slice(0, hi).concat(lines.slice(j)).join('\n').replace(/\n{3,}/g, '\n\n').trim();
92
+ return { summary: main, findings };
93
+ }
94
+ /** Count tool_use steps by tool name for the `toolCounts` field. */
95
+ export function tallyTools(steps) {
96
+ const counts = {};
97
+ for (const s of steps) {
98
+ if (s.kind !== 'step' || !s.tool)
99
+ continue;
100
+ counts[s.tool] = (counts[s.tool] ?? 0) + 1;
101
+ }
102
+ return counts;
103
+ }
104
+ /** Write one session record as `<runDir>/meta.json`. The id (runId) + the
105
+ * conversation are decided by the caller at run start (so screenshots + report
106
+ * share the folder). NEVER throws; returns the path or an error string. */
107
+ export async function writeSessionRecord(devRoot, conversationId, runId, rec) {
108
+ try {
109
+ const dir = runDir(devRoot, conversationId, runId);
110
+ await mkdir(dir, { recursive: true });
111
+ const record = { version: SESSION_RECORD_VERSION, id: runId, conversationId, ...rec };
112
+ const path = join(dir, 'meta.json');
113
+ await writeFile(path, JSON.stringify(record, null, 2) + '\n', 'utf-8');
114
+ return { path, id: runId };
115
+ }
116
+ catch (err) {
117
+ return { error: err instanceof Error ? err.message : String(err) };
118
+ }
119
+ }
120
+ /** List every run's meta.json across all conversations: `.hover/runs/<conv>/<run>/meta.json`.
121
+ * Best-effort; returns [] if no runs yet. */
122
+ export async function listSessionRecords(devRoot) {
123
+ const out = [];
124
+ const root = conversationsDir(devRoot);
125
+ let convs;
126
+ try {
127
+ convs = await readdir(root);
128
+ }
129
+ catch {
130
+ return out;
131
+ }
132
+ for (const conv of convs) {
133
+ let runIds;
134
+ try {
135
+ runIds = await readdir(join(root, conv));
136
+ }
137
+ catch {
138
+ continue;
139
+ }
140
+ for (const rid of runIds) {
141
+ const path = join(root, conv, rid, 'meta.json');
142
+ try {
143
+ out.push({ path, rec: JSON.parse(await readFile(path, 'utf-8')) });
144
+ }
145
+ catch {
146
+ /* not a run dir / unreadable — skip */
147
+ }
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ /**
153
+ * Mark the session that produced `promptText` as crystallized: find the most
154
+ * recent record matching the prompt that has no `specSlug` yet, set
155
+ * `outcome: 'saved'` + the slug. Save-as-spec arrives as a separate WS message
156
+ * after the run record was already written, so this is a patch, keyed on the
157
+ * prompt (the `user` seed step) — tolerant by design; a miss is a no-op.
158
+ * NEVER throws.
159
+ */
160
+ export async function markSessionSaved(devRoot, promptText, specSlug) {
161
+ try {
162
+ const records = (await listSessionRecords(devRoot)).sort((a, b) => String(b.rec.startedAt).localeCompare(String(a.rec.startedAt)));
163
+ for (const { path, rec } of records) {
164
+ if (rec.specSlug || rec.prompt !== promptText)
165
+ continue;
166
+ rec.outcome = 'saved';
167
+ rec.specSlug = specSlug;
168
+ await writeFile(path, JSON.stringify(rec, null, 2) + '\n', 'utf-8');
169
+ return;
170
+ }
171
+ }
172
+ catch {
173
+ /* no ledger yet / unreadable — fine */
174
+ }
175
+ }
@@ -0,0 +1,30 @@
1
+ import type { SkillStep } from './specStep.js';
2
+ /**
3
+ * Length of the leading login prefix among `actions` (a spec's tool steps,
4
+ * POST-redaction). The login flow = the steps up to AND INCLUDING the submit
5
+ * click that follows the LAST credential fill (e.g. navigate → type email →
6
+ * type password → click "Sign in"). `envVars` are the redaction env-var names.
7
+ *
8
+ * Returns 0 when there are no redacted credentials, or none are filled in the
9
+ * steps — so a spec with no login keeps today's inline behavior unchanged (no
10
+ * regression). The caller slices `actions[0..N)` as the auth prefix and
11
+ * `actions[N..]` as the business flow.
12
+ */
13
+ export declare function authPrefixLength(actions: SkillStep[], envVars: readonly string[]): number;
14
+ /**
15
+ * Stage 4a — propose the playwright.config edit that registers the auth-fixture
16
+ * setup project. AST-based (ts-morph) so it only reprints what it touches and
17
+ * preserves the user's formatting. Adds:
18
+ *
19
+ * projects: [
20
+ * { name: 'setup', testMatch: /.*\.setup\.ts$/ },
21
+ * { name: 'chromium', dependencies: ['setup'] },
22
+ * ]
23
+ *
24
+ * Returns the edited source, or null when it can't safely edit — no config
25
+ * object found, or `projects` ALREADY exists (merging into a user's project
26
+ * matrix is risky; the caller degrades to the static paste hint instead). The
27
+ * edit is never applied here; the caller shows it for approval first.
28
+ */
29
+ export declare function addSetupProjectToConfig(source: string): string | null;
30
+ //# sourceMappingURL=authFixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authFixture.d.ts","sourceRoot":"","sources":["../../src/specs/authFixture.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAiC/C;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAazF;AA0BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBrE"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Auth-as-fixture (crystallization debt 3) — login-prefix detection.
3
+ *
4
+ * Today a recorded login is crystallized INLINE into every spec and re-run
5
+ * through the UI each test. The fix is to lift the login into a Playwright setup
6
+ * project that authenticates ONCE, save `storageState`, and have specs start
7
+ * already authenticated. The first, pure step is detecting which leading steps
8
+ * ARE the login flow — done here so it can be unit-tested in isolation, with no
9
+ * codegen changes (those land in later stages).
10
+ *
11
+ * Signal: `redactSteps` (writeSpec.ts) already rewrites credential values to
12
+ * `process.env.<envVar> ?? ''`, so the credential-bearing steps are exactly the
13
+ * fills whose value references one of the run's redaction env vars. The login
14
+ * prefix is the run of steps up to AND INCLUDING the submit click that follows
15
+ * the last credential fill.
16
+ *
17
+ * See docs/superpowers/specs/2026-06-24-auth-as-fixture.md.
18
+ */
19
+ import { Project, SyntaxKind, Node } from 'ts-morph';
20
+ const CLICK_TOOLS = new Set(['browser_click', 'click_control']);
21
+ /** Bare tool name — grounded steps arrive as `mcp__hover-control__click_control`,
22
+ * playwright ones as bare `browser_click`. */
23
+ const bareTool = (t) => (t ?? '').replace(/^mcp__[a-z0-9_-]+?__/, '');
24
+ /** The string values a fill-type action writes, across the tool variants
25
+ * (browser_type / fill_control / select_control / browser_fill_form). */
26
+ function fillValues(step) {
27
+ if (step.kind !== 'step' || !step.input)
28
+ return [];
29
+ const input = step.input;
30
+ const out = [];
31
+ if (typeof input.text === 'string')
32
+ out.push(input.text); // browser_type
33
+ if (typeof input.value === 'string')
34
+ out.push(input.value); // fill_control / select_control
35
+ if (Array.isArray(input.fields)) {
36
+ // browser_fill_form
37
+ for (const f of input.fields) {
38
+ if (f && typeof f.value === 'string')
39
+ out.push(f.value);
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+ /** True when an action fills one of the redacted credential env refs. `actions`
45
+ * are POST-redaction, so a credential value reads `process.env.<envVar> ?? ''`. */
46
+ function fillsCredential(step, envVars) {
47
+ if (!envVars.length)
48
+ return false;
49
+ const values = fillValues(step);
50
+ return values.some((v) => envVars.some((name) => v.includes(`process.env.${name}`)));
51
+ }
52
+ /**
53
+ * Length of the leading login prefix among `actions` (a spec's tool steps,
54
+ * POST-redaction). The login flow = the steps up to AND INCLUDING the submit
55
+ * click that follows the LAST credential fill (e.g. navigate → type email →
56
+ * type password → click "Sign in"). `envVars` are the redaction env-var names.
57
+ *
58
+ * Returns 0 when there are no redacted credentials, or none are filled in the
59
+ * steps — so a spec with no login keeps today's inline behavior unchanged (no
60
+ * regression). The caller slices `actions[0..N)` as the auth prefix and
61
+ * `actions[N..]` as the business flow.
62
+ */
63
+ export function authPrefixLength(actions, envVars) {
64
+ if (!envVars.length)
65
+ return 0;
66
+ let lastCred = -1;
67
+ for (let i = 0; i < actions.length; i++) {
68
+ if (fillsCredential(actions[i], envVars))
69
+ lastCred = i;
70
+ }
71
+ if (lastCred < 0)
72
+ return 0;
73
+ // Extend through the submit click immediately after the last credential fill
74
+ // (the "Sign in" button). A non-click next step means login auto-submitted (or
75
+ // we've already moved into the app), so stop at the fill — don't over-capture.
76
+ const next = actions[lastCred + 1];
77
+ if (next && CLICK_TOOLS.has(bareTool(next.tool)))
78
+ return lastCred + 2;
79
+ return lastCred + 1;
80
+ }
81
+ /**
82
+ * Locate the Playwright config object literal — the argument of `defineConfig({…})`
83
+ * or a bare `export default {…}` — so the setup project can be inserted into it.
84
+ */
85
+ function findConfigObject(sf) {
86
+ const def = sf.getExportAssignment((d) => !d.isExportEquals());
87
+ const expr = def?.getExpression();
88
+ if (expr) {
89
+ if (Node.isObjectLiteralExpression(expr))
90
+ return expr;
91
+ if (Node.isCallExpression(expr)) {
92
+ const arg = expr.getArguments()[0];
93
+ if (arg && Node.isObjectLiteralExpression(arg))
94
+ return arg;
95
+ }
96
+ }
97
+ // Fallback: a defineConfig(...) call anywhere in the file.
98
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
99
+ if (call.getExpression().getText() === 'defineConfig') {
100
+ const arg = call.getArguments()[0];
101
+ if (arg && Node.isObjectLiteralExpression(arg))
102
+ return arg;
103
+ }
104
+ }
105
+ return undefined;
106
+ }
107
+ /**
108
+ * Stage 4a — propose the playwright.config edit that registers the auth-fixture
109
+ * setup project. AST-based (ts-morph) so it only reprints what it touches and
110
+ * preserves the user's formatting. Adds:
111
+ *
112
+ * projects: [
113
+ * { name: 'setup', testMatch: /.*\.setup\.ts$/ },
114
+ * { name: 'chromium', dependencies: ['setup'] },
115
+ * ]
116
+ *
117
+ * Returns the edited source, or null when it can't safely edit — no config
118
+ * object found, or `projects` ALREADY exists (merging into a user's project
119
+ * matrix is risky; the caller degrades to the static paste hint instead). The
120
+ * edit is never applied here; the caller shows it for approval first.
121
+ */
122
+ export function addSetupProjectToConfig(source) {
123
+ try {
124
+ const project = new Project({ useInMemoryFileSystem: true, compilerOptions: { allowJs: true } });
125
+ const sf = project.createSourceFile('__pwconfig.ts', source, { overwrite: true });
126
+ const obj = findConfigObject(sf);
127
+ if (!obj)
128
+ return null;
129
+ if (obj.getProperty('projects'))
130
+ return null; // user already manages projects — don't risk it
131
+ obj.addPropertyAssignment({
132
+ name: 'projects',
133
+ initializer: [
134
+ '[',
135
+ " { name: 'setup', testMatch: /.*\\.setup\\.ts$/ },",
136
+ " { name: 'chromium', dependencies: ['setup'] },",
137
+ ' ]',
138
+ ].join('\n'),
139
+ });
140
+ return sf.getFullText();
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
@@ -1,4 +1,4 @@
1
- import type { SkillStep } from '../skills/writeSkill.js';
1
+ import type { SkillStep } from '../specs/specStep.js';
2
2
  export interface SharedFlow {
3
3
  /** The shared signature prefix, one entry per step. */
4
4
  signatures: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"detectSharedFlows.d.ts","sourceRoot":"","sources":["../../src/specs/detectSharedFlows.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;2CACuC;IACvC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;wDACoD;IACpD,WAAW,EAAE,SAAS,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B;2EACuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;sDACkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAgC5E;AAuDD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CAiCvB"}
1
+ {"version":3,"file":"detectSharedFlows.d.ts","sourceRoot":"","sources":["../../src/specs/detectSharedFlows.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;2CACuC;IACvC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;wDACoD;IACpD,WAAW,EAAE,SAAS,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B;2EACuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;sDACkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAgC5E;AAwDD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CAiCvB"}
@@ -17,9 +17,9 @@
17
17
  * same signature even though their typed values differ — value vs. structure
18
18
  * separation is mechanical (D4).
19
19
  */
20
- import { readdir, readFile } from 'node:fs/promises';
20
+ import { readdir } from 'node:fs/promises';
21
21
  import { join } from 'node:path';
22
- import { sidecarDir } from './sidecar.js';
22
+ import { sidecarDir, legacySidecarDir, parseSidecarFile } from './sidecar.js';
23
23
  import { humanStep } from './humanSteps.js';
24
24
  /**
25
25
  * Reduce one captured step to a signature string: the tool plus its structural
@@ -60,31 +60,30 @@ export function stepSignature(tool, rawInput) {
60
60
  return null;
61
61
  }
62
62
  }
63
- /** Read and parse every sidecar under `.hover/`. Malformed files are skipped
64
- * (better to detect across the valid ones than fail because one is broken). */
63
+ /** Read and parse every sidecar under `.hover/sidecars/`, unioned with any
64
+ * still in the legacy `__vibe_tests__/.hover/` home (current home wins on a
65
+ * slug collision). Malformed files are skipped (better to detect across the
66
+ * valid ones than fail because one is broken). */
65
67
  async function readSidecars(devRoot) {
66
- const dir = sidecarDir(devRoot);
67
- let entries;
68
- try {
69
- entries = await readdir(dir);
70
- }
71
- catch {
72
- return [];
73
- }
74
- const out = [];
75
- for (const entry of entries) {
76
- if (!entry.endsWith('.json'))
77
- continue;
68
+ const bySlug = new Map();
69
+ for (const dir of [legacySidecarDir(devRoot), sidecarDir(devRoot)]) {
70
+ let entries;
78
71
  try {
79
- const sc = JSON.parse(await readFile(join(dir, entry), 'utf-8'));
80
- if (Array.isArray(sc.steps) && typeof sc.slug === 'string')
81
- out.push(sc);
72
+ entries = await readdir(dir);
82
73
  }
83
74
  catch {
84
- // skip malformed sidecar
75
+ continue;
76
+ }
77
+ for (const entry of entries) {
78
+ if (!entry.endsWith('.json'))
79
+ continue;
80
+ const sc = await parseSidecarFile(join(dir, entry));
81
+ if (sc && Array.isArray(sc.steps) && typeof sc.slug === 'string') {
82
+ bySlug.set(sc.slug, sc); // later dir (current home) overwrites
83
+ }
85
84
  }
86
85
  }
87
- return out;
86
+ return [...bySlug.values()];
88
87
  }
89
88
  /** Project a sidecar's steps to (signature, prose) lists, dropping
90
89
  * non-flow steps. */
@@ -11,7 +11,7 @@
11
11
  * emitters with a `this.page` page variable, so a Page Object's selectors match
12
12
  * the crystallized specs exactly.
13
13
  */
14
- import type { SkillStep } from '../skills/writeSkill.js';
14
+ import type { SkillStep } from '../specs/specStep.js';
15
15
  export interface PageObjectResult {
16
16
  /** PascalCase class name, e.g. `LoginPage`. */
17
17
  className: string;
@@ -1 +1 @@
1
- {"version":3,"file":"generatePageObject.d.ts","sourceRoot":"","sources":["../../src/specs/generatePageObject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAUzD,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,gBAAgB,CAoElB"}
1
+ {"version":3,"file":"generatePageObject.d.ts","sourceRoot":"","sources":["../../src/specs/generatePageObject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAUtD,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,gBAAgB,CAoElB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Self-heal Stage 2 — the heal prompt.
3
+ *
4
+ * When a saved spec fails on replay (the app changed → a locator no longer
5
+ * matches), healing re-performs the flow against the LIVE app and fixes the
6
+ * broken step(s). This builds the instruction that drives that run: the agent
7
+ * gets the spec's intended flow (its source) + exactly what broke (the parsed
8
+ * failures), and re-locates via the grounded control tools + source reader.
9
+ *
10
+ * The heal then crystallizes through the normal candidate flow (record_candidate
11
+ * / fallback) — deterministic re-render, human-reviewed; the agent re-locates,
12
+ * it does not author the spec. Pure: prompt-building only.
13
+ */
14
+ import type { RunFailure } from './runFailures.js';
15
+ /** A short, chat-friendly label for the heal run (the user bubble), vs the full
16
+ * prompt the agent receives. */
17
+ export declare function healLabel(slug: string): string;
18
+ export declare function buildHealPrompt(slug: string, specSource: string, failures: RunFailure[]): string;
19
+ //# sourceMappingURL=healPrompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healPrompt.d.ts","sourceRoot":"","sources":["../../src/specs/healPrompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;iCACiC;AACjC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,CA2ChG"}
@@ -0,0 +1,48 @@
1
+ /** A short, chat-friendly label for the heal run (the user bubble), vs the full
2
+ * prompt the agent receives. */
3
+ export function healLabel(slug) {
4
+ return `🏥 Heal "${slug}" — re-running the flow to fix what changed`;
5
+ }
6
+ export function buildHealPrompt(slug, specSource, failures) {
7
+ const failureLines = failures.length > 0
8
+ ? failures.map(f => {
9
+ const what = f.failingLocator
10
+ ? `${f.failingAction ?? 'a step'} on \`${f.failingLocator}\` no longer matches`
11
+ : (f.error || 'a step failed');
12
+ return ` - ${what}`;
13
+ }).join('\n')
14
+ : ' - (no structured failure captured — re-run the whole flow and fix whatever no longer works)';
15
+ return [
16
+ `You are REPAIRING a saved Playwright test that no longer passes because the`,
17
+ `app under test changed. Re-perform its flow against the LIVE app and fix only`,
18
+ `the step(s) that broke — do not invent new behavior or add unrelated steps.`,
19
+ ``,
20
+ `Test: "${slug}"`,
21
+ ``,
22
+ `What it does (the saved spec — this is the intended flow to reproduce):`,
23
+ `\`\`\`ts`,
24
+ specSource.trim(),
25
+ `\`\`\``,
26
+ ``,
27
+ `What broke on replay:`,
28
+ failureLines,
29
+ ``,
30
+ `How to repair it:`,
31
+ ` - Open the app and walk the SAME flow, interacting through the grounded`,
32
+ ` control tools (click_control / fill_control / select_control / …) so the`,
33
+ ` repaired selectors stay replayable.`,
34
+ ` - Where a step's old selector no longer matches, find the element that step`,
35
+ ` INTENDED and operate that instead. Read the component source if you are`,
36
+ ` unsure why it moved or what replaced it.`,
37
+ ` - JUDGE broke-vs-changed: if a failure is because the app INTENTIONALLY`,
38
+ ` changed (the feature now works differently — not a regression), adapt the`,
39
+ ` flow to the new correct behavior and say so in your summary. If it looks`,
40
+ ` like a real regression (the app is wrong), report it as a finding and heal`,
41
+ ` to what the test originally intended.`,
42
+ ` - Keep dynamic content dynamic: if a step grounds on data that varies`,
43
+ ` run-to-run, flag it dynamic — don't freeze this run's value.`,
44
+ ``,
45
+ `When the flow works end to end, call record_candidate with the test's name so`,
46
+ `the repaired version can be saved. Do not write any file yourself.`,
47
+ ].join('\n');
48
+ }
@@ -1,18 +1,14 @@
1
1
  /**
2
2
  * Translate the captured `browser_*` tool calls into plain English.
3
3
  *
4
- * Used by:
5
- * - writeSpec.ts to enrich the generated `.spec.ts` JSDoc with a
6
- * numbered "Steps:" block that QA / PMs can read without grokking
7
- * `getByRole(...)`.
8
- * - writeCaseCsv.ts — to populate the Step column of an
9
- * Xray-compatible test case CSV, so the same prose travels into
10
- * Jira / Xray / Zephyr.
4
+ * Used by writeSpec.ts to enrich the generated `.spec.ts` JSDoc with a
5
+ * numbered "Steps:" block that QA / PMs can read without grokking
6
+ * `getByRole(...)`.
11
7
  *
12
8
  * Mirrors the tool dispatch table in writeSpec.ts:translateStep — when
13
9
  * a new replayable browser action is added there, add it here too.
14
10
  */
15
- import type { SkillStep } from '../skills/writeSkill.js';
11
+ import type { SkillStep } from '../specs/specStep.js';
16
12
  /** A single human-readable line for one tool call, or null to skip. */
17
13
  export declare function humanStep(tool: string, rawInput: unknown): string | null;
18
14
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"humanSteps.d.ts","sourceRoot":"","sources":["../../src/specs/humanSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwDxE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAmBvD"}
1
+ {"version":3,"file":"humanSteps.d.ts","sourceRoot":"","sources":["../../src/specs/humanSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwDxE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAmBvD"}
@@ -91,7 +91,12 @@ function describe(raw) {
91
91
  const s = String(raw ?? '').trim();
92
92
  return s.length > 0 ? s : 'the target element';
93
93
  }
94
- /** Wrap in double-quotes for prose; escape internal quotes. */
94
+ /** Wrap in double-quotes for prose; escape internal quotes. A redacted
95
+ * credential (stored as a `process.env.X …` expression) shows as the masked
96
+ * `$X` instead — the prose, like the code, never reveals the secret. */
95
97
  function quote(s) {
98
+ const env = /^process\.env\.([A-Za-z0-9_]+)/.exec(s);
99
+ if (env)
100
+ return `$${env[1]}`;
96
101
  return `"${s.replace(/"/g, '\\"')}"`;
97
102
  }
@@ -5,6 +5,20 @@ export declare class OptimizeError extends Error {
5
5
  }
6
6
  /** Runs the codegen LLM on a prompt and returns its raw text output. */
7
7
  export type RunCodegen = (prompt: string) => Promise<string>;
8
+ /** Project context fed to the refinement pass so the candidate FITS the existing
9
+ * suite: the team's conventions + the reusable Page Objects to prefer over raw
10
+ * locators. Relevant files only (POMs + conventions), NOT the whole suite — the
11
+ * refinement is a cheap pass, keep the context bounded. */
12
+ export interface SuiteContext {
13
+ conventions?: string;
14
+ pages: {
15
+ name: string;
16
+ source: string;
17
+ }[];
18
+ }
19
+ /** Best-effort gather of the suite context (conventions.md + __vibe_tests__/pages
20
+ * Page Objects). Missing files → empty; never throws. */
21
+ export declare function gatherSuiteContext(devRoot: string): Promise<SuiteContext>;
8
22
  export interface OptimizeResult {
9
23
  /** Absolute path of the written candidate (never the original spec). */
10
24
  candidatePath: string;
@@ -20,7 +34,7 @@ export declare function optimizeSpec(devRoot: string, slug: string, runCodegen:
20
34
  * same rules the deterministic path enforces (semantic selectors, no XPath, no
21
35
  * waitForTimeout, keep the test.step shape).
22
36
  */
23
- export declare function buildOptimizePrompt(draft: string, sidecar: SpecSidecar | null, seeds?: SeedRule[]): string;
37
+ export declare function buildOptimizePrompt(draft: string, sidecar: SpecSidecar | null, seeds?: SeedRule[], suite?: SuiteContext): string;
24
38
  /** Strip a ```ts fence if the model wrapped its output in one. */
25
39
  export declare function extractCode(raw: string): string;
26
40
  /**
@@ -32,11 +46,4 @@ export declare function validateSpecCode(code: string): {
32
46
  ok: boolean;
33
47
  errors: string[];
34
48
  };
35
- /** Promote an optimization candidate to the real spec (overwriting it) and
36
- * remove the candidate. Returns the written spec path. The human's "Use
37
- * optimized" / `mv` action. */
38
- export declare function promoteOptimized(devRoot: string, slug: string): Promise<string>;
39
- /** Discard an optimization candidate (delete the .draft, leave the spec). The
40
- * human's "Keep original". */
41
- export declare function discardOptimized(devRoot: string, slug: string): Promise<void>;
42
49
  //# sourceMappingURL=optimizeSpec.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"optimizeSpec.d.ts","sourceRoot":"","sources":["../../src/specs/optimizeSpec.ts"],"names":[],"mappings":"AAeA,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAA4B,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGrE,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb;2EACuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,cAAc,CAAC,CA2CzB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GAAG,IAAI,EAC3B,KAAK,GAAE,QAAQ,EAAO,GACrB,MAAM,CAmDR;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAWhF;AAyBD;;gCAEgC;AAChC,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYrF;AAED;+BAC+B;AAC/B,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF"}
1
+ {"version":3,"file":"optimizeSpec.d.ts","sourceRoot":"","sources":["../../src/specs/optimizeSpec.ts"],"names":[],"mappings":"AAeA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGzE,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE7D;;;4DAG4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3C;AAOD;0DAC0D;AAC1D,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAgB/E;AAED,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb;2EACuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,cAAc,CAAC,CAwCzB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GAAG,IAAI,EAC3B,KAAK,GAAE,QAAQ,EAAO,EACtB,KAAK,GAAE,YAA4B,GAClC,MAAM,CAkFR;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAWhF"}