@jobshimo/browser-link 0.8.2 → 0.9.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.
Files changed (116) hide show
  1. package/dist/agent-instructions/content.js +42 -27
  2. package/dist/agent-instructions/content.js.map +1 -1
  3. package/dist/agent-instructions/file-ops.js +7 -2
  4. package/dist/agent-instructions/file-ops.js.map +1 -1
  5. package/dist/bridge/events.d.ts +3 -0
  6. package/dist/bridge/events.js +8 -0
  7. package/dist/bridge/events.js.map +1 -1
  8. package/dist/commands/doctor.js +30 -1
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/update-check.d.ts +25 -0
  11. package/dist/commands/update-check.js +108 -0
  12. package/dist/commands/update-check.js.map +1 -0
  13. package/dist/commands/welcome.d.ts +15 -0
  14. package/dist/commands/welcome.js +44 -2
  15. package/dist/commands/welcome.js.map +1 -1
  16. package/dist/extension/background.js +37 -1
  17. package/dist/extension/background.js.map +1 -1
  18. package/dist/extension/manifest.json +1 -1
  19. package/dist/extension/popup.d.ts +2 -1
  20. package/dist/extension/popup.html +128 -50
  21. package/dist/extension/popup.js +22 -3
  22. package/dist/extension/popup.js.map +1 -1
  23. package/dist/map/tools.d.ts +1 -5
  24. package/dist/map/tools.js +45 -0
  25. package/dist/map/tools.js.map +1 -1
  26. package/dist/server.js +42 -36
  27. package/dist/server.js.map +1 -1
  28. package/dist/tools/browser-definitions.d.ts +6 -0
  29. package/dist/tools/browser-definitions.js +150 -0
  30. package/dist/tools/browser-definitions.js.map +1 -1
  31. package/dist/tools/browser-dispatch.d.ts +8 -14
  32. package/dist/tools/browser-dispatch.js +10 -0
  33. package/dist/tools/browser-dispatch.js.map +1 -1
  34. package/dist/tools/server-instructions.d.ts +16 -2
  35. package/dist/tools/server-instructions.js +87 -68
  36. package/dist/tools/server-instructions.js.map +1 -1
  37. package/dist/tools/tab-claims.d.ts +5 -1
  38. package/dist/tools/tab-claims.js +17 -0
  39. package/dist/tools/tab-claims.js.map +1 -1
  40. package/dist/tools/types.d.ts +26 -1
  41. package/dist/ui/app.js +40 -5
  42. package/dist/ui/app.js.map +1 -1
  43. package/dist/ui/components.d.ts +15 -3
  44. package/dist/ui/components.js +34 -14
  45. package/dist/ui/components.js.map +1 -1
  46. package/dist/ui/hooks/use-update-check.d.ts +16 -0
  47. package/dist/ui/hooks/use-update-check.js +48 -0
  48. package/dist/ui/hooks/use-update-check.js.map +1 -0
  49. package/dist/ui/primitives/badge.d.ts +11 -0
  50. package/dist/ui/primitives/badge.js +35 -0
  51. package/dist/ui/primitives/badge.js.map +1 -0
  52. package/dist/ui/primitives/check-row.d.ts +11 -0
  53. package/dist/ui/primitives/check-row.js +10 -0
  54. package/dist/ui/primitives/check-row.js.map +1 -0
  55. package/dist/ui/primitives/footer-keys.d.ts +12 -0
  56. package/dist/ui/primitives/footer-keys.js +11 -0
  57. package/dist/ui/primitives/footer-keys.js.map +1 -0
  58. package/dist/ui/primitives/index.d.ts +8 -0
  59. package/dist/ui/primitives/index.js +13 -0
  60. package/dist/ui/primitives/index.js.map +1 -0
  61. package/dist/ui/primitives/inline-spinner.d.ts +7 -0
  62. package/dist/ui/primitives/inline-spinner.js +23 -0
  63. package/dist/ui/primitives/inline-spinner.js.map +1 -0
  64. package/dist/ui/primitives/key-cap.d.ts +6 -0
  65. package/dist/ui/primitives/key-cap.js +6 -0
  66. package/dist/ui/primitives/key-cap.js.map +1 -0
  67. package/dist/ui/primitives/menu-row.d.ts +17 -0
  68. package/dist/ui/primitives/menu-row.js +8 -0
  69. package/dist/ui/primitives/menu-row.js.map +1 -0
  70. package/dist/ui/primitives/section-head.d.ts +11 -0
  71. package/dist/ui/primitives/section-head.js +7 -0
  72. package/dist/ui/primitives/section-head.js.map +1 -0
  73. package/dist/ui/primitives/status-bar.d.ts +13 -0
  74. package/dist/ui/primitives/status-bar.js +17 -0
  75. package/dist/ui/primitives/status-bar.js.map +1 -0
  76. package/dist/ui/screens/about.js +13 -4
  77. package/dist/ui/screens/about.js.map +1 -1
  78. package/dist/ui/screens/agent-instructions.d.ts +7 -1
  79. package/dist/ui/screens/agent-instructions.js +62 -46
  80. package/dist/ui/screens/agent-instructions.js.map +1 -1
  81. package/dist/ui/screens/client-picker.js +64 -16
  82. package/dist/ui/screens/client-picker.js.map +1 -1
  83. package/dist/ui/screens/doctor.js +20 -7
  84. package/dist/ui/screens/doctor.js.map +1 -1
  85. package/dist/ui/screens/empty-clients.d.ts +8 -0
  86. package/dist/ui/screens/empty-clients.js +57 -0
  87. package/dist/ui/screens/empty-clients.js.map +1 -0
  88. package/dist/ui/screens/extension.js +25 -8
  89. package/dist/ui/screens/extension.js.map +1 -1
  90. package/dist/ui/screens/free-port.js +48 -33
  91. package/dist/ui/screens/free-port.js.map +1 -1
  92. package/dist/ui/screens/index.d.ts +2 -0
  93. package/dist/ui/screens/index.js +2 -0
  94. package/dist/ui/screens/index.js.map +1 -1
  95. package/dist/ui/screens/install-result.js +29 -6
  96. package/dist/ui/screens/install-result.js.map +1 -1
  97. package/dist/ui/screens/language.js +39 -18
  98. package/dist/ui/screens/language.js.map +1 -1
  99. package/dist/ui/screens/menu.d.ts +10 -1
  100. package/dist/ui/screens/menu.js +118 -30
  101. package/dist/ui/screens/menu.js.map +1 -1
  102. package/dist/ui/screens/multi-agent.js +24 -18
  103. package/dist/ui/screens/multi-agent.js.map +1 -1
  104. package/dist/ui/screens/permissions.js +145 -33
  105. package/dist/ui/screens/permissions.js.map +1 -1
  106. package/dist/ui/screens/port-collision.d.ts +18 -0
  107. package/dist/ui/screens/port-collision.js +95 -0
  108. package/dist/ui/screens/port-collision.js.map +1 -0
  109. package/dist/ui/screens/updates.js +44 -21
  110. package/dist/ui/screens/updates.js.map +1 -1
  111. package/dist/ui/screens/welcome.js +56 -26
  112. package/dist/ui/screens/welcome.js.map +1 -1
  113. package/dist/ui/tokens.d.ts +37 -0
  114. package/dist/ui/tokens.js +58 -0
  115. package/dist/ui/tokens.js.map +1 -0
  116. package/package.json +1 -1
