@angelky7/dsh-browser-control 1.2.0 → 1.3.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/README.en.md CHANGED
@@ -64,8 +64,8 @@ In one line: **for "use MY browser" tasks (logged-in Bilibili, Zhihu, admin pane
64
64
 
65
65
  | File | Purpose |
66
66
  |---|---|
67
- | [DSH-Browser-Control-v1.2.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.2.0/DSH-Browser-Control-v1.2.0.zip) | Chrome extension (unzip and load; this release adds the three cookie commands — reinstall required) |
68
- | [dsh-browser-control-plugin-v1.2.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.2.0/dsh-browser-control-plugin-v1.2.0.zip) | dsh plugin (offline fallback; online installs use Option A/B) |
67
+ | [DSH-Browser-Control-v1.3.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.3.0/DSH-Browser-Control-v1.3.0.zip) | Chrome extension (unzip and load; extension code is unchanged since 1.2.0 — no reinstall needed) |
68
+ | [dsh-browser-control-plugin-v1.3.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.3.0/dsh-browser-control-plugin-v1.3.0.zip) | dsh plugin (offline fallback; online installs use Option A/B) |
69
69
 
70
70
  ## Install the Chrome extension (30 seconds)
71
71
 
@@ -104,7 +104,7 @@ npm install @angelky7/dsh-browser-control
104
104
 
105
105
  ```bash
106
106
  # Straight from GitHub
107
- dsh plugin --profile web add "github:angelky7/dsh-browser-control#v1.2.0"
107
+ dsh plugin --profile web add "github:angelky7/dsh-browser-control#v1.3.0"
108
108
 
109
109
  # Local checkout for debugging (note: the explicit file: prefix is required)
110
110
  dsh plugin --profile web add "file:D:\path\to\dsh-browser-control"
package/README.md CHANGED
@@ -64,8 +64,8 @@ Chrome 扩展(CDP 驱动)
64
64
 
65
65
  | 文件 | 说明 |
66
66
  |---|---|
67
- | [DSH-Browser-Control-v1.2.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.2.0/DSH-Browser-Control-v1.2.0.zip) | Chrome 扩展(解压后加载;这一版扩展新增了 cookie 三条命令,**必须重装**) |
68
- | [dsh-browser-control-plugin-v1.2.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.2.0/dsh-browser-control-plugin-v1.2.0.zip) | dsh 插件(离线兜底,在线装直接用方式 A/B) |
67
+ | [DSH-Browser-Control-v1.3.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.3.0/DSH-Browser-Control-v1.3.0.zip) | Chrome 扩展(解压后加载;与 1.2.0 相比扩展代码无改动,已装 1.2.0 不必重装) |
68
+ | [dsh-browser-control-plugin-v1.3.0.zip](https://github.com/angelky7/dsh-browser-control/releases/download/v1.3.0/dsh-browser-control-plugin-v1.3.0.zip) | dsh 插件(离线兜底,在线装直接用方式 A/B) |
69
69
 
70
70
  ## 安装 Chrome 扩展(30 秒)
71
71
 
@@ -104,7 +104,7 @@ npm install @angelky7/dsh-browser-control
104
104
 
105
105
  ```bash
106
106
  # 直接从 GitHub 安装
107
- dsh plugin --profile web add "github:angelky7/dsh-browser-control#v1.2.0"
107
+ dsh plugin --profile web add "github:angelky7/dsh-browser-control#v1.3.0"
108
108
 
109
109
  # 本地目录调试(注意:必须显式 file: 前缀)
110
110
  dsh plugin --profile web add "file:D:\path\to\dsh-browser-control"
package/lib/index.js CHANGED
@@ -939,6 +939,15 @@ function policyRefusal(command, flags, params) {
939
939
  * fix, so the model can tell the user what to do instead of hanging.
940
940
  * @module @deepseek-ai/dsh-browser-bridge
941
941
  */
942
+ /** Navigation wait ceiling (same as browser_wait); the bridge gets this plus BRIDGE_MARGIN_MS. */
943
+ const NAV_MAX_MS = 12e4;
944
+ /**
945
+ * Extra time handed to the bridge on top of the navigation budget. Without it a
946
+ * caller-requested budget longer than the bridge default (60s) would be beaten by
947
+ * the bridge, and the model would get `command_timeout` (effect unknown) instead
948
+ * of a navigation timeout (nothing was touched) - two very different next steps.
949
+ */
950
+ const BRIDGE_MARGIN_MS = 2e3;
942
951
  /** Cordis plugin name used by loader diagnostics. */
943
952
  const name = "browser-bridge";
944
953
  /** The tool registry this plugin contributes `browser_*` tools to. */
@@ -1236,6 +1245,10 @@ function applyBrowserTools(ctx, controller) {
1236
1245
  tabId: {
1237
1246
  type: "number",
1238
1247
  description: "Target tab; defaults to the active tab."
1248
+ },
1249
+ timeoutMs: {
1250
+ type: "number",
1251
+ description: `How long to wait for the page load to settle: defaults to 15000, capped at ${NAV_MAX_MS}. Raise it for slow pages instead of retrying; drop it to 3000-5000 when you do not need the page to finish loading and will read/wait afterwards.`
1239
1252
  }
1240
1253
  },
1241
1254
  output: {
@@ -1287,7 +1300,9 @@ function applyBrowserTools(ctx, controller) {
1287
1300
  async execute(args, exec) {
1288
1301
  const params = { url: args.url };
1289
1302
  if (args.tabId !== void 0) params.tabId = args.tabId;
1290
- const raw = await controller.execute("nav", params, exec.signal);
1303
+ const budgetMs = typeof args.timeoutMs === "number" && Number.isFinite(args.timeoutMs) ? Math.min(NAV_MAX_MS, Math.max(100, Math.trunc(args.timeoutMs))) : 15e3;
1304
+ params.timeoutMs = budgetMs;
1305
+ const raw = await controller.execute("nav", params, exec.signal, budgetMs + BRIDGE_MARGIN_MS);
1291
1306
  const out = { tabId: raw.tabId };
1292
1307
  if (typeof raw.url === "string") out.url = raw.url;
1293
1308
  if (typeof raw.title === "string") out.title = raw.title;
@@ -2041,6 +2056,8 @@ function applyBrowserTools(ctx, controller) {
2041
2056
  }
2042
2057
  }
2043
2058
  }));
2059
+ /** Page-side ceiling of the eval race in the extension; the bridge budget adds slack on top. */
2060
+ const EVAL_MAX_MS = 12e4;
2044
2061
  ctx.tools.register(defineTool({
2045
2062
  name: "browser_evaluate",
2046
2063
  description: "Run JavaScript in the page and get the JSON result back as a string. Prefer read-only inspection.",
@@ -2053,6 +2070,10 @@ function applyBrowserTools(ctx, controller) {
2053
2070
  tabId: {
2054
2071
  type: "number",
2055
2072
  description: "Target tab; defaults to the active tab."
2073
+ },
2074
+ timeoutMs: {
2075
+ type: "number",
2076
+ description: `Give up after this many milliseconds; defaults to 60000, capped at ${EVAL_MAX_MS}.`
2056
2077
  }
2057
2078
  },
2058
2079
  output: {
@@ -2081,10 +2102,15 @@ function applyBrowserTools(ctx, controller) {
2081
2102
  kind: "other"
2082
2103
  }),
2083
2104
  async execute(args, exec) {
2084
- const raw = await controller.execute("eval", args.tabId === void 0 ? { expression: args.expression } : {
2085
- expression: args.expression,
2086
- tabId: args.tabId
2087
- }, exec.signal);
2105
+ const params = { expression: args.expression };
2106
+ if (args.tabId !== void 0) params.tabId = args.tabId;
2107
+ let bridgeCeiling;
2108
+ if (typeof args.timeoutMs === "number" && Number.isFinite(args.timeoutMs)) {
2109
+ const evalBudget = Math.min(EVAL_MAX_MS, Math.max(100, Math.trunc(args.timeoutMs)));
2110
+ params.timeoutMs = evalBudget;
2111
+ bridgeCeiling = evalBudget + 2e3;
2112
+ }
2113
+ const raw = await controller.execute("eval", params, exec.signal, bridgeCeiling);
2088
2114
  let json;
2089
2115
  try {
2090
2116
  json = JSON.stringify(raw.value) ?? String(raw.value);
@@ -24,6 +24,15 @@ import { defineTool } from '@deepseek-ai/dsh-tools';
24
24
  import { BridgeServer, cleanupArtifacts } from "./server.js";
25
25
  import { BridgeError, classify } from "./errors.js";
26
26
  import { policyRefusal } from "./policy.js";
27
+ /** Navigation wait ceiling (same as browser_wait); the bridge gets this plus BRIDGE_MARGIN_MS. */
28
+ const NAV_MAX_MS = 120_000;
29
+ /**
30
+ * Extra time handed to the bridge on top of the navigation budget. Without it a
31
+ * caller-requested budget longer than the bridge default (60s) would be beaten by
32
+ * the bridge, and the model would get `command_timeout` (effect unknown) instead
33
+ * of a navigation timeout (nothing was touched) - two very different next steps.
34
+ */
35
+ const BRIDGE_MARGIN_MS = 2_000;
27
36
  // Re-exported so the policy tables stay testable from the published bundle
28
37
  // (verify/verify_policy.mjs reconciles them against the extension's COMMANDS).
29
38
  export { LOCAL_DESTRUCTIVE_COMMANDS, PAGE_MUTATING_COMMANDS, READ_ONLY_ALLOWED, SCRIPT_COMMANDS, policyRefusal } from "./policy.js";
@@ -358,6 +367,7 @@ function applyBrowserTools(ctx, controller) {
358
367
  parameters: {
359
368
  url: { type: 'string', required: true, description: 'Absolute URL to open in the tab.' },
360
369
  tabId: { type: 'number', description: 'Target tab; defaults to the active tab.' },
370
+ timeoutMs: { type: 'number', description: `How long to wait for the page load to settle: defaults to 15000, capped at ${NAV_MAX_MS}. Raise it for slow pages instead of retrying; drop it to 3000-5000 when you do not need the page to finish loading and will read/wait afterwards.` },
361
371
  },
362
372
  output: {
363
373
  schema: {
@@ -397,7 +407,11 @@ function applyBrowserTools(ctx, controller) {
397
407
  const params = { url: args.url };
398
408
  if (args.tabId !== undefined)
399
409
  params.tabId = args.tabId;
400
- const raw = await controller.execute('nav', params, exec.signal);
410
+ const budgetMs = typeof args.timeoutMs === 'number' && Number.isFinite(args.timeoutMs)
411
+ ? Math.min(NAV_MAX_MS, Math.max(100, Math.trunc(args.timeoutMs)))
412
+ : 15_000;
413
+ params.timeoutMs = budgetMs;
414
+ const raw = await controller.execute('nav', params, exec.signal, budgetMs + BRIDGE_MARGIN_MS);
401
415
  // The declared schema is closed, so the fields describing a navigation that did
402
416
  // not arrive have to be carried over on purpose. The old shape check
403
417
  // (`siteUnreachable === true`) also missed the object the extension really
@@ -866,12 +880,15 @@ function applyBrowserTools(ctx, controller) {
866
880
  }
867
881
  },
868
882
  }));
883
+ /** Page-side ceiling of the eval race in the extension; the bridge budget adds slack on top. */
884
+ const EVAL_MAX_MS = 120_000;
869
885
  ctx.tools.register(defineTool({
870
886
  name: 'browser_evaluate',
871
887
  description: 'Run JavaScript in the page and get the JSON result back as a string. Prefer read-only inspection.',
872
888
  parameters: {
873
889
  expression: { type: 'string', required: true, description: 'JavaScript expression or statement sequence; awaited like a promise body.' },
874
890
  tabId: { type: 'number', description: 'Target tab; defaults to the active tab.' },
891
+ timeoutMs: { type: 'number', description: `Give up after this many milliseconds; defaults to 60000, capped at ${EVAL_MAX_MS}.` },
875
892
  },
876
893
  output: {
877
894
  schema: {
@@ -886,7 +903,19 @@ function applyBrowserTools(ctx, controller) {
886
903
  },
887
904
  presentCall: () => ({ card: 'generic', title: 'Evaluate in page', kind: 'other' }),
888
905
  async execute(args, exec) {
889
- const raw = await controller.execute('eval', args.tabId === undefined ? { expression: args.expression } : { expression: args.expression, tabId: args.tabId }, exec.signal);
906
+ const params = { expression: args.expression };
907
+ if (args.tabId !== undefined)
908
+ params.tabId = args.tabId;
909
+ // The extension races the evaluation at this budget; give the bridge 2s of
910
+ // slack so the page-side timeout reports first. Omitted → send nothing and
911
+ // let the bridge default (60s) govern, exactly as before the knob existed.
912
+ let bridgeCeiling;
913
+ if (typeof args.timeoutMs === 'number' && Number.isFinite(args.timeoutMs)) {
914
+ const evalBudget = Math.min(EVAL_MAX_MS, Math.max(100, Math.trunc(args.timeoutMs)));
915
+ params.timeoutMs = evalBudget;
916
+ bridgeCeiling = evalBudget + 2_000;
917
+ }
918
+ const raw = await controller.execute('eval', params, exec.signal, bridgeCeiling);
890
919
  let json;
891
920
  try {
892
921
  json = JSON.stringify(raw.value) ?? String(raw.value);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@angelky7/dsh-browser-control",
3
3
  "description": "Local WebSocket bridge between dsh and the DSH Browser Control browser extension, with model-facing browser_* tools and a Settings-managed on/off switch",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "build": "tsc -p tsconfig.json && tsdown",
38
38
  "typecheck": "tsc -p tsconfig.json --noEmit",
39
39
  "check": "npm run typecheck && npm run build && publint",
40
- "verify": "node verify/verify_config_patch.mjs && node verify/verify_peers.mjs && node verify/verify_surface.mjs && node verify/verify_tab_groups.mjs && node verify/verify_tabs_close_many.mjs && node verify/verify_cdp_retry.mjs && node verify/verify_snapshot_ax.mjs && node verify/verify_hard_lock.mjs && node verify/verify_policy.mjs && node verify/verify_cookies.mjs && node verify/verify_extension_e2e.mjs && node verify/verify_plugin.mjs legacy && node verify/verify_plugin.mjs conflict && node verify/verify_plugin.mjs new && node verify/verify_http.mjs && node verify/verify_errors.mjs && node verify/verify_hold.mjs && node verify/verify_protocol.mjs && node verify/verify_bundle_http.mjs && node verify/verify_nav_report.mjs && node verify/verify_nav_landing.mjs && node verify/verify_render_contract.mjs && node verify/verify_press_events.mjs"
40
+ "verify": "node verify/verify_config_patch.mjs && node verify/verify_peers.mjs && node verify/verify_surface.mjs && node verify/verify_tab_groups.mjs && node verify/verify_tabs_close_many.mjs && node verify/verify_cdp_retry.mjs && node verify/verify_snapshot_ax.mjs && node verify/verify_hard_lock.mjs && node verify/verify_policy.mjs && node verify/verify_cookies.mjs && node verify/verify_extension_e2e.mjs && node verify/verify_plugin.mjs legacy && node verify/verify_plugin.mjs conflict && node verify/verify_plugin.mjs new && node verify/verify_http.mjs && node verify/verify_errors.mjs && node verify/verify_hold.mjs && node verify/verify_protocol.mjs && node verify/verify_bundle_http.mjs && node verify/verify_nav_report.mjs && node verify/verify_nav_landing.mjs && node verify/verify_render_contract.mjs && node verify/verify_press_events.mjs && node verify/verify_nav_timeout.mjs"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public",