@jobshimo/browser-link 0.8.2 → 0.8.5

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.
@@ -2,12 +2,29 @@
2
2
  * MCP tool definitions for the browser-bridge family. Kept separate from
3
3
  * the runtime dispatcher so the JSON schemas stay reviewable in one place
4
4
  * and the dispatch logic stays small.
5
+ *
6
+ * Each entry carries a `doc` block (`ToolDoc`) with structured human-facing
7
+ * documentation. `buildServerInstructions()` reads those blocks to produce
8
+ * the SERVER_INSTRUCTIONS string the MCP host receives on `initialize`. The
9
+ * structured shape keeps the "when to use" copy beside the tool that owns
10
+ * it instead of drifting in a single monolithic string.
5
11
  */
6
12
  export const BROWSER_TOOL_DEFINITIONS = [
7
13
  {
8
14
  name: 'browser.list_tabs',
9
15
  description: 'List Chrome tabs currently connected to browser-link. A tab is connected only after the user clicks Connect in the extension popup. Each entry includes tab_id, url, title, claimed_by (null when free, or { agent_id, pid, binary, label?, claimed_at, last_activity_at } when another agent owns it) and claimed_by_me (true when YOU hold the claim).',
10
16
  inputSchema: { type: 'object', properties: {}, additionalProperties: false },
17
+ doc: {
18
+ purpose: 'List the Chrome tabs the user has explicitly connected through the browser-link extension popup.',
19
+ when_to_use: [
20
+ 'Before doing anything on a tab whose state you do not already own.',
21
+ 'When the user mentions a UI bug, web page, or asks "does X work" — call this FIRST.',
22
+ 'To see which tabs are claimed by other agents (claimed_by) and which are yours (claimed_by_me).',
23
+ ],
24
+ gotchas: [
25
+ 'Returns only tabs the user has connected manually. If the list is empty the user has not connected anything yet — ask them to open the extension popup.',
26
+ ],
27
+ },
11
28
  },
12
29
  {
13
30
  name: 'browser.claim_tab',
@@ -28,6 +45,18 @@ export const BROWSER_TOOL_DEFINITIONS = [
28
45
  required: ['tab_id'],
29
46
  additionalProperties: false,
30
47
  },
48
+ doc: {
49
+ purpose: 'Reserve a tab cooperatively so other MCP clients sharing the bridge see it is in use.',
50
+ when_to_use: [
51
+ 'Before a multi-step flow on a tab in multi-agent mode, so other agents see you working on it.',
52
+ 'To refresh the inactivity TTL or update the display label on a tab you already hold.',
53
+ ],
54
+ gotchas: [
55
+ 'Action tools (click/type/navigate/evaluate) auto-claim a free tab on first use, so explicit claim_tab is only required for early reservation.',
56
+ 'On conflict the response includes the existing claim — do NOT spin-retry; pick a different tab or surface the conflict to the user.',
57
+ ],
58
+ example: 'browser.claim_tab({ tab_id: "tab_1", label: "claude-code", ttl_minutes: 15 })',
59
+ },
31
60
  },
32
61
  {
33
62
  name: 'browser.release_tab',
@@ -38,11 +67,27 @@ export const BROWSER_TOOL_DEFINITIONS = [
38
67
  required: ['tab_id'],
39
68
  additionalProperties: false,
40
69
  },
70
+ doc: {
71
+ purpose: 'Hand a previously claimed tab back so another agent can take it.',
72
+ when_to_use: [
73
+ 'After you finished working on a tab and want to hand it off before the TTL expires.',
74
+ ],
75
+ gotchas: [
76
+ 'Claims also auto-release on agent disconnect and after the inactivity TTL (default 10 minutes) — explicit release is only for early hand-off.',
77
+ ],
78
+ },
41
79
  },
42
80
  {
43
81
  name: 'browser.my_tabs',
44
82
  description: 'List the tabs YOU currently hold a claim on. Returns { claims: [{ tab_id, claimed_at, last_activity_at, ttl_ms, label? }] } sorted by claimed_at. Use this to answer the user when they ask which tabs you are working on.',
45
83
  inputSchema: { type: 'object', properties: {}, additionalProperties: false },
84
+ doc: {
85
+ purpose: 'Return the tabs the current agent has claimed, with timestamps and TTL.',
86
+ when_to_use: [
87
+ 'When the user asks which tab you are using ("¿qué pestaña tenés?", "which tab are you on?").',
88
+ 'To verify which tab is yours before performing an action in multi-agent mode.',
89
+ ],
90
+ },
46
91
  },
47
92
  {
48
93
  name: 'browser.ping',
@@ -53,6 +98,10 @@ export const BROWSER_TOOL_DEFINITIONS = [
53
98
  required: ['tab_id'],
54
99
  additionalProperties: false,
55
100
  },
101
+ doc: {
102
+ purpose: 'Confirm the bridge to a specific tab is healthy and read back its title/url.',
103
+ when_to_use: ['When you suspect a tab may have been closed or disconnected between calls.'],
104
+ },
56
105
  },
57
106
  {
58
107
  name: 'browser.navigate',
@@ -67,6 +116,17 @@ export const BROWSER_TOOL_DEFINITIONS = [
67
116
  required: ['tab_id', 'url'],
68
117
  additionalProperties: false,
69
118
  },
119
+ doc: {
120
+ purpose: 'Drive a connected tab to a new URL.',
121
+ when_to_use: [
122
+ 'The user asks you to open a page in the browser ("abrí esto en el navegador", "navigate to X").',
123
+ 'You need to reach a specific route before snapshotting or interacting.',
124
+ ],
125
+ gotchas: [
126
+ 'Defaults to wait_for_load=true so the snapshot you take next reflects the loaded page.',
127
+ ],
128
+ example: 'browser.navigate({ tab_id: "tab_1", url: "https://example.com" })',
129
+ },
70
130
  },
71
131
  {
72
132
  name: 'browser.snapshot',
@@ -77,6 +137,17 @@ export const BROWSER_TOOL_DEFINITIONS = [
77
137
  required: ['tab_id'],
78
138
  additionalProperties: false,
79
139
  },
140
+ doc: {
141
+ purpose: 'Inspect what is currently on the tab — title, URL, visible text, interactive elements with selectors.',
142
+ when_to_use: [
143
+ 'Before suggesting any code change to a UI component — verify the current state, do NOT speculate.',
144
+ 'Before clicking or typing, to find a stable selector for the target element.',
145
+ 'When the user reports a layout or visual issue and you need to ground your reasoning in what is actually rendered.',
146
+ ],
147
+ gotchas: [
148
+ 'The snapshot is the source of truth; the persistent map is a cache, not a substitute.',
149
+ ],
150
+ },
80
151
  },
81
152
  {
82
153
  name: 'browser.console',
@@ -90,6 +161,16 @@ export const BROWSER_TOOL_DEFINITIONS = [
90
161
  required: ['tab_id'],
91
162
  additionalProperties: false,
92
163
  },
164
+ doc: {
165
+ purpose: 'Read recent console messages from the tab — log, info, warn, error, debug.',
166
+ when_to_use: [
167
+ 'When the user says "the button does not work" or "something is broken" — check console errors first.',
168
+ 'After an action to see what the page logged in response.',
169
+ ],
170
+ gotchas: [
171
+ 'Rolling buffer of 200 entries — older logs are dropped. Snapshot console output early in a long session.',
172
+ ],
173
+ },
93
174
  },
94
175
  {
95
176
  name: 'browser.network',
@@ -103,6 +184,17 @@ export const BROWSER_TOOL_DEFINITIONS = [
103
184
  required: ['tab_id'],
104
185
  additionalProperties: false,
105
186
  },
187
+ doc: {
188
+ purpose: 'List recent network requests with status, mime, size and timing.',
189
+ when_to_use: [
190
+ 'When the user reports a failed API call, slow request, or a 4xx/5xx response in the page.',
191
+ 'To verify whether a request fired after a click or form submission.',
192
+ ],
193
+ gotchas: [
194
+ 'Rolling buffer of 200 entries — pair with url_filter to narrow the result.',
195
+ 'Use browser.network_body with the request_id to fetch a specific response body.',
196
+ ],
197
+ },
106
198
  },
107
199
  {
108
200
  name: 'browser.network_body',
@@ -116,6 +208,12 @@ export const BROWSER_TOOL_DEFINITIONS = [
116
208
  required: ['tab_id', 'request_id'],
117
209
  additionalProperties: false,
118
210
  },
211
+ doc: {
212
+ purpose: 'Fetch the response body for one request_id returned by browser.network.',
213
+ when_to_use: [
214
+ 'After identifying a suspicious request in browser.network, to see what the server returned.',
215
+ ],
216
+ },
119
217
  },
120
218
  {
121
219
  name: 'browser.click',
@@ -129,6 +227,16 @@ export const BROWSER_TOOL_DEFINITIONS = [
129
227
  required: ['tab_id', 'selector'],
130
228
  additionalProperties: false,
131
229
  },
230
+ doc: {
231
+ purpose: 'Click an element identified by a CSS selector.',
232
+ when_to_use: [
233
+ 'After browser.snapshot returned a selector for the element the user asked you to interact with.',
234
+ ],
235
+ gotchas: [
236
+ 'Never click a selector you have not just verified via browser.snapshot or browser.map.recall — speculating wastes a turn.',
237
+ 'Auto-claims the tab on first use in multi-agent mode.',
238
+ ],
239
+ },
132
240
  },
133
241
  {
134
242
  name: 'browser.type',
@@ -144,6 +252,15 @@ export const BROWSER_TOOL_DEFINITIONS = [
144
252
  required: ['tab_id', 'selector', 'text'],
145
253
  additionalProperties: false,
146
254
  },
255
+ doc: {
256
+ purpose: 'Focus an input element by selector and type text into it.',
257
+ when_to_use: [
258
+ 'After browser.snapshot returned a selector for the input the user wants filled.',
259
+ ],
260
+ gotchas: [
261
+ 'Pass clear:true when you need to replace the current value instead of appending to it.',
262
+ ],
263
+ },
147
264
  },
148
265
  {
149
266
  name: 'browser.evaluate',
@@ -157,6 +274,13 @@ export const BROWSER_TOOL_DEFINITIONS = [
157
274
  required: ['tab_id', 'expression'],
158
275
  additionalProperties: false,
159
276
  },
277
+ doc: {
278
+ purpose: 'Execute a JavaScript expression in the page and return its value.',
279
+ when_to_use: [
280
+ 'When snapshot/click/type are not expressive enough — pulling a computed value, reading a JS variable, or invoking page APIs.',
281
+ ],
282
+ gotchas: ['Wrap multi-step logic in an IIFE that returns the value you want.'],
283
+ },
160
284
  },
161
285
  {
162
286
  name: 'browser.events',
@@ -175,6 +299,16 @@ export const BROWSER_TOOL_DEFINITIONS = [
175
299
  },
176
300
  additionalProperties: false,
177
301
  },
302
+ doc: {
303
+ purpose: 'Inspect bridge lifecycle events — primary elections, tab registrations, tab renames.',
304
+ when_to_use: [
305
+ 'When a tool call returns "Tab not connected: …" — look for a tab-renamed entry to find the new tab_id.',
306
+ 'To diagnose why a tab disappeared between calls.',
307
+ ],
308
+ gotchas: [
309
+ 'Pass latest_id from the previous call as since_id to page through new entries efficiently.',
310
+ ],
311
+ },
178
312
  },