@@ -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"}
@@ -52,7 +52,7 @@ export type ClaimEvent = {
52
52
  kind: 'tab-released';
53
53
  tab_id: string;
54
54
  agent_id: string;
55
- reason: 'explicit' | 'agent-disconnect' | 'ttl';
55
+ reason: 'explicit' | 'agent-disconnect' | 'ttl' | 'reset';
56
56
  } | {
57
57
  kind: 'tab-claim-rejected';
58
58
  tab_id: string;
@@ -110,6 +110,10 @@ export declare class TabClaimRegistry {
110
110
  pruneStale(): TabClaim[];
111
111
  /** Test helper. Production callers should not need this. */
112
112
  size(): number;
113
+ /** Drop every claim, emitting one `tab-released` event per dropped claim
114
+ * (reason: 'reset'). Used by `browser.reset` to wipe ownership in one
115
+ * step without iterating from the caller side. */
116
+ releaseAll(): TabClaim[];
113
117
  private isExpired;
114
118
  private claimInternal;
115
119
  }
@@ -126,6 +126,23 @@ export class TabClaimRegistry {
126
126
  size() {
127
127
  return this.claims.size;
128
128
  }
129
+ /** Drop every claim, emitting one `tab-released` event per dropped claim
130
+ * (reason: 'reset'). Used by `browser.reset` to wipe ownership in one
131
+ * step without iterating from the caller side. */
132
+ releaseAll() {
133
+ const released = [];
134
+ for (const [tabId, claim] of this.claims) {
135
+ released.push(claim);
136
+ this.onEvent({
137
+ kind: 'tab-released',
138
+ tab_id: tabId,
139
+ agent_id: claim.agent_id,
140
+ reason: 'reset',
141
+ });
142
+ }
143
+ this.claims.clear();
144
+ return released;
145
+ }
129
146
  isExpired(claim) {
130
147
  return this.now() - claim.last_activity_at >= claim.ttl_ms;
131
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tab-claims.js","sourceRoot":"","sources":["../../src/tools/tab-claims.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tab-claims.js","sourceRoot":"","sources":["../../src/tools/tab-claims.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -1,11 +1,22 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useApp, useInput } from 'ink';
3
3
  import { useState } from 'react';
4
- import { AboutView, AgentInstructionsView, ClientPicker, DoctorView, ExtensionView, FreePortView, InstallResultView, LanguageView, MainMenu, MultiAgentView, PermissionsView, UpdatesView, WelcomeScreen, } from './screens/index.js';
4
+ import { AboutView, AgentInstructionsView, ClientPicker, DoctorView, EmptyClientsView, 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';
9
+ import { INSTALLERS } from '../installers/index.js';
8
10
  const REPO_URL = 'https://github.com/jobshimo/browser-link';
11
+ /* True when at least one of the supported MCP clients is detected on
12
+ * disk. When false, the register flow short-circuits to the
13
+ * EmptyClientsView instead of rendering a picker the user can't act on.
14
+ *
15
+ * `detect()` does a file existence check — cheap enough to run on every
16
+ * navigation to the picker, and accurate after a manual install. */
17
+ function anyClientDetected() {
18
+ return INSTALLERS.some((i) => i.detect().installed);
19
+ }
9
20
  export function App({ initialLanguage, skipWelcome }) {
10
21
  const { exit } = useApp();
11
22
  const [language, setLanguage] = useState(initialLanguage);
@@ -22,6 +33,17 @@ export function App({ initialLanguage, skipWelcome }) {
22
33
  const backToMenu = () => {
23
34
  setScreen({ kind: 'menu' });
24
35
  };
36
+ /* When the user picks Register from the menu, we route to either the
37
+ * full picker or the empty state depending on whether any client is
38
+ * actually present. The detection runs at navigation time so a user
39
+ * that installs Claude in another terminal and comes back doesn't get
40
+ * stuck on the empty screen forever. */
41
+ const enterPickClient = () => {
42
+ if (anyClientDetected())
43
+ setScreen({ kind: 'pick-client' });
44
+ else
45
+ setScreen({ kind: 'empty-clients' });
46
+ };
25
47
  switch (screen.kind) {
26
48
  case 'welcome':
27
49
  return (_jsx(WelcomeScreen, { language: language, hideDismiss: screen.hideDismiss, onAccept: () => {
@@ -33,9 +55,18 @@ export function App({ initialLanguage, skipWelcome }) {
33
55
  case 'menu':
34
56
  return (_jsx(MainMenu, { language: language, onSelect: (action) => {
35
57
  if (action === 'register')
36
- setScreen({ kind: 'pick-client' });
37
- else if (action === 'instructions')
38
- setScreen({ kind: 'agent-instructions' });
58
+ enterPickClient();
59
+ else if (action === 'instructions') {
60
+ // If at least one client is outdated, auto-focus the first one
61
+ // so the next Enter refreshes it. The lookup is cheap (three
62
+ // file stats); doing it here keeps the navigation contract
63
+ // out of the menu screen and away from the installer module.
64
+ const firstOutdated = statusAll().find((r) => r.state.kind === 'installed-outdated');
65
+ setScreen({
66
+ kind: 'agent-instructions',
67
+ initialCursorClient: firstOutdated?.client,
68
+ });
69
+ }
39
70
  else if (action === 'permissions')
40
71
  setScreen({ kind: 'permissions' });
41
72
  else if (action === 'multiAgent')
@@ -63,6 +94,10 @@ export function App({ initialLanguage, skipWelcome }) {
63
94
  const report = installFor(id);
64
95
  setScreen({ kind: 'install-result', report });
65
96
  }, onBack: backToMenu }));
97
+ case 'empty-clients':
98
+ return (_jsx(EmptyClientsView, { language: language, onRescan: enterPickClient, onOpenRepo: () => {
99
+ openUrl(REPO_URL);
100
+ }, onBack: backToMenu }));
66
101
  case 'install-result':
67
102
  return _jsx(InstallResultView, { language: language, report: screen.report, onBack: backToMenu });
68
103
  case 'permissions':
@@ -85,7 +120,7 @@ export function App({ initialLanguage, skipWelcome }) {
85
120
  case 'about':
86
121
  return _jsx(AboutView, { language: language, onBack: backToMenu });
87
122
  case 'agent-instructions':
88
- return _jsx(AgentInstructionsView, { language: language, onBack: backToMenu });
123
+ return (_jsx(AgentInstructionsView, { language: language, onBack: backToMenu, initialCursorClient: screen.initialCursorClient }));
89
124
  }
90
125
  }
91
126
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/ui/app.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,YAAY,EACZ,UAAU,EACV,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,eAAe,EACf,WAAW,EACX,aAAa,GAEd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAsB,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG/C,MAAM,QAAQ,GAAG,0CAA0C,CAAC;AAsB5D,MAAM,UAAU,GAAG,CAAC,EAAE,eAAe,EAAE,WAAW,EAAY;IAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAW,eAAe,CAAC,CAAC;IACpE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAClC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,CACzE,CAAC;IAEF,2EAA2E;IAC3E,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACvB,IAAI,GAAG,CAAC,IAAI,IAAI,MAAM,KAAK,GAAG;YAAE,IAAI,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,CACL,KAAC,aAAa,IACZ,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,CAAC,WAAW,EAC/B,QAAQ,EAAE,GAAG,EAAE;oBACb,UAAU,EAAE,CAAC;gBACf,CAAC,EACD,SAAS,EAAE,GAAG,EAAE;oBACd,UAAU,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC5C,UAAU,EAAE,CAAC;gBACf,CAAC,EACD,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,IAAI,GACZ,CACH,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO,CACL,KAAC,QAAQ,IACP,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,MAAkB,EAAE,EAAE;oBAC/B,IAAI,MAAM,KAAK,UAAU;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;yBACzD,IAAI,MAAM,KAAK,cAAc;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;yBACzE,IAAI,MAAM,KAAK,aAAa;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;yBACjE,IAAI,MAAM,KAAK,YAAY;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;yBAChE,IAAI,MAAM,KAAK,WAAW;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;yBAC7D,IAAI,MAAM,KAAK,QAAQ;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;yBACvD,IAAI,MAAM,KAAK,SAAS;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;yBACzD,IAAI,MAAM,KAAK,UAAU;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;yBAC5D,IAAI,MAAM,KAAK,UAAU;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;yBAC3D,IAAI,MAAM,KAAK,OAAO;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;yBACrD,IAAI,MAAM,KAAK,SAAS;wBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;yBAC5E,IAAI,MAAM,KAAK,MAAM;wBAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;oBAC9C,uCAAuC;gBACzC,CAAC,EACD,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,IAAI,GACZ,CACH,CAAC;QAEJ,KAAK,aAAa;YAChB,OAAO,CACL,KAAC,YAAY,IACX,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,CAAC,EAAY,EAAE,EAAE;oBACvB,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;oBAC9B,SAAS,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAAC;gBAChD,CAAC,EACD,MAAM,EAAE,UAAU,GAClB,CACH,CAAC;QAEJ,KAAK,gBAAgB;YACnB,OAAO,KAAC,iBAAiB,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAE9F,KAAK,aAAa;YAChB,OAAO,KAAC,eAAe,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAErE,KAAK,aAAa;YAChB,OAAO,KAAC,cAAc,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAEpE,KAAK,WAAW;YACd,OAAO,KAAC,aAAa,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAEnE,KAAK,QAAQ;YACX,OAAO,KAAC,UAAU,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAEhE,KAAK,SAAS;YACZ,OAAO,KAAC,WAAW,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAEjE,KAAK,WAAW;YACd,OAAO,KAAC,YAAY,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAElE,KAAK,UAAU;YACb,OAAO,CACL,KAAC,YAAY,IACX,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;oBACf,WAAW,CAAC,IAAI,CAAC,CAAC;oBAClB,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,CAAC,EACD,MAAM,EAAE,UAAU,GAClB,CACH,CAAC;QAEJ,KAAK,OAAO;YACV,OAAO,KAAC,SAAS,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;QAE/D,KAAK,oBAAoB;YACvB,OAAO,KAAC,qBAAqB,IAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAI,CAAC;IAC7E,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/ui/app.tsx"],"names":[],"mappings":"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"}
@@ -1,14 +1,26 @@
1
1
  import type { ReactNode } from 'react';
2
2
  interface FrameProps {
3
- title: string;
4
- footer: string;
3
+ title: ReactNode;
4
+ /** Footer slot — typically a <FooterKeys> from primitives, but plain
5
+ * strings are still accepted for the few screens that interleave help
6
+ * text into the footer. */
7
+ footer: ReactNode;
8
+ /** Right-aligned tag rendered next to the title — e.g. "PRIMARY",
9
+ * "v0.9.0 · EN · single-agent". */
10
+ badge?: ReactNode;
11
+ /** Override the border color. Defaults to gray; error screens pass red. */
12
+ borderColor?: string;
5
13
  children: ReactNode;
6
14
  }
7
- export declare function Frame({ title, footer, children }: FrameProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function Frame({ title, footer, badge, borderColor, children }: FrameProps): import("react/jsx-runtime").JSX.Element;
8
16
  interface MenuItem<V extends string> {
9
17
  value: V;
10
18
  label: string;
11
19
  hint?: string;
20
+ /** Optional single-character hotkey marker — rendered as `[h]` before
21
+ * the label. Screens that wire hotkeys via useInput should set this so
22
+ * the visual cue and the keyboard handler stay in sync. */
23
+ hotkey?: string;
12
24
  }
13
25
  interface MenuProps<V extends string> {
14
26
  items: MenuItem<V>[];
@@ -1,27 +1,47 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
3
  import { INSTALLERS } from '../installers/index.js';
4
- export function Frame({ title, footer, children }) {
5
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: title }), _jsx(StatusBar, {})] }), _jsx(Box, { flexDirection: "column", children: children }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: footer }) })] }));
4
+ import { COLORS, GLYPHS } from './tokens.js';
5
+ import { StatusBar } from './primitives/index.js';
6
+ export function Frame({ title, footer, badge, borderColor = 'gray', children }) {
7
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: COLORS.heading, bold: true, children: title }), badge !== undefined && (_jsx(Box, { marginLeft: 2, flexGrow: 1, justifyContent: "flex-end", children: badge }))] }), _jsx(LiveStatusBar, {})] }), _jsx(Box, { flexDirection: "column", children: children }), _jsx(Box, { marginTop: 1, children: typeof footer === 'string' ? _jsx(FooterText, { text: footer }) : footer })] }));
6
8
  }
