@trusty-squire/mcp 0.8.2-rc.12 → 0.8.2-rc.18

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.
@@ -200,6 +200,8 @@ export declare function parsePostVerifyStep(raw: string, allowedSelectors?: Read
200
200
  export declare function isTruncatedCapture(sourceText: string, capturedKey: string): boolean;
201
201
  export declare function extractQuotedTokenFromReason(reason: string, pageText: string): string | null;
202
202
  export declare function extractAllLabeledTokensFromReason(reason: string, pageText: string): Record<string, string>;
203
+ export declare function hasAnyExtractedCredential(creds: Record<string, string>): boolean;
204
+ export declare function isMultiCredBundle(creds: Record<string, string>): boolean;
203
205
  export declare function extractApiKeyFromText(text: string): string | null;
204
206
  export declare function pickVerificationLink(links: readonly string[]): string | null;
205
207
  export declare class SignupAgent {
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/bot/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/bot/agent.ts"],"names":[],"mappings":"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"}
package/dist/bot/agent.js CHANGED
@@ -1591,6 +1591,43 @@ export function extractAllLabeledTokensFromReason(reason, pageText) {
1591
1591
  function escapeRegex(s) {
1592
1592
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1593
1593
  }
1594
+ // Keys that the postVerifyLoop's accumulator stores for housekeeping —
1595
+ // they're NOT extracted credentials and must NOT count as "we found
1596
+ // something" when deciding whether an extract round succeeded.
1597
+ const NON_CREDENTIAL_KEYS = new Set([
1598
+ "api_key_truncated", // truncated stub from extractCredentials Pass 1
1599
+ "password", // signup form metadata (email-verification path)
1600
+ "email", // signup form metadata
1601
+ ]);
1602
+ // True iff the credentials Record holds at least one extracted value
1603
+ // (api_key, username, or any labeled multi-cred field). Excludes
1604
+ // metadata + truncated stubs. Used to decide "this extract round
1605
+ // produced something — continue the loop / capture a synthetic extract
1606
+ // round" vs "every tier missed — try the planner-quoted fallback".
1607
+ export function hasAnyExtractedCredential(creds) {
1608
+ for (const key of Object.keys(creds)) {
1609
+ if (NON_CREDENTIAL_KEYS.has(key))
1610
+ continue;
1611
+ return true;
1612
+ }
1613
+ return false;
1614
+ }
1615
+ // True iff the credentials Record contains a multi-credential bundle
1616
+ // — anything beyond the legacy single api_key/username pair. Used by
1617
+ // the post-verify loop's early-exit so a partial multi-cred capture
1618
+ // doesn't return prematurely (Cloudinary's api_key surfaces 4-5
1619
+ // rounds before api_secret; the legacy exit fired the moment api_key
1620
+ // was set, losing cloud_name + api_secret).
1621
+ export function isMultiCredBundle(creds) {
1622
+ for (const key of Object.keys(creds)) {
1623
+ if (NON_CREDENTIAL_KEYS.has(key))
1624
+ continue;
1625
+ if (key === "api_key" || key === "username")
1626
+ continue;
1627
+ return true;
1628
+ }
1629
+ return false;
1630
+ }
1594
1631
  export function extractApiKeyFromText(text) {
1595
1632
  const prefixed = [
1596
1633
  /\bre_[a-zA-Z0-9_]{20,}\b/, // Resend (key body contains underscores)
@@ -3517,14 +3554,20 @@ export class SignupAgent {
3517
3554
  }
3518
3555
  }
3519
3556
  let credentials = await this.extractCredentials();
3520
- if (credentials.api_key === undefined) {
3521
- credentials = await this.postVerifyLoop({
3522
- service: task.service,
3523
- maxRounds: task.postVerifyMaxRounds ?? 12,
3524
- steps,
3525
- ...(task.scopeHint !== undefined ? { scopeHint: task.scopeHint } : {}),
3526
- });
3527
- }
3557
+ // 0.8.2-rc.15 always enter postVerifyLoop. The legacy short-
3558
+ // circuit ("only call postVerifyLoop if api_key wasn't already
3559
+ // visible") returned early on multi-cred services that happen to
3560
+ // land with api_key plain-visible — cloud_name + api_secret on
3561
+ // Cloudinary, application_id + admin_api_key on Algolia — and the
3562
+ // siblings were never extracted. postVerifyLoop's top-of-iter
3563
+ // early-exit is itself multi-cred-aware (rc.13), so when there's
3564
+ // nothing more to do, it returns on the first iteration.
3565
+ credentials = await this.postVerifyLoop({
3566
+ service: task.service,
3567
+ maxRounds: task.postVerifyMaxRounds ?? 12,
3568
+ steps,
3569
+ ...(task.scopeHint !== undefined ? { scopeHint: task.scopeHint } : {}),
3570
+ });
3528
3571
  if (credentials.api_key !== undefined) {
3529
3572
  return {
3530
3573
  success: true,
@@ -3883,6 +3926,26 @@ ${formatInventory(input.inventory)}`,
3883
3926
  }
3884
3927
  async postVerifyLoop(args) {
3885
3928
  let credentials = await this.extractCredentials();
3929
+ // 0.8.2-rc.15 — also seed DOM-proximity at loop entry. If the
3930
+ // bot lands directly on the api-keys page (Cloudinary navigates
3931
+ // through onboarding to the dashboard automatically, sometimes
3932
+ // landing on /settings/api-keys), labeled siblings are visible
3933
+ // immediately and the loop's top-of-iter check (which respects
3934
+ // isMultiCredBundle) can hold the loop open for the planner to
3935
+ // emit an explicit extract. Without this seed, only api_key
3936
+ // would be set on entry and isMultiCredBundle would return
3937
+ // false → loop exits with a partial bundle.
3938
+ try {
3939
+ const labeledSeed = await this.extractFromDomProximity();
3940
+ for (const [k, v] of Object.entries(labeledSeed)) {
3941
+ if (credentials[k] === undefined)
3942
+ credentials[k] = v;
3943
+ }
3944
+ }
3945
+ catch {
3946
+ // Non-fatal — the planner's explicit extract round will run
3947
+ // DOM-proximity again, this is just an opportunistic seed.
3948
+ }
3886
3949
  let loginAttempts = 0;
3887
3950
  let planFailures = 0;
3888
3951
  // 0.8.2-rc.6 — separate counter for upstream-blip retries. Doesn't
@@ -3984,11 +4047,60 @@ ${formatInventory(input.inventory)}`,
3984
4047
  // contiguous 0..N-1 chain regardless of how many planner re-plans
3985
4048
  // happen mid-run.
3986
4049
  let capturedRound = 0;
4050
+ // 0.8.2-rc.12 — multi-cred-aware loop exit. Track the number of
4051
+ // distinct credential keys we've accumulated; if we're in a
4052
+ // multi-cred bundle (cloud_name, api_secret, application_id, …)
4053
+ // keep planning past the first api_key surfacing so siblings can
4054
+ // accumulate. Bounded by `roundsSinceLastNewCredential` so a
4055
+ // page that never produces a sibling doesn't loop forever.
4056
+ let lastCredentialKeyCount = Object.keys(credentials).filter((k) => !NON_CREDENTIAL_KEYS.has(k)).length;
4057
+ let roundsSinceLastNewCredential = 0;
4058
+ const MAX_ROUNDS_AWAITING_MORE_CREDENTIALS = 3;
4059
+ // 0.8.2-rc.16 — when the loop's pre-entry seed already had a
4060
+ // credential (Cloudinary's billing/plans page exposes the api_key
4061
+ // via a hidden field that extractCredentials catches), we cannot
4062
+ // trust that result as authoritative for multi-cred: the bot
4063
+ // hasn't navigated to a labeled api-keys page yet, so cloud_name
4064
+ // + api_secret are not yet visible to extractFromDomProximity.
4065
+ // Hold the loop open until the planner has issued at least one
4066
+ // explicit extract step — only then has the bot affirmatively
4067
+ // surveyed the labeled credentials surface.
4068
+ const seedHadCredential = credentials.api_key !== undefined || credentials.username !== undefined;
4069
+ let plannerExtractEmitted = false;
3987
4070
  for (let round = 0; round < args.maxRounds; round++) {
3988
- if (credentials.api_key !== undefined || credentials.username !== undefined) {
4071
+ const currentCredentialKeyCount = Object.keys(credentials).filter((k) => !NON_CREDENTIAL_KEYS.has(k)).length;
4072
+ if (currentCredentialKeyCount > lastCredentialKeyCount) {
4073
+ roundsSinceLastNewCredential = 0;
4074
+ lastCredentialKeyCount = currentCredentialKeyCount;
4075
+ }
4076
+ else if (lastCredentialKeyCount > 0) {
4077
+ roundsSinceLastNewCredential += 1;
4078
+ }
4079
+ // Multi-cred services hold the loop open until either the
4080
+ // planner returns `done`, the budget expires, or we've made
4081
+ // no credential progress for MAX_ROUNDS_AWAITING_MORE_CREDENTIALS
4082
+ // consecutive rounds. Single-cred services keep the legacy
4083
+ // behavior of returning the moment api_key surfaces — EXCEPT
4084
+ // when the api_key came from the pre-loop seed and the
4085
+ // planner hasn't yet emitted an explicit extract step. In
4086
+ // that case we let the planner run until extract fires.
4087
+ const inMultiCredMode = isMultiCredBundle(credentials);
4088
+ const haveOnlySeedCredentials = seedHadCredential && !plannerExtractEmitted;
4089
+ if (!inMultiCredMode &&
4090
+ (credentials.api_key !== undefined || credentials.username !== undefined) &&
4091
+ !haveOnlySeedCredentials) {
3989
4092
  args.steps.push(`Post-verify: credentials found on round ${round}.`);
3990
4093
  return credentials;
3991
4094
  }
4095
+ if (inMultiCredMode &&
4096
+ roundsSinceLastNewCredential >= MAX_ROUNDS_AWAITING_MORE_CREDENTIALS &&
4097
+ (credentials.api_key !== undefined || credentials.username !== undefined)) {
4098
+ const summary = Object.keys(credentials)
4099
+ .filter((k) => !NON_CREDENTIAL_KEYS.has(k))
4100
+ .join(", ");
4101
+ args.steps.push(`Post-verify: multi-cred bundle stable for ${roundsSinceLastNewCredential} rounds — returning what we have (${summary}).`);
4102
+ return credentials;
4103
+ }
3992
4104
  // Settle the page first — the previous round's click may have
3993
4105
  // triggered a navigation, and reading a page mid-navigation
3994
4106
  // throws "execution context destroyed". waitForFormReady is
@@ -4438,126 +4550,128 @@ ${formatInventory(input.inventory)}`,
4438
4550
  hint = undefined;
4439
4551
  try {
4440
4552
  if (nextStep.kind === "extract") {
4441
- credentials = await this.extractCredentials();
4442
- if (credentials.api_key === undefined) {
4443
- // rc.28 planner-quoted-token fallback. The regex
4444
- // library missed (IPInfo's 14-char hex; some other
4445
- // shape) but the planner's reason often literally
4446
- // quotes the value. Accept it IF it's also present
4447
- // verbatim in the visible page text — that's the
4448
- // anti-hallucination guardrail.
4449
- // rc.38 — verify the planner-quoted value against both
4450
- // visible text AND every input's `value` attribute. The
4451
- // rc.37 Upstash retest showed the bot quoting a bare UUID
4452
- // it observed in a create-key modal whose UUID lived in
4453
- // an <input readonly value="…"> textContent doesn't
4454
- // include input values, so the verbatim-in-page check
4455
- // rejected a real credential. Concatenating input values
4456
- // closes the gap without weakening the anti-hallucination
4457
- // guarantee (the candidate still has to appear SOMEWHERE
4458
- // verifiable on the page).
4459
- const [pageText, inputValues] = await Promise.all([
4460
- this.browser.extractText().catch(() => ""),
4461
- this.browser.extractAllInputValues().catch(() => []),
4462
- ]);
4463
- const verifySource = pageText + "\n" + inputValues.join("\n");
4464
- // Phase E multi-cred-aware extraction. Try the labeled
4465
- // multi-credential parser FIRST. If the planner labeled
4466
- // 2+ distinct credentials in its reason, fold them all
4467
- // into the credentials Record. If the parser found at
4468
- // least one new value (cloud_name, api_secret, etc.
4469
- // anything beyond the single api_key the legacy path
4470
- // captures), prefer this. Falls through to the single-
4471
- // value extractQuotedTokenFromReason when no labeled
4472
- // tokens parsed (single-cred services, ad-hoc planner
4473
- // prose without explicit labels).
4474
- const labeled = extractAllLabeledTokensFromReason(nextStep.reason, verifySource);
4475
- const labeledKeys = Object.keys(labeled);
4476
- if (labeledKeys.length >= 2 || (labeledKeys.length === 1 && labeled["api_key"] === undefined)) {
4477
- credentials = { ...credentials, ...labeled };
4478
- const summary = labeledKeys
4479
- .map((k) => `${k}=${labeled[k].slice(0, 4)}…${labeled[k].slice(-4)}`)
4480
- .join(", ");
4481
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: extracted ${labeledKeys.length} labeled credential(s) ` +
4482
- `via Phase E parser (${summary})`);
4483
- // When the planner's reason explicitly flags a masked
4484
- // credential ("api_secret is masked", "hidden behind
4485
- // asterisks", "click Reveal to show"), Phase E only
4486
- // captured the visible values — try to reveal + extract
4487
- // the rest on the same round before continuing. Without
4488
- // this, the loop returns success with a partial bundle
4489
- // and never tries the reveal click.
4490
- const MASKED_HINT = /\b(?:masked|hidden|bullets?|asterisks?|••+|\*{3,}|reveal|unmask)\b/i;
4491
- if (MASKED_HINT.test(nextStep.reason)) {
4492
- try {
4493
- const revealRes = await this.browser.revealMaskedCredentials();
4494
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: reveal pass clicked=${revealRes.clicked} diagnostic=[${revealRes.diagnostic.join("; ")}]`);
4495
- if (revealRes.clicked > 0) {
4496
- const labeledAfter = await this.extractFromDomProximity();
4497
- const newKeys = Object.keys(labeledAfter).filter((k) => credentials[k] === undefined);
4498
- if (newKeys.length > 0) {
4499
- for (const k of newKeys)
4500
- credentials[k] = labeledAfter[k];
4501
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: post-reveal DOM-proximity extracted ${newKeys.length} more (${newKeys.join(", ")})`);
4502
- }
4503
- else {
4504
- // Surface ALL labeled candidates we found, so
4505
- // we can see whether the value is on-page but
4506
- // mislabeled vs. genuinely not surfaced.
4507
- const allLabeled = await this.browser.extractLabeledCredentialCandidates();
4508
- const summary = allLabeled
4509
- .filter((c) => !c.isMasked)
4510
- .slice(0, 8)
4511
- .map((c) => `${c.value.slice(0, 6)}…(${c.value.length}ch)/${c.label ?? "no-label"}`)
4512
- .join(", ");
4513
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: post-reveal had ${allLabeled.length} candidates; visible: ${summary}`);
4514
- }
4515
- }
4553
+ // rc.16 record that the planner has now affirmatively
4554
+ // asked to extract from the current page. The top-of-iter
4555
+ // early-exit consults this to distinguish "api_key came
4556
+ // from a hidden field on a billing page" (don't exit) from
4557
+ // "api_key came from a labeled credential row the planner
4558
+ // just observed" (safe to exit on single-cred services).
4559
+ plannerExtractEmitted = true;
4560
+ // 0.8.2-rc.12 — multi-cred preservation + always-on Phase E.
4561
+ //
4562
+ // Pre-rc.12 the extract step was a tower of "if no api_key,
4563
+ // try Phase E; else done." That short-circuit silently lost
4564
+ // cloud_name + api_secret on Cloudinary-class services whose
4565
+ // api_key is plain-visible to the legacy regex extractor —
4566
+ // the legacy path filled credentials.api_key, the if-branch
4567
+ // skipped Phase E entirely, and the loop's top-of-iter exit
4568
+ // returned a partial bundle.
4569
+ //
4570
+ // New shape: run the legacy extractor, Phase E, the reveal
4571
+ // pass, and DOM-proximity UNCONDITIONALLY on every extract
4572
+ // round, merging each into `credentials` first-wins. A later
4573
+ // pass never clobbers a value an earlier pass labeled. This
4574
+ // mirrors the design doc: Phase E is the multi-cred surface;
4575
+ // single-cred is just multi-cred-with-one-key.
4576
+ const [pageText, inputValues] = await Promise.all([
4577
+ this.browser.extractText().catch(() => ""),
4578
+ this.browser.extractAllInputValues().catch(() => []),
4579
+ ]);
4580
+ const verifySource = pageText + "\n" + inputValues.join("\n");
4581
+ // Tier 1 legacy single-cred extractor (api_key by shape).
4582
+ // Merge into the running accumulator instead of overwriting;
4583
+ // a Phase E label captured on a prior round wins over a
4584
+ // later legacy regex hit.
4585
+ const legacy = await this.extractCredentials();
4586
+ for (const [k, v] of Object.entries(legacy)) {
4587
+ if (credentials[k] === undefined)
4588
+ credentials[k] = v;
4589
+ }
4590
+ // Tier 2 — Phase E labeled-token parser over the planner's
4591
+ // reason. Picks up cloud_name='dlq4xgrca' / api_key='4917…'
4592
+ // / application_id='X' / admin_api_key='…' style narrative.
4593
+ const labeled = extractAllLabeledTokensFromReason(nextStep.reason, verifySource);
4594
+ const labeledNewKeys = Object.keys(labeled).filter((k) => credentials[k] === undefined);
4595
+ if (labeledNewKeys.length > 0) {
4596
+ for (const k of labeledNewKeys)
4597
+ credentials[k] = labeled[k];
4598
+ const summary = labeledNewKeys
4599
+ .map((k) => `${k}=${labeled[k].slice(0, 4)}…${labeled[k].slice(-4)}`)
4600
+ .join(", ");
4601
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: Phase E surfaced ${labeledNewKeys.length} labeled credential(s) (${summary})`);
4602
+ }
4603
+ // Tier 2.5 — reveal-then-extract when the planner explicitly
4604
+ // flagged a masked credential. Fires whether or not we
4605
+ // already have other credentials — Cloudinary's api_secret
4606
+ // sits beside an already-visible api_key in the table.
4607
+ const MASKED_HINT = /\b(?:masked|hidden|bullets?|asterisks?|••+|\*{3,}|reveal|unmask)\b/i;
4608
+ if (MASKED_HINT.test(nextStep.reason)) {
4609
+ try {
4610
+ const revealRes = await this.browser.revealMaskedCredentials();
4611
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: reveal pass clicked=${revealRes.clicked} diagnostic=[${revealRes.diagnostic.join("; ")}]`);
4612
+ if (revealRes.clicked > 0) {
4613
+ const labeledAfter = await this.extractFromDomProximity();
4614
+ const afterNewKeys = Object.keys(labeledAfter).filter((k) => credentials[k] === undefined);
4615
+ if (afterNewKeys.length > 0) {
4616
+ for (const k of afterNewKeys)
4617
+ credentials[k] = labeledAfter[k];
4618
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: post-reveal DOM-proximity extracted ${afterNewKeys.length} more (${afterNewKeys.join(", ")})`);
4516
4619
  }
4517
- catch (err) {
4518
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: reveal pass error (${err instanceof Error ? err.message : String(err)})`);
4620
+ else {
4621
+ // Diagnostic: which candidates were seen on the page?
4622
+ // Helps debug "Reveal click landed but the value
4623
+ // didn't appear in proximity to a known label".
4624
+ const allLabeled = await this.browser.extractLabeledCredentialCandidates();
4625
+ const candSummary = allLabeled
4626
+ .filter((c) => !c.isMasked)
4627
+ .slice(0, 8)
4628
+ .map((c) => `${c.value.slice(0, 6)}…(${c.value.length}ch)/${c.label ?? "no-label"}`)
4629
+ .join(", ");
4630
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: post-reveal had ${allLabeled.length} candidates; visible: ${candSummary}`);
4519
4631
  }
4520
4632
  }
4521
- consecutiveFailedExtracts = 0;
4522
- continue;
4523
4633
  }
4524
- const quoted = extractQuotedTokenFromReason(nextStep.reason, verifySource);
4525
- if (quoted !== null) {
4526
- credentials = { ...credentials, api_key: quoted };
4527
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: extracted token via ` +
4528
- `planner-quoted fallback (${quoted.slice(0, 4)}…${quoted.slice(-4)})`);
4529
- consecutiveFailedExtracts = 0;
4530
- continue;
4531
- }
4532
- // Tier 4 — DOM-proximity labeled credential extraction.
4533
- // Run BEFORE bailing the extract. Walks the visible DOM,
4534
- // finds credential-shape strings, pairs each with its
4535
- // nearest credential-label text by Euclidean center
4536
- // distance. Catches multi-cred pages where the planner
4537
- // mentioned ONE value but the DOM shows several (the
4538
- // planner's narrative-style extract reason missed the
4539
- // sibling labels). Also tries to unmask hidden secrets
4540
- // first by clicking visible Reveal/Eye/Copy buttons.
4541
- try {
4542
- await this.browser.revealMaskedCredentials();
4543
- }
4544
- catch {
4545
- // Best-effort; never block the extract pass on a
4546
- // reveal-click failure.
4634
+ catch (err) {
4635
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: reveal pass error (${err instanceof Error ? err.message : String(err)})`);
4547
4636
  }
4637
+ }
4638
+ // Tier 3 — DOM-proximity labeled extractor. Walks the
4639
+ // visible DOM, pairs credential-shape strings with their
4640
+ // nearest credential-label text. Catches services whose
4641
+ // planner-reason narrative missed sibling labels but whose
4642
+ // DOM still has them as <td>/<dt> pairs.
4643
+ try {
4548
4644
  const labeledFromDom = await this.extractFromDomProximity();
4549
- const newKeys = Object.keys(labeledFromDom).filter((k) => credentials[k] === undefined);
4550
- if (newKeys.length > 0) {
4551
- for (const k of newKeys)
4645
+ const domNewKeys = Object.keys(labeledFromDom).filter((k) => credentials[k] === undefined);
4646
+ if (domNewKeys.length > 0) {
4647
+ for (const k of domNewKeys)
4552
4648
  credentials[k] = labeledFromDom[k];
4553
- const summary = newKeys
4554
- .map((k) => {
4555
- const v = labeledFromDom[k];
4556
- return `${k}=${v.slice(0, 4)}…${v.slice(-4)}`;
4557
- })
4649
+ const summary = domNewKeys
4650
+ .map((k) => `${k}=${labeledFromDom[k].slice(0, 4)}…${labeledFromDom[k].slice(-4)}`)
4558
4651
  .join(", ");
4559
- args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: extracted ${newKeys.length} labeled credential(s) ` +
4560
- `via DOM-proximity fallback (${summary})`);
4652
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: DOM-proximity surfaced ${domNewKeys.length} more (${summary})`);
4653
+ }
4654
+ }
4655
+ catch {
4656
+ // best-effort; never abort an extract pass on DOM-proximity
4657
+ // failure (page mid-navigation etc).
4658
+ }
4659
+ // Anything found across all tiers? hasMultiCredCredentials
4660
+ // also catches non-api_key labels (cloud_name, application_id).
4661
+ if (hasAnyExtractedCredential(credentials)) {
4662
+ consecutiveFailedExtracts = 0;
4663
+ continue;
4664
+ }
4665
+ // True extract failure — every tier missed. Try the legacy
4666
+ // single-value planner-quoted fallback for services whose
4667
+ // planner prose just bare-quotes the value without a known
4668
+ // label vocabulary (Railway UUID-only, IPInfo 14-hex).
4669
+ {
4670
+ const quoted = extractQuotedTokenFromReason(nextStep.reason, verifySource);
4671
+ if (quoted !== null) {
4672
+ credentials.api_key = quoted;
4673
+ args.steps.push(`Post-verify ${round + 1}/${args.maxRounds}: extracted token via ` +
4674
+ `planner-quoted fallback (${quoted.slice(0, 4)}…${quoted.slice(-4)})`);
4561
4675
  consecutiveFailedExtracts = 0;
4562
4676
  continue;
4563
4677
  }
@@ -4625,9 +4739,6 @@ ${formatInventory(input.inventory)}`,
4625
4739
  "generate a fresh one — its full value is shown once, on creation.";
4626
4740
  }
4627
4741
  }
4628
- else {
4629
- consecutiveFailedExtracts = 0;
4630
- }
4631
4742
  }
4632
4743
  else if (nextStep.kind === "click") {
4633
4744
  await this.browser.click(nextStep.selector);
@@ -4643,13 +4754,46 @@ ${formatInventory(input.inventory)}`,
4643
4754
  // services without modal-delay returns in <1s. Saves both
4644
4755
  // time (no overshoot wait) and correctness (catches the
4645
4756
  // modal-render race).
4757
+ // 0.8.2-rc.12 — merge polled extract into the running
4758
+ // credentials accumulator (was previously assigned to a
4759
+ // throwaway `pollExtract` local). On modal-key reveal
4760
+ // flows (OpenRouter, Anthropic, OpenAI) the credential
4761
+ // appears only here, and the legacy assignment was lost
4762
+ // unless the next round's top-of-iter re-read just
4763
+ // happened to find it again — a flaky guarantee.
4764
+ //
4765
+ // 0.8.2-rc.15 — also poll DOM-proximity. A click that
4766
+ // reveals an api_secret next to a known label (Cloudinary
4767
+ // reveal click → api_secret becomes visible next to "API
4768
+ // Secret" text) wouldn't surface in the legacy api_key-
4769
+ // shaped regex, so a multi-cred reveal landed nothing
4770
+ // unless the explicit extract round re-fired afterward.
4646
4771
  const credentialDeadline = Date.now() + 8000;
4647
- let pollExtract = {};
4648
4772
  while (Date.now() < credentialDeadline) {
4649
4773
  await this.browser.wait(0.5);
4650
4774
  try {
4651
- pollExtract = await this.extractCredentials();
4652
- if (pollExtract.api_key !== undefined)
4775
+ const pollExtract = await this.extractCredentials();
4776
+ for (const [k, v] of Object.entries(pollExtract)) {
4777
+ if (credentials[k] === undefined)
4778
+ credentials[k] = v;
4779
+ }
4780
+ try {
4781
+ const pollLabeled = await this.extractFromDomProximity();
4782
+ for (const [k, v] of Object.entries(pollLabeled)) {
4783
+ if (credentials[k] === undefined)
4784
+ credentials[k] = v;
4785
+ }
4786
+ }
4787
+ catch {
4788
+ // DOM-proximity failure is non-fatal; we'll retry
4789
+ // the next tick or fall through to the next round.
4790
+ }
4791
+ // Early-exit when we have an api_key — most services'
4792
+ // happy path completes in <1s. Multi-cred siblings
4793
+ // (api_secret, cloud_name) keep accumulating across
4794
+ // subsequent rounds; we don't hold the inner poll for
4795
+ // them here.
4796
+ if (credentials.api_key !== undefined)
4653
4797
  break;
4654
4798
  }
4655
4799
  catch {
@@ -4734,9 +4878,24 @@ ${formatInventory(input.inventory)}`,
4734
4878
  }
4735
4879
  // Re-extract — but tolerate the page still navigating from the
4736
4880
  // step just taken; the next round settles and re-reads.
4737
- const hadCredentialsBefore = credentials.api_key !== undefined || credentials.username !== undefined;
4881
+ // 0.8.2-rc.12 MERGE into the running accumulator. The pre-
4882
+ // rc.12 unconditional assignment wiped multi-cred fields the
4883
+ // explicit extract round just accumulated (cloud_name, api_secret,
4884
+ // etc.); on the next round's top-of-iter early-exit, only the
4885
+ // legacy single api_key survived.
4886
+ // 0.8.2-rc.12 — count distinct credential keys before re-extract
4887
+ // so the synthetic-extract trigger fires on ANY new key, not just
4888
+ // the legacy api_key / username pair. A cloudinary reveal click
4889
+ // can produce a fresh api_secret while api_key was already set;
4890
+ // the pre-rc.12 trigger silently skipped the synthetic capture
4891
+ // and the synthesizer then rejected on no_extract_step.
4892
+ const credCountBefore = Object.keys(credentials).filter((k) => !NON_CREDENTIAL_KEYS.has(k)).length;
4738
4893
  try {
4739
- credentials = await this.extractCredentials();
4894
+ const reExtract = await this.extractCredentials();
4895
+ for (const [k, v] of Object.entries(reExtract)) {
4896
+ if (credentials[k] === undefined)
4897
+ credentials[k] = v;
4898
+ }
4740
4899
  }
4741
4900
  catch {
4742
4901
  // page mid-navigation — next round's waitForFormReady handles it
@@ -4754,8 +4913,8 @@ ${formatInventory(input.inventory)}`,
4754
4913
  // RIGHT NOW (the action just ran, the token row is now visible).
4755
4914
  // Best-effort — a capture failure must never block returning the
4756
4915
  // credential we already have.
4757
- const haveNewCredentials = !hadCredentialsBefore &&
4758
- (credentials.api_key !== undefined || credentials.username !== undefined);
4916
+ const credCountAfter = Object.keys(credentials).filter((k) => !NON_CREDENTIAL_KEYS.has(k)).length;
4917
+ const haveNewCredentials = credCountAfter > credCountBefore;
4759
4918
  if (haveNewCredentials && nextStep.kind !== "extract") {
4760
4919
  try {
4761
4920
  const [postState, postInventory] = await Promise.all([
@@ -4936,17 +5095,30 @@ Strategy:
4936
5095
  return "extract" for a masked key, and do not return "extract" twice
4937
5096
  in a row. Instead click "Create API Key" / "New API Key" / "Generate"
4938
5097
  to make a fresh key, then extract its full value.
4939
- - **REVEAL-CLICK BEFORE EXTRACT** — when a credential is shown masked
4940
- (•••••, asterisks, dots) AND there is a VISIBLE "Show", "Reveal",
4941
- "Eye", or eye-icon button NEXT TO IT (typically same row in a
4942
- credentials table Cloudinary, Twilio, Stripe all follow this
4943
- pattern for api_secret / auth_token / secret_key), emit a CLICK
4944
- on that show/reveal button FIRST. Do NOT return extract on the same
4945
- round as the masked display — the masked text would be parsed as
4946
- the value. Next round the value will be visible and your extract
4947
- step can quote it. The bot's reveal-pass is a fallback; explicit
4948
- clicks via the planner are more reliable because you can see the
4949
- exact button in the screenshot.
5098
+ - **PARTIAL MULTI-CRED EXTRACT IS BETTER THAN ZERO** — on a multi-
5099
+ cred page where some credentials are visible and others are masked
5100
+ behind a Reveal button, return {"kind":"extract"} NOW for the
5101
+ visible labels (the bot's labeled extractor folds them into the
5102
+ credentials bundle) AND in the same reason field flag the masked
5103
+ credential so the bot's automatic reveal pass fires. Example
5104
+ reason for Cloudinary: "cloud_name='dlq4xgrca' and
5105
+ api_key='491741466469613' are visible in the table; api_secret is
5106
+ hidden behind a Reveal button please unmask." The masked
5107
+ credential's label MUST appear with one of the trigger words
5108
+ (masked / hidden / reveal / unmask / bullets / asterisks) so the
5109
+ reveal pass triggers. Do this BEFORE attempting any explicit
5110
+ reveal click — getting the visible values into the bundle first
5111
+ means a failed reveal click only loses the masked credential, not
5112
+ the visible ones too.
5113
+ - **REVEAL-CLICK AS A FALLBACK** — when the page has ONLY a masked
5114
+ credential (no visible siblings) AND there is a VISIBLE "Show",
5115
+ "Reveal", "Eye", or eye-icon button next to it, emit a CLICK on
5116
+ that button. If a previous reveal click had no effect (the page's
5117
+ inventory and screenshot look identical), do NOT keep retrying —
5118
+ emit {"kind":"extract"} anyway: the bot's labeled extractor will
5119
+ capture whatever IS visible (even if just a cloud_name with no
5120
+ api_secret) and return the partial bundle to the caller, which is
5121
+ more useful than five wasted rounds of clicking a dead reveal.
4950
5122
  - To reach API keys, prefer a {"kind":"navigate"} straight to the
4951
5123
  service's API-keys settings URL — note these usually live under the
4952
5124
  user/ACCOUNT settings, not a project or workspace's settings.