179
313
  ];
180
314
  //# sourceMappingURL=browser-definitions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-definitions.js","sourceRoot":"","sources":["../../src/tools/browser-definitions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-definitions.js","sourceRoot":"","sources":["../../src/tools/browser-definitions.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,17 @@
1
+ /**
2
+ * Build the MCP `initialize.instructions` payload from the structured `doc`
3
+ * blocks each tool definition carries. Keeping the per-tool copy beside the
4
+ * tool definition (in `browser-definitions.ts` and `map/tools.ts`) prevents
5
+ * drift between the schema and the human-facing documentation.
6
+ *
7
+ * `SERVER_INSTRUCTIONS` is computed once at module load and exported as a
8
+ * plain string so the existing consumers (`server.ts`, `bridge/server.ts`)
9
+ * keep working without changes.
10
+ */
11
+ /** Generate the SERVER_INSTRUCTIONS string from the tool definitions.
12
+ * Exported for tests and for any future caller that needs to re-render
13
+ * the string after a hot-reload or runtime tool registration. */
14
+ export declare function buildServerInstructions(): string;
1
15
  /** Usage protocol pushed to the MCP client on `initialize`. Plain string,
2
- * intentionally kept short. Edit here when the protocol changes. */
3
- export declare const SERVER_INSTRUCTIONS = "browser-link bridges Claude Code to the Chrome tabs the user has\nexplicitly connected through the companion extension, and ships a\npersistent UI map backed by a local SQLite DB. The data dir resolves\nper-OS via env-paths ($XDG_DATA_HOME/browser-link on Linux,\n~/Library/Application Support/browser-link on macOS, %APPDATA%/browser-link\non Windows). Override with $BROWSER_LINK_DATA_DIR. The map is private\nand per-machine; never persisted in any repo.\n\n## When operating on a tab\n\n1. Before doing anything on a tab whose URL you don't already know,\n call `browser.map.recall` with { origin } (and optionally url) to load\n selectors, flows and gotchas previously learned for that app.\n2. If recall returns entries with `failed_at` more recent than\n `verified_at`, treat them as suspect: re-verify (snapshot / evaluate)\n before reusing, or replace them.\n3. After every interaction that used a map entry, call\n `browser.map.record_use` with { entry_id, ok }. ok=true updates\n verified_at; ok=false updates failed_at. Keep the map honest.\n4. After a non-trivial flow that worked end-to-end, persist it with\n `browser.map.save`. Three `kind` values:\n - selector: { selector, evidence? } \u2014 a CSS selector tied to a purpose.\n - flow: { steps: [...] } \u2014 an ordered list of actions to reach an outcome.\n - gotcha: { body } \u2014 free-form note about something non-obvious.\n Use `url_pattern` = pathname (exact). Promote to glob only if you have\n evidence of a parametric route. Provide `purpose` as a stable, reusable\n label (\"open task detail dialog\", not \"open IB0311 detail\").\n5. Never save selectors or flows you have not just successfully executed.\n6. Never store domain data (IDs, user names, dates, etc.). The map captures\n UI structure only.\n\n## Identifying the app\n\n- `origin` = scheme://host:port of the tab.\n- `app_key` distinguishes apps that share an origin over time. On first\n save you may omit it; it will be derived from the page title (slugified).\n Use `browser.map.rename_app` if that initial guess is poor.\n\n## Sharing tabs with other agents\n\nThis primary may be serving several MCP clients at once (multi-agent mode).\nTo stop two agents fighting over the same Chrome tab there is a cooperative\nclaim layer:\n\n- `browser.list_tabs` includes `claimed_by` (null if free, otherwise the\n agent that holds the claim) and `claimed_by_me` (boolean). Use it before\n starting work on a tab whose state you don't already own.\n- `browser.my_tabs` returns YOUR active claims with timestamps. If the\n user asks which tab you are using, this is the answer.\n- Action tools (`browser.click`, `browser.type`, `browser.navigate`,\n `browser.evaluate`) auto-claim a free tab on first use and refresh\n activity on subsequent calls. If another agent holds the tab, they\n return an error naming the owner \u2014 do NOT retry blindly; ask the user\n whose tab it should be, or use a different tab.\n- Read tools (`browser.snapshot`, `browser.console`, `browser.network`,\n `browser.network_body`, `browser.events`, `browser.ping`) ignore claims.\n- `browser.claim_tab({ tab_id, ttl_minutes?, label? })` reserves a tab\n explicitly. Provide a stable `label` (eg \"claude-code\", \"opencode\") so\n other agents and the user see WHO holds the tab. The label is display\n only \u2014 security relies on the IPC session id (kernel-vetted), not on\n what an agent calls itself.\n- `browser.release_tab({ tab_id })` hands a tab back. Claims also auto-\n release when an agent disconnects or after the inactivity TTL elapses\n (default 10 minutes), so explicit release is only needed for early\n hand-off.\n\nWhen you get a claim-conflict error: do NOT spin-retry. Either work on a\ndifferent tab from `list_tabs`, or surface the conflict to the user and\nlet them decide.\n\n## When something is wrong\n\n- A selector from recall fails \u2192 record_use({ok:false}), learn the new\n one, save it (upsert on purpose).\n- A whole app got refactored \u2192 `browser.map.forget` the app_id and let\n the map repopulate as you learn the new structure.\n- A tool call fails with \"Tab not connected: tab_X\" \u2192 call\n `browser.events` to see whether the bridge changed primary (the\n Chrome tab probably got a new tab_id after a reconnect). Look for a\n `tab-renamed` event with previous=tab_X and resume on the current id.\n\nThe map is a cache of navigation, not a substitute for `browser.snapshot`.\nThe live snapshot is always the source of truth.";
16
+ * generated from the per-tool `doc` blocks at module load. */
17
+ export declare const SERVER_INSTRUCTIONS: string;
@@ -1,6 +1,19 @@
1
- /** Usage protocol pushed to the MCP client on `initialize`. Plain string,
2
- * intentionally kept short. Edit here when the protocol changes. */
3
- export const SERVER_INSTRUCTIONS = `browser-link bridges Claude Code to the Chrome tabs the user has
1
+ /**
2
+ * Build the MCP `initialize.instructions` payload from the structured `doc`
3
+ * blocks each tool definition carries. Keeping the per-tool copy beside the
4
+ * tool definition (in `browser-definitions.ts` and `map/tools.ts`) prevents
5
+ * drift between the schema and the human-facing documentation.
6
+ *
7
+ * `SERVER_INSTRUCTIONS` is computed once at module load and exported as a
8
+ * plain string so the existing consumers (`server.ts`, `bridge/server.ts`)
9
+ * keep working without changes.
10
+ */
11
+ import { BROWSER_TOOL_DEFINITIONS } from './browser-definitions.js';
12
+ import { MAP_TOOL_DEFINITIONS } from '../map/tools.js';
13
+ /** Stable preamble — explains what the bridge is, where state lives, and
14
+ * what the agent must NOT do. Lives here (not in a tool doc) because it is
15
+ * cross-cutting context, not tied to any one tool. */
16
+ const PREAMBLE = `browser-link bridges Claude Code to the Chrome tabs the user has
4
17
  explicitly connected through the companion extension, and ships a