7
- function StatusBar() {
8
- return (_jsx(Box, { children: INSTALLERS.map((inst, i) => {
9
- const d = inst.detect();
10
- const { color, label } = !d.installed
11
- ? { color: 'gray', label: 'not detected' }
12
- : d.registered
13
- ? { color: 'green', label: 'registered' }
14
- : { color: 'yellow', label: 'not registered' };
15
- return (_jsx(Box, { marginRight: i === INSTALLERS.length - 1 ? 0 : 3, children: _jsxs(Text, { children: [_jsx(Text, { bold: true, children: inst.displayName }), _jsx(Text, { color: "gray", children: " \u00B7 " }), _jsx(Text, { color: color, children: label })] }) }, inst.id));
16
- }) }));
9
+ function FooterText({ text }) {
10
+ return (_jsx(Text, { color: COLORS.muted, dimColor: true, children: text }));
11
+ }
12
+ /* Project the installer registry into the StatusBar primitive's input
13
+ * shape. Held inside this module so the rest of the UI doesn't reach
14
+ * into INSTALLERS just to render the header. */
15
+ function LiveStatusBar() {
16
+ const items = INSTALLERS.map((inst) => {
17
+ const d = inst.detect();
18
+ let state;
19
+ let label;
20
+ if (!d.installed) {
21
+ state = 'not detected';
22
+ label = 'not detected';
23
+ }
24
+ else if (d.registered) {
25
+ state = 'registered';
26
+ label = 'registered';
27
+ }
28
+ else {
29
+ state = 'not registered';
30
+ label = 'not registered';
31
+ }
32
+ return { name: inst.displayName, state, label };
33
+ });
34
+ return _jsx(StatusBar, { items: items });
17
35
  }
18
36
  /* Pure render of a vertical menu — the App owns the selectedIndex state and
19
37
  * the key handling (we don't pull in ink-select-input so we can colour and
20
- * format hints exactly the way we want). */
38
+ * format hints exactly the way we want). Items with a `hotkey` render a
39
+ * `[h]` marker before the label; the keyboard binding itself is set up by
40
+ * the screen's `useInput`. */
21
41
  export function Menu({ items, selectedIndex }) {
22
42
  return (_jsx(Box, { flexDirection: "column", children: items.map((item, i) => {
23
43
  const isSel = i === selectedIndex;
24
- return (_jsxs(Box, { children: [_jsx(Text, { color: isSel ? 'cyan' : 'gray', children: isSel ? '❯ ' : ' ' }), _jsx(Text, { color: isSel ? 'white' : 'gray', bold: isSel, children: item.label }), item.hint && (_jsxs(Text, { color: "gray", dimColor: true, children: [' ', item.hint] }))] }, item.value));
44
+ return (_jsxs(Box, { children: [_jsx(Text, { color: isSel ? COLORS.focus : COLORS.muted, children: isSel ? `${GLYPHS.cursor} ` : ' ' }), item.hotkey !== undefined && item.hotkey !== '' && (_jsxs(Text, { children: [_jsx(Text, { color: COLORS.muted, children: "[" }), _jsx(Text, { color: isSel ? COLORS.focus : COLORS.primary, bold: isSel, underline: true, children: item.hotkey }), _jsx(Text, { color: COLORS.muted, children: "] " })] })), _jsx(Text, { color: isSel ? 'white' : COLORS.muted, bold: isSel, children: item.label }), item.hint !== undefined && item.hint !== '' && (_jsxs(Text, { color: COLORS.muted, dimColor: true, children: [' ', item.hint] }))] }, item.value));
25
45
  }) }));
26
46
  }
27
47
  //# sourceMappingURL=components.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/ui/components.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/ui/components.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"}