@trusty-squire/mcp 0.9.16 → 0.9.17-rc.2

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 (56) hide show
  1. package/dist/bot/affordance-probe.d.ts +15 -0
  2. package/dist/bot/affordance-probe.d.ts.map +1 -0
  3. package/dist/bot/affordance-probe.js +63 -0
  4. package/dist/bot/affordance-probe.js.map +1 -0
  5. package/dist/bot/agent.d.ts +31 -1
  6. package/dist/bot/agent.d.ts.map +1 -1
  7. package/dist/bot/agent.js +1826 -129
  8. package/dist/bot/agent.js.map +1 -1
  9. package/dist/bot/browser.d.ts +9 -0
  10. package/dist/bot/browser.d.ts.map +1 -1
  11. package/dist/bot/browser.js +281 -8
  12. package/dist/bot/browser.js.map +1 -1
  13. package/dist/bot/extraction.d.ts +18 -0
  14. package/dist/bot/extraction.d.ts.map +1 -0
  15. package/dist/bot/extraction.js +55 -0
  16. package/dist/bot/extraction.js.map +1 -0
  17. package/dist/bot/form-fill.d.ts +144 -0
  18. package/dist/bot/form-fill.d.ts.map +1 -0
  19. package/dist/bot/form-fill.js +320 -0
  20. package/dist/bot/form-fill.js.map +1 -0
  21. package/dist/bot/google-login.d.ts.map +1 -1
  22. package/dist/bot/google-login.js +6 -2
  23. package/dist/bot/google-login.js.map +1 -1
  24. package/dist/bot/llm-client.d.ts +12 -0
  25. package/dist/bot/llm-client.d.ts.map +1 -1
  26. package/dist/bot/llm-client.js +99 -0
  27. package/dist/bot/llm-client.js.map +1 -1
  28. package/dist/bot/nav-search.d.ts +80 -0
  29. package/dist/bot/nav-search.d.ts.map +1 -0
  30. package/dist/bot/nav-search.js +409 -0
  31. package/dist/bot/nav-search.js.map +1 -0
  32. package/dist/bot/oauth-flow.d.ts +48 -0
  33. package/dist/bot/oauth-flow.d.ts.map +1 -0
  34. package/dist/bot/oauth-flow.js +111 -0
  35. package/dist/bot/oauth-flow.js.map +1 -0
  36. package/dist/bot/onboarding-capture.d.ts +4 -0
  37. package/dist/bot/onboarding-capture.d.ts.map +1 -1
  38. package/dist/bot/onboarding-capture.js +5 -0
  39. package/dist/bot/onboarding-capture.js.map +1 -1
  40. package/dist/bot/redact.d.ts +1 -0
  41. package/dist/bot/redact.d.ts.map +1 -1
  42. package/dist/bot/redact.js +46 -0
  43. package/dist/bot/redact.js.map +1 -1
  44. package/dist/skill-registry-client.d.ts +4 -0
  45. package/dist/skill-registry-client.d.ts.map +1 -1
  46. package/dist/skill-registry-client.js +4 -0
  47. package/dist/skill-registry-client.js.map +1 -1
  48. package/dist/tools/provision-any.d.ts +21 -0
  49. package/dist/tools/provision-any.d.ts.map +1 -1
  50. package/dist/tools/provision-any.js +16 -7
  51. package/dist/tools/provision-any.js.map +1 -1
  52. package/dist/tools/signup-telemetry.d.ts +6 -0
  53. package/dist/tools/signup-telemetry.d.ts.map +1 -1
  54. package/dist/tools/signup-telemetry.js +4 -0
  55. package/dist/tools/signup-telemetry.js.map +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1,409 @@
