cdp-toolkit 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js CHANGED
@@ -13,6 +13,16 @@ function leaseTtlMs() {
13
13
  const raw = Number(process.env.CDP_LEASE_TTL_MS);
14
14
  return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LEASE_TTL_MS;
15
15
  }
16
+ var longLived = false;
17
+ function markLongLivedProcess(value = true) {
18
+ longLived = value;
19
+ }
20
+ function requireLease() {
21
+ if (!longLived)
22
+ return false;
23
+ const raw = (process.env.CDP_REQUIRE_LEASE ?? "").trim().toLowerCase();
24
+ return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
25
+ }
16
26
  function defaultLabel() {
17
27
  return `pid-${process.pid}`;
18
28
  }
@@ -99,7 +109,8 @@ async function claimLease(backend, targetId, opts) {
99
109
  label: opts.label,
100
110
  createdAt: now,
101
111
  lastUsedAt: now,
102
- ttlMs: opts.ttlMs ?? leaseTtlMs()
112
+ ttlMs: opts.ttlMs ?? leaseTtlMs(),
113
+ auto: opts.auto === true
103
114
  };
104
115
  try {
105
116
  await writeFile(leaseFile(backend, targetId), JSON.stringify(record), { flag: "wx" });
@@ -175,8 +186,16 @@ async function assertLeaseOk(backend, targetId, ctx = {}) {
175
186
  const held = rec && !staleReason(rec, { now, liveIds: ctx.liveIds }) ? rec : undefined;
176
187
  const where = describeTarget(targetId, ctx);
177
188
  if (token === undefined) {
178
- if (!held)
189
+ if (!held) {
190
+ if (requireLease()) {
191
+ await claimLease(backend, targetId, { label: defaultLabel(), ttlMs: leaseTtlMs(), auto: true, now });
192
+ }
179
193
  return;
194
+ }
195
+ if (held.auto === true && held.pid === process.pid) {
196
+ await touchLease(held, now);
197
+ return;
198
+ }
180
199
  throw new LeaseConflictError(`${where} is leased by '${held.label}' (pid ${held.pid}). Pass that lease's token as the 'lease' argument, or call release_page to free it. list_leases shows every active lease.`, targetId, held.label);
181
200
  }
182
201
  const parts = tokenParts(token);
@@ -184,8 +203,12 @@ async function assertLeaseOk(backend, targetId, ctx = {}) {
184
203
  throw new LeaseConflictError(`malformed lease token for ${where}. Pass back the token claim_page returned, never a constructed one.`, targetId);
185
204
  }
186
205
  if (parts.backend !== backend || parts.targetId !== targetId) {
187
- if (!held)
206
+ if (!held) {
207
+ if (requireLease()) {
208
+ await claimLease(backend, targetId, { label: defaultLabel(), ttlMs: leaseTtlMs(), auto: true, now });
209
+ }
188
210
  return;
211
+ }
189
212
  throw new LeaseConflictError(`the lease token you passed is for ${parts.backend} target '${parts.targetId}', not ${where}, which is leased by '${held.label}'. Resolve the tab you actually hold, or claim this one.`, targetId, held.label);
190
213
  }
191
214
  if (!held) {
@@ -1429,6 +1452,20 @@ async function recordOrigin(backend, targetId, opts = {}) {
1429
1452
  await writeFile2(file, JSON.stringify(record), { flag: "wx" });
1430
1453
  } catch {}
1431
1454
  }
1455
+ async function readOrigin(backend, targetId) {
1456
+ let raw;
1457
+ try {
1458
+ raw = await readFile2(originFile(backend, targetId), "utf8");
1459
+ } catch {
1460
+ return;
1461
+ }
1462
+ try {
1463
+ const rec = JSON.parse(raw);
1464
+ if (typeof rec?.targetId === "string" && typeof rec?.label === "string" && typeof rec?.createdAt === "number")
1465
+ return rec;
1466
+ } catch {}
1467
+ return;
1468
+ }
1432
1469
  async function listOrigins(opts = {}) {
1433
1470
  let names = [];
1434
1471
  try {
@@ -1486,59 +1523,43 @@ async function newTrackedPage(driver, backend, opts = {}) {
1486
1523
  return page;
1487
1524
  }
1488
1525
 
1489
- // src/leases-tools.ts
1490
- class LeaseToolError extends Error {
1491
- }
1492
- function backendOf(driver) {
1493
- return driver.scheme === "bidi" ? "firefox" : "chrome";
1494
- }
1495
- async function claimPage(driver, args = {}) {
1496
- const backend = backendOf(driver);
1497
- const label = typeof args.label === "string" && args.label.length ? args.label : defaultLabel();
1498
- const pages = await driver.listPages();
1499
- let targetId = args.targetId;
1500
- let url = args.url ?? "about:blank";
1501
- if (targetId === undefined || targetId === "") {
1502
- const page = await newTrackedPage(driver, backend, { url: args.url, label });
1503
- targetId = page.id;
1504
- url = page.url;
1505
- } else {
1506
- const existing = pages.find((p) => p.id === targetId);
1507
- if (!existing)
1508
- throw new LeaseToolError(`claim_page: no page target with id '${targetId}'`);
1509
- url = existing.url;
1526
+ // src/reap.ts
1527
+ function staleAgentTabs(input) {
1528
+ const live = new Set(input.livePageIds);
1529
+ const out = [];
1530
+ for (const row of input.leases) {
1531
+ if (row.backend !== input.backend)
1532
+ continue;
1533
+ if (row.unreadable !== undefined)
1534
+ continue;
1535
+ if (row.stale !== "dead-pid" && row.stale !== "expired")
1536
+ continue;
1537
+ if (!live.has(row.targetId))
1538
+ continue;
1539
+ const origin = input.origins.get(row.targetId);
1540
+ if (origin === undefined || origin.unreadable !== undefined)
1541
+ continue;
1542
+ out.push({ targetId: row.targetId, label: row.label, reason: row.stale });
1510
1543
  }
1511
- const liveIds = [...pages.map((p) => p.id), targetId];
1512
- const { record, token } = await claimLease(backend, targetId, {
1513
- label,
1514
- ttlMs: typeof args.ttlMs === "number" && args.ttlMs > 0 ? args.ttlMs : leaseTtlMs(),
1515
- liveIds
1516
- });
1517
- return {
1518
- lease: token,
1519
- targetId,
1520
- url,
1521
- label: record.label,
1522
- ttlMs: record.ttlMs,
1523
- expiresAt: record.lastUsedAt + record.ttlMs
1524
- };
1544
+ return out;
1525
1545
  }
1526
- async function releasePage(_driver, args) {
1527
- if (typeof args.lease !== "string" || !args.lease.length) {
1528
- throw new LeaseToolError("release_page requires the 'lease' token returned by claim_page");
1546
+ async function reapStaleAgentTabs(driver, backend) {
1547
+ const livePageIds = (await driver.listPages()).map((p) => p.id);
1548
+ const [origins, leases] = await Promise.all([
1549
+ originIndex(backend, undefined),
1550
+ listLeases({ liveIds: livePageIds, liveBackend: backend }).catch(() => [])
1551
+ ]);
1552
+ const candidates = staleAgentTabs({ backend, livePageIds, origins, leases });
1553
+ const closed = [];
1554
+ for (const c of candidates) {
1555
+ const res = await driver.closePage(c.targetId).catch(() => ({ success: false }));
1556
+ if (res.success !== true)
1557
+ continue;
1558
+ await releaseLeaseFor(backend, c.targetId);
1559
+ closed.push(c);
1529
1560
  }
1530
- return releaseLease(args.lease);
1531
- }
1532
- async function listLeasesTool(driver, _args = {}) {
1533
- const liveIds = (await driver.listPages()).map((p) => p.id);
1534
- const leases = await listLeases({ liveIds, liveBackend: backendOf(driver) });
1535
- return { leases, count: leases.length };
1561
+ return closed;
1536
1562
  }
1537
- var LEASE_TOOLS = {
1538
- claim_page: claimPage,
1539
- release_page: releasePage,
1540
- list_leases: listLeasesTool
1541
- };
1542
1563
 
1543
1564
  // src/shared-tools.ts
1544
1565
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
@@ -1551,7 +1572,7 @@ class SharedToolError extends Error {
1551
1572
  function target3(p) {
1552
1573
  return { id: p.id, url: p.url, title: p.title };
1553
1574
  }
1554
- function backendOf2(driver) {
1575
+ function backendOf(driver) {
1555
1576
  return driver.scheme === "bidi" ? "firefox" : "chrome";
1556
1577
  }
1557
1578
  async function withPage2(driver, target, fn) {
@@ -1565,7 +1586,7 @@ async function withPage2(driver, target, fn) {
1565
1586
  async function resolvePage(driver, selector) {
1566
1587
  const pages = await driver.listPages();
1567
1588
  const hit = await pickPage(driver, pages, selector);
1568
- await assertLeaseOk(backendOf2(driver), hit.id, { url: hit.url, title: hit.title });
1589
+ await assertLeaseOk(backendOf(driver), hit.id, { url: hit.url, title: hit.title });
1569
1590
  return hit;
1570
1591
  }
1571
1592
  async function pickPage(driver, pages, selector) {
@@ -1620,8 +1641,10 @@ async function reapSet(driver, pages, all) {
1620
1641
  }
1621
1642
  }
1622
1643
  async function listPages(driver, args = {}) {
1623
- const pages = await driver.listPages({ all: args.all });
1624
- const ledger = await originIndex(backendOf2(driver), await reapSet(driver, pages, args.all));
1644
+ const reaped = requireLease() ? await reapStaleAgentTabs(driver, backendOf(driver)) : [];
1645
+ const reapedIds = new Set(reaped.map((r) => r.targetId));
1646
+ const pages = (await driver.listPages({ all: args.all })).filter((p) => !reapedIds.has(p.id));
1647
+ const ledger = await originIndex(backendOf(driver), await reapSet(driver, pages, args.all));
1625
1648
  const annotated = pages.map((p) => {
1626
1649
  const rec = ledger.get(p.id);
1627
1650
  if (!rec)
@@ -1630,16 +1653,18 @@ async function listPages(driver, args = {}) {
1630
1653
  return { ...p, origin: "unknown", originUnreadable: rec.unreadable };
1631
1654
  return { ...p, origin: "agent", label: rec.label, createdAt: rec.createdAt };
1632
1655
  });
1633
- return { pages: annotated, count: annotated.length };
1656
+ return { pages: annotated, count: annotated.length, ...reaped.length ? { reaped } : {} };
1634
1657
  }
1635
1658
  async function newPage(driver, args = {}) {
1636
1659
  const label = typeof args.label === "string" && args.label.length ? args.label : defaultLabel();
1637
- const p = await newTrackedPage(driver, backendOf2(driver), { url: args.url, label });
1638
- if (args.claim !== true)
1660
+ const p = await newTrackedPage(driver, backendOf(driver), { url: args.url, label });
1661
+ const explicit = args.claim === true;
1662
+ if (!explicit && !requireLease())
1639
1663
  return { targetId: p.id, url: p.url };
1640
- const { record, token } = await claimLease(backendOf2(driver), p.id, {
1664
+ const { record, token } = await claimLease(backendOf(driver), p.id, {
1641
1665
  label,
1642
- ttlMs: typeof args.ttlMs === "number" && args.ttlMs > 0 ? args.ttlMs : leaseTtlMs()
1666
+ ttlMs: typeof args.ttlMs === "number" && args.ttlMs > 0 ? args.ttlMs : leaseTtlMs(),
1667
+ auto: !explicit
1643
1668
  });
1644
1669
  return { targetId: p.id, url: p.url, lease: token, label: record.label, expiresAt: record.lastUsedAt + record.ttlMs };
1645
1670
  }
@@ -1650,7 +1675,7 @@ async function closePage(driver, args) {
1650
1675
  const res = await driver.closePage(p.id);
1651
1676
  if (!res.success)
1652
1677
  return { closed: p.id, success: false, leaseReleased: false };
1653
- const released = await releaseLeaseFor(backendOf2(driver), p.id);
1678
+ const released = await releaseLeaseFor(backendOf(driver), p.id);
1654
1679
  return { closed: p.id, success: true, ...released.released ? { leaseReleased: true } : {} };
1655
1680
  }
1656
1681
  async function writeSelectedFile(id) {
@@ -1975,6 +2000,103 @@ var SHARED_TOOLS = {
1975
2000
  handle_dialog: handleDialog
1976
2001
  };
1977
2002
 
2003
+ // src/leases-tools.ts
2004
+ class LeaseToolError extends Error {
2005
+ }
2006
+ function backendOf2(driver) {
2007
+ return driver.scheme === "bidi" ? "firefox" : "chrome";
2008
+ }
2009
+ async function claimPage(driver, args = {}) {
2010
+ const hasTarget = typeof args.target === "string" && args.target.length > 0;
2011
+ const hasTargetId = typeof args.targetId === "string" && args.targetId.length > 0;
2012
+ if (hasTarget && hasTargetId) {
2013
+ throw new LeaseToolError("claim_page takes at most one of 'target' (any selector: active | index:N | url:<substr> | title:<substr> | <targetId>) or 'targetId' (an exact target id, kept for back-compat). Pass 'target' alone to claim an open tab, or neither to open a fresh one.");
2014
+ }
2015
+ const backend = backendOf2(driver);
2016
+ const label = typeof args.label === "string" && args.label.length ? args.label : defaultLabel();
2017
+ const pages = await driver.listPages();
2018
+ let targetId;
2019
+ let url;
2020
+ let opened;
2021
+ if (hasTarget) {
2022
+ const hit = await pickPage(driver, pages, args.target).catch((err) => {
2023
+ throw new LeaseToolError(`claim_page: no open tab matches target '${args.target}' (${err.message}). No tab was opened: claim_page never creates one when 'target' is given.`);
2024
+ });
2025
+ targetId = hit.id;
2026
+ url = hit.url;
2027
+ opened = false;
2028
+ } else if (hasTargetId) {
2029
+ const existing = pages.find((p) => p.id === args.targetId);
2030
+ if (!existing)
2031
+ throw new LeaseToolError(`claim_page: no page target with id '${args.targetId}'`);
2032
+ targetId = existing.id;
2033
+ url = existing.url;
2034
+ opened = false;
2035
+ } else {
2036
+ const page = await newTrackedPage(driver, backend, { url: args.url, label });
2037
+ targetId = page.id;
2038
+ url = page.url;
2039
+ opened = true;
2040
+ }
2041
+ const liveIds = [...pages.map((p) => p.id), targetId];
2042
+ const { record, token } = await claimLease(backend, targetId, {
2043
+ label,
2044
+ ttlMs: typeof args.ttlMs === "number" && args.ttlMs > 0 ? args.ttlMs : leaseTtlMs(),
2045
+ liveIds
2046
+ });
2047
+ return {
2048
+ lease: token,
2049
+ targetId,
2050
+ url,
2051
+ label: record.label,
2052
+ ttlMs: record.ttlMs,
2053
+ expiresAt: record.lastUsedAt + record.ttlMs,
2054
+ opened
2055
+ };
2056
+ }
2057
+ async function releasePage(driver, args = {}) {
2058
+ const hasLease = typeof args.lease === "string" && args.lease.length > 0;
2059
+ const hasTarget = typeof args.target === "string" && args.target.length > 0;
2060
+ if (hasLease === hasTarget) {
2061
+ throw new LeaseToolError("release_page takes exactly one of 'lease' (the token claim_page returned) or 'target' (a selector for a tab this process holds)");
2062
+ }
2063
+ const backend = backendOf2(driver);
2064
+ let targetId;
2065
+ let released;
2066
+ if (hasLease) {
2067
+ const parts = tokenParts(args.lease);
2068
+ if (!parts)
2069
+ return { released: false, closed: false };
2070
+ targetId = parts.targetId;
2071
+ released = (await releaseLease(args.lease)).released;
2072
+ } else {
2073
+ const page = await resolvePage(driver, args.target);
2074
+ targetId = page.id;
2075
+ released = (await releaseLeaseFor(backend, targetId)).released;
2076
+ }
2077
+ if (!released)
2078
+ return { released: false, closed: false, ...hasTarget ? { targetId } : {} };
2079
+ const shouldClose = args.close === false ? false : args.close === true ? true : await readOrigin(backend, targetId) !== undefined;
2080
+ if (!shouldClose)
2081
+ return { released: true, closed: false, targetId };
2082
+ const res = await driver.closePage(targetId).catch(() => ({ success: false }));
2083
+ return { released: true, closed: res.success === true, targetId };
2084
+ }
2085
+ async function listLeasesTool(driver, _args = {}) {
2086
+ const backend = backendOf2(driver);
2087
+ const reaped = requireLease() ? await reapStaleAgentTabs(driver, backend) : [];
2088
+ const reapedIds = new Set(reaped.map((r) => r.targetId));
2089
+ const liveIds = (await driver.listPages()).map((p) => p.id);
2090
+ const all = await listLeases({ liveIds, liveBackend: backend });
2091
+ const leases = all.filter((l) => !(l.backend === backend && reapedIds.has(l.targetId)));
2092
+ return { leases, count: leases.length, ...reaped.length ? { reaped } : {} };
2093
+ }
2094
+ var LEASE_TOOLS = {
2095
+ claim_page: claimPage,
2096
+ release_page: releasePage,
2097
+ list_leases: listLeasesTool
2098
+ };
2099
+
1978
2100
  // src/tools/console.ts
1979
2101
  import { readFile as readFile3 } from "node:fs/promises";
1980
2102
 
@@ -3181,13 +3303,13 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
3181
3303
  var MANIFEST = [
3182
3304
  {
3183
3305
  name: "list_pages",
3184
- description: "Enumerate browser page targets via the CDP browser endpoint (GET /json/list). By default returns only page-type tabs; set 'all' to also include workers and background pages. Each entry carries the targetId used as a target selector elsewhere, plus an 'origin' field recording where the tab came from: 'agent' means this toolkit created it (the entry then also carries the creating 'label' and 'createdAt'), and this stays true after the creating agent releases its lease or dies, which is what makes a stray agent tab findable later. 'unknown' means there is no creation record. It never says 'human': the toolkit cannot prove a person opened a tab, so 'unknown' is the honest word for a tab it did not create, one opened before the toolkit ran, or one whose record could not be written. A tab whose record exists but could not be read reports origin 'unknown' plus 'originUnreadable', so a broken record is never mistaken for no record.",
3306
+ description: "Enumerate browser page targets via the CDP browser endpoint (GET /json/list). By default returns only page-type tabs; set 'all' to also include workers and background pages. Each entry carries the targetId used as a target selector elsewhere, plus an 'origin' field recording where the tab came from: 'agent' means this toolkit created it (the entry then also carries the creating 'label' and 'createdAt'), and this stays true after the creating agent releases its lease or dies, which is what makes a stray agent tab findable later. 'unknown' means there is no creation record. It never says 'human': the toolkit cannot prove a person opened a tab, so 'unknown' is the honest word for a tab it did not create, one opened before the toolkit ran, or one whose record could not be written. A tab whose record exists but could not be read reports origin 'unknown' plus 'originUnreadable', so a broken record is never mistaken for no record. Under CDP_REQUIRE_LEASE this call also reaps: a tab this toolkit created whose lease is stale because the owning process died or the TTL elapsed is closed, and the closed tabs are reported in an additive 'reaped' array ({targetId,label,reason}) that is present only when something was actually closed. A tab with no lease is never reaped, so tabs opened by a caller that never uses leases are untouched.",
3185
3307
  inputSchema: {
3186
3308
  type: "object",
3187
3309
  properties: {
3188
3310
  lease: {
3189
3311
  type: "string",
3190
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3312
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3191
3313
  },
3192
3314
  all: {
3193
3315
  type: "boolean",
@@ -3206,7 +3328,7 @@ var MANIFEST = [
3206
3328
  properties: {
3207
3329
  lease: {
3208
3330
  type: "string",
3209
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3331
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3210
3332
  },
3211
3333
  url: {
3212
3334
  type: "string",
@@ -3214,7 +3336,7 @@ var MANIFEST = [
3214
3336
  },
3215
3337
  claim: {
3216
3338
  type: "boolean",
3217
- description: "Claim the new tab atomically as part of creating it and return a lease token alongside {targetId,url}. Default false, which is byte-identical to the pre-1.2 behavior."
3339
+ description: "Claim the new tab atomically as part of creating it and return a lease token alongside {targetId,url}. Default false, which is byte-identical to the pre-1.2 behavior. Under CDP_REQUIRE_LEASE the new tab is claimed and a lease returned even without claim:true, because a tab nobody holds is a tab nobody may drive; passing claim:true additionally makes the lease an explicit one, which requires its token on every later call even from this same process."
3218
3340
  },
3219
3341
  label: {
3220
3342
  type: "string",
@@ -3237,7 +3359,7 @@ var MANIFEST = [
3237
3359
  properties: {
3238
3360
  lease: {
3239
3361
  type: "string",
3240
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3362
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3241
3363
  },
3242
3364
  target: {
3243
3365
  type: "string",
@@ -3258,7 +3380,7 @@ var MANIFEST = [
3258
3380
  properties: {
3259
3381
  lease: {
3260
3382
  type: "string",
3261
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3383
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3262
3384
  },
3263
3385
  target: {
3264
3386
  type: "string",
@@ -3279,7 +3401,7 @@ var MANIFEST = [
3279
3401
  properties: {
3280
3402
  lease: {
3281
3403
  type: "string",
3282
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3404
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3283
3405
  },
3284
3406
  target: {
3285
3407
  type: "string",
@@ -3321,7 +3443,7 @@ var MANIFEST = [
3321
3443
  properties: {
3322
3444
  lease: {
3323
3445
  type: "string",
3324
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3446
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3325
3447
  },
3326
3448
  target: {
3327
3449
  type: "string",
@@ -3354,7 +3476,7 @@ var MANIFEST = [
3354
3476
  properties: {
3355
3477
  lease: {
3356
3478
  type: "string",
3357
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3479
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3358
3480
  },
3359
3481
  target: {
3360
3482
  type: "string",
@@ -3391,7 +3513,7 @@ var MANIFEST = [
3391
3513
  properties: {
3392
3514
  lease: {
3393
3515
  type: "string",
3394
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs."
3516
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3395
3517
  },
3396
3518
  target: {
3397
3519
  type: "string",
@@ -3422,7 +3544,7 @@ var MANIFEST = [
3422
3544
  properties: {
3423
3545
  lease: {
3424
3546
  type: "string",
3425
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs."
3547
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3426
3548
  },
3427
3549
  target: {
3428
3550
  type: "string",
@@ -3478,7 +3600,7 @@ var MANIFEST = [
3478
3600
  properties: {
3479
3601
  lease: {
3480
3602
  type: "string",
3481
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs."
3603
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3482
3604
  },
3483
3605
  target: {
3484
3606
  type: "string",
@@ -3513,7 +3635,7 @@ var MANIFEST = [
3513
3635
  properties: {
3514
3636
  lease: {
3515
3637
  type: "string",
3516
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3638
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3517
3639
  },
3518
3640
  target: {
3519
3641
  type: "string",
@@ -3536,7 +3658,7 @@ var MANIFEST = [
3536
3658
  properties: {
3537
3659
  lease: {
3538
3660
  type: "string",
3539
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3661
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3540
3662
  },
3541
3663
  target: {
3542
3664
  type: "string",
@@ -3576,7 +3698,7 @@ var MANIFEST = [
3576
3698
  properties: {
3577
3699
  lease: {
3578
3700
  type: "string",
3579
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3701
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3580
3702
  },
3581
3703
  target: {
3582
3704
  type: "string",
@@ -3603,7 +3725,7 @@ var MANIFEST = [
3603
3725
  properties: {
3604
3726
  lease: {
3605
3727
  type: "string",
3606
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3728
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3607
3729
  },
3608
3730
  target: {
3609
3731
  type: "string",
@@ -3655,7 +3777,7 @@ var MANIFEST = [
3655
3777
  properties: {
3656
3778
  lease: {
3657
3779
  type: "string",
3658
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3780
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3659
3781
  },
3660
3782
  target: {
3661
3783
  type: "string",
@@ -3688,7 +3810,7 @@ var MANIFEST = [
3688
3810
  properties: {
3689
3811
  lease: {
3690
3812
  type: "string",
3691
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3813
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3692
3814
  },
3693
3815
  target: {
3694
3816
  type: "string",
@@ -3734,7 +3856,7 @@ var MANIFEST = [
3734
3856
  properties: {
3735
3857
  lease: {
3736
3858
  type: "string",
3737
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3859
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3738
3860
  },
3739
3861
  target: {
3740
3862
  type: "string",
@@ -3767,7 +3889,7 @@ var MANIFEST = [
3767
3889
  properties: {
3768
3890
  lease: {
3769
3891
  type: "string",
3770
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3892
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3771
3893
  },
3772
3894
  target: {
3773
3895
  type: "string",
@@ -3799,7 +3921,7 @@ var MANIFEST = [
3799
3921
  properties: {
3800
3922
  lease: {
3801
3923
  type: "string",
3802
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3924
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3803
3925
  },
3804
3926
  target: {
3805
3927
  type: "string",
@@ -3838,7 +3960,7 @@ var MANIFEST = [
3838
3960
  properties: {
3839
3961
  lease: {
3840
3962
  type: "string",
3841
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
3963
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3842
3964
  },
3843
3965
  target: {
3844
3966
  type: "string",
@@ -3889,7 +4011,7 @@ var MANIFEST = [
3889
4011
  properties: {
3890
4012
  lease: {
3891
4013
  type: "string",
3892
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4014
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3893
4015
  },
3894
4016
  target: {
3895
4017
  type: "string",
@@ -3989,7 +4111,7 @@ var MANIFEST = [
3989
4111
  properties: {
3990
4112
  lease: {
3991
4113
  type: "string",
3992
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4114
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
3993
4115
  },
3994
4116
  target: {
3995
4117
  type: "string",
@@ -4027,7 +4149,7 @@ var MANIFEST = [
4027
4149
  properties: {
4028
4150
  lease: {
4029
4151
  type: "string",
4030
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4152
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4031
4153
  },
4032
4154
  target: {
4033
4155
  type: "string",
@@ -4064,7 +4186,7 @@ var MANIFEST = [
4064
4186
  properties: {
4065
4187
  lease: {
4066
4188
  type: "string",
4067
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4189
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4068
4190
  },
4069
4191
  target: {
4070
4192
  type: "string",
@@ -4091,7 +4213,7 @@ var MANIFEST = [
4091
4213
  properties: {
4092
4214
  lease: {
4093
4215
  type: "string",
4094
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4216
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4095
4217
  },
4096
4218
  target: {
4097
4219
  type: "string",
@@ -4114,7 +4236,7 @@ var MANIFEST = [
4114
4236
  properties: {
4115
4237
  lease: {
4116
4238
  type: "string",
4117
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4239
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4118
4240
  },
4119
4241
  target: {
4120
4242
  type: "string",
@@ -4145,7 +4267,7 @@ var MANIFEST = [
4145
4267
  properties: {
4146
4268
  lease: {
4147
4269
  type: "string",
4148
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4270
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4149
4271
  },
4150
4272
  target: {
4151
4273
  type: "string",
@@ -4180,7 +4302,7 @@ var MANIFEST = [
4180
4302
  properties: {
4181
4303
  lease: {
4182
4304
  type: "string",
4183
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4305
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4184
4306
  },
4185
4307
  target: {
4186
4308
  type: "string",
@@ -4206,7 +4328,7 @@ var MANIFEST = [
4206
4328
  properties: {
4207
4329
  lease: {
4208
4330
  type: "string",
4209
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4331
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4210
4332
  },
4211
4333
  target: {
4212
4334
  type: "string",
@@ -4225,7 +4347,7 @@ var MANIFEST = [
4225
4347
  properties: {
4226
4348
  lease: {
4227
4349
  type: "string",
4228
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4350
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4229
4351
  },
4230
4352
  tracePath: {
4231
4353
  type: "string",
@@ -4244,7 +4366,7 @@ var MANIFEST = [
4244
4366
  properties: {
4245
4367
  lease: {
4246
4368
  type: "string",
4247
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4369
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4248
4370
  },
4249
4371
  target: {
4250
4372
  type: "string",
@@ -4282,7 +4404,7 @@ var MANIFEST = [
4282
4404
  properties: {
4283
4405
  lease: {
4284
4406
  type: "string",
4285
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4407
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4286
4408
  },
4287
4409
  target: {
4288
4410
  type: "string",
@@ -4329,7 +4451,7 @@ var MANIFEST = [
4329
4451
  properties: {
4330
4452
  lease: {
4331
4453
  type: "string",
4332
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4454
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4333
4455
  },
4334
4456
  target: {
4335
4457
  type: "string",
@@ -4352,7 +4474,7 @@ var MANIFEST = [
4352
4474
  properties: {
4353
4475
  lease: {
4354
4476
  type: "string",
4355
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4477
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4356
4478
  },
4357
4479
  target: {
4358
4480
  type: "string",
@@ -4375,7 +4497,7 @@ var MANIFEST = [
4375
4497
  properties: {
4376
4498
  lease: {
4377
4499
  type: "string",
4378
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4500
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4379
4501
  },
4380
4502
  url: {
4381
4503
  type: "string",
@@ -4419,7 +4541,7 @@ var MANIFEST = [
4419
4541
  properties: {
4420
4542
  lease: {
4421
4543
  type: "string",
4422
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4544
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4423
4545
  },
4424
4546
  target: {
4425
4547
  type: "string",
@@ -4489,7 +4611,7 @@ var MANIFEST = [
4489
4611
  properties: {
4490
4612
  lease: {
4491
4613
  type: "string",
4492
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4614
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4493
4615
  },
4494
4616
  target: {
4495
4617
  type: "string",
@@ -4508,7 +4630,7 @@ var MANIFEST = [
4508
4630
  properties: {
4509
4631
  lease: {
4510
4632
  type: "string",
4511
- description: "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
4633
+ description: "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
4512
4634
  },
4513
4635
  target: {
4514
4636
  type: "string",
@@ -4525,17 +4647,21 @@ var MANIFEST = [
4525
4647
  },
4526
4648
  {
4527
4649
  name: "claim_page",
4528
- description: "Take exclusive ownership of a browser tab and return an opaque lease token. With no targetId, opens a fresh tab (optionally at url) and claims it, so 'give me my own tab' is one call. Any later tool call against a leased tab must carry the matching token in its 'lease' argument or it is refused, naming the holder. The lease is reclaimable once its owning process dies, its ttlMs elapses without use, or its tab is closed. Refused from the CLI: a CLI invocation is one process per call, so its lease would be reclaimable immediately.",
4650
+ description: "Take exclusive ownership of a browser tab and return an opaque lease token. Two modes. FRESH TAB: with no target and no targetId, opens a new tab (optionally at url) and claims it, so 'give me my own tab' is one call. TAKEOVER: with target, claims a tab that is already open — this is how you work in a tab the human already has open when they ask you to, instead of opening your own — resolving any target selector against the live page list and never creating anything. The answer's 'opened' flag says which happened (true only when this call created the tab), and that same creation record is what release_page consults, so a tab you took over is left open when you release it. Any later tool call against a leased tab must carry the matching token in its 'lease' argument or it is refused, naming the holder. The lease is reclaimable once its owning process dies, its ttlMs elapses without use, or its tab is closed. Refused from the CLI: a CLI invocation is one process per call, so its lease would be reclaimable immediately.",
4529
4651
  inputSchema: {
4530
4652
  type: "object",
4531
4653
  properties: {
4654
+ target: {
4655
+ type: "string",
4656
+ description: "Take over an already-open tab, e.g. one the human has open, when asked to: pass any target selector — active | index:N | url:<substr> | title:<substr> | <targetId>. Resolved against the live page list only, so it NEVER opens a tab: a selector that matches nothing is an error, not a new blank tab. The tab is left open on release because the toolkit did not create it. Refused if another live process holds it, including a lease the gate acquired for that process automatically under CDP_REQUIRE_LEASE: this takes over unleased (human) tabs and never steals one from a live agent. Mutually exclusive with targetId."
4657
+ },
4532
4658
  targetId: {
4533
4659
  type: "string",
4534
- description: "Claim this already-open page target instead of opening a new tab. Must be an exact target id, not a selector."
4660
+ description: "Claim this already-open page target instead of opening a new tab. Must be an exact target id, not a selector. Kept for back-compat: prefer 'target', which accepts an exact id too plus every other selector form. Mutually exclusive with target."
4535
4661
  },
4536
4662
  url: {
4537
4663
  type: "string",
4538
- description: "When opening a fresh tab, navigate it here. Ignored when targetId is given."
4664
+ description: "When opening a fresh tab, navigate it here. Ignored when target or targetId is given, since both of those claim a tab that is already open."
4539
4665
  },
4540
4666
  label: {
4541
4667
  type: "string",
@@ -4552,24 +4678,30 @@ var MANIFEST = [
4552
4678
  },
4553
4679
  {
4554
4680
  name: "release_page",
4555
- description: "Release a held lease, given its token. Idempotent: releasing an already-released, reclaimed, or expired lease reports released:false rather than erroring. Does not close the tab.",
4681
+ description: "Give a lease back, and close the tab if this toolkit opened it. Takes exactly one of 'lease' (the token claim_page returned) or 'target' (a selector for a tab this process holds, which is how you release a lease the gate acquired for you automatically, since that path never hands you a token). A tab with a creation record from this toolkit is closed; a tab that was already open and merely claimed is released and left alone. Override either way with 'close'. Idempotent: an already-released, reclaimed, or expired lease reports released:false, and a release that did not happen never closes anything, because by then the tab may belong to another agent. Answers {released, closed, targetId}.",
4556
4682
  inputSchema: {
4557
4683
  type: "object",
4558
4684
  properties: {
4559
4685
  lease: {
4560
4686
  type: "string",
4561
- description: "The opaque token claim_page (or new_page with claim:true) returned."
4687
+ description: "The opaque token claim_page (or new_page with claim:true) returned. Mutually exclusive with 'target'. Under CDP_REQUIRE_LEASE a lease the gate acquired for you automatically never produced a token in the first place, so give 'target' instead."
4688
+ },
4689
+ target: {
4690
+ type: "string",
4691
+ description: "Target selector for a tab this process holds: active | index:N | url:<substr> | title:<substr> | <targetId>. Mutually exclusive with 'lease'. Refused if another process holds the tab."
4692
+ },
4693
+ close: {
4694
+ type: "boolean",
4695
+ description: "Force the close decision instead of letting the creation ledger decide. true closes even a tab this toolkit did not open; false keeps an agent-created tab open. Omit for the default, which closes only tabs this toolkit created."
4562
4696
  }
4563
4697
  },
4564
- required: [
4565
- "lease"
4566
- ],
4698
+ required: [],
4567
4699
  additionalProperties: false
4568
4700
  }
4569
4701
  },
4570
4702
  {
4571
4703
  name: "list_leases",
4572
- description: 'Enumerate every active lease for diagnosis: backend, target id, agent label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is still alive, and whether the lease is reclaimable and why. Requires no token. Never returns the lease nonce, so this cannot be used to forge a token. A row for a lease file that could not be read or parsed instead carries `unreadable` (the errno, or "unparseable"), with label, pid, and the timestamp fields as zero placeholders and stale always false, since stale is what marks a lease free to take and an unreadable one must never read that way.',
4704
+ description: "Enumerate every active lease for diagnosis: backend, target id, agent label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is still alive, and whether the lease is reclaimable and why. Requires no token. Never returns the lease nonce, so this cannot be used to forge a token. A row for a lease file that could not be read or parsed instead carries `unreadable` (the errno, or \"unparseable\"), with label, pid, and the timestamp fields as zero placeholders and stale always false, since stale is what marks a lease free to take and an unreadable one must never read that way. Under CDP_REQUIRE_LEASE this call reaps abandoned agent tabs exactly as list_pages does, reporting them in an additive 'reaped' array and omitting their rows from the listing.",
4573
4705
  inputSchema: {
4574
4706
  type: "object",
4575
4707
  properties: {},
@@ -6283,7 +6415,7 @@ var FIREFOX_TOOLS = {
6283
6415
  };
6284
6416
 
6285
6417
  // src/mcp.ts
6286
- var VERSION = "1.6.0";
6418
+ var VERSION = "1.7.0";
6287
6419
  var BROWSER = resolveBrowserKind(stripBrowserFlag(process.argv.slice(2)));
6288
6420
  var AVAILABILITY = toolAvailability(BROWSER);
6289
6421
  var AVAILABLE_NAMES = new Set(AVAILABILITY.available);
@@ -6340,6 +6472,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
6340
6472
  });
6341
6473
  });
6342
6474
  auditCoverage();
6475
+ markLongLivedProcess();
6343
6476
  await server.connect(new StdioServerTransport);
6344
6477
  console.error(`[cdp-toolkit] MCP server v${VERSION} ready, browser=${BROWSER}, ${AVAILABILITY.available.length} tools, CDP_BASE=${BASE}`);
6345
6478
  var shuttingDown = false;