unbrowse 9.4.6 → 9.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unbrowse",
3
- "version": "9.4.6",
3
+ "version": "9.4.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/unbrowse-ai/unbrowse.git"
package/runtime/cli.js CHANGED
@@ -1805,7 +1805,7 @@ var init_cached_resolution2 = __esm(() => {
1805
1805
  });
1806
1806
 
1807
1807
  // .tmp-runtime-src/build-info.generated.ts
1808
- var BUILD_RELEASE_VERSION = "9.4.6", BUILD_GIT_SHA = "7dbe211a85f6", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiOS40LjYiLCJnaXRfc2hhIjoiN2RiZTIxMWE4NWY2IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA3ZGJlMjExYTg1ZjYiLCJpc3N1ZWRfYXQiOiIyMDI2LTA2LTE3VDA1OjExOjA5LjM3N1oifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "dfmT3oOkn1DfPkayFn9QI8qxLZwEPmX8pymVxidycUI", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
1808
+ var BUILD_RELEASE_VERSION = "9.4.8", BUILD_GIT_SHA = "6232e149b808", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiOS40LjgiLCJnaXRfc2hhIjoiNjIzMmUxNDliODA4IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA2MjMyZTE0OWI4MDgiLCJpc3N1ZWRfYXQiOiIyMDI2LTA2LTE3VDA1OjU2OjU5LjI5NVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "il6JUjT-czqTgXfNfTKHuvYt9woEMgOWvq3Bt83mrho", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
1809
1809
 
1810
1810
  // .tmp-runtime-src/version.ts
1811
1811
  import { createHash as createHash4 } from "crypto";