5
18
  persistent UI map backed by a local SQLite DB. The data dir resolves
6
19
  per-OS via env-paths ($XDG_DATA_HOME/browser-link on Linux,
@@ -8,79 +21,85 @@ per-OS via env-paths ($XDG_DATA_HOME/browser-link on Linux,
8
21
  on Windows). Override with $BROWSER_LINK_DATA_DIR. The map is private
9
22
  and per-machine; never persisted in any repo.
10
23
 
11
- ## When operating on a tab
12
-
13
- 1. Before doing anything on a tab whose URL you don't already know,
14
- call \`browser.map.recall\` with { origin } (and optionally url) to load
15
- selectors, flows and gotchas previously learned for that app.
16
- 2. If recall returns entries with \`failed_at\` more recent than
17
- \`verified_at\`, treat them as suspect: re-verify (snapshot / evaluate)
18
- before reusing, or replace them.
19
- 3. After every interaction that used a map entry, call
20
- \`browser.map.record_use\` with { entry_id, ok }. ok=true updates
21
- verified_at; ok=false updates failed_at. Keep the map honest.
22
- 4. After a non-trivial flow that worked end-to-end, persist it with
23
- \`browser.map.save\`. Three \`kind\` values:
24
- - selector: { selector, evidence? } — a CSS selector tied to a purpose.
25
- - flow: { steps: [...] } — an ordered list of actions to reach an outcome.
26
- - gotcha: { body } — free-form note about something non-obvious.
27
- Use \`url_pattern\` = pathname (exact). Promote to glob only if you have
28
- evidence of a parametric route. Provide \`purpose\` as a stable, reusable
29
- label ("open task detail dialog", not "open IB0311 detail").
30
- 5. Never save selectors or flows you have not just successfully executed.
31
- 6. Never store domain data (IDs, user names, dates, etc.). The map captures
32
- UI structure only.
33
-
34
- ## Identifying the app
24
+ ## Reflex protocol (ALWAYS ACTIVE)
35
25
 
36
- - \`origin\` = scheme://host:port of the tab.
37
- - \`app_key\` distinguishes apps that share an origin over time. On first
38
- save you may omit it; it will be derived from the page title (slugified).
39
- Use \`browser.map.rename_app\` if that initial guess is poor.
26
+ Tools you have here see only Chrome tabs the user explicitly connected
27
+ through the companion extension. Never reason about state you cannot
28
+ see call \`browser.list_tabs\` BEFORE answering when the user mentions
29
+ a UI element, a web app, a URL, a broken layout, "the page", or asks
30
+ "does X work". Take a \`browser.snapshot\` before suggesting any UI code
31
+ change. If a call returns "Tab not connected", call \`browser.events\`
32
+ to find the new tab_id before retrying. After a non-trivial flow worked
33
+ end-to-end, persist UI structure (NEVER domain data) with
34
+ \`browser.map.save\`.
40
35
 
41
- ## Sharing tabs with other agents
36
+ ## Sharing tabs with other agents (multi-agent mode)
42
37
 
43
- This primary may be serving several MCP clients at once (multi-agent mode).
44
- To stop two agents fighting over the same Chrome tab there is a cooperative
45
- claim layer:
38
+ Several MCP clients may share one bridge. To stop two agents fighting
39
+ over the same Chrome tab, a cooperative claim layer is in place:
46
40
 
47
- - \`browser.list_tabs\` includes \`claimed_by\` (null if free, otherwise the
48
- agent that holds the claim) and \`claimed_by_me\` (boolean). Use it before
49
- starting work on a tab whose state you don't already own.
50
- - \`browser.my_tabs\` returns YOUR active claims with timestamps. If the
51
- user asks which tab you are using, this is the answer.
52
41
  - Action tools (\`browser.click\`, \`browser.type\`, \`browser.navigate\`,
53
- \`browser.evaluate\`) auto-claim a free tab on first use and refresh
54
- activity on subsequent calls. If another agent holds the tab, they
55
- return an error naming the owner do NOT retry blindly; ask the user
56
- whose tab it should be, or use a different tab.
42
+ \`browser.evaluate\`) auto-claim a free tab on first use. If another
43
+ agent holds the tab, they return an error naming the owner — do NOT
44
+ retry blindly; ask the user whose tab it should be, or use a
45
+ different tab.
57
46
  - Read tools (\`browser.snapshot\`, \`browser.console\`, \`browser.network\`,
58
- \`browser.network_body\`, \`browser.events\`, \`browser.ping\`) ignore claims.
59
- - \`browser.claim_tab({ tab_id, ttl_minutes?, label? })\` reserves a tab
60
- explicitly. Provide a stable \`label\` (eg "claude-code", "opencode") so
61
- other agents and the user see WHO holds the tab. The label is display
62
- only security relies on the IPC session id (kernel-vetted), not on
63
- what an agent calls itself.
64
- - \`browser.release_tab({ tab_id })\` hands a tab back. Claims also auto-
65
- release when an agent disconnects or after the inactivity TTL elapses
66
- (default 10 minutes), so explicit release is only needed for early
67
- hand-off.
47
+ \`browser.network_body\`, \`browser.events\`, \`browser.ping\`) ignore
48
+ claims.
49
+ - Use \`browser.claim_tab\` with a stable \`label\` ("claude-code",
50
+ "opencode") to reserve a tab before a multi-step flow; release with
51
+ \`browser.release_tab\` (or let the inactivity TTL handle it).
68
52
 
69
- When you get a claim-conflict error: do NOT spin-retry. Either work on a
70
- different tab from \`list_tabs\`, or surface the conflict to the user and
71
- let them decide.
53
+ The label is display only security relies on the IPC session id
54
+ (kernel-vetted), not on what an agent calls itself. When you get a
55
+ claim-conflict error: do NOT spin-retry. Either work on a different tab
56
+ from \`list_tabs\`, or surface the conflict to the user.
72
57
 
73
- ## When something is wrong
58
+ ## Identifying the app
74
59
 
75
- - A selector from recall fails → record_use({ok:false}), learn the new
76
- one, save it (upsert on purpose).
77
- - A whole app got refactored \`browser.map.forget\` the app_id and let
78
- the map repopulate as you learn the new structure.
79
- - A tool call fails with "Tab not connected: tab_X" → call
80
- \`browser.events\` to see whether the bridge changed primary (the
81
- Chrome tab probably got a new tab_id after a reconnect). Look for a
82
- \`tab-renamed\` event with previous=tab_X and resume on the current id.
60
+ - \`origin\` = scheme://host:port of the tab.
61
+ - \`app_key\` distinguishes apps that share an origin over time. On
62
+ first save you may omit it; it will be derived from the page title
63
+ (slugified). Use \`browser.map.rename_app\` if that initial guess is
64
+ poor.
83
65
 
84
- The map is a cache of navigation, not a substitute for \`browser.snapshot\`.
85
- The live snapshot is always the source of truth.`;
66
+ The live snapshot is always the source of truth. The persistent map is
67
+ a cache of navigation, not a substitute.`;
68
+ /** Render a single tool's documentation as a markdown section. Skips
69
+ * tools without a `doc` block (the structured shape is opt-in for now
70
+ * so future contributors can stage the migration tool-by-tool). */
71
+ function renderTool(def) {
72
+ if (!def.doc)
73
+ return null;
74
+ const { purpose, when_to_use, gotchas, example } = def.doc;
75
+ const lines = [`### ${def.name}`, '', purpose, '', '**When to use:**'];
76
+ for (const w of when_to_use)
77
+ lines.push(`- ${w}`);
78
+ if (gotchas && gotchas.length > 0) {
79
+ lines.push('', '**Gotchas:**');
80
+ for (const g of gotchas)
81
+ lines.push(`- ${g}`);
82
+ }
83
+ if (example !== undefined && example !== '') {
84
+ lines.push('', '**Example:**', '```', example, '```');
85
+ }
86
+ return lines.join('\n');
87
+ }
88
+ /** Generate the SERVER_INSTRUCTIONS string from the tool definitions.
89
+ * Exported for tests and for any future caller that needs to re-render
90
+ * the string after a hot-reload or runtime tool registration. */
91
+ export function buildServerInstructions() {
92
+ const all = [...BROWSER_TOOL_DEFINITIONS, ...MAP_TOOL_DEFINITIONS];
93
+ const sections = [PREAMBLE, '', '## Tools'];
94
+ for (const def of all) {
95
+ const rendered = renderTool(def);
96
+ if (rendered) {
97
+ sections.push('', rendered);
98
+ }
99
+ }
100
+ return sections.join('\n');
101
+ }
102
+ /** Usage protocol pushed to the MCP client on `initialize`. Plain string,
103
+ * generated from the per-tool `doc` blocks at module load. */
104
+ export const SERVER_INSTRUCTIONS = buildServerInstructions();
86
105
  //# sourceMappingURL=server-instructions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-instructions.js","sourceRoot":"","sources":["../../src/tools/server-instructions.ts"],"names":[],"mappings":"AAAA;oEACoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAkFc,CAAC"}