1
+ // nav-search.ts — goal-directed search over a dashboard's affordances for the
2
+ // POST-signup "find/create the API key" phase. This is strangler-fig slice 1 of
3
+ // de-monolithing agent.ts: the enumeration, ranking, and goal classification are
4
+ // PURE functions (inventory / url / text in, decision out — no browser, no LLM),
5
+ // so they're unit-testable in isolation. The browser-driving search loop (click →
6
+ // overlay → verify → extract) is a thin orchestrator over these, added in a later
7
+ // task. Design + reviewed decisions: docs/DESIGN-post-signup-nav-search.md.
8
+ //
9
+ // Why this exists: the current greedy postVerifyLoop guesses URLs (404s) and
10
+ // flails to a 600s timeout because it has no goal definition and no map. Every
11
+ // dashboard DOES expose a finite set of navigable affordances — links AND buttons,
12
+ // some behind expandable menus. Rank them deterministically toward "API keys",
13
+ // click the real ones, stop on a concrete goal. The LLM is a bounded tiebreaker,
14
+ // not the loop driver (reviewed decision A1).
15
+ import { findCreateKeyAffordance, detectExistingAccountNoExtract } from "./agent.js";
16
+ // Resolve a candidate's href to an absolute URL worth navigating to, or null
17
+ // when it isn't a real destination (empty, "#", javascript:, mailto:, or a bare
18
+ // fragment). Relative paths resolve against the current page URL. Pure.
19
+ export function resolveNavHref(href, currentUrl) {
20
+ if (href === null)
21
+ return null;
22
+ const h = href.trim();
23
+ if (h.length === 0 || h === "#" || h.startsWith("#"))
24
+ return null;
25
+ if (/^(?:javascript:|mailto:|tel:)/i.test(h))
26
+ return null;
27
+ try {
28
+ const abs = new URL(h, currentUrl);
29
+ if (abs.protocol !== "http:" && abs.protocol !== "https:")
30
+ return null;
31
+ // A link that points back to exactly where we are is not progress.
32
+ if (abs.href === currentUrl)
33
+ return null;
34
+ return abs.href;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ // True if `href` resolves to a DIFFERENT registrable domain than the page we're
41
+ // on — i.e. it would navigate off the authenticated app (e.g. console.neon.tech
42
+ // → neon.com/docs). The key hunt must stay inside the app; a marketing/docs link
43
+ // is a dead end that also burns the step budget and drops the session. Buttons
44
+ // and same-site/relative links are NOT off-site. Registrable domain = last two
45
+ // labels (good enough for these dev-tool hosts; no PSL dependency). Pure.
46
+ export function isOffSiteHref(currentUrl, href) {
47
+ const abs = resolveNavHref(href, currentUrl);
48
+ if (abs === null)
49
+ return false; // relative/self/non-navigable → never off-site
50
+ try {
51
+ const reg = (h) => h.split(".").slice(-2).join(".");
52
+ return reg(new URL(abs).hostname) !== reg(new URL(currentUrl).hostname);
53
+ }
54
+ catch {
55
+ return true; // unparseable target → treat as off-site (don't follow)
56
+ }
57
+ }
58
+ // Union two inventory snapshots, deduped by selector (first wins). Used to
59
+ // survive expandLatentNav's destructive menu-toggling: an affordance present
60
+ // in EITHER the pre- or post-expand read is kept, so an already-open dropdown
61
+ // that the toggle later closes still contributes its items. Pure.
62
+ export function mergeInventories(a, b) {
63
+ const bySelector = new Map();
64
+ for (const el of [...a, ...b]) {
65
+ if (!bySelector.has(el.selector))
66
+ bySelector.set(el.selector, el);
67
+ }
68
+ return [...bySelector.values()];
69
+ }
70
+ // Destructive / irreversible actions nav-search must NEVER auto-click — neither
71
+ // by deterministic rank nor by LLM tiebreak. The search clicks affordances
72
+ // unattended chasing a key; a positional/portaled mis-click on one of these
73
+ // could delete the account or revoke a credential. Excluded at enumeration so
74
+ // no downstream path can ever reach them. (Observed: the LLM tiebreak once
75
+ // picked "Delete Account" on a settings page that had no keys.)
76
+ const DESTRUCTIVE_TEXT = /\b(?:delete|remove|deactivate|destroy|revoke|cancel\s+(?:account|subscription|plan)|close\s+account|wipe|reset\s+account|leave\s+(?:team|organization|org))\b/i;
77
+ // Pull the navigable affordances out of an inventory. Pure.
78
+ export function enumerateCandidates(inventory) {
79
+ const out = [];
80
+ for (const el of inventory) {
81
+ const clickable = el.tag === "a" || el.tag === "button" || el.role === "link" || el.role === "button";
82
+ if (!clickable)
83
+ continue;
84
+ if (el.visible === false)
85
+ continue;
86
+ const text = [el.visibleText, el.ariaLabel, el.title, el.labelText, el.iconLabel]
87
+ .filter((s) => s !== null && s !== undefined && s.length > 0)
88
+ .join(" ")
89
+ .trim();
90
+ if (DESTRUCTIVE_TEXT.test(text))
91
+ continue; // never auto-click a destructive control
92
+ const href = el.href ?? null;
93
+ if (text.length === 0 && (href === null || href.length === 0))
94
+ continue;
95
+ out.push({
96
+ selector: el.selector,
97
+ href,
98
+ text,
99
+ isAnchor: el.tag === "a",
100
+ inViewport: el.inViewport === true,
101
+ });
102
+ }
103
+ return out;
104
+ }
105
+ // THE key-destination URL pattern — the single source of truth used by BOTH the
106
+ // ranker (href match) and the goal verifier (am I on a key surface?). They MUST
107
+ // agree: if the ranker navigates to a URL it thinks is a key destination, the
108
+ // goal verifier has to recognize the same URL, or the loop arrives and never
109
+ // extracts. The loose tokens (settings/account/keys/tokens/developers) are
110
+ // trusted because an href/url is a structured path, not free text.
111
+ export const KEYS_DESTINATION_URL = /\/(?:api[-_]?keys?|api[-_]?tokens?|access[-_]?tokens?|auth[-_]?tokens?|secret[-_]?keys?|personal[-_]?access[-_]?tokens?|developers?|settings|account|keys?|tokens?)(?:[/?#]|$)/i;
112
+ const KEYS_HREF = KEYS_DESTINATION_URL;
113
+ const KEYS_TEXT_STRONG = /\b(?:api|access|secret|auth|personal\s+access)\s*(?:keys?|tokens?)\b/i;
114
+ const KEYS_TEXT_WEAK = /\b(?:developers?|settings|account)\b/i;
115
+ const NEG_TEXT = /\b(?:billing|invoices?|docs|documentation|pricing|log\s*out|sign\s*out|keyboard\s+shortcuts)\b/i;
116
+ export function scoreCandidate(c) {
117
+ if (NEG_TEXT.test(c.text))
118
+ return 0;
119
+ // Base = keys relevance. Anchor/viewport are TIEBREAKERS that only apply on a
120
+ // relevant base — otherwise every visible link would score >0 and a plain
121
+ // "Dashboard" link would rank as a candidate.
122
+ let base = 0;
123
+ if (c.href !== null && KEYS_HREF.test(c.href))
124
+ base += 4; // a real navigable path
125
+ if (KEYS_TEXT_STRONG.test(c.text))
126
+ base += 3; // explicit "API key(s)/token(s)"
127
+ else if (KEYS_TEXT_WEAK.test(c.text))
128
+ base += 1; // settings/account/developers
129
+ if (base === 0)
130
+ return 0; // no keys relevance → not a candidate
131
+ let s = base;
132
+ if (c.isAnchor)
133
+ s += 1; // prefer real anchors over role=button
134
+ if (c.inViewport)
135
+ s += 1;
136
+ return s;
137
+ }
138
+ export function rankCandidates(candidates) {
139
+ const scored = candidates
140
+ .map((c) => ({ c, s: scoreCandidate(c) }))
141
+ .filter((x) => x.s > 0)
142
+ .sort((a, b) => b.s - a.s);
143
+ const ranked = scored.map((x) => x.c);
144
+ const needsTiebreak = ranked.length === 0 || (scored.length >= 2 && scored[0].s === scored[1].s);
145
+ return { ranked, needsTiebreak };
146
+ }
147
+ export function assessKeyGoal(input) {
148
+ // A create-key affordance on a key surface → mint a fresh key. This is checked
149
+ // BEFORE the existing-account-no-extract heuristic below, and deliberately so:
150
+ // an EMPTY keys table still renders its column headers ("Key name" / "Created" /
151
+ // "Last used"), which that heuristic mistakes for an existing masked listing
152
+ // (groq's /keys on a virgin account) — and then extraction finds nothing and the
153
+ // loop wanders off-surface. When a "Create API Key" button is right there,
154
+ // minting is unambiguously the move: it yields a fresh extractable key whether
155
+ // the account is virgin OR has masked existing keys. A stray "create" button
156
+ // elsewhere can't hijack the search — we gate on being on a key surface.
157
+ const create = findCreateKeyAffordance(input.inventory);
158
+ if (create !== null && KEYS_DESTINATION_URL.test(input.url)) {
159
+ return { kind: "create_gated", createSelector: create.selector };
160
+ }
161
+ // No create affordance, but an existing-key listing with no re-reveal (e.g.
162
+ // Neon) IS arrival — the caller extracts/handles whatever is shown.
163
+ if (detectExistingAccountNoExtract({
164
+ url: input.url,
165
+ pageText: input.pageText,
166
+ lastPlannerReason: "",
167
+ })) {
168
+ return { kind: "on_key_surface" };
169
+ }
170
+ // On a keys/settings surface but no create affordance yet (key may be masked /
171
+ // behind a reveal / already listed) → let the caller run the extractor.
172
+ if (KEYS_DESTINATION_URL.test(input.url)) {
173
+ return { kind: "on_key_surface" };
174
+ }
175
+ // A create affordance off a non-key URL is still worth trying as a last move,
176
+ // but it's not arrival — keep searching with it available to the caller.
177
+ return { kind: "not_yet" };
178
+ }
179
+ // ── overlay / wizard handling (T3) ───────────────────────────────────────────
180
+ // Onboarding wizards and modals are a RECURRING obstacle (imagekit role-select,
181
+ // unify "Hire Assistant", "name your project") — each currently re-improvised and
182
+ // trapped the bot. One mechanism: when blocked, DISMISS the overlay (skip/close)
183
+ // or, failing that, ADVANCE the wizard (Next/Continue). Pure detection here; the
184
+ // click (and an Escape-key fallback) is the loop's browser action.
185
+ // Generalizes the inline WIZARD_FORWARD (agent.ts:10413). A forward control that
186
+ // advances a multi-step onboarding wizard.
187
+ const WIZARD_ADVANCE = /^\s*(?:next|continue|submit|finish|done|get\s+started|let'?s\s+go|proceed)\s*$/i;
188
+ // A control that skips/closes an onboarding step or modal entirely — preferred
189
+ // over advancing, since skipping gets us to the dashboard fastest.
190
+ const OVERLAY_DISMISS = /\b(?:skip(?:\s+for\s+now)?|dismiss|not\s+now|maybe\s+later|no\s+thanks?|close|×|✕|✖)\b/i;
191
+ function isClickable(el) {
192
+ return ((el.tag === "button" || el.tag === "a" || el.role === "button" || el.role === "link") &&
193
+ el.visible !== false);
194
+ }
195
+ function elText(el) {
196
+ return [el.visibleText, el.ariaLabel, el.title, el.labelText, el.iconLabel]
197
+ .filter((s) => s !== null && s !== undefined && s.length > 0)
198
+ .join(" ")
199
+ .trim();
200
+ }
201
+ // Find a skip/close affordance for a blocking onboarding step or modal. Pure.
202
+ export function findOverlayDismiss(inventory) {
203
+ for (const el of inventory) {
204
+ if (!isClickable(el))
205
+ continue;
206
+ const t = elText(el);
207
+ if (t.length === 0)
208
+ continue;
209
+ // Long text that merely CONTAINS "close" (e.g. "Close your first deal") is
210
+ // not a dismiss control — require the control to be short/affordance-shaped.
211
+ if (t.length > 24)
212
+ continue;
213
+ if (OVERLAY_DISMISS.test(t))
214
+ return el;
215
+ }
216
+ return null;
217
+ }
218
+ // Find a Next/Continue-style control that advances a wizard. Pure. Matches on
219
+ // the WHOLE label (anchored) so a "Continue with Google" OAuth button or a
220
+ // "Submit feedback" doesn't trip it.
221
+ export function findWizardAdvance(inventory) {
222
+ for (const el of inventory) {
223
+ if (!isClickable(el))
224
+ continue;
225
+ if (WIZARD_ADVANCE.test(elText(el)))
226
+ return el;
227
+ }
228
+ return null;
229
+ }
230
+ // On an onboarding CHOICE step (a role/usage picker that gates progress — no
231
+ // nav, no skip, no Next: unify's "Just for me / For my team", imagekit's role
232
+ // select), "satisfy the minimal step": pick the LEAST-committal option so the
233
+ // flow advances toward the dashboard. Returns the selector, or null when this
234
+ // isn't a recognizable choice step (so the caller doesn't click random buttons).
235
+ const ONBOARDING_CONTEXT = /\b(?:how (?:do|will) you (?:plan to )?use|get started|welcome to|set\s*up your|tell us about|what brings you|choose your|select (?:your )?(?:a )?role|how do you describe)\b/i;
236
+ const MINIMAL_CHOICE = /\b(?:just for me|personal|individual|myself|solo|skip|i'?m an individual|for myself)\b/i;
237
+ export function planOnboardingChoice(input) {
238
+ const onboardingish = /\/(?:onboarding|welcome|setup|get-started)\b/i.test(input.url) ||
239
+ ONBOARDING_CONTEXT.test(input.pageText);
240
+ if (!onboardingish)
241
+ return null;
242
+ const choices = input.inventory.filter((el) => (el.tag === "button" || el.role === "button") &&
243
+ el.visible !== false &&
244
+ (el.visibleText ?? el.ariaLabel ?? "").trim().length > 0);
245
+ if (choices.length === 0)
246
+ return null;
247
+ const text = (el) => (el.visibleText ?? el.ariaLabel ?? "").trim();
248
+ const minimal = choices.find((el) => MINIMAL_CHOICE.test(text(el)));
249
+ return (minimal ?? choices[0]).selector;
250
+ }
251
+ export async function runNavSearch(browser, deps) {
252
+ const maxSteps = deps.maxSteps ?? 12;
253
+ const log = deps.log ?? (() => { });
254
+ const tried = new Set(); // affordance selectors already clicked
255
+ const overlayTried = new Set(); // overlay controls already actioned
256
+ const capture = async (action, inv, selector) => {
257
+ if (deps.captureRound === undefined)
258
+ return;
259
+ try {
260
+ await deps.captureRound({
261
+ url: browser.currentUrl(),
262
+ inventory: inv,
263
+ action,
264
+ ...(selector !== undefined ? { selector } : {}),
265
+ });
266
+ }
267
+ catch {
268
+ // capture is best-effort — never fail the search
269
+ }
270
+ };
271
+ for (let step = 0; step < maxSteps; step++) {
272
+ await browser.settle();
273
+ let inv = await browser.extractInventory();
274
+ // Per-step diagnostic so a failed run is debuggable from the step trail
275
+ // alone (URL + element count + goal verdict + text snippet) — mirrors the
276
+ // greedy loop's "Inventory diagnostic" line. Without it an exhaustion is
277
+ // a black box: we can't see what page each click landed on.
278
+ {
279
+ const durl = browser.currentUrl();
280
+ const dtext = (await browser.extractText().catch(() => "")).replace(/\s+/g, " ").trim();
281
+ const dgoal = assessKeyGoal({ url: durl, pageText: dtext, inventory: inv });
282
+ log(`nav-search: step ${step} url=${durl} elements=${inv.length} goal=${dgoal.kind} ` +
283
+ `text="${dtext.slice(0, 160)}"`);
284
+ }
285
+ // 1) Clear a blocking onboarding overlay / modal before anything else.
286
+ const overlay = planOverlayStep(inv);
287
+ if (overlay.kind !== "none" && !overlayTried.has(overlay.selector)) {
288
+ overlayTried.add(overlay.selector);
289
+ log(`nav-search: overlay ${overlay.kind} → ${overlay.selector}`);
290
+ await capture(overlay.kind === "dismiss" ? "overlay_dismiss" : "overlay_advance", inv, overlay.selector);
291
+ try {
292
+ await browser.clickSelector(overlay.selector);
293
+ }
294
+ catch {
295
+ await browser.pressEscape().catch(() => { }); // modal with no in-DOM close
296
+ }
297
+ continue;
298
+ }
299
+ // 2) Goal check. Try extraction whenever we're plausibly on a key surface
300
+ // (on_key_surface OR create_gated — both imply we're at the keys page,
301
+ // and after a create-click the key may now be present). Extraction-first
302
+ // so a freshly-created key isn't missed because the create button persists.
303
+ const url = browser.currentUrl();
304
+ const text = await browser.extractText().catch(() => "");
305
+ const goal = assessKeyGoal({ url, pageText: text, inventory: inv });
306
+ if (goal.kind === "on_key_surface" || goal.kind === "create_gated") {
307
+ const creds = await deps.extractKey().catch(() => null);
308
+ if (creds !== null && Object.keys(creds).length > 0) {
309
+ log(`nav-search: key extracted on ${url}`);
310
+ await capture("extract", inv);
311
+ return { kind: "found", credentials: creds };
312
+ }
313
+ }
314
+ // 2b) No key yet, but a create affordance is available and untried → MINT.
315
+ // Prefer the full mint dep (it drives the two-step "name + confirm"
316
+ // modal, waits out the create POST's server round-trip, and reveals a
317
+ // masked-on-first-show value) — a bare click would leave the modal
318
+ // un-submitted and the loop would then dismiss it as an overlay. Fall
319
+ // back to a bare click only when no mint dep is wired (unit tests).
320
+ if (goal.kind === "create_gated" && !tried.has(goal.createSelector)) {
321
+ tried.add(goal.createSelector);
322
+ log(`nav-search: create-key subgoal → ${goal.createSelector}`);
323
+ await capture("create_key", inv, goal.createSelector);
324
+ if (deps.mintKey !== undefined) {
325
+ const minted = await deps.mintKey().catch(() => null);
326
+ if (minted !== null && Object.keys(minted).length > 0) {
327
+ log(`nav-search: minted key on ${url}`);
328
+ await capture("extract", inv);
329
+ return { kind: "found", credentials: minted };
330
+ }
331
+ continue;
332
+ }
333
+ await browser.clickSelector(goal.createSelector).catch(() => { });
334
+ continue;
335
+ }
336
+ // 3) Move: expand latent nav, then rank candidates from the UNION of the
337
+ // pre-expand and post-expand inventories. expandLatentNav toggles
338
+ // aria-haspopup menus blindly — if a menu (e.g. the user-avatar dropdown
339
+ // holding Account/Settings/Billing) was ALREADY open, the toggle closes
340
+ // it and a post-expand-only read loses exactly the keys-bearing nav. The
341
+ // union keeps an already-open menu's items AND adds a newly-opened one's.
342
+ const invBefore = inv;
343
+ await browser.expandLatentNav().catch(() => { });
344
+ const invAfter = await browser.extractInventory();
345
+ const mergedInv = mergeInventories(invBefore, invAfter);
346
+ inv = mergedInv;
347
+ // Drop already-tried AND off-site anchors: the key always lives inside the
348
+ // authenticated app, never on its marketing/docs domain.
349
+ const candidates = enumerateCandidates(mergedInv).filter((c) => !tried.has(c.selector) && !isOffSiteHref(url, c.href));
350
+ const rank = rankCandidates(candidates);
351
+ let pick = rank.ranked[0]?.selector ?? null;
352
+ if (pick === null && rank.needsTiebreak && deps.tiebreak !== undefined && candidates.length > 0) {
353
+ pick = await deps.tiebreak(candidates).catch(() => null);
354
+ if (pick !== null && tried.has(pick))
355
+ pick = null;
356
+ }
357
+ if (pick === null) {
358
+ // No rankable nav — but a gating onboarding CHOICE step (role/usage
359
+ // picker) blocks the dashboard. Satisfy the minimal step to advance.
360
+ const choice = planOnboardingChoice({ url, pageText: text, inventory: inv });
361
+ if (choice !== null && !tried.has(choice)) {
362
+ tried.add(choice);
363
+ log(`nav-search: onboarding choice → ${choice}`);
364
+ await capture("overlay_advance", inv, choice);
365
+ await browser.clickSelector(choice).catch(() => { });
366
+ continue;
367
+ }
368
+ // Dump what WAS on the page (text + href + selector) so an exhaustion is
369
+ // diagnosable: did the keys nav exist but score 0, or was it genuinely
370
+ // absent (behind a menu/icon we didn't expand)?
371
+ const seen = enumerateCandidates(inv).map((c) => `[${c.isAnchor ? "a" : "btn"}] "${c.text.slice(0, 40)}" href=${c.href ?? "-"} sel=${c.selector}`);
372
+ log(`nav-search: candidates exhausted — no self-serve key surface reachable. ` +
373
+ `page had ${seen.length} clickable(s): ${seen.join(" | ")}`);
374
+ return { kind: "no_self_serve_key" };
375
+ }
376
+ tried.add(pick);
377
+ const picked = candidates.find((c) => c.selector === pick);
378
+ const pickText = picked?.text ?? "";
379
+ // Prefer direct href-navigation for anchor picks: a click on a portaled/
380
+ // animated dropdown item (avatar menu, Radix popover) is fragile and often
381
+ // no-ops. The href is the known destination — go there.
382
+ const hrefTarget = picked?.isAnchor === true ? resolveNavHref(picked.href, url) : null;
383
+ await capture("navigate", inv, pick);
384
+ if (hrefTarget !== null) {
385
+ log(`nav-search: → "${pickText.slice(0, 40)}" via href ${hrefTarget}`);
386
+ await browser.navigate(hrefTarget).catch(() => { });
387
+ }
388
+ else {
389
+ log(`nav-search: → "${pickText.slice(0, 40)}" ${pick}`);
390
+ await browser.clickSelector(pick).catch(() => { });
391
+ }
392
+ }
393
+ log(`nav-search: step cap (${maxSteps}) reached without a key`);
394
+ return { kind: "no_self_serve_key" };
395
+ }
396
+ // Plan one step to get past a blocking overlay/wizard: prefer dismissing
397
+ // (skip/close — exits the wizard) over advancing (only when there's no skip).
398
+ // Pure; the caller clicks the selector (with an Escape-key fallback for modals
399
+ // that expose no in-DOM close control).
400
+ export function planOverlayStep(inventory) {
401
+ const dismiss = findOverlayDismiss(inventory);
402
+ if (dismiss !== null)
403
+ return { kind: "dismiss", selector: dismiss.selector };
404
+ const advance = findWizardAdvance(inventory);
405
+ if (advance !== null)
406
+ return { kind: "advance", selector: advance.selector };
407
+ return { kind: "none" };
408
+ }
409
+ //# sourceMappingURL=nav-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nav-search.js","sourceRoot":"","sources":["../../src/bot/nav-search.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,gFAAgF;AAChF,iFAAiF;AACjF,iFAAiF;AACjF,kFAAkF;AAClF,kFAAkF;AAClF,4EAA4E;AAC5E,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,mFAAmF;AACnF,+EAA+E;AAC/E,iFAAiF;AACjF,8CAA8C;AAG9C,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAYrF,6EAA6E;AAC7E,gFAAgF;AAChF,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,IAAmB,EAAE,UAAkB;IACpE,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,IAAI,gCAAgC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QACnC,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACvE,mEAAmE;QACnE,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,+EAA+E;AAC/E,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,IAAmB;IACnE,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC7C,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC,CAAC,+CAA+C;IAC/E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpE,OAAO,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,wDAAwD;IACvE,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,kEAAkE;AAClE,MAAM,UAAU,gBAAgB,CAC9B,CAAgC,EAChC,CAAgC;IAEhC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA8B,CAAC;IACzD,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,gFAAgF;AAChF,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,gBAAgB,GACpB,gKAAgK,CAAC;AAEnK,4DAA4D;AAC5D,MAAM,UAAU,mBAAmB,CAAC,SAAwC;IAC1E,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,SAAS,GACb,EAAE,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC;QACtF,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,IAAI,EAAE,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QACnC,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC;aAC9E,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aACzE,IAAI,CAAC,GAAG,CAAC;aACT,IAAI,EAAE,CAAC;QACV,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,yCAAyC;QACpF,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;YAAE,SAAS;QACxE,GAAG,CAAC,IAAI,CAAC;YACP,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,IAAI;YACJ,IAAI;YACJ,QAAQ,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG;YACxB,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,IAAI;SACnC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,6EAA6E;AAC7E,2EAA2E;AAC3E,mEAAmE;AACnE,MAAM,CAAC,MAAM,oBAAoB,GAC/B,iLAAiL,CAAC;AACpL,MAAM,SAAS,GAAG,oBAAoB,CAAC;AACvC,MAAM,gBAAgB,GAAG,uEAAuE,CAAC;AACjG,MAAM,cAAc,GAAG,uCAAuC,CAAC;AAC/D,MAAM,QAAQ,GACZ,iGAAiG,CAAC;AAEpG,MAAM,UAAU,cAAc,CAAC,CAAe;IAC5C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACpC,8EAA8E;IAC9E,0EAA0E;IAC1E,8CAA8C;IAC9C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,IAAI,IAAI,CAAC,CAAC,CAAC,wBAAwB;IAClF,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/B,IAAI,IAAI,CAAC,CAAC,CAAC,iCAAiC;SACzC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,IAAI,IAAI,CAAC,CAAC,CAAC,8BAA8B;IAC/E,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,sCAAsC;IAChE,IAAI,CAAC,GAAG,IAAI,CAAC;IACb,IAAI,CAAC,CAAC,QAAQ;QAAE,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC;IAC/D,IAAI,CAAC,CAAC,UAAU;QAAE,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,CAAC,CAAC;AACX,CAAC;AAWD,MAAM,UAAU,cAAc,CAAC,UAAmC;IAChE,MAAM,MAAM,GAAG,UAAU;SACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SACtB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,aAAa,GACjB,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnC,CAAC;AAWD,MAAM,UAAU,aAAa,CAAC,KAI7B;IACC,+EAA+E;IAC/E,+EAA+E;IAC/E,iFAAiF;IACjF,6EAA6E;IAC7E,iFAAiF;IACjF,2EAA2E;IAC3E,+EAA+E;IAC/E,6EAA6E;IAC7E,yEAAyE;IACzE,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACxD,IAAI,MAAM,KAAK,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IACnE,CAAC;IACD,4EAA4E;IAC5E,oEAAoE;IACpE,IACE,8BAA8B,CAAC;QAC7B,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,iBAAiB,EAAE,EAAE;KACtB,CAAC,EACF,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACpC,CAAC;IACD,+EAA+E;IAC/E,wEAAwE;IACxE,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACpC,CAAC;IACD,8EAA8E;IAC9E,yEAAyE;IACzE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,iFAAiF;AACjF,iFAAiF;AACjF,mEAAmE;AAEnE,iFAAiF;AACjF,2CAA2C;AAC3C,MAAM,cAAc,GAClB,iFAAiF,CAAC;AACpF,+EAA+E;AAC/E,mEAAmE;AACnE,MAAM,eAAe,GACnB,yFAAyF,CAAC;AAE5F,SAAS,WAAW,CAAC,EAAsB;IACzC,OAAO,CACL,CAAC,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC;QACrF,EAAE,CAAC,OAAO,KAAK,KAAK,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,EAAsB;IACpC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC;SACxE,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SACzE,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,kBAAkB,CAChC,SAAwC;IAExC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAAE,SAAS;QAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAC7B,2EAA2E;QAC3E,6EAA6E;QAC7E,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS;QAC5B,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,2EAA2E;AAC3E,qCAAqC;AACrC,MAAM,UAAU,iBAAiB,CAC/B,SAAwC;IAExC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAAE,SAAS;QAC/B,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAOD,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,iFAAiF;AACjF,MAAM,kBAAkB,GACtB,+KAA+K,CAAC;AAClL,MAAM,cAAc,GAClB,yFAAyF,CAAC;AAE5F,MAAM,UAAU,oBAAoB,CAAC,KAIpC;IACC,MAAM,aAAa,GACjB,+CAA+C,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/D,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CACpC,CAAC,EAAE,EAAE,EAAE,CACL,CAAC,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC;QAC7C,EAAE,CAAC,OAAO,KAAK,KAAK;QACpB,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAC3D,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,CAAC,EAAsB,EAAU,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/F,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC;AAC3C,CAAC;AA6DD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA6B,EAC7B,IAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC,CAAC,uCAAuC;IACxE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC,CAAC,oCAAoC;IAE5E,MAAM,OAAO,GAAG,KAAK,EACnB,MAAqF,EACrF,GAAkC,EAClC,QAAiB,EACF,EAAE;QACjB,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,OAAO;QAC5C,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC;gBACtB,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE;gBACzB,SAAS,EAAE,GAAG;gBACd,MAAM;gBACN,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,iDAAiD;QACnD,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;QAC3C,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAE3C,wEAAwE;QACxE,0EAA0E;QAC1E,yEAAyE;QACzE,4DAA4D;QAC5D,CAAC;YACC,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACxF,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5E,GAAG,CACD,oBAAoB,IAAI,QAAQ,IAAI,aAAa,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,IAAI,GAAG;gBAC/E,SAAS,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAClC,CAAC;QACJ,CAAC;QAED,uEAAuE;QACvE,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,GAAG,CAAC,uBAAuB,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;YACzG,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,6BAA6B;YAC5E,CAAC;YACD,SAAS;QACX,CAAC;QAED,0EAA0E;QAC1E,0EAA0E;QAC1E,4EAA4E;QAC5E,+EAA+E;QAC/E,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACnE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpD,GAAG,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;gBAC3C,MAAM,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;gBAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,2EAA2E;QAC3E,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;YACpE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC/B,GAAG,CAAC,oCAAoC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YAC/D,MAAM,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YACtD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;gBACtD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtD,GAAG,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;oBACxC,MAAM,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;oBAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;gBAChD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACjE,SAAS;QACX,CAAC;QAED,yEAAyE;QACzE,qEAAqE;QACrE,4EAA4E;QAC5E,2EAA2E;QAC3E,4EAA4E;QAC5E,6EAA6E;QAC7E,MAAM,SAAS,GAAG,GAAG,CAAC;QACtB,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAClD,MAAM,SAAS,GAAG,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxD,GAAG,GAAG,SAAS,CAAC;QAChB,2EAA2E;QAC3E,yDAAyD;QACzD,MAAM,UAAU,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC,MAAM,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAC7D,CAAC;QACF,MAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,IAAI,GAAkB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;QAC3D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChG,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,IAAI,GAAG,IAAI,CAAC;QACpD,CAAC;QACD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,oEAAoE;YACpE,qEAAqE;YACrE,MAAM,MAAM,GAAG,oBAAoB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7E,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1C,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClB,GAAG,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;gBACjD,MAAM,OAAO,CAAC,iBAAiB,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC9C,MAAM,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpD,SAAS;YACX,CAAC;YACD,yEAAyE;YACzE,uEAAuE;YACvE,gDAAgD;YAChD,MAAM,IAAI,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,GAAG,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC,QAAQ,EAAE,CACxG,CAAC;YACF,GAAG,CACD,0EAA0E;gBACxE,YAAY,IAAI,CAAC,MAAM,kBAAkB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAC;YACF,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACpC,yEAAyE;QACzE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,UAAU,GAAG,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,MAAM,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,GAAG,CAAC,kBAAkB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,UAAU,EAAE,CAAC,CAAC;YACvE,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,kBAAkB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,yBAAyB,QAAQ,yBAAyB,CAAC,CAAC;IAChE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;AACvC,CAAC;AAED,yEAAyE;AACzE,8EAA8E;AAC9E,+EAA+E;AAC/E,wCAAwC;AACxC,MAAM,UAAU,eAAe,CAAC,SAAwC;IACtE,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC7E,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { OAuthProviderId } from "./oauth-providers.js";
2
+ export type ProviderAuthState = "consent" | "needs_login" | "challenge" | "not_provider";
3
+ export declare function isAccountChooserUrl(url: string): boolean;
4
+ export interface OAuthState {
5
+ providerId: OAuthProviderId;
6
+ consentAlreadyApproved: boolean;
7
+ omniauthPostTried: boolean;
8
+ allowBlindOAuthConsent: boolean;
9
+ allowExtraOAuthScopes: readonly string[];
10
+ }
11
+ export interface OAuthObservation {
12
+ isChooser: boolean;
13
+ authState: ProviderAuthState;
14
+ hasLoginForm: boolean;
15
+ omniAuthPassthru: boolean;
16
+ scopes: readonly string[] | null;
17
+ dangerPhrases: readonly string[];
18
+ domBasicFromDom: boolean;
19
+ domBasicGis: boolean;
20
+ }
21
+ export type AdvanceMode = "approve" | "blind" | "soft";
22
+ export type OAuthAction = {
23
+ kind: "click_account_card";
24
+ } | {
25
+ kind: "advance_consent";
26
+ mode: AdvanceMode;
27
+ onAdvanceFail: "abort" | "bounded_wait" | "wait_nav";
28
+ } | {
29
+ kind: "recover_omniauth_post";
30
+ } | {
31
+ kind: "settle_left_provider";
32
+ } | {
33
+ kind: "handle_challenge";
34
+ } | {
35
+ kind: "abort";
36
+ reason: "needs_login" | "oauth_consent_needs_review";
37
+ clearProviderLoggedIn: boolean;
38
+ unauthorizedScopes?: readonly string[];
39
+ };
40
+ export interface OAuthStep {
41
+ action: OAuthAction;
42
+ nextState: OAuthState;
43
+ }
44
+ export interface OAuthDeps {
45
+ scopesAreBasic: (scopes: readonly string[]) => boolean;
46
+ }
47
+ export declare function decideOAuthStep(state: OAuthState, obs: OAuthObservation, deps: OAuthDeps): OAuthStep;
48
+ //# sourceMappingURL=oauth-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-flow.d.ts","sourceRoot":"","sources":["../../src/bot/oauth-flow.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAK5D,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,CAAC;AAQzF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AAID,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,eAAe,CAAC;IAC5B,sBAAsB,EAAE,OAAO,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC;IAChC,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAGD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IAEtB,gBAAgB,EAAE,OAAO,CAAC;IAE1B,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AACvD,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAK9B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,OAAO,GAAG,cAAc,GAAG,UAAU,CAAA;CAAE,GACpG;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,aAAa,GAAG,4BAA4B,CAAC;IAGrD,qBAAqB,EAAE,OAAO,CAAC;IAE/B,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEN,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IAGxB,cAAc,EAAE,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC;CACxD;AAKD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,SAAS,GACd,SAAS,CA6EX"}
@@ -0,0 +1,111 @@
1
+ // oauth-flow.ts — the PURE decision REDUCER for the OAuth/consent phase, carved
2
+ // out of runOAuthFlow's ~1450-line state machine (strangler slice 2 — see
3
+ // docs/DESIGN-oauth-consent-engine.md). Eng-reviewed (Claude + Codex): an
4
+ // action-only function was too thin for a stateful machine, so this models the
5
+ // whole decision as a reducer:
6
+ //
7
+ // decideOAuthStep(state, observation, deps) → { action, nextState }
8
+ //
9
+ // Browser-free and exhaustively unit-tested so the security-critical decisions
10
+ // (never type into a login form; never blind-approve a non-basic scope) and the
11
+ // intricate consent ORDERING are verifiable in isolation.
12
+ //
13
+ // BOUNDARY: the reducer DECIDES; the executor (agent.ts) does the I/O and owns
14
+ // the advance-success bookkeeping. Specifically the executor, not the reducer:
15
+ // • gathers the `observation` (reads the browser: url, scopes, DOM checks),
16
+ // • performs the consent advance (`advanceOAuthConsent`) for advance_consent
17
+ // actions and handles its !advanced micro-logic per `onAdvanceFail`,
18
+ // • flips `consentAlreadyApproved` → true on a SUCCESSFUL advance (the live
19
+ // code only sets it after the advance lands),
20
+ // • owns the hydrate-retry budget (`consentAdvanceWaits`) — pure I/O timing,
21
+ // not a decision,
22
+ // • runs the challenge mechanics, OmniAuth POST, notifications.
23
+ // The reducer never touches a browser and only mutates `omniauthPostTried`
24
+ // (a POST is "tried" regardless of outcome — a decision-relevant fact).
25
+ // The Google "Choose an account" chooser. Its "…to continue to <app>" copy
26
+ // matches the consent classifier, but it is an account PICKER, not a scope
27
+ // grant — it must be clicked through BEFORE the consent decision runs. The live
28
+ // loop gates this on Google (eng-review #8); the executor passes `isChooser`
29
+ // already provider-gated, but the helper is exported for that computation.
30
+ const ACCOUNT_CHOOSER_URL = /\/(?:accountchooser|chooseaccount|oauthchooseaccount)/i;
31
+ export function isAccountChooserUrl(url) {
32
+ return ACCOUNT_CHOOSER_URL.test(url);
33
+ }
34
+ // Decide the next OAuth step. PURE. Mirrors the live loop's branch ORDER exactly
35
+ // (the consent ordering is security- and correctness-critical — see the inline
36
+ // step numbers against agent.ts).
37
+ export function decideOAuthStep(state, obs, deps) {
38
+ const keep = (action) => ({ action, nextState: state });
39
+ // The account chooser is handled FIRST, before the auth-state branch.
40
+ if (obs.isChooser)
41
+ return keep({ kind: "click_account_card" });
42
+ switch (obs.authState) {
43
+ case "not_provider":
44
+ // OmniAuth GET-passthru → re-POST once; else the flow left the provider.
45
+ if (obs.omniAuthPassthru && !state.omniauthPostTried) {
46
+ return {
47
+ action: { kind: "recover_omniauth_post" },
48
+ nextState: { ...state, omniauthPostTried: true },
49
+ };
50
+ }
51
+ return keep({ kind: "settle_left_provider" });
52
+ case "challenge":
53
+ return keep({ kind: "handle_challenge" });
54
+ case "needs_login":
55
+ return keep({ kind: "abort", reason: "needs_login", clearProviderLoggedIn: true });
56
+ case "consent": {
57
+ // INVARIANT #1: a live login form on a "consent"-classified page → never
58
+ // type; abort needs_login.
59
+ if (obs.hasLoginForm) {
60
+ return keep({ kind: "abort", reason: "needs_login", clearProviderLoggedIn: true });
61
+ }
62
+ // ── readable scopes (scope gate, invariant #2) ──
63
+ if (obs.scopes !== null) {
64
+ const nonBasic = obs.scopes.filter((s) => !deps.scopesAreBasic([s]));
65
+ const unauthorized = nonBasic.filter((s) => !state.allowExtraOAuthScopes.includes(s));
66
+ if (unauthorized.length > 0) {
67
+ return keep({
68
+ kind: "abort",
69
+ reason: "oauth_consent_needs_review",
70
+ clearProviderLoggedIn: false,
71
+ unauthorizedScopes: unauthorized,
72
+ });
73
+ }
74
+ // basic, or every non-basic scope pre-approved → approve.
75
+ return keep({ kind: "advance_consent", mode: "approve", onAdvanceFail: "abort" });
76
+ }
77
+ // ── scopes unreadable (opaque part= URL) — ORDER MIRRORS agent.ts ──
78
+ // 1. danger scope-grant verb phrases in the DOM → abort (it IS a grant).
79
+ if (obs.dangerPhrases.length > 0) {
80
+ return keep({
81
+ kind: "abort",
82
+ reason: "oauth_consent_needs_review",
83
+ clearProviderLoggedIn: false,
84
+ });
85
+ }
86
+ // 2. basic-only DOM recover (only on the FIRST consent page) [agent.ts:7648].
87
+ if (state.providerId === "google" && !state.consentAlreadyApproved && obs.domBasicFromDom) {
88
+ return keep({ kind: "advance_consent", mode: "approve", onAdvanceFail: "abort" });
89
+ }
90
+ // 3. F16: post-grant page after an earlier approval → soft-advance [7679].
91
+ if (state.consentAlreadyApproved) {
92
+ return keep({ kind: "advance_consent", mode: "soft", onAdvanceFail: "wait_nav" });
93
+ }
94
+ // 4. blind-consent (user delegated) → advance with bounded hydrate retry [7705].
95
+ if (state.allowBlindOAuthConsent) {
96
+ return keep({ kind: "advance_consent", mode: "blind", onAdvanceFail: "bounded_wait" });
97
+ }
98
+ // 5. GIS basic-identity recover (second DOM check) [7742].
99
+ if (obs.domBasicGis) {
100
+ return keep({ kind: "advance_consent", mode: "approve", onAdvanceFail: "abort" });
101
+ }
102
+ // 6. conservative abort — unreadable scopes, no recovery signal [7753].
103
+ return keep({
104
+ kind: "abort",
105
+ reason: "oauth_consent_needs_review",
106
+ clearProviderLoggedIn: false,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=oauth-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-flow.js","sourceRoot":"","sources":["../../src/bot/oauth-flow.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,8 @@ export interface OnboardingRoundCapture {
16
16
  };
17
17
  inventory: readonly InteractiveElement[];
18
18
  observed: PostVerifyStep;
19
+ resolved_model?: string;
20
+ resolved_provider?: string;
19
21
  }
20
22
  export interface OnboardingCaseFile {
21
23
  capture_format_version: typeof CAPTURE_FORMAT_VERSION;
@@ -25,6 +27,8 @@ export interface OnboardingCaseFile {
25
27
  state: OnboardingRoundCapture["state"];
26
28
  inventory: readonly InteractiveElement[];
27
29
  observed: PostVerifyStep;
30
+ resolved_model?: string;
31
+ resolved_provider?: string;
28
32
  expect: null;
29
33
  prev_hash: string | null;
30
34
  content_hash: string;
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-capture.d.ts","sourceRoot":"","sources":["../../src/bot/onboarding-capture.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK7E,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AAUjD,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjD;AAWD,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAkBD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAGzC,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAID,MAAM,WAAW,kBAAkB;IACjC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACvC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,IAAI,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AA2BD,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAUjD;AAkBD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAwC1E;AAkBD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IAEZ,kBAAkB,EAAE,OAAO,CAAC;IAG5B,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAGrC,aAAa,EAAE,YAAY,CAAC;IAE5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAKD,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAGD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,iBAAiB,EAAE,OAAO,EAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,gBAAgB,CAelB;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAkB7E;AAWD,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,GAC1C;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EACF,iBAAiB,GACjB,eAAe,GACf,oBAAoB,GACpB,eAAe,GACf,WAAW,GACX,aAAa,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,iBAAiB,CA8FnB"}
1
+ {"version":3,"file":"onboarding-capture.d.ts","sourceRoot":"","sources":["../../src/bot/onboarding-capture.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK7E,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AAUjD,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjD;AAWD,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAkBD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAGzC,QAAQ,EAAE,cAAc,CAAC;IAKzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAID,MAAM,WAAW,kBAAkB;IACjC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACvC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC,QAAQ,EAAE,cAAc,CAAC;IAKzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,IAAI,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AA2BD,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAUjD;AAkBD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CA6C1E;AAkBD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IAEZ,kBAAkB,EAAE,OAAO,CAAC;IAG5B,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAGrC,aAAa,EAAE,YAAY,CAAC;IAE5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAKD,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAGD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,iBAAiB,EAAE,OAAO,EAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,gBAAgB,CAelB;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAkB7E;AAWD,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,GAC1C;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EACF,iBAAiB,GACjB,eAAe,GACf,oBAAoB,GACpB,eAAe,GACf,WAAW,GACX,aAAa,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,iBAAiB,CA8FnB"}