@@ -228824,6 +228824,7 @@ import {
228824
228824
  mkdir as mkdir8,
228825
228825
  readdir as readdir6,
228826
228826
  readFile as readFile6,
228827
+ rename as rename6,
228827
228828
  stat as stat4,
228828
228829
  unlink as unlink6,
228829
228830
  writeFile as writeFile6,
@@ -228831,7 +228832,7 @@ import {
228831
228832
  } from "node:fs/promises";
228832
228833
  import { homedir as homedir42 } from "node:os";
228833
228834
  import { join as join62 } from "node:path";
228834
- import { createHash as createHash20 } from "node:crypto";
228835
+ import { createHash as createHash20, randomBytes as randomBytes14 } from "node:crypto";
228835
228836
  function statelessTmpRoot() {
228836
228837
  return join62(homedir42(), ".unbrowse", "tmp");
228837
228838
  }
@@ -228845,8 +228846,17 @@ function sessionPath(sessionId) {
228845
228846
  async function writeSessionRecord(rec) {
228846
228847
  const path26 = sessionPath(rec.sessionId);
228847
228848
  await mkdir8(join62(path26, ".."), { recursive: true });
228848
- await writeFile6(path26, JSON.stringify(rec, null, 2) + `
228849
+ const tmp = `${path26}.tmp.${process.pid}.${randomBytes14(6).toString("hex")}`;
228850
+ await writeFile6(tmp, JSON.stringify(rec, null, 2) + `
228849
228851
  `, { mode: 384 });
228852
+ try {
228853
+ await rename6(tmp, path26);
228854
+ } catch (err) {
228855
+ try {
228856
+ await unlink6(tmp);
228857
+ } catch {}
228858
+ throw err;
228859
+ }
228850
228860
  return path26;
228851
228861
  }
228852
228862
  async function readSessionRecord(sessionId) {
@@ -228913,11 +228923,48 @@ async function mostRecentSession() {
228913
228923
  }
228914
228924
  return newest;
228915
228925
  }
228916
- async function resolveSession(explicitId) {
228926
+ function isProcessAlive(pid) {
228927
+ if (!Number.isInteger(pid) || pid <= 0)
228928
+ return false;
228929
+ try {
228930
+ process.kill(pid, 0);
228931
+ return true;
228932
+ } catch (err) {
228933
+ return err.code === "EPERM";
228934
+ }
228935
+ }
228936
+ async function mostRecentLiveSession() {
228937
+ const recs = [];
228938
+ for await (const path26 of walkSessionFiles()) {
228939
+ try {
228940
+ recs.push(JSON.parse(await readFile6(path26, "utf8")));
228941
+ } catch {}
228942
+ }
228943
+ recs.sort((a, b) => b.createdAt - a.createdAt);
228944
+ for (const rec of recs) {
228945
+ if (isProcessAlive(rec.chromePid))
228946
+ return rec;
228947
+ await deleteSessionRecord(rec.sessionId).catch(() => {
228948
+ return;
228949
+ });
228950
+ }
228951
+ return null;
228952
+ }
228953
+ async function resolveSession(explicitId, opts = {}) {
228954
+ const probeLive = opts.probeLive ?? true;
228917
228955
  if (explicitId) {
228918
- return readSessionRecord(explicitId);
228956
+ const rec = await readSessionRecord(explicitId);
228957
+ if (probeLive && !isProcessAlive(rec.chromePid)) {
228958
+ await deleteSessionRecord(rec.sessionId).catch(() => {
228959
+ return;
228960
+ });
228961
+ const err = new Error("session_expired");
228962
+ err.code = "session_expired";
228963
+ throw err;
228964
+ }
228965
+ return rec;
228919
228966
  }
228920
- const recent = await mostRecentSession();
228967
+ const recent = probeLive ? await mostRecentLiveSession() : await mostRecentSession();
228921
228968
  if (!recent) {
228922
228969
  const err = new Error("no_active_session");
228923
228970
  err.code = "no_active_session";
@@ -228925,6 +228972,44 @@ async function resolveSession(explicitId) {
228925
228972
  }
228926
228973
  return recent;
228927
228974
  }
228975
+ async function reapStaleSessions(opts = {}) {
228976
+ const envMax = Number.parseInt(process.env.UNBROWSE_MAX_BROWSE_SESSIONS ?? "", 10);
228977
+ const maxLive = opts.maxLive ?? (Number.isInteger(envMax) && envMax > 0 ? envMax : 8);
228978
+ const recs = [];
228979
+ for await (const path26 of walkSessionFiles()) {
228980
+ try {
228981
+ recs.push(JSON.parse(await readFile6(path26, "utf8")));
228982
+ } catch {}
228983
+ }
228984
+ let reaped = 0;
228985
+ const live = [];
228986
+ for (const rec of recs) {
228987
+ if (isProcessAlive(rec.chromePid)) {
228988
+ live.push(rec);
228989
+ } else {
228990
+ await deleteSessionRecord(rec.sessionId).catch(() => {
228991
+ return;
228992
+ });
228993
+ reaped++;
228994
+ }
228995
+ }
228996
+ if (live.length > maxLive) {
228997
+ live.sort((a, b) => a.createdAt - b.createdAt);
228998
+ for (const rec of live.slice(0, live.length - maxLive)) {
228999
+ const shared = await anotherSessionUsesChrome(rec.chromePid, rec.sessionId);
229000
+ if (!shared) {
229001
+ try {
229002
+ process.kill(rec.chromePid, "SIGTERM");
229003
+ } catch {}
229004
+ }
229005
+ await deleteSessionRecord(rec.sessionId).catch(() => {
229006
+ return;
229007
+ });
229008
+ reaped++;
229009
+ }
229010
+ }
229011
+ return reaped;
229012
+ }
228928
229013
  async function anotherSessionUsesChrome(chromePid, excludeSessionId) {
228929
229014
  const excludeFile = `${excludeSessionId}.json`;
228930
229015
  for await (const path26 of walkSessionFiles()) {
@@ -228974,8 +229059,11 @@ async function handler14(parsed, opts) {
228974
229059
  process.exit(EX_USAGE);
228975
229060
  }
228976
229061
  try {
229062
+ await reapStaleSessions().catch(() => {
229063
+ return;
229064
+ });
228977
229065
  const wsEndpoint = typeof parsed.flags.ws === "string" ? parsed.flags.ws : undefined;
228978
- const conn = wsEndpoint ? await attach(wsEndpoint) : await spawnChrome({ headless: true, perContextProxy: true, persist: true });
229066
+ const conn = wsEndpoint ? await attach(wsEndpoint) : await spawnChrome({ headless: true, perContextProxy: false, persist: true });
228979
229067
  const target = await createTarget(conn, url, {});
228980
229068
  const sessionId = randomUUID2();
228981
229069
  const rec = {
@@ -229904,7 +229992,7 @@ var init_values = __esm(() => {
229904
229992
  });
229905
229993
 
229906
229994
  // .tmp-runtime-src/cli-v7/act/fill.ts
229907
- import { randomBytes as randomBytes14, createHash as createHash25 } from "node:crypto";
229995
+ import { randomBytes as randomBytes15, createHash as createHash25 } from "node:crypto";
229908
229996
  function canonicalizeSignedFragment2(body) {
229909
229997
  return JSON.stringify({
229910
229998
  pointer: body.pointer,
@@ -230015,7 +230103,7 @@ async function handler15(parsed, opts) {
230015
230103
  }
230016
230104
  const contextHashHex = deriveContextHash(rec.sessionId, selector, currentUrl, Date.now());
230017
230105
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
230018
- const nonce = new Uint8Array(randomBytes14(32));
230106
+ const nonce = new Uint8Array(randomBytes15(32));
230019
230107
  let resolved;
230020
230108
  try {
230021
230109
  resolved = await resolve16(pointerUri, nonce, {
@@ -230128,7 +230216,7 @@ var init_fill = __esm(() => {
230128
230216
 
230129
230217
  // .tmp-runtime-src/cli-v7/act/fill-form.ts
230130
230218
  import { spawnSync as spawnSync4 } from "node:child_process";
230131
- import { randomBytes as randomBytes15, createHash as createHash26 } from "node:crypto";
230219
+ import { randomBytes as randomBytes16, createHash as createHash26 } from "node:crypto";
230132
230220
  import { homedir as homedir44 } from "node:os";
230133
230221
  import { join as join64 } from "node:path";
230134
230222
  function sha256Hex7(s) {
@@ -230384,7 +230472,7 @@ async function handler16(parsed, opts) {
230384
230472
  }
230385
230473
  const pointerUri = slot.value_pointer;
230386
230474
  const fieldContextHash = sha256Hex7(`${rec.sessionId}:${slot.selector}:${currentUrl}:${Math.floor(Date.now() / FIVE_MINUTES_MS3)}`);
230387
- const nonce = new Uint8Array(randomBytes15(32));
230475
+ const nonce = new Uint8Array(randomBytes16(32));
230388
230476
  let resolved;
230389
230477
  try {
230390
230478
  resolved = await resolve16(pointerUri, nonce, {
@@ -230493,7 +230581,7 @@ var init_fill_form = __esm(() => {
230493
230581
  });
230494
230582
 
230495
230583
  // .tmp-runtime-src/cli-v7/act/type.ts
230496
- import { randomBytes as randomBytes16, createHash as createHash27 } from "node:crypto";
230584
+ import { randomBytes as randomBytes17, createHash as createHash27 } from "node:crypto";
230497
230585
  function canonicalizeSignedFragment3(body) {
230498
230586
  return JSON.stringify({
230499
230587
  pointer: body.pointer,
@@ -230633,7 +230721,7 @@ async function handler17(parsed, opts) {
230633
230721
  const auditUrl = `${apiBase.replace(/\/$/, "")}/v1/audit/fill`;
230634
230722
  const contextHashHex = deriveContextHash2(rec.sessionId, currentUrl, Date.now());
230635
230723
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
230636
- const nonce = new Uint8Array(randomBytes16(32));
230724
+ const nonce = new Uint8Array(randomBytes17(32));
230637
230725
  let resolved;
230638
230726
  try {
230639
230727
  resolved = await resolve16(pointerUri, nonce, {
@@ -231010,7 +231098,7 @@ var init_press = __esm(() => {
231010
231098
  });
231011
231099
 
231012
231100
  // .tmp-runtime-src/cli-v7/act/select.ts
231013
- import { randomBytes as randomBytes17, createHash as createHash28 } from "node:crypto";
231101
+ import { randomBytes as randomBytes18, createHash as createHash28 } from "node:crypto";
231014
231102
  function canonicalizeSignedFragment4(body) {
231015
231103
  return JSON.stringify({
231016
231104
  pointer: body.pointer,
@@ -231189,7 +231277,7 @@ async function handler20(parsed, opts) {
231189
231277
  const pointerUri = pointerArg;
231190
231278
  const contextHashHex = deriveContextHash(rec.sessionId, selector, currentUrl, Date.now());
231191
231279
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
231192
- const nonce = new Uint8Array(randomBytes17(32));
231280
+ const nonce = new Uint8Array(randomBytes18(32));
231193
231281
  let resolved;
231194
231282
  try {
231195
231283
  resolved = await resolve16(pointerUri, nonce, {
@@ -231613,7 +231701,7 @@ var init_submit = __esm(() => {
231613
231701
  });
231614
231702
 
231615
231703
  // .tmp-runtime-src/cli-v7/act/execute.ts
231616
- import { randomBytes as randomBytes18, createHash as createHash29 } from "node:crypto";
231704
+ import { randomBytes as randomBytes19, createHash as createHash29 } from "node:crypto";
231617
231705
  function sha256Hex10(s) {
231618
231706
  return createHash29("sha256").update(s, "utf8").digest("hex");
231619
231707
  }
@@ -231698,7 +231786,7 @@ async function fetchEndpointDescriptor(endpointId, apiBase, parsed) {
231698
231786
  };
231699
231787
  }
231700
231788
  async function resolveSlot(opts) {
231701
- const nonce = new Uint8Array(randomBytes18(32));
231789
+ const nonce = new Uint8Array(randomBytes19(32));
231702
231790
  const contextHashHex = deriveExecContextHash(opts.sessionId, opts.locator, opts.url);
231703
231791
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
231704
231792
  const resolved = await resolve16(opts.pointerUri, nonce, {
@@ -232457,7 +232545,7 @@ async function handler26(parsed, opts) {
232457
232545
  const explicitId = parsed.positional[0] ?? (typeof parsed.flags.session === "string" ? parsed.flags.session : undefined);
232458
232546
  let rec;
232459
232547
  try {
232460
- rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined);
232548
+ rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined, { probeLive: false });
232461
232549
  } catch (err) {
232462
232550
  if (!explicitId && err.code === "no_active_session") {
232463
232551
  emit({ ok: true, subcommand: "act close", op_kind: meta.op_kind, idempotent_noop: true }, opts);
@@ -232593,7 +232681,7 @@ async function handler27(parsed, opts) {
232593
232681
  const explicitId = parsed.positional[0] ?? (typeof parsed.flags.session === "string" ? parsed.flags.session : undefined);
232594
232682
  let rec;
232595
232683
  try {
232596
- rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined);
232684
+ rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined, { probeLive: false });
232597
232685
  } catch (err) {
232598
232686
  if (!explicitId && err.code === "no_active_session") {
232599
232687
  emit({
@@ -233368,7 +233456,7 @@ var init_escalate_on_miss = __esm(() => {
233368
233456
  });
233369
233457
 
233370
233458
  // .tmp-runtime-src/cli-v7/eval/resolve.ts
233371
- import { createHash as createHash33, randomBytes as randomBytes19 } from "node:crypto";
233459
+ import { createHash as createHash33, randomBytes as randomBytes20 } from "node:crypto";
233372
233460
  function searchToShortlist(results) {
233373
233461
  return { domain_results: [], global_results: Array.isArray(results) ? results : [] };
233374
233462
  }
@@ -233476,7 +233564,7 @@ async function handler44(parsed, opts) {
233476
233564
  process.exit(ok2 ? 0 : EX_GENERIC);
233477
233565
  } catch {}
233478
233566
  }
233479
- const nonce = bytesToBase648(new Uint8Array(randomBytes19(32)));
233567
+ const nonce = bytesToBase648(new Uint8Array(randomBytes20(32)));
233480
233568
  const fragment = canonicalizeSignedFragment({
233481
233569
  intent,
233482
233570
  surrogateUrl: urlFlag ?? null,
@@ -234763,7 +234851,7 @@ var init_stats = __esm(() => {
234763
234851
  });
234764
234852
 
234765
234853
  // .tmp-runtime-src/cli-v7/eval/skills.ts
234766
- import { createHash as createHash39, randomBytes as randomBytes20 } from "node:crypto";
234854
+ import { createHash as createHash39, randomBytes as randomBytes21 } from "node:crypto";
234767
234855
  function resolveApiBase4() {
234768
234856
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
234769
234857
  }
@@ -234851,7 +234939,7 @@ async function handler54(parsed, opts) {
234851
234939
  let backendError = null;
234852
234940
  const pubkeyBytes = await getWalletPubkey();
234853
234941
  const walletPubkey = bytesToHex17(pubkeyBytes);
234854
- const nonce = bytesToBase649(new Uint8Array(randomBytes20(32)));
234942
+ const nonce = bytesToBase649(new Uint8Array(randomBytes21(32)));
234855
234943
  const fragment = canonicalizeSignedFragment({
234856
234944
  op: "list_skills",
234857
234945
  domain: domainFlag ?? null,
@@ -234961,7 +235049,7 @@ var init_skills = __esm(() => {
234961
235049
  });
234962
235050
 
234963
235051
  // .tmp-runtime-src/cli-v7/eval/skill.ts
234964
- import { createHash as createHash40, randomBytes as randomBytes21 } from "node:crypto";
235052
+ import { createHash as createHash40, randomBytes as randomBytes22 } from "node:crypto";
234965
235053
  function resolveApiBase5() {
234966
235054
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
234967
235055
  }
@@ -235025,7 +235113,7 @@ async function handler55(parsed, opts) {
235025
235113
  let backendError = null;
235026
235114
  const pubkeyBytes = await getWalletPubkey();
235027
235115
  const walletPubkey = bytesToHex18(pubkeyBytes);
235028
- const nonce = bytesToBase6410(new Uint8Array(randomBytes21(32)));
235116
+ const nonce = bytesToBase6410(new Uint8Array(randomBytes22(32)));
235029
235117
  const fragment = canonicalizeSignedFragment({ op: "get_skill", skillId, nonce }, ["op", "skillId", "nonce"]);
235030
235118
  const signed = await signBytes(new TextEncoder().encode(fragment));
235031
235119
  const signatureHex = bytesToHex18(signed.signature);
@@ -235138,7 +235226,7 @@ var init_skill2 = __esm(async () => {
235138
235226
  });
235139
235227
 
235140
235228
  // .tmp-runtime-src/cli-v7/eval/earnings.ts
235141
- import { createHash as createHash41, randomBytes as randomBytes22 } from "node:crypto";
235229
+ import { createHash as createHash41, randomBytes as randomBytes23 } from "node:crypto";
235142
235230
  function resolveApiBase6() {
235143
235231
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
235144
235232
  }
@@ -235197,7 +235285,7 @@ async function handler56(parsed, opts) {
235197
235285
  const headers = { accept: "application/json" };
235198
235286
  if (fresh)
235199
235287
  headers["cache-control"] = "no-cache";
235200
- const nonce = bytesToBase6411(new Uint8Array(randomBytes22(32)));
235288
+ const nonce = bytesToBase6411(new Uint8Array(randomBytes23(32)));
235201
235289
  const fragment = canonicalizeSignedFragment({
235202
235290
  op: "get_earnings",
235203
235291
  agentId,
package/runtime/mcp.js CHANGED
@@ -36310,7 +36310,7 @@ var init_cached_resolution = __esm(() => {
36310
36310
  });
36311
36311
 
36312
36312
  // .tmp-runtime-src/build-info.generated.ts
36313
- var BUILD_RELEASE_VERSION = "9.4.6", BUILD_GIT_SHA = "7dbe211a85f6", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiOS40LjYiLCJnaXRfc2hhIjoiN2RiZTIxMWE4NWY2IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA3ZGJlMjExYTg1ZjYiLCJpc3N1ZWRfYXQiOiIyMDI2LTA2LTE3VDA1OjExOjA5LjM3N1oifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "dfmT3oOkn1DfPkayFn9QI8qxLZwEPmX8pymVxidycUI", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
36313
+ var BUILD_RELEASE_VERSION = "9.4.8", BUILD_GIT_SHA = "6232e149b808", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiOS40LjgiLCJnaXRfc2hhIjoiNjIzMmUxNDliODA4IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA2MjMyZTE0OWI4MDgiLCJpc3N1ZWRfYXQiOiIyMDI2LTA2LTE3VDA1OjU2OjU5LjI5NVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "il6JUjT-czqTgXfNfTKHuvYt9woEMgOWvq3Bt83mrho", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
36314
36314
 
36315
36315
  // .tmp-runtime-src/version.ts
36316
36316
  import { createHash as createHash4 } from "crypto";
@@ -222213,6 +222213,7 @@ import {
222213
222213
  mkdir as mkdir6,
222214
222214
  readdir as readdir4,
222215
222215
  readFile as readFile4,
222216
+ rename as rename4,
222216
222217
  stat as stat3,
222217
222218
  unlink as unlink4,
222218
222219
  writeFile as writeFile4,
@@ -222220,7 +222221,7 @@ import {
222220
222221
  } from "node:fs/promises";
222221
222222
  import { homedir as homedir36 } from "node:os";
222222
222223
  import { join as join53 } from "node:path";
222223
- import { createHash as createHash22 } from "node:crypto";
222224
+ import { createHash as createHash22, randomBytes as randomBytes11 } from "node:crypto";
222224
222225
  function statelessTmpRoot() {
222225
222226
  return join53(homedir36(), ".unbrowse", "tmp");
222226
222227
  }
@@ -222234,8 +222235,17 @@ function sessionPath(sessionId) {
222234
222235
  async function writeSessionRecord(rec) {
222235
222236
  const path26 = sessionPath(rec.sessionId);
222236
222237
  await mkdir6(join53(path26, ".."), { recursive: true });
222237
- await writeFile4(path26, JSON.stringify(rec, null, 2) + `
222238
+ const tmp = `${path26}.tmp.${process.pid}.${randomBytes11(6).toString("hex")}`;
222239
+ await writeFile4(tmp, JSON.stringify(rec, null, 2) + `
222238
222240
  `, { mode: 384 });
222241
+ try {
222242
+ await rename4(tmp, path26);
222243
+ } catch (err) {
222244
+ try {
222245
+ await unlink4(tmp);
222246
+ } catch {}
222247
+ throw err;
222248
+ }
222239
222249
  return path26;
222240
222250
  }
222241
222251
  async function readSessionRecord(sessionId) {
@@ -222302,11 +222312,48 @@ async function mostRecentSession() {
222302
222312
  }
222303
222313
  return newest;
222304
222314
  }
222305
- async function resolveSession(explicitId) {
222315
+ function isProcessAlive(pid) {
222316
+ if (!Number.isInteger(pid) || pid <= 0)
222317
+ return false;
222318
+ try {
222319
+ process.kill(pid, 0);
222320
+ return true;
222321
+ } catch (err) {
222322
+ return err.code === "EPERM";
222323
+ }
222324
+ }
222325
+ async function mostRecentLiveSession() {
222326
+ const recs = [];
222327
+ for await (const path26 of walkSessionFiles()) {
222328
+ try {
222329
+ recs.push(JSON.parse(await readFile4(path26, "utf8")));
222330
+ } catch {}
222331
+ }
222332
+ recs.sort((a, b) => b.createdAt - a.createdAt);
222333
+ for (const rec of recs) {
222334
+ if (isProcessAlive(rec.chromePid))
222335
+ return rec;
222336
+ await deleteSessionRecord(rec.sessionId).catch(() => {
222337
+ return;
222338
+ });
222339
+ }
222340
+ return null;
222341
+ }
222342
+ async function resolveSession(explicitId, opts = {}) {
222343
+ const probeLive = opts.probeLive ?? true;
222306
222344
  if (explicitId) {
222307
- return readSessionRecord(explicitId);
222345
+ const rec = await readSessionRecord(explicitId);
222346
+ if (probeLive && !isProcessAlive(rec.chromePid)) {
222347
+ await deleteSessionRecord(rec.sessionId).catch(() => {
222348
+ return;
222349
+ });
222350
+ const err = new Error("session_expired");
222351
+ err.code = "session_expired";
222352
+ throw err;
222353
+ }
222354
+ return rec;
222308
222355
  }
222309
- const recent = await mostRecentSession();
222356
+ const recent = probeLive ? await mostRecentLiveSession() : await mostRecentSession();
222310
222357
  if (!recent) {
222311
222358
  const err = new Error("no_active_session");
222312
222359
  err.code = "no_active_session";
@@ -222314,6 +222361,44 @@ async function resolveSession(explicitId) {
222314
222361
  }
222315
222362
  return recent;
222316
222363
  }
222364
+ async function reapStaleSessions(opts = {}) {
222365
+ const envMax = Number.parseInt(process.env.UNBROWSE_MAX_BROWSE_SESSIONS ?? "", 10);
222366
+ const maxLive = opts.maxLive ?? (Number.isInteger(envMax) && envMax > 0 ? envMax : 8);
222367
+ const recs = [];
222368
+ for await (const path26 of walkSessionFiles()) {
222369
+ try {
222370
+ recs.push(JSON.parse(await readFile4(path26, "utf8")));
222371
+ } catch {}
222372
+ }
222373
+ let reaped = 0;
222374
+ const live = [];
222375
+ for (const rec of recs) {
222376
+ if (isProcessAlive(rec.chromePid)) {
222377
+ live.push(rec);
222378
+ } else {
222379
+ await deleteSessionRecord(rec.sessionId).catch(() => {
222380
+ return;
222381
+ });
222382
+ reaped++;
222383
+ }
222384
+ }
222385
+ if (live.length > maxLive) {
222386
+ live.sort((a, b) => a.createdAt - b.createdAt);
222387
+ for (const rec of live.slice(0, live.length - maxLive)) {
222388
+ const shared = await anotherSessionUsesChrome(rec.chromePid, rec.sessionId);
222389
+ if (!shared) {
222390
+ try {
222391
+ process.kill(rec.chromePid, "SIGTERM");
222392
+ } catch {}
222393
+ }
222394
+ await deleteSessionRecord(rec.sessionId).catch(() => {
222395
+ return;
222396
+ });
222397
+ reaped++;
222398
+ }
222399
+ }
222400
+ return reaped;
222401
+ }
222317
222402
  async function anotherSessionUsesChrome(chromePid, excludeSessionId) {
222318
222403
  const excludeFile = `${excludeSessionId}.json`;
222319
222404
  for await (const path26 of walkSessionFiles()) {
@@ -222367,8 +222452,11 @@ async function handler14(parsed, opts) {
222367
222452
  process.exit(EX_USAGE);
222368
222453
  }
222369
222454
  try {
222455
+ await reapStaleSessions().catch(() => {
222456
+ return;
222457
+ });
222370
222458
  const wsEndpoint = typeof parsed.flags.ws === "string" ? parsed.flags.ws : undefined;
222371
- const conn = wsEndpoint ? await attach(wsEndpoint) : await spawnChrome({ headless: true, perContextProxy: true, persist: true });
222459
+ const conn = wsEndpoint ? await attach(wsEndpoint) : await spawnChrome({ headless: true, perContextProxy: false, persist: true });
222372
222460
  const target = await createTarget(conn, url, {});
222373
222461
  const sessionId = randomUUID4();
222374
222462
  const rec = {
@@ -223302,7 +223390,7 @@ __export(exports_fill, {
223302
223390
  handler: () => handler15,
223303
223391
  deriveContextHash: () => deriveContextHash
223304
223392
  });
223305
- import { randomBytes as randomBytes11, createHash as createHash27 } from "node:crypto";
223393
+ import { randomBytes as randomBytes12, createHash as createHash27 } from "node:crypto";
223306
223394
  function canonicalizeSignedFragment2(body) {
223307
223395
  return JSON.stringify({
223308
223396
  pointer: body.pointer,
@@ -223413,7 +223501,7 @@ async function handler15(parsed, opts) {
223413
223501
  }
223414
223502
  const contextHashHex = deriveContextHash(rec.sessionId, selector, currentUrl, Date.now());
223415
223503
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
223416
- const nonce = new Uint8Array(randomBytes11(32));
223504
+ const nonce = new Uint8Array(randomBytes12(32));
223417
223505
  let resolved;
223418
223506
  try {
223419
223507
  resolved = await resolve12(pointerUri, nonce, {
@@ -223533,7 +223621,7 @@ __export(exports_fill_form, {
223533
223621
  deriveFormContextHash: () => deriveFormContextHash
223534
223622
  });
223535
223623
  import { spawnSync as spawnSync4 } from "node:child_process";
223536
- import { randomBytes as randomBytes12, createHash as createHash28 } from "node:crypto";
223624
+ import { randomBytes as randomBytes13, createHash as createHash28 } from "node:crypto";
223537
223625
  import { homedir as homedir38 } from "node:os";
223538
223626
  import { join as join55 } from "node:path";
223539
223627
  function sha256Hex7(s) {
@@ -223789,7 +223877,7 @@ async function handler16(parsed, opts) {
223789
223877
  }
223790
223878
  const pointerUri = slot.value_pointer;
223791
223879
  const fieldContextHash = sha256Hex7(`${rec.sessionId}:${slot.selector}:${currentUrl}:${Math.floor(Date.now() / FIVE_MINUTES_MS3)}`);
223792
- const nonce = new Uint8Array(randomBytes12(32));
223880
+ const nonce = new Uint8Array(randomBytes13(32));
223793
223881
  let resolved;
223794
223882
  try {
223795
223883
  resolved = await resolve12(pointerUri, nonce, {
@@ -223902,7 +223990,7 @@ var exports_type = {};
223902
223990
  __export(exports_type, {
223903
223991
  handler: () => handler17
223904
223992
  });
223905
- import { randomBytes as randomBytes13, createHash as createHash29 } from "node:crypto";
223993
+ import { randomBytes as randomBytes14, createHash as createHash29 } from "node:crypto";
223906
223994
  function canonicalizeSignedFragment3(body) {
223907
223995
  return JSON.stringify({
223908
223996
  pointer: body.pointer,
@@ -224042,7 +224130,7 @@ async function handler17(parsed, opts) {
224042
224130
  const auditUrl = `${apiBase.replace(/\/$/, "")}/v1/audit/fill`;
224043
224131
  const contextHashHex = deriveContextHash2(rec.sessionId, currentUrl, Date.now());
224044
224132
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
224045
- const nonce = new Uint8Array(randomBytes13(32));
224133
+ const nonce = new Uint8Array(randomBytes14(32));
224046
224134
  let resolved;
224047
224135
  try {
224048
224136
  resolved = await resolve12(pointerUri, nonce, {
@@ -224431,7 +224519,7 @@ var exports_select = {};
224431
224519
  __export(exports_select, {
224432
224520
  handler: () => handler20
224433
224521
  });
224434
- import { randomBytes as randomBytes14, createHash as createHash30 } from "node:crypto";
224522
+ import { randomBytes as randomBytes15, createHash as createHash30 } from "node:crypto";
224435
224523
  function canonicalizeSignedFragment4(body) {
224436
224524
  return JSON.stringify({
224437
224525
  pointer: body.pointer,
@@ -224610,7 +224698,7 @@ async function handler20(parsed, opts) {
224610
224698
  const pointerUri = pointerArg;
224611
224699
  const contextHashHex = deriveContextHash(rec.sessionId, selector, currentUrl, Date.now());
224612
224700
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
224613
- const nonce = new Uint8Array(randomBytes14(32));
224701
+ const nonce = new Uint8Array(randomBytes15(32));
224614
224702
  let resolved;
224615
224703
  try {
224616
224704
  resolved = await resolve12(pointerUri, nonce, {
@@ -225046,7 +225134,7 @@ var exports_execute = {};
225046
225134
  __export(exports_execute, {
225047
225135
  handler: () => handler23
225048
225136
  });
225049
- import { randomBytes as randomBytes15, createHash as createHash31 } from "node:crypto";
225137
+ import { randomBytes as randomBytes16, createHash as createHash31 } from "node:crypto";
225050
225138
  function sha256Hex10(s) {
225051
225139
  return createHash31("sha256").update(s, "utf8").digest("hex");
225052
225140
  }
@@ -225131,7 +225219,7 @@ async function fetchEndpointDescriptor(endpointId, apiBase, parsed) {
225131
225219
  };
225132
225220
  }
225133
225221
  async function resolveSlot(opts) {
225134
- const nonce = new Uint8Array(randomBytes15(32));
225222
+ const nonce = new Uint8Array(randomBytes16(32));
225135
225223
  const contextHashHex = deriveExecContextHash(opts.sessionId, opts.locator, opts.url);
225136
225224
  const contextHashBytes = Buffer.from(contextHashHex, "hex");
225137
225225
  const resolved = await resolve12(opts.pointerUri, nonce, {
@@ -225903,7 +225991,7 @@ async function handler26(parsed, opts) {
225903
225991
  const explicitId = parsed.positional[0] ?? (typeof parsed.flags.session === "string" ? parsed.flags.session : undefined);
225904
225992
  let rec;
225905
225993
  try {
225906
- rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined);
225994
+ rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined, { probeLive: false });
225907
225995
  } catch (err) {
225908
225996
  if (!explicitId && err.code === "no_active_session") {
225909
225997
  emit({ ok: true, subcommand: "act close", op_kind: meta.op_kind, idempotent_noop: true }, opts);
@@ -226043,7 +226131,7 @@ async function handler27(parsed, opts) {
226043
226131
  const explicitId = parsed.positional[0] ?? (typeof parsed.flags.session === "string" ? parsed.flags.session : undefined);
226044
226132
  let rec;
226045
226133
  try {
226046
- rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined);
226134
+ rec = explicitId ? await readSessionRecord(explicitId) : await resolveSession(undefined, { probeLive: false });
226047
226135
  } catch (err) {
226048
226136
  if (!explicitId && err.code === "no_active_session") {
226049
226137
  emit({
@@ -226845,7 +226933,7 @@ __export(exports_resolve, {
226845
226933
  searchToShortlist: () => searchToShortlist,
226846
226934
  handler: () => handler44
226847
226935
  });
226848
- import { createHash as createHash35, randomBytes as randomBytes16 } from "node:crypto";
226936
+ import { createHash as createHash35, randomBytes as randomBytes17 } from "node:crypto";
226849
226937
  function searchToShortlist(results) {
226850
226938
  return { domain_results: [], global_results: Array.isArray(results) ? results : [] };
226851
226939
  }
@@ -226953,7 +227041,7 @@ async function handler44(parsed, opts) {
226953
227041
  process.exit(ok2 ? 0 : EX_GENERIC);
226954
227042
  } catch {}
226955
227043
  }
226956
- const nonce = bytesToBase647(new Uint8Array(randomBytes16(32)));
227044
+ const nonce = bytesToBase647(new Uint8Array(randomBytes17(32)));
226957
227045
  const fragment = canonicalizeSignedFragment({
226958
227046
  intent,
226959
227047
  surrogateUrl: urlFlag ?? null,
@@ -228323,7 +228411,7 @@ var exports_skills = {};
228323
228411
  __export(exports_skills, {
228324
228412
  handler: () => handler54
228325
228413
  });
228326
- import { createHash as createHash41, randomBytes as randomBytes17 } from "node:crypto";
228414
+ import { createHash as createHash41, randomBytes as randomBytes18 } from "node:crypto";
228327
228415
  function resolveApiBase4() {
228328
228416
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
228329
228417
  }
@@ -228411,7 +228499,7 @@ async function handler54(parsed, opts) {
228411
228499
  let backendError = null;
228412
228500
  const pubkeyBytes = await getWalletPubkey();
228413
228501
  const walletPubkey = bytesToHex16(pubkeyBytes);
228414
- const nonce = bytesToBase648(new Uint8Array(randomBytes17(32)));
228502
+ const nonce = bytesToBase648(new Uint8Array(randomBytes18(32)));
228415
228503
  const fragment = canonicalizeSignedFragment({
228416
228504
  op: "list_skills",
228417
228505
  domain: domainFlag ?? null,
@@ -228525,7 +228613,7 @@ var exports_skill2 = {};
228525
228613
  __export(exports_skill2, {
228526
228614
  handler: () => handler55
228527
228615
  });
228528
- import { createHash as createHash42, randomBytes as randomBytes18 } from "node:crypto";
228616
+ import { createHash as createHash42, randomBytes as randomBytes19 } from "node:crypto";
228529
228617
  function resolveApiBase5() {
228530
228618
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
228531
228619
  }
@@ -228589,7 +228677,7 @@ async function handler55(parsed, opts) {
228589
228677
  let backendError = null;
228590
228678
  const pubkeyBytes = await getWalletPubkey();
228591
228679
  const walletPubkey = bytesToHex17(pubkeyBytes);
228592
- const nonce = bytesToBase649(new Uint8Array(randomBytes18(32)));
228680
+ const nonce = bytesToBase649(new Uint8Array(randomBytes19(32)));
228593
228681
  const fragment = canonicalizeSignedFragment({ op: "get_skill", skillId, nonce }, ["op", "skillId", "nonce"]);
228594
228682
  const signed = await signBytes(new TextEncoder().encode(fragment));
228595
228683
  const signatureHex = bytesToHex17(signed.signature);
@@ -228706,7 +228794,7 @@ var exports_earnings = {};
228706
228794
  __export(exports_earnings, {
228707
228795
  handler: () => handler56
228708
228796
  });
228709
- import { createHash as createHash43, randomBytes as randomBytes19 } from "node:crypto";
228797
+ import { createHash as createHash43, randomBytes as randomBytes20 } from "node:crypto";
228710
228798
  function resolveApiBase6() {
228711
228799
  return process.env.UNBROWSE_API_URL ?? process.env.UNBROWSE_BACKEND_URL ?? DEFAULT_BACKEND_URL;
228712
228800
  }
@@ -228765,7 +228853,7 @@ async function handler56(parsed, opts) {
228765
228853
  const headers = { accept: "application/json" };
228766
228854
  if (fresh)
228767
228855
  headers["cache-control"] = "no-cache";
228768
- const nonce = bytesToBase6410(new Uint8Array(randomBytes19(32)));
228856
+ const nonce = bytesToBase6410(new Uint8Array(randomBytes20(32)));
228769
228857
  const fragment = canonicalizeSignedFragment({
228770
228858
  op: "get_earnings",
228771
228859
  agentId,
@@ -234486,7 +234574,7 @@ __export(exports_vault2, {
234486
234574
  getCredential: () => getCredential2,
234487
234575
  deleteCredential: () => deleteCredential2
234488
234576
  });
234489
- import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv6, randomBytes as randomBytes20 } from "crypto";
234577
+ import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv6, randomBytes as randomBytes21 } from "crypto";
234490
234578
  import { existsSync as existsSync57, mkdirSync as mkdirSync37, readFileSync as readFileSync47, writeFileSync as writeFileSync33 } from "fs";
234491
234579
  import { join as join65 } from "path";
234492
234580
  import { homedir as homedir48 } from "os";
@@ -234568,7 +234656,7 @@ function getOrCreateKey2() {
234568
234656
  mkdirSync37(VAULT_DIR2, { recursive: true, mode: 448 });
234569
234657
  if (existsSync57(KEY_FILE3))
234570
234658
  return readFileSync47(KEY_FILE3);
234571
- const key2 = randomBytes20(32);
234659
+ const key2 = randomBytes21(32);
234572
234660
  writeFileSync33(KEY_FILE3, key2, { mode: 384 });
234573
234661
  return key2;
234574
234662
  }
@@ -234597,7 +234685,7 @@ function readVaultFile2() {
234597
234685
  }
234598
234686
  function writeVaultFile2(data2) {
234599
234687
  const key2 = getOrCreateKey2();
234600
- const iv = randomBytes20(16);
234688
+ const iv = randomBytes21(16);
234601
234689
  const cipher = createCipheriv4("aes-256-cbc", key2, iv);
234602
234690
  const enc2 = Buffer.concat([cipher.update(JSON.stringify(data2), "utf8"), cipher.final()]);
234603
234691
  writeFileSync33(VAULT_FILE2, Buffer.concat([iv, enc2]), { mode: 384 });
Binary file
@@ -2,7 +2,7 @@
2
2
  "repo_url": "https://github.com/justrach/kuri.git",
3
3
  "branch": "adding-extensions",
4
4
  "source_sha": "149881254046a20778f642b69f20f0c6468f6fb4",
5
- "built_at": "2026-06-17T04:52:34.112Z",
5
+ "built_at": "2026-06-17T05:38:20.711Z",
6
6
  "binaries": {
7
7
  "darwin-arm64": {
8
8
  "zig_target": "aarch64-macos",
@@ -21,11 +21,11 @@
21
21
  },
22
22
  "linux-x64": {
23
23
  "zig_target": "x86_64-linux",
24
- "sha256": "cb569b4c62bec7750c26296995233210fddc8cd705f202317c84598be3a2ab20"
24
+ "sha256": "67beaecf2eb2e79d5753b3bfca2189879a9390c7c957f601fe0381fe7143232e"
25
25
  },
26
26
  "win-x64": {
27
27
  "zig_target": "x86_64-windows-gnu",
28
- "sha256": "c11585f8a0f37b7bc9d806f4abe1cb8214df7e8e72c6137f9687c8bc9a0983ad",
28
+ "sha256": "9f98f92332eed0bddf66e33e2a86222c9b953a16103d2db7d37dfecb7278885f",
29
29
  "source": "pre-staged"
30
30
  }
31
31
  },
@@ -33,22 +33,22 @@
33
33
  "darwin-arm64": {
34
34
  "zig_target": "aarch64-macos",
35
35
  "lib": "libkuri_ffi.dylib",
36
- "sha256": "ec187aa7dd740d7f9019d4bb87e60cd560bb598507c665950a81dea1decb21c3"
36
+ "sha256": "18af0fbf604d5f4037dde9d84ce153b9dc5388500a10b73fcb3d0a26a3e0f0b4"
37
37
  },
38
38
  "darwin-x64": {
39
39
  "zig_target": "x86_64-macos",
40
40
  "lib": "libkuri_ffi.dylib",
41
- "sha256": "f5d9f19aefbd48bfdad8c8cd2edc5e90f4f26e12b46f54c2c06f6e1a7d6412a5"
41
+ "sha256": "0878786f78ed181cab625559fccf43a9602a9dffcdac5ae78728fc2edeb2aec4"
42
42
  },
43
43
  "linux-arm64": {
44
44
  "zig_target": "aarch64-linux",
45
45
  "lib": "libkuri_ffi.so",
46
- "sha256": "4d51b7c929470ceadd4f19264ccadc4bc281fc66936ebb1fadb72c0a57af4ce9"
46
+ "sha256": "6c970a279635a94d6d904e33edf9aea6d46bb04ad2a34fdcfdbbc4ba189df3d7"
47
47
  },
48
48
  "linux-x64": {
49
49
  "zig_target": "x86_64-linux",
50
50
  "lib": "libkuri_ffi.so",
51
- "sha256": "c149020821b3f0e776972eb64cb9ca0fdd5180698d2f72f267bdd96be1d75d9b"
51
+ "sha256": "4225545bcfa7cc30dd9a148f9942a0166af4dcb2b747686dd0a61ecb3688656d"
52
52
  }
53
53
  }
54
54
  }
Binary file