1
+ {"version":3,"file":"server-instructions.js","sourceRoot":"","sources":["../../src/tools/server-instructions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAGvD;;sDAEsD;AACtD,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAmDwB,CAAC;AAE1C;;mEAEmE;AACnE,SAAS,UAAU,CAAC,GAAmB;IACrC,IAAI,CAAC,GAAG,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC;IAC3D,MAAM,KAAK,GAAa,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,kBAAkB,CAAC,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClD,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;iEAEiE;AACjE,MAAM,UAAU,uBAAuB;IACrC,MAAM,GAAG,GAAqB,CAAC,GAAG,wBAAwB,EAAE,GAAG,oBAAoB,CAAC,CAAC;IACrF,MAAM,QAAQ,GAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC;IACtD,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED;8DAC8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,EAAE,CAAC"}
@@ -1,6 +1,31 @@
1
- /** Shape of an MCP tool definition for our ListToolsRequestSchema response. */
1
+ /**
2
+ * Structured human-facing documentation co-located with each tool definition.
3
+ *
4
+ * Rendered into the MCP SERVER_INSTRUCTIONS string by
5
+ * `tools/server-instructions.ts`. The structured shape lets us keep the
6
+ * "what / when / gotchas / example" close to the tool itself instead of
7
+ * drifting in a big monolithic string, and lets tests assert per-tool
8
+ * completeness (purpose + when_to_use are mandatory).
9
+ */
10
+ export interface ToolDoc {
11
+ /** What the tool is for, one sentence. */
12
+ purpose: string;
13
+ /** When the agent should reach for it — triggers in plain language. */
14
+ when_to_use: string[];
15
+ /** Non-obvious gotchas / contracts to honour. Optional. */
16
+ gotchas?: string[];
17
+ /** A short representative invocation snippet. Optional. */
18
+ example?: string;
19
+ }
20
+ /** Shape of an MCP tool definition for our ListToolsRequestSchema response.
21
+ *
22
+ * The optional `doc` field carries the structured documentation consumed by
23
+ * `buildServerInstructions()`. Tools that omit it are not surfaced in the
24
+ * generated instructions; tools that include it must provide non-empty
25
+ * `purpose` and `when_to_use` (asserted by tests). */
2
26
  export interface ToolDefinition {
3
27
  name: string;
4
28
  description: string;
5
29
  inputSchema: Record<string, unknown>;
30
+ doc?: ToolDoc;
6
31
  }
package/dist/ui/app.js CHANGED
@@ -4,6 +4,7 @@ import { useState } from 'react';
4
4
  import { AboutView, AgentInstructionsView, ClientPicker, DoctorView, ExtensionView, FreePortView, InstallResultView, LanguageView, MainMenu, MultiAgentView, PermissionsView, UpdatesView, WelcomeScreen, } from './screens/index.js';
5
5
  import { saveConfig } from '../config.js';
6
6
  import { installFor } from '../commands/install.js';
7
+ import { statusAll } from '../commands/instructions.js';
7
8
  import { openUrl } from '../utils/open-url.js';
8
9
  const REPO_URL = 'https://github.com/jobshimo/browser-link';
9
10
  export function App({ initialLanguage, skipWelcome }) {
@@ -34,8 +35,17 @@ export function App({ initialLanguage, skipWelcome }) {
34
35
  return (_jsx(MainMenu, { language: language, onSelect: (action) => {
35
36
  if (action === 'register')
36
37
  setScreen({ kind: 'pick-client' });
37
- else if (action === 'instructions')
38
- setScreen({ kind: 'agent-instructions' });
38
+ else if (action === 'instructions') {
39
+ // If at least one client is outdated, auto-focus the first one
40
+ // so the next Enter refreshes it. The lookup is cheap (three
41
+ // file stats); doing it here keeps the navigation contract
42
+ // out of the menu screen and away from the installer module.
43
+ const firstOutdated = statusAll().find((r) => r.state.kind === 'installed-outdated');
44
+ setScreen({
45
+ kind: 'agent-instructions',
46
+ initialCursorClient: firstOutdated?.client,
47
+ });
48
+ }
39
49
  else if (action === 'permissions')
40
50
  setScreen({ kind: 'permissions' });
41
51
  else if (action === 'multiAgent')
@@ -85,7 +95,7 @@ export function App({ initialLanguage, skipWelcome }) {
85
95
  case 'about':
86
96
  return _jsx(AboutView, { language: language, onBack: backToMenu });
87
97
  case 'agent-instructions':
88
- return _jsx(AgentInstructionsView, { language: language, onBack: backToMenu });
98
+ return (_jsx(AgentInstructionsView, { language: language, onBack: backToMenu, initialCursorClient: screen.initialCursorClient }));
89
99
  }
90
100
  }
91
101
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/ui/app.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/ui/app.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface UpdateCheckState {
2
+ /** Latest version on the npm registry, or null when we have not been
3
+ * able to fetch it (offline, registry down, first-call still in flight). */
4
+ latest: string | null;
5
+ /** True only when latest > current. The banner consumer renders only
6
+ * when this is true, so failures collapse to "no banner". */
7
+ isNewer: boolean;
8
+ }
9
+ interface HookOptions {
10
+ /** Override the underlying check call. Tests inject a stub here. */
11
+ runCheck?: () => Promise<UpdateCheckState>;
12
+ /** Override the interval. Tests pass a tiny value to fast-forward. */
13
+ intervalMs?: number;
14
+ }
15
+ export declare function useBackgroundUpdateCheck(opts?: HookOptions): UpdateCheckState;
16
+ export {};
@@ -0,0 +1,48 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { checkForUpdates } from '../../commands/update-check.js';
3
+ /**
4
+ * React hook that runs a background update check on mount and again every
5
+ * six hours while the TUI is open. The lookup is silent on failure — when
6
+ * the npm registry is unreachable the hook simply returns null, which the
7
+ * banner consumer interprets as "no banner".
8
+ *
9
+ * The 6h cadence matches the on-disk cache TTL in `commands/update-check`
10
+ * so the cheap path (cache hit) is the one that actually fires within a
11
+ * single TUI session.
12
+ *
13
+ * A test seam (`runCheck`) lets the unit suite inject a synthetic check
14
+ * function — see `use-update-check.test.tsx`. Production callers should
15
+ * leave it undefined.
16
+ */
17
+ const SIX_HOURS_MS = 6 * 60 * 60 * 1000;
18
+ export function useBackgroundUpdateCheck(opts = {}) {
19
+ const { runCheck, intervalMs = SIX_HOURS_MS } = opts;
20
+ const [state, setState] = useState({ latest: null, isNewer: false });
21
+ useEffect(() => {
22
+ let cancelled = false;
23
+ const doCheck = async () => {
24
+ try {
25
+ const next = runCheck
26
+ ? await runCheck()
27
+ : await checkForUpdates().then((r) => ({ latest: r.latest, isNewer: r.isNewer }));
28
+ if (!cancelled)
29
+ setState(next);
30
+ }
31
+ catch {
32
+ // Passive banner — failure is silent. Leave the previous state in
33
+ // place (so a stale-but-still-useful "update available" survives
34
+ // a transient network hiccup).
35
+ }
36
+ };
37
+ void doCheck();
38
+ const timer = setInterval(() => {
39
+ void doCheck();
40
+ }, intervalMs);
41
+ return () => {
42
+ cancelled = true;
43
+ clearInterval(timer);
44
+ };
45
+ }, [runCheck, intervalMs]);
46
+ return state;
47
+ }
48
+ //# sourceMappingURL=use-update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-update-check.js","sourceRoot":"","sources":["../../../src/ui/hooks/use-update-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE;;;;;;;;;;;;;GAaG;AAEH,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAkBxC,MAAM,UAAU,wBAAwB,CAAC,OAAoB,EAAE;IAC7D,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC;IACrD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAEvF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;YACxC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,QAAQ;oBACnB,CAAC,CAAC,MAAM,QAAQ,EAAE;oBAClB,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACpF,IAAI,CAAC,SAAS;oBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC;gBACP,kEAAkE;gBAClE,iEAAiE;gBACjE,+BAA+B;YACjC,CAAC;QACH,CAAC,CAAC;QACF,KAAK,OAAO,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,KAAK,OAAO,EAAE,CAAC;QACjB,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IAE3B,OAAO,KAAK,CAAC;AACf,CAAC"}