unbrowse 6.6.0-preview.0 → 6.6.1
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/cli.js +103 -16
- package/dist/mcp.js +4 -4
- package/dist/server.js +93 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ var __promiseAll = (args) => Promise.all(args);
|
|
|
31
31
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
32
32
|
|
|
33
33
|
// ../../src/build-info.generated.ts
|
|
34
|
-
var BUILD_RELEASE_VERSION = "6.6.
|
|
34
|
+
var BUILD_RELEASE_VERSION = "6.6.1", BUILD_GIT_SHA = "a3c7f85c4099", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiNi42LjEiLCJnaXRfc2hhIjoiYTNjN2Y4NWM0MDk5IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBhM2M3Zjg1YzQwOTkiLCJpc3N1ZWRfYXQiOiIyMDI2LTA1LTA0VDA2OjQ4OjUzLjMwM1oifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "RoWkpJScjvL9xSx7GAwPPi1CvFFWKxuDt2VHYZFlVss", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
|
|
35
35
|
|
|
36
36
|
// ../../src/version.ts
|
|
37
37
|
import { createHash } from "crypto";
|
|
@@ -5050,7 +5050,25 @@ function parseArgs(argv) {
|
|
|
5050
5050
|
} else if (a.startsWith("--")) {
|
|
5051
5051
|
const key = a.slice(2);
|
|
5052
5052
|
const next = rest[i + 1];
|
|
5053
|
-
const valueExpectedFlags = new Set([
|
|
5053
|
+
const valueExpectedFlags = new Set([
|
|
5054
|
+
"skill",
|
|
5055
|
+
"endpoint",
|
|
5056
|
+
"intent",
|
|
5057
|
+
"url",
|
|
5058
|
+
"domain",
|
|
5059
|
+
"params",
|
|
5060
|
+
"path",
|
|
5061
|
+
"extract",
|
|
5062
|
+
"limit",
|
|
5063
|
+
"session",
|
|
5064
|
+
"ref",
|
|
5065
|
+
"text",
|
|
5066
|
+
"value",
|
|
5067
|
+
"form-selector",
|
|
5068
|
+
"submit-selector",
|
|
5069
|
+
"wait-for",
|
|
5070
|
+
"timeout-ms"
|
|
5071
|
+
]);
|
|
5054
5072
|
if (valueExpectedFlags.has(key)) {
|
|
5055
5073
|
if (next === undefined)
|
|
5056
5074
|
die(`--${key} requires a value`);
|
|
@@ -5379,14 +5397,29 @@ async function cmdResolve(flags) {
|
|
|
5379
5397
|
}, endpointNeedsThirdPartyTermsConfirmation = function(endpoint) {
|
|
5380
5398
|
return endpoint.requires_third_party_terms_confirmation === true;
|
|
5381
5399
|
}, resolveSkillId = function() {
|
|
5382
|
-
return result.skill?.skill_id ?? result.skill_id;
|
|
5400
|
+
return result.skill?.skill_id ?? result.skill_id ?? result.result?.skill_id;
|
|
5401
|
+
}, resolveAvailableEndpoints = function() {
|
|
5402
|
+
return Array.isArray(result.available_endpoints) ? result.available_endpoints : Array.isArray(result.result?.available_endpoints) ? result.result.available_endpoints : undefined;
|
|
5403
|
+
}, endpointIsSafeToAutoExecute = function(endpoint) {
|
|
5404
|
+
const method = String(endpoint.method ?? "GET").toUpperCase();
|
|
5405
|
+
if (method !== "GET" && method !== "HEAD")
|
|
5406
|
+
return false;
|
|
5407
|
+
if (endpoint.needs_params && Object.keys(extraParams).length === 0)
|
|
5408
|
+
return false;
|
|
5409
|
+
return true;
|
|
5383
5410
|
};
|
|
5384
5411
|
const body = { intent };
|
|
5385
5412
|
const url = flags.url;
|
|
5386
5413
|
const domain = flags.domain;
|
|
5387
|
-
const
|
|
5388
|
-
const
|
|
5389
|
-
const
|
|
5414
|
+
const endpointFlag = flags["endpoint-id"] ?? flags.endpoint;
|
|
5415
|
+
const explicitEndpointId = typeof endpointFlag === "string" ? endpointFlag : undefined;
|
|
5416
|
+
const noExecute = flags["no-execute"] === true;
|
|
5417
|
+
const autoExecute = !noExecute;
|
|
5418
|
+
const cliKv = flags._params;
|
|
5419
|
+
const extraParams = {
|
|
5420
|
+
...flags.params ? JSON.parse(flags.params) : {},
|
|
5421
|
+
...cliKv && Object.keys(cliKv).length > 0 ? cliKv : {}
|
|
5422
|
+
};
|
|
5390
5423
|
if (url) {
|
|
5391
5424
|
body.params = { url };
|
|
5392
5425
|
body.context = { url };
|
|
@@ -5429,23 +5462,36 @@ async function cmdResolve(flags) {
|
|
|
5429
5462
|
if (loginUrl)
|
|
5430
5463
|
info(`Authentication required. Run: unbrowse login --url "${loginUrl}"`);
|
|
5431
5464
|
}
|
|
5432
|
-
if (explicitEndpointId &&
|
|
5465
|
+
if (explicitEndpointId && resolveAvailableEndpoints()) {
|
|
5433
5466
|
const skillId = resolveSkillId();
|
|
5434
5467
|
if (skillId) {
|
|
5468
|
+
const resolvedSource = typeof result.source === "string" ? result.source : undefined;
|
|
5435
5469
|
result = await withPendingNotice(api2("POST", `/v1/skills/${skillId}/execute`, execBody(explicitEndpointId)), "Executing selected endpoint...");
|
|
5470
|
+
if (resolvedSource && typeof result.source !== "string")
|
|
5471
|
+
result.source = resolvedSource;
|
|
5436
5472
|
}
|
|
5437
5473
|
}
|
|
5438
|
-
|
|
5439
|
-
|
|
5474
|
+
const endpointsForAutoExecute = resolveAvailableEndpoints();
|
|
5475
|
+
if (autoExecute && endpointsForAutoExecute) {
|
|
5476
|
+
const endpoints = endpointsForAutoExecute;
|
|
5440
5477
|
const skillId = resolveSkillId();
|
|
5441
5478
|
if (skillId && endpoints.length > 0) {
|
|
5442
5479
|
const bestEndpoint = endpoints[0];
|
|
5480
|
+
const resolvedSource = typeof result.source === "string" ? result.source : undefined;
|
|
5443
5481
|
if (endpointNeedsThirdPartyTermsConfirmation(bestEndpoint) && !flags["confirm-third-party-terms"]) {
|
|
5444
5482
|
process.stderr.write(`Skipping auto-execute: endpoint ${bestEndpoint.endpoint_id ?? "?"} ` + `requires explicit third-party terms confirmation. ` + `Re-run with --confirm-third-party-terms to proceed.
|
|
5445
5483
|
`);
|
|
5484
|
+
} else if (!endpointIsSafeToAutoExecute(bestEndpoint)) {
|
|
5485
|
+
result.next_action = {
|
|
5486
|
+
title: "Execute selected endpoint",
|
|
5487
|
+
command: `unbrowse execute --skill ${skillId} --endpoint ${bestEndpoint.endpoint_id}`,
|
|
5488
|
+
why: "Resolve found a candidate but did not auto-execute because the endpoint is not a safe ready GET."
|
|
5489
|
+
};
|
|
5446
5490
|
} else {
|
|
5447
5491
|
info(`Auto-executing endpoint: ${bestEndpoint.description ?? bestEndpoint.endpoint_id}`);
|
|
5448
5492
|
result = await withPendingNotice(api2("POST", `/v1/skills/${skillId}/execute`, execBody(bestEndpoint.endpoint_id)), "Executing best endpoint...");
|
|
5493
|
+
if (resolvedSource && typeof result.source !== "string")
|
|
5494
|
+
result.source = resolvedSource;
|
|
5449
5495
|
}
|
|
5450
5496
|
}
|
|
5451
5497
|
}
|
|
@@ -6289,7 +6335,7 @@ var CLI_REFERENCE = {
|
|
|
6289
6335
|
{ name: "mcp", usage: "[--no-auto-start]", desc: "Run the stdio MCP server" },
|
|
6290
6336
|
{ name: "setup", usage: "[--opencode auto|global|project|off] [--no-start]", desc: "Bootstrap browser deps + Open Code command" },
|
|
6291
6337
|
{ name: "upgrade", usage: "", desc: "Check latest release and print the right upgrade command" },
|
|
6292
|
-
{ name: "resolve", usage: '--intent "..." [--domain "..."] [--url "..."] [opts]', desc: "
|
|
6338
|
+
{ name: "resolve", usage: '--intent "..." [--domain "..."] [--url "..."] [opts]', desc: "Resolve an intent, auto-executing the top safe GET endpoint by default; pass --no-execute for metadata only" },
|
|
6293
6339
|
{ name: "explain", usage: '--intent "..." --url "..." [--top N]', desc: "Emit top-N candidate endpoints + evidence for an LLM judge to pick from (no heuristic verdict \u2014 primitives + agent judgment)" },
|
|
6294
6340
|
{ name: "execute", usage: "--skill ID --endpoint ID [-p key=val ...] [--params '{json}'] [opts]", desc: "Execute a specific endpoint. Pass replay params via repeated -p key=val flags or --params with a JSON object" },
|
|
6295
6341
|
{ name: "feedback", usage: "--skill ID --endpoint ID --rating N", desc: "Submit feedback (mandatory after resolve)" },
|
|
@@ -6304,6 +6350,7 @@ var CLI_REFERENCE = {
|
|
|
6304
6350
|
{ name: "skill", usage: "<id>", desc: "Get skill details" },
|
|
6305
6351
|
{ name: "cleanup-stale", usage: "[--skill ID] [--domain host] [--limit N]", desc: "Verify skills and evict stale cached endpoints" },
|
|
6306
6352
|
{ name: "sessions", usage: '--domain "..." [--limit N]', desc: "Debug session logs" },
|
|
6353
|
+
{ name: "inspect", usage: "[--session id] [--all]", desc: "Inspect live browser capture evidence, candidate endpoints, and next actions" },
|
|
6307
6354
|
{ name: "go", usage: "<url> [--session id]", desc: "Open a fresh Kuri browser tab, or reuse explicit --session" },
|
|
6308
6355
|
{ name: "submit", usage: "[--session id] [--form-selector sel] [--submit-selector sel] [--wait-for hint] [--assist-site-state]", desc: "Submit current form. Thin browser-native proxy by default; site-state assist and same-origin rehydrate are explicit opt-ins" },
|
|
6309
6356
|
{ name: "snap", usage: "[--session id] [--filter interactive]", desc: "A11y snapshot with @eN refs" },
|
|
@@ -6342,7 +6389,8 @@ var CLI_REFERENCE = {
|
|
|
6342
6389
|
{ flag: "--opencode auto|global|project|off", desc: "setup: install /unbrowse command for Open Code" }
|
|
6343
6390
|
],
|
|
6344
6391
|
resolveExecuteFlags: [
|
|
6345
|
-
{ flag: "--execute", desc: "
|
|
6392
|
+
{ flag: "--no-execute", desc: "Resolve only; do not auto-execute safe GET endpoints" },
|
|
6393
|
+
{ flag: "--execute", desc: "Deprecated no-op alias; safe GET execution is now the default" },
|
|
6346
6394
|
{ flag: "--schema", desc: "Show response schema + extraction hints only (no data)" },
|
|
6347
6395
|
{ flag: '--path "data.items[]"', desc: "Drill into result before extract/output" },
|
|
6348
6396
|
{ flag: '--extract "field1,alias:deep.path.to.val"', desc: "Pick specific fields (no piping needed)" },
|
|
@@ -6611,6 +6659,7 @@ async function cmdStatus(flags) {
|
|
|
6611
6659
|
const versionInfo = checkServerVersion(BASE_URL, import.meta.url);
|
|
6612
6660
|
let activeSessions = [];
|
|
6613
6661
|
let sessionCount = 0;
|
|
6662
|
+
let latestSessionId = null;
|
|
6614
6663
|
if (healthy) {
|
|
6615
6664
|
try {
|
|
6616
6665
|
const res = await fetch(`${BASE_URL}/v1/browse/sessions`, { signal: AbortSignal.timeout(2000) });
|
|
@@ -6618,6 +6667,7 @@ async function cmdStatus(flags) {
|
|
|
6618
6667
|
const data = await res.json();
|
|
6619
6668
|
activeSessions = data.sessions ?? [];
|
|
6620
6669
|
sessionCount = data.count ?? activeSessions.length;
|
|
6670
|
+
latestSessionId = data.latest_session_id ?? null;
|
|
6621
6671
|
}
|
|
6622
6672
|
} catch {}
|
|
6623
6673
|
}
|
|
@@ -6626,10 +6676,34 @@ async function cmdStatus(flags) {
|
|
|
6626
6676
|
url: BASE_URL,
|
|
6627
6677
|
...versionInfo ?? {},
|
|
6628
6678
|
active_browse_sessions: sessionCount,
|
|
6679
|
+
latest_session_id: latestSessionId,
|
|
6629
6680
|
sessions: activeSessions,
|
|
6630
6681
|
chrome_debug_url: process.env.CHROME_DEBUG_URL ?? null
|
|
6631
6682
|
}, !!flags.pretty);
|
|
6632
6683
|
}
|
|
6684
|
+
async function cmdInspect(args, flags) {
|
|
6685
|
+
const explicitSession = typeof flags.session === "string" ? flags.session : typeof args[0] === "string" ? args[0] : undefined;
|
|
6686
|
+
const sessions = await api2("GET", "/v1/browse/sessions");
|
|
6687
|
+
if (flags.all) {
|
|
6688
|
+
output(sessions, !!flags.pretty);
|
|
6689
|
+
return;
|
|
6690
|
+
}
|
|
6691
|
+
const latestSessionId = sessions.latest_session_id ?? sessions.sessions?.at(-1)?.session_id;
|
|
6692
|
+
const sessionId = explicitSession ?? latestSessionId;
|
|
6693
|
+
if (!sessionId) {
|
|
6694
|
+
output({
|
|
6695
|
+
error: "no_active_session",
|
|
6696
|
+
message: "No active browse session to inspect.",
|
|
6697
|
+
next_action: {
|
|
6698
|
+
title: "Open a browser session",
|
|
6699
|
+
command: 'unbrowse go "https://example.com" --pretty',
|
|
6700
|
+
why: "Inspection reads live HAR/interceptor evidence from an active Kuri session."
|
|
6701
|
+
}
|
|
6702
|
+
}, !!flags.pretty);
|
|
6703
|
+
return;
|
|
6704
|
+
}
|
|
6705
|
+
output(await api2("GET", `/v1/browse/sessions/${encodeURIComponent(sessionId)}/buffer`), !!flags.pretty);
|
|
6706
|
+
}
|
|
6633
6707
|
async function cmdRestart(flags) {
|
|
6634
6708
|
info("Restarting server...");
|
|
6635
6709
|
await restartServer(BASE_URL, import.meta.url);
|
|
@@ -6843,7 +6917,7 @@ async function cmdSnap(flags) {
|
|
|
6843
6917
|
}
|
|
6844
6918
|
}
|
|
6845
6919
|
async function cmdClick(args, flags) {
|
|
6846
|
-
const ref = args[0];
|
|
6920
|
+
const ref = args[0] ?? (typeof flags.ref === "string" ? flags.ref : undefined);
|
|
6847
6921
|
if (!ref)
|
|
6848
6922
|
die("Usage: unbrowse click <ref>");
|
|
6849
6923
|
output(await api2("POST", "/v1/browse/click", {
|
|
@@ -6852,10 +6926,10 @@ async function cmdClick(args, flags) {
|
|
|
6852
6926
|
}), false);
|
|
6853
6927
|
}
|
|
6854
6928
|
async function cmdFill(args, flags) {
|
|
6855
|
-
const ref = args[0];
|
|
6856
|
-
const value = args.slice(1).join(" ");
|
|
6929
|
+
const ref = args[0] ?? (typeof flags.ref === "string" ? flags.ref : undefined);
|
|
6930
|
+
const value = args.length > 1 ? args.slice(1).join(" ") : typeof flags.text === "string" ? flags.text : typeof flags.value === "string" ? flags.value : "";
|
|
6857
6931
|
if (!ref || !value)
|
|
6858
|
-
die(
|
|
6932
|
+
die('Usage: unbrowse fill <ref> <value> (also: unbrowse fill --ref e5 --text "hello")');
|
|
6859
6933
|
output(await api2("POST", "/v1/browse/fill", {
|
|
6860
6934
|
ref,
|
|
6861
6935
|
value,
|
|
@@ -7290,7 +7364,17 @@ async function cmdConnectChrome() {
|
|
|
7290
7364
|
console.error("Could not connect to Chrome. Make sure all Chrome windows are closed and try again.");
|
|
7291
7365
|
}
|
|
7292
7366
|
async function main() {
|
|
7293
|
-
const
|
|
7367
|
+
const parsed = parseArgs(process.argv);
|
|
7368
|
+
let { command, args, flags } = parsed;
|
|
7369
|
+
const cliParams = parsed.params;
|
|
7370
|
+
if (command === "browse") {
|
|
7371
|
+
const subcommand = args.shift();
|
|
7372
|
+
if (!subcommand || subcommand === "help") {
|
|
7373
|
+
printHelp();
|
|
7374
|
+
process.exit(subcommand === "help" ? 0 : 1);
|
|
7375
|
+
}
|
|
7376
|
+
command = subcommand;
|
|
7377
|
+
}
|
|
7294
7378
|
if (Object.keys(cliParams).length > 0) {
|
|
7295
7379
|
flags._params = cliParams;
|
|
7296
7380
|
}
|
|
@@ -7359,6 +7443,7 @@ async function main() {
|
|
|
7359
7443
|
"search",
|
|
7360
7444
|
"sessions",
|
|
7361
7445
|
"status",
|
|
7446
|
+
"inspect",
|
|
7362
7447
|
"stop",
|
|
7363
7448
|
"restart",
|
|
7364
7449
|
"upgrade",
|
|
@@ -7455,6 +7540,8 @@ async function main() {
|
|
|
7455
7540
|
return cmdSearch(flags);
|
|
7456
7541
|
case "sessions":
|
|
7457
7542
|
return cmdSessions(flags);
|
|
7543
|
+
case "inspect":
|
|
7544
|
+
return cmdInspect(args, flags);
|
|
7458
7545
|
case "go":
|
|
7459
7546
|
return cmdGo(args, flags);
|
|
7460
7547
|
case "submit":
|
package/dist/mcp.js
CHANGED
|
@@ -226,11 +226,11 @@ import { dirname, join, parse } from "path";
|
|
|
226
226
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
227
227
|
|
|
228
228
|
// ../../src/build-info.generated.ts
|
|
229
|
-
var BUILD_RELEASE_VERSION = "6.6.
|
|
230
|
-
var BUILD_GIT_SHA = "
|
|
229
|
+
var BUILD_RELEASE_VERSION = "6.6.1";
|
|
230
|
+
var BUILD_GIT_SHA = "a3c7f85c4099";
|
|
231
231
|
var BUILD_CODE_HASH = "5d9ebf619c61";
|
|
232
|
-
var BUILD_RELEASE_MANIFEST_BASE64 = "
|
|
233
|
-
var BUILD_RELEASE_MANIFEST_SIGNATURE = "
|
|
232
|
+
var BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiNi42LjEiLCJnaXRfc2hhIjoiYTNjN2Y4NWM0MDk5IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBhM2M3Zjg1YzQwOTkiLCJpc3N1ZWRfYXQiOiIyMDI2LTA1LTA0VDA2OjQ4OjUzLjMwM1oifQ";
|
|
233
|
+
var BUILD_RELEASE_MANIFEST_SIGNATURE = "RoWkpJScjvL9xSx7GAwPPi1CvFFWKxuDt2VHYZFlVss";
|
|
234
234
|
var BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
|
|
235
235
|
var BUILD_DEFAULT_PROFILE = "";
|
|
236
236
|
|
package/dist/server.js
CHANGED
|
@@ -7342,7 +7342,7 @@ var init_capture = __esm(async () => {
|
|
|
7342
7342
|
});
|
|
7343
7343
|
|
|
7344
7344
|
// ../../src/build-info.generated.ts
|
|
7345
|
-
var BUILD_RELEASE_VERSION = "6.6.
|
|
7345
|
+
var BUILD_RELEASE_VERSION = "6.6.1", BUILD_GIT_SHA = "a3c7f85c4099", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiNi42LjEiLCJnaXRfc2hhIjoiYTNjN2Y4NWM0MDk5IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBhM2M3Zjg1YzQwOTkiLCJpc3N1ZWRfYXQiOiIyMDI2LTA1LTA0VDA2OjQ4OjUzLjMwM1oifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "RoWkpJScjvL9xSx7GAwPPi1CvFFWKxuDt2VHYZFlVss", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai", BUILD_DEFAULT_PROFILE = "";
|
|
7346
7346
|
|
|
7347
7347
|
// ../../src/version.ts
|
|
7348
7348
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -25769,9 +25769,7 @@ async function resolveRequestedBrowseSession(sessions, client, requestedSessionI
|
|
|
25769
25769
|
const live = await listLiveBrowseSessions(sessions, client);
|
|
25770
25770
|
if (live.length === 0)
|
|
25771
25771
|
throw new BrowseSessionError("no_active_session");
|
|
25772
|
-
|
|
25773
|
-
throw new BrowseSessionError("session_id_required");
|
|
25774
|
-
return live[0];
|
|
25772
|
+
return live[live.length - 1];
|
|
25775
25773
|
}
|
|
25776
25774
|
async function withSessionQueue(sessionId, fn) {
|
|
25777
25775
|
const prev = sessionQueues.get(sessionId) ?? Promise.resolve();
|
|
@@ -27921,6 +27919,17 @@ function passiveIndexFromRequests(requests, pageUrl, options = {}) {
|
|
|
27921
27919
|
function passiveIndexHar(entries, pageUrl, options = {}) {
|
|
27922
27920
|
passiveIndexFromRequests(harEntriesToRawRequests(entries), pageUrl, options);
|
|
27923
27921
|
}
|
|
27922
|
+
function rememberInspectedHarEntries(sessionId, entries) {
|
|
27923
|
+
if (entries.length === 0)
|
|
27924
|
+
return;
|
|
27925
|
+
const existing = inspectedHarEntries.get(sessionId) ?? [];
|
|
27926
|
+
inspectedHarEntries.set(sessionId, [...existing, ...entries]);
|
|
27927
|
+
}
|
|
27928
|
+
function drainInspectedHarEntries(sessionId) {
|
|
27929
|
+
const entries = inspectedHarEntries.get(sessionId) ?? [];
|
|
27930
|
+
inspectedHarEntries.delete(sessionId);
|
|
27931
|
+
return entries;
|
|
27932
|
+
}
|
|
27924
27933
|
function browseBrokerPorts() {
|
|
27925
27934
|
return Array.from({ length: BROWSE_BROKER_MAX }, (_, index) => BROWSE_BROKER_BASE_PORT + index);
|
|
27926
27935
|
}
|
|
@@ -28161,9 +28170,23 @@ async function registerRoutes(app) {
|
|
|
28161
28170
|
domain: s.domain,
|
|
28162
28171
|
har_active: s.harActive,
|
|
28163
28172
|
broker_port: s.brokerPort ?? null,
|
|
28164
|
-
streaming_publish_active: streamingWatchers.has(s.sessionId)
|
|
28173
|
+
streaming_publish_active: streamingWatchers.has(s.sessionId),
|
|
28174
|
+
marketplace_publish: (() => {
|
|
28175
|
+
const decision = decideCheckpointPublish(s.domain || profileName(s.url));
|
|
28176
|
+
return {
|
|
28177
|
+
enabled: decision.publishQueued,
|
|
28178
|
+
mode: decision.mode,
|
|
28179
|
+
reason: decision.reason
|
|
28180
|
+
};
|
|
28181
|
+
})(),
|
|
28182
|
+
suggested_commands: [
|
|
28183
|
+
`unbrowse inspect --session ${s.sessionId} --pretty`,
|
|
28184
|
+
`unbrowse resolve --intent "<task>" --url "${s.url}" --pretty`,
|
|
28185
|
+
`unbrowse close --session ${s.sessionId}`
|
|
28186
|
+
]
|
|
28165
28187
|
}));
|
|
28166
|
-
|
|
28188
|
+
const latest = sessions[sessions.length - 1] ?? null;
|
|
28189
|
+
return reply.send({ sessions, count: sessions.length, latest_session_id: latest?.session_id ?? null });
|
|
28167
28190
|
});
|
|
28168
28191
|
app.get("/v1/browse/sessions/:id/buffer", async (req, reply) => {
|
|
28169
28192
|
const { id } = req.params;
|
|
@@ -28190,6 +28213,7 @@ async function registerRoutes(app) {
|
|
|
28190
28213
|
const broker = brokerForSession(session);
|
|
28191
28214
|
const stopResult = await broker.harStop(session.tabId);
|
|
28192
28215
|
harEntries = stopResult.entries ?? [];
|
|
28216
|
+
rememberInspectedHarEntries(session.sessionId, harEntries);
|
|
28193
28217
|
try {
|
|
28194
28218
|
await broker.harStart(session.tabId);
|
|
28195
28219
|
} catch {}
|
|
@@ -28197,6 +28221,23 @@ async function registerRoutes(app) {
|
|
|
28197
28221
|
harError = err instanceof Error ? err.message : String(err);
|
|
28198
28222
|
}
|
|
28199
28223
|
}
|
|
28224
|
+
const rawRequests = [
|
|
28225
|
+
...Array.isArray(intercepted) ? intercepted : [],
|
|
28226
|
+
...harEntriesToRawRequests(harEntries, session.url)
|
|
28227
|
+
];
|
|
28228
|
+
const candidateEndpoints = extractEndpoints(rawRequests, undefined, {
|
|
28229
|
+
pageUrl: session.url,
|
|
28230
|
+
finalUrl: session.url
|
|
28231
|
+
}).slice(0, 10).map((endpoint) => ({
|
|
28232
|
+
endpoint_id: endpoint.endpoint_id,
|
|
28233
|
+
method: endpoint.method,
|
|
28234
|
+
url_template: endpoint.url_template,
|
|
28235
|
+
description: endpoint.description ?? generateLocalDescription(endpoint),
|
|
28236
|
+
reliability_score: endpoint.reliability_score,
|
|
28237
|
+
idempotency: endpoint.idempotency,
|
|
28238
|
+
auth_token_count: endpoint.auth_tokens?.length ?? 0
|
|
28239
|
+
}));
|
|
28240
|
+
const publishDecision = decideCheckpointPublish(session.domain || profileName(session.url));
|
|
28200
28241
|
return reply.send({
|
|
28201
28242
|
session: {
|
|
28202
28243
|
session_id: session.sessionId,
|
|
@@ -28204,7 +28245,12 @@ async function registerRoutes(app) {
|
|
|
28204
28245
|
url: session.url,
|
|
28205
28246
|
domain: session.domain,
|
|
28206
28247
|
har_active: session.harActive,
|
|
28207
|
-
streaming_publish_active: streamingWatchers.has(session.sessionId)
|
|
28248
|
+
streaming_publish_active: streamingWatchers.has(session.sessionId),
|
|
28249
|
+
marketplace_publish: {
|
|
28250
|
+
enabled: publishDecision.publishQueued,
|
|
28251
|
+
mode: publishDecision.mode,
|
|
28252
|
+
reason: publishDecision.reason
|
|
28253
|
+
}
|
|
28208
28254
|
},
|
|
28209
28255
|
intercepted_requests: intercepted,
|
|
28210
28256
|
intercepted_count: Array.isArray(intercepted) ? intercepted.length : 0,
|
|
@@ -28218,7 +28264,26 @@ async function registerRoutes(app) {
|
|
|
28218
28264
|
})),
|
|
28219
28265
|
har_count: harEntries.length,
|
|
28220
28266
|
har_error: harError,
|
|
28221
|
-
total_captured: (Array.isArray(intercepted) ? intercepted.length : 0) + harEntries.length
|
|
28267
|
+
total_captured: (Array.isArray(intercepted) ? intercepted.length : 0) + harEntries.length,
|
|
28268
|
+
candidate_endpoints: candidateEndpoints,
|
|
28269
|
+
candidate_endpoint_count: candidateEndpoints.length,
|
|
28270
|
+
next_actions: [
|
|
28271
|
+
{
|
|
28272
|
+
title: "Resolve from captured evidence",
|
|
28273
|
+
command: `unbrowse resolve --intent "<task>" --url "${session.url}" --pretty`,
|
|
28274
|
+
why: "Runs the normal resolver after the current in-flight capture has been exposed."
|
|
28275
|
+
},
|
|
28276
|
+
{
|
|
28277
|
+
title: "Checkpoint and publish review material",
|
|
28278
|
+
command: `unbrowse sync --session ${session.sessionId} --pretty`,
|
|
28279
|
+
why: "Keeps the tab open and compiles current browser traffic into local skill evidence."
|
|
28280
|
+
},
|
|
28281
|
+
{
|
|
28282
|
+
title: "Close after judging",
|
|
28283
|
+
command: `unbrowse close --session ${session.sessionId}`,
|
|
28284
|
+
why: "Flushes final capture, saves auth, and stops the live tab."
|
|
28285
|
+
}
|
|
28286
|
+
]
|
|
28222
28287
|
});
|
|
28223
28288
|
});
|
|
28224
28289
|
app.get("/v1/trace/:trace_id", async (req, reply) => {
|
|
@@ -28897,7 +28962,20 @@ async function registerRoutes(app) {
|
|
|
28897
28962
|
}
|
|
28898
28963
|
function sendBrowseSessionError(reply, error) {
|
|
28899
28964
|
if (error instanceof BrowseSessionError) {
|
|
28900
|
-
|
|
28965
|
+
const latestSession = Array.from(browseSessions.values()).at(-1);
|
|
28966
|
+
return reply.code(error.statusCode).send({
|
|
28967
|
+
error: error.code,
|
|
28968
|
+
...latestSession ? { latest_session_id: latestSession.sessionId } : {},
|
|
28969
|
+
next_action: latestSession ? {
|
|
28970
|
+
title: "Retry with latest active session",
|
|
28971
|
+
command: `unbrowse inspect --session ${latestSession.sessionId} --pretty`,
|
|
28972
|
+
why: "A live session exists; inspect it or pass --session to the browser command."
|
|
28973
|
+
} : {
|
|
28974
|
+
title: "Open a browser session",
|
|
28975
|
+
command: 'unbrowse go "<url>" --pretty',
|
|
28976
|
+
why: "This command needs a live Kuri-backed browse session."
|
|
28977
|
+
}
|
|
28978
|
+
});
|
|
28901
28979
|
}
|
|
28902
28980
|
if (isRecoverableBrowseFailure(error)) {
|
|
28903
28981
|
return reply.code(502).send({
|
|
@@ -28953,6 +29031,7 @@ async function registerRoutes(app) {
|
|
|
28953
29031
|
} catch {}
|
|
28954
29032
|
} catch {}
|
|
28955
29033
|
}
|
|
29034
|
+
harEntries = [...drainInspectedHarEntries(session.sessionId), ...harEntries];
|
|
28956
29035
|
const allRequests = await enrichPassiveCaptureRequests({
|
|
28957
29036
|
tabId: session.tabId,
|
|
28958
29037
|
captureUrl: session.url,
|
|
@@ -29075,6 +29154,7 @@ async function registerRoutes(app) {
|
|
|
29075
29154
|
streamingWatchers.delete(sessionId);
|
|
29076
29155
|
}
|
|
29077
29156
|
streamingState.delete(sessionId);
|
|
29157
|
+
inspectedHarEntries.delete(sessionId);
|
|
29078
29158
|
}
|
|
29079
29159
|
async function flushBrowseCapture(session, options = {}) {
|
|
29080
29160
|
let harEntries = [];
|
|
@@ -29084,6 +29164,7 @@ async function registerRoutes(app) {
|
|
|
29084
29164
|
harEntries = entries;
|
|
29085
29165
|
} catch {}
|
|
29086
29166
|
}
|
|
29167
|
+
harEntries = [...drainInspectedHarEntries(session.sessionId), ...harEntries];
|
|
29087
29168
|
session.harActive = false;
|
|
29088
29169
|
const allRequests = await enrichPassiveCaptureRequests({
|
|
29089
29170
|
tabId: session.tabId,
|
|
@@ -29300,6 +29381,7 @@ async function registerRoutes(app) {
|
|
|
29300
29381
|
streaming_publish_active: streamingWatchers.has(session.sessionId),
|
|
29301
29382
|
attached_existing_chrome: result.attachedExistingChrome ?? false,
|
|
29302
29383
|
chrome_debug_url: process.env.CHROME_DEBUG_URL ?? null,
|
|
29384
|
+
inspect_command: `unbrowse inspect --session ${session.sessionId} --pretty`,
|
|
29303
29385
|
inspect_buffer: `GET ${process.env.UNBROWSE_API_BASE ?? "http://127.0.0.1:6969"}/v1/browse/sessions/${session.sessionId}/buffer`,
|
|
29304
29386
|
marketplace_publish_enabled: publishDecision.publishQueued,
|
|
29305
29387
|
marketplace_publish_mode: publishDecision.mode,
|
|
@@ -29605,7 +29687,7 @@ function saveTrace(trace) {
|
|
|
29605
29687
|
const t = trace;
|
|
29606
29688
|
writeFileSync13(join19(TRACES_DIR, `${t.trace_id}.json`), JSON.stringify(trace, null, 2));
|
|
29607
29689
|
}
|
|
29608
|
-
var BETA_API_URL, TRACES_DIR, BROWSE_BROKER_MAX, BROWSE_BROKER_BASE_PORT, browseSessions, statsCache = null, STATS_CACHE_TTL;
|
|
29690
|
+
var BETA_API_URL, TRACES_DIR, BROWSE_BROKER_MAX, BROWSE_BROKER_BASE_PORT, browseSessions, inspectedHarEntries, statsCache = null, STATS_CACHE_TTL;
|
|
29609
29691
|
var init_routes = __esm(async () => {
|
|
29610
29692
|
init_client();
|
|
29611
29693
|
init_reverse_engineer();
|
|
@@ -29644,6 +29726,7 @@ var init_routes = __esm(async () => {
|
|
|
29644
29726
|
BROWSE_BROKER_MAX = Math.max(1, Number(process.env.KURI_MULTI_BROKER_MAX ?? "1"));
|
|
29645
29727
|
BROWSE_BROKER_BASE_PORT = Number(process.env.KURI_PORT ?? "7700");
|
|
29646
29728
|
browseSessions = new Map;
|
|
29729
|
+
inspectedHarEntries = new Map;
|
|
29647
29730
|
STATS_CACHE_TTL = 5 * 60 * 1000;
|
|
29648
29731
|
});
|
|
29649
29732
|
|