unbrowse 6.0.0 → 6.1.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/cli.js +90 -9
- package/dist/mcp.js +66 -5
- package/dist/server.js +1005 -68
- package/package.json +1 -1
- package/vendor/kuri/darwin-arm64/kuri +0 -0
- package/vendor/kuri/manifest.json +3 -3
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.
|
|
34
|
+
var BUILD_RELEASE_VERSION = "6.1.0", BUILD_GIT_SHA = "82d14e507af6", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiNi4xLjAiLCJnaXRfc2hhIjoiODJkMTRlNTA3YWY2IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA4MmQxNGU1MDdhZjYiLCJpc3N1ZWRfYXQiOiIyMDI2LTA1LTAxVDAwOjI1OjUwLjExMFoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "gOz02sMxkYuLKvc24oN5EVm8VEQo2dftkUpMS5RMjiE", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
|
|
35
35
|
|
|
36
36
|
// ../../src/version.ts
|
|
37
37
|
import { createHash } from "crypto";
|
|
@@ -3109,6 +3109,10 @@ The Unbrowse Terms of Service have been updated.`);
|
|
|
3109
3109
|
async function ensureRegistered(options) {
|
|
3110
3110
|
if (LOCAL_ONLY)
|
|
3111
3111
|
return;
|
|
3112
|
+
if (process.env.UNBROWSE_SKIP_TOS_CHECK === "1") {
|
|
3113
|
+
console.log("[unbrowse] ToS check skipped (non-interactive/server mode)");
|
|
3114
|
+
return;
|
|
3115
|
+
}
|
|
3112
3116
|
const exitOnFailure = options?.exitOnFailure ?? true;
|
|
3113
3117
|
const usableKey = await findUsableApiKey();
|
|
3114
3118
|
if (usableKey) {
|
|
@@ -4428,12 +4432,22 @@ function parseArgs(argv) {
|
|
|
4428
4432
|
const rest = command === "help" ? raw : raw.slice(1);
|
|
4429
4433
|
const positional = [];
|
|
4430
4434
|
const flags = {};
|
|
4435
|
+
const params = {};
|
|
4431
4436
|
for (let i = 0;i < rest.length; i++) {
|
|
4432
4437
|
const a = rest[i];
|
|
4433
|
-
if (a
|
|
4438
|
+
if (a === "-p" || a === "--param") {
|
|
4439
|
+
const next = rest[i + 1];
|
|
4440
|
+
if (next && next.includes("=")) {
|
|
4441
|
+
const eq = next.indexOf("=");
|
|
4442
|
+
params[next.slice(0, eq)] = next.slice(eq + 1);
|
|
4443
|
+
i++;
|
|
4444
|
+
} else {
|
|
4445
|
+
die(`-p requires key=value, got: ${next ?? "<end of args>"}`);
|
|
4446
|
+
}
|
|
4447
|
+
} else if (a.startsWith("--")) {
|
|
4434
4448
|
const key = a.slice(2);
|
|
4435
4449
|
const next = rest[i + 1];
|
|
4436
|
-
if (!next || next.startsWith("--")) {
|
|
4450
|
+
if (!next || next.startsWith("--") || next === "-p" || next === "--param") {
|
|
4437
4451
|
flags[key] = true;
|
|
4438
4452
|
} else {
|
|
4439
4453
|
flags[key] = next;
|
|
@@ -4443,7 +4457,7 @@ function parseArgs(argv) {
|
|
|
4443
4457
|
positional.push(a);
|
|
4444
4458
|
}
|
|
4445
4459
|
}
|
|
4446
|
-
return { command, args: positional, flags };
|
|
4460
|
+
return { command, args: positional, flags, params };
|
|
4447
4461
|
}
|
|
4448
4462
|
async function api2(method, path9, body) {
|
|
4449
4463
|
let target = `${BASE_URL}${path9}`;
|
|
@@ -4625,6 +4639,62 @@ function telemetryDomainFromInput(domain, url) {
|
|
|
4625
4639
|
return null;
|
|
4626
4640
|
}
|
|
4627
4641
|
}
|
|
4642
|
+
async function cmdExplain(flags) {
|
|
4643
|
+
const intent = flags.intent;
|
|
4644
|
+
const url = flags.url;
|
|
4645
|
+
const top = parseInt(flags.top ?? "5", 10) || 5;
|
|
4646
|
+
if (!intent || !url) {
|
|
4647
|
+
process.stderr.write(`usage: unbrowse explain --intent "..." --url "..." [--top N]
|
|
4648
|
+
`);
|
|
4649
|
+
process.exit(2);
|
|
4650
|
+
}
|
|
4651
|
+
const body = {
|
|
4652
|
+
intent,
|
|
4653
|
+
params: { url },
|
|
4654
|
+
context: { url },
|
|
4655
|
+
projection: { raw: true }
|
|
4656
|
+
};
|
|
4657
|
+
let result;
|
|
4658
|
+
try {
|
|
4659
|
+
result = await api2("POST", "/v1/intent/resolve", body);
|
|
4660
|
+
} catch (err) {
|
|
4661
|
+
process.stderr.write(`explain failed: ${err.message}
|
|
4662
|
+
`);
|
|
4663
|
+
process.exit(1);
|
|
4664
|
+
}
|
|
4665
|
+
const r = result.result ?? result;
|
|
4666
|
+
const ae = r.available_endpoints ?? [];
|
|
4667
|
+
const ao = r.available_operations ?? [];
|
|
4668
|
+
const out = {
|
|
4669
|
+
intent,
|
|
4670
|
+
context_url: url,
|
|
4671
|
+
diagnostic: r.diagnostic,
|
|
4672
|
+
shortlist_for_judgment: ae.slice(0, top).map((ep, i) => ({
|
|
4673
|
+
rank: i,
|
|
4674
|
+
endpoint_id: ep.endpoint_id,
|
|
4675
|
+
method: ep.method,
|
|
4676
|
+
url: ep.url,
|
|
4677
|
+
score: ep.score,
|
|
4678
|
+
description: ep.description,
|
|
4679
|
+
input_params: ep.input_params,
|
|
4680
|
+
schema_summary: ep.schema_summary,
|
|
4681
|
+
example_fields: ep.example_fields,
|
|
4682
|
+
sample_values: ep.sample_values,
|
|
4683
|
+
needs_params: ep.needs_params,
|
|
4684
|
+
trigger_url: ep.trigger_url
|
|
4685
|
+
})),
|
|
4686
|
+
agent_facing_shortlist: ao.slice(0, top).map((op, i) => ({
|
|
4687
|
+
rank: i,
|
|
4688
|
+
endpoint_id: op.endpoint_id,
|
|
4689
|
+
method: op.method,
|
|
4690
|
+
url_template: op.url_template ?? op.url,
|
|
4691
|
+
description: op.description_out ?? op.description
|
|
4692
|
+
})),
|
|
4693
|
+
judgment_question: `Given the intent ${JSON.stringify(intent)} on ${JSON.stringify(url)}, ` + `which of the candidate endpoints in shortlist_for_judgment best satisfies the intent? ` + `Reply with the endpoint_id of the best match and a one-line reason. ` + `If none match, say defer_to_capture.`
|
|
4694
|
+
};
|
|
4695
|
+
process.stdout.write(JSON.stringify(out, null, 2) + `
|
|
4696
|
+
`);
|
|
4697
|
+
}
|
|
4628
4698
|
async function cmdResolve(flags) {
|
|
4629
4699
|
const intent = flags.intent;
|
|
4630
4700
|
if (!intent)
|
|
@@ -4886,6 +4956,10 @@ async function cmdExecute(flags) {
|
|
|
4886
4956
|
if (flags.params) {
|
|
4887
4957
|
body.params = { ...body.params, ...JSON.parse(flags.params) };
|
|
4888
4958
|
}
|
|
4959
|
+
const cliKv = flags._params;
|
|
4960
|
+
if (cliKv && Object.keys(cliKv).length > 0) {
|
|
4961
|
+
body.params = { ...body.params, ...cliKv };
|
|
4962
|
+
}
|
|
4889
4963
|
if (flags.url) {
|
|
4890
4964
|
body.context_url = flags.url;
|
|
4891
4965
|
body.params.url = flags.url;
|
|
@@ -4961,16 +5035,17 @@ async function cmdExecute(flags) {
|
|
|
4961
5035
|
output(out, !!flags.pretty);
|
|
4962
5036
|
return;
|
|
4963
5037
|
}
|
|
5038
|
+
const AUTOEXTRACT_HINT_THRESHOLD = 65536;
|
|
4964
5039
|
if (!rawFlag && !pathFlag && !extractFlag && !schemaFlag) {
|
|
4965
5040
|
const raw = JSON.stringify(result.result);
|
|
4966
|
-
if (raw && raw.length >
|
|
5041
|
+
if (raw && raw.length > AUTOEXTRACT_HINT_THRESHOLD) {
|
|
4967
5042
|
const schema = schemaOf(result.result);
|
|
4968
5043
|
output({
|
|
4969
5044
|
trace: result.trace,
|
|
4970
5045
|
...result.impact ? { impact: result.impact } : {},
|
|
4971
5046
|
...result.next_actions ? { next_actions: result.next_actions } : {},
|
|
4972
5047
|
extraction_hints: {
|
|
4973
|
-
message:
|
|
5048
|
+
message: `Response is ${Math.round(raw.length / 1024)}KB (over ${AUTOEXTRACT_HINT_THRESHOLD / 1024}KB). Use --path/--extract/--limit to filter, --schema for structure, or --raw for full response.`,
|
|
4974
5049
|
schema_tree: schema,
|
|
4975
5050
|
response_bytes: raw.length
|
|
4976
5051
|
}
|
|
@@ -5297,8 +5372,9 @@ var CLI_REFERENCE = {
|
|
|
5297
5372
|
{ name: "mcp", usage: "[--no-auto-start]", desc: "Run the stdio MCP server" },
|
|
5298
5373
|
{ name: "setup", usage: "[--opencode auto|global|project|off] [--no-start]", desc: "Bootstrap browser deps + Open Code command" },
|
|
5299
5374
|
{ name: "upgrade", usage: "", desc: "Check latest release and print the right upgrade command" },
|
|
5300
|
-
{ name: "resolve", usage: '--intent "..." [--domain "..."] [--url "..."] [opts]', desc: "
|
|
5301
|
-
{ name: "
|
|
5375
|
+
{ name: "resolve", usage: '--intent "..." [--domain "..."] [--url "..."] [opts]', desc: "Returns ranked shortlist of endpoints for an intent. Pick one and call execute. (Two tool calls is the contract \u2014 autoexec is opt-in via --execute, not the default.)" },
|
|
5376
|
+
{ 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)" },
|
|
5377
|
+
{ 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" },
|
|
5302
5378
|
{ name: "feedback", usage: "--skill ID --endpoint ID --rating N", desc: "Submit feedback (mandatory after resolve)" },
|
|
5303
5379
|
{ name: "annotate", usage: "--skill ID --endpoint ID --text 'tip' [--constraint 'param:rule:message']", desc: "Contribute best practices or constraints for an endpoint" },
|
|
5304
5380
|
{ name: "review", usage: "--skill ID --endpoints '[...]'", desc: "Push reviewed descriptions/schema metadata back to a captured skill before publish" },
|
|
@@ -6206,7 +6282,10 @@ async function cmdConnectChrome() {
|
|
|
6206
6282
|
console.error("Could not connect to Chrome. Make sure all Chrome windows are closed and try again.");
|
|
6207
6283
|
}
|
|
6208
6284
|
async function main() {
|
|
6209
|
-
const { command, args, flags } = parseArgs(process.argv);
|
|
6285
|
+
const { command, args, flags, params: cliParams } = parseArgs(process.argv);
|
|
6286
|
+
if (Object.keys(cliParams).length > 0) {
|
|
6287
|
+
flags._params = cliParams;
|
|
6288
|
+
}
|
|
6210
6289
|
const noAutoStart = !!flags["no-auto-start"];
|
|
6211
6290
|
if (command === "help" || flags.help) {
|
|
6212
6291
|
printHelp();
|
|
@@ -6322,6 +6401,8 @@ async function main() {
|
|
|
6322
6401
|
return cmdSetup(flags);
|
|
6323
6402
|
case "resolve":
|
|
6324
6403
|
return cmdResolve(flags);
|
|
6404
|
+
case "explain":
|
|
6405
|
+
return cmdExplain(flags);
|
|
6325
6406
|
case "execute":
|
|
6326
6407
|
case "exec":
|
|
6327
6408
|
return cmdExecute(flags);
|
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.
|
|
230
|
-
var BUILD_GIT_SHA = "
|
|
229
|
+
var BUILD_RELEASE_VERSION = "6.1.0";
|
|
230
|
+
var BUILD_GIT_SHA = "82d14e507af6";
|
|
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 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiNi4xLjAiLCJnaXRfc2hhIjoiODJkMTRlNTA3YWY2IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUA4MmQxNGU1MDdhZjYiLCJpc3N1ZWRfYXQiOiIyMDI2LTA1LTAxVDAwOjI1OjUwLjExMFoifQ";
|
|
233
|
+
var BUILD_RELEASE_MANIFEST_SIGNATURE = "gOz02sMxkYuLKvc24oN5EVm8VEQo2dftkUpMS5RMjiE";
|
|
234
234
|
var BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
|
|
235
235
|
|
|
236
236
|
// ../../src/version.ts
|
|
@@ -1665,7 +1665,7 @@ var tools = [
|
|
|
1665
1665
|
},
|
|
1666
1666
|
{
|
|
1667
1667
|
name: "unbrowse_resolve",
|
|
1668
|
-
description: "START HERE for every website task.
|
|
1668
|
+
description: "START HERE for every website task. Returns ranked shortlist of cached endpoints. Read the shortlist, pick the one that matches your intent (use the example_response_compact and requires fields as evidence), then call unbrowse_execute with that endpoint_id. Two tool calls is the contract \u2014 there is no auto-exec. If no_cached_match, fall through to unbrowse_go to capture fresh.",
|
|
1669
1669
|
inputSchema: {
|
|
1670
1670
|
type: "object",
|
|
1671
1671
|
properties: {
|
|
@@ -2525,6 +2525,67 @@ var tools = [
|
|
|
2525
2525
|
const result = await api2("POST", `/v1/skills/${skillId}/endpoints/${endpointId}/annotate`, body);
|
|
2526
2526
|
return successResult(result, "Annotation saved. Other agents will see your contribution when using this endpoint.");
|
|
2527
2527
|
}
|
|
2528
|
+
},
|
|
2529
|
+
{
|
|
2530
|
+
name: "unbrowse_diagnose",
|
|
2531
|
+
description: "Capture visual + structured context for diagnosing an unbrowse failure. Takes a screenshot of the current page and returns it alongside the current resolve diagnostic. Use when resolve/execute fails and you need to see what the page actually looks like (auth wall, loading spinner, empty state).",
|
|
2532
|
+
inputSchema: {
|
|
2533
|
+
type: "object",
|
|
2534
|
+
properties: {
|
|
2535
|
+
session_id: { type: "string", description: "Optional browse session id." },
|
|
2536
|
+
context: { type: "string", description: "Description of what was being attempted when it failed." }
|
|
2537
|
+
},
|
|
2538
|
+
additionalProperties: false
|
|
2539
|
+
},
|
|
2540
|
+
annotations: { readOnlyHint: true },
|
|
2541
|
+
handler: async (args) => {
|
|
2542
|
+
await ensureServerReady();
|
|
2543
|
+
const sessionId = typeof args.session_id === "string" ? args.session_id : undefined;
|
|
2544
|
+
const screenshot = await api2("GET", "/v1/browse/screenshot", sessionId ? { session_id: sessionId } : undefined);
|
|
2545
|
+
const diagnostic = await api2("GET", "/v1/stats/health", undefined);
|
|
2546
|
+
return successResult({
|
|
2547
|
+
screenshot: typeof screenshot.screenshot === "string" ? screenshot.screenshot : null,
|
|
2548
|
+
tab_id: screenshot.tab_id ?? null,
|
|
2549
|
+
diagnosis_context: args.context ?? null,
|
|
2550
|
+
status: diagnostic
|
|
2551
|
+
}, "Diagnosis capture complete. Screenshot + context returned.");
|
|
2552
|
+
}
|
|
2553
|
+
},
|
|
2554
|
+
{
|
|
2555
|
+
name: "unbrowse_trace",
|
|
2556
|
+
description: "Get the full execution trace for the most recent resolve/execute call, including diagnostic confidence scores, endpoint scores, and visual context. Use to understand WHY a specific endpoint was or wasn't selected.",
|
|
2557
|
+
inputSchema: {
|
|
2558
|
+
type: "object",
|
|
2559
|
+
properties: {
|
|
2560
|
+
trace_id: { type: "string", description: "Optional specific trace ID. Defaults to most recent." }
|
|
2561
|
+
},
|
|
2562
|
+
additionalProperties: false
|
|
2563
|
+
},
|
|
2564
|
+
annotations: { readOnlyHint: true },
|
|
2565
|
+
handler: async (args) => {
|
|
2566
|
+
await ensureServerReady();
|
|
2567
|
+
const result = await api2("GET", `/v1/trace/${args.trace_id ?? "latest"}`, undefined);
|
|
2568
|
+
return successResult(result, "Execution trace with diagnostic context.");
|
|
2569
|
+
}
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
name: "unbrowse_validate",
|
|
2573
|
+
description: "Validate a captured skill's quality by taking screenshots of the page while exercising its endpoints. Helps diagnose if a skill's endpoints actually match the live page. Returns screenshots at key interaction points alongside endpoint response data.",
|
|
2574
|
+
inputSchema: {
|
|
2575
|
+
type: "object",
|
|
2576
|
+
properties: {
|
|
2577
|
+
skill_id: { type: "string", description: "Skill ID to validate." },
|
|
2578
|
+
url: { type: "string", description: "Page URL to validate against." }
|
|
2579
|
+
},
|
|
2580
|
+
required: ["skill_id"],
|
|
2581
|
+
additionalProperties: false
|
|
2582
|
+
},
|
|
2583
|
+
annotations: { openWorldHint: true },
|
|
2584
|
+
handler: async (args) => {
|
|
2585
|
+
await ensureServerReady();
|
|
2586
|
+
const result = await api2("GET", `/v1/skills/${args.skill_id}/validate`, args.url ? { url: args.url } : undefined);
|
|
2587
|
+
return successResult(result, "Skill validation complete. Returns screenshots + endpoint match quality.");
|
|
2588
|
+
}
|
|
2528
2589
|
}
|
|
2529
2590
|
];
|
|
2530
2591
|
var toolMap = new Map(tools.map((tool) => [tool.name, tool]));
|