@ank1015/llm-extension 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +214 -0
  2. package/dist/chrome/background.js +244 -0
  3. package/dist/chrome/manifest.json +23 -0
  4. package/dist/index.d.ts +8 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +8 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/native/host-wrapper.sh +11 -0
  9. package/dist/native/host.d.ts +2 -0
  10. package/dist/native/host.d.ts.map +1 -0
  11. package/dist/native/host.js +21 -0
  12. package/dist/native/host.js.map +1 -0
  13. package/dist/native/server.d.ts +28 -0
  14. package/dist/native/server.d.ts.map +1 -0
  15. package/dist/native/server.js +112 -0
  16. package/dist/native/server.js.map +1 -0
  17. package/dist/native/stdio.d.ts +21 -0
  18. package/dist/native/stdio.d.ts.map +1 -0
  19. package/dist/native/stdio.js +94 -0
  20. package/dist/native/stdio.js.map +1 -0
  21. package/dist/protocol/constants.d.ts +26 -0
  22. package/dist/protocol/constants.d.ts.map +1 -0
  23. package/dist/protocol/constants.js +26 -0
  24. package/dist/protocol/constants.js.map +1 -0
  25. package/dist/protocol/types.d.ts +39 -0
  26. package/dist/protocol/types.d.ts.map +1 -0
  27. package/dist/protocol/types.js +3 -0
  28. package/dist/protocol/types.js.map +1 -0
  29. package/dist/sdk/action/diff.d.ts +7 -0
  30. package/dist/sdk/action/diff.d.ts.map +1 -0
  31. package/dist/sdk/action/diff.js +54 -0
  32. package/dist/sdk/action/diff.js.map +1 -0
  33. package/dist/sdk/action/helpers.d.ts +23 -0
  34. package/dist/sdk/action/helpers.d.ts.map +1 -0
  35. package/dist/sdk/action/helpers.js +93 -0
  36. package/dist/sdk/action/helpers.js.map +1 -0
  37. package/dist/sdk/action/index.d.ts +6 -0
  38. package/dist/sdk/action/index.d.ts.map +1 -0
  39. package/dist/sdk/action/index.js +4 -0
  40. package/dist/sdk/action/index.js.map +1 -0
  41. package/dist/sdk/action/script.d.ts +4 -0
  42. package/dist/sdk/action/script.d.ts.map +1 -0
  43. package/dist/sdk/action/script.js +359 -0
  44. package/dist/sdk/action/script.js.map +1 -0
  45. package/dist/sdk/action/types.d.ts +47 -0
  46. package/dist/sdk/action/types.d.ts.map +1 -0
  47. package/dist/sdk/action/types.js +2 -0
  48. package/dist/sdk/action/types.js.map +1 -0
  49. package/dist/sdk/client.d.ts +42 -0
  50. package/dist/sdk/client.d.ts.map +1 -0
  51. package/dist/sdk/client.js +118 -0
  52. package/dist/sdk/client.js.map +1 -0
  53. package/dist/sdk/connect.d.ts +29 -0
  54. package/dist/sdk/connect.d.ts.map +1 -0
  55. package/dist/sdk/connect.js +99 -0
  56. package/dist/sdk/connect.js.map +1 -0
  57. package/dist/sdk/index.d.ts +17 -0
  58. package/dist/sdk/index.d.ts.map +1 -0
  59. package/dist/sdk/index.js +19 -0
  60. package/dist/sdk/index.js.map +1 -0
  61. package/dist/sdk/observe/helpers.d.ts +16 -0
  62. package/dist/sdk/observe/helpers.d.ts.map +1 -0
  63. package/dist/sdk/observe/helpers.js +278 -0
  64. package/dist/sdk/observe/helpers.js.map +1 -0
  65. package/dist/sdk/observe/index.d.ts +6 -0
  66. package/dist/sdk/observe/index.d.ts.map +1 -0
  67. package/dist/sdk/observe/index.js +4 -0
  68. package/dist/sdk/observe/index.js.map +1 -0
  69. package/dist/sdk/observe/script.d.ts +7 -0
  70. package/dist/sdk/observe/script.d.ts.map +1 -0
  71. package/dist/sdk/observe/script.js +680 -0
  72. package/dist/sdk/observe/script.js.map +1 -0
  73. package/dist/sdk/observe/storage.d.ts +39 -0
  74. package/dist/sdk/observe/storage.d.ts.map +1 -0
  75. package/dist/sdk/observe/storage.js +83 -0
  76. package/dist/sdk/observe/storage.js.map +1 -0
  77. package/dist/sdk/observe/types.d.ts +140 -0
  78. package/dist/sdk/observe/types.d.ts.map +1 -0
  79. package/dist/sdk/observe/types.js +2 -0
  80. package/dist/sdk/observe/types.js.map +1 -0
  81. package/dist/sdk/window.d.ts +97 -0
  82. package/dist/sdk/window.d.ts.map +1 -0
  83. package/dist/sdk/window.js +795 -0
  84. package/dist/sdk/window.js.map +1 -0
  85. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # @ank1015/llm-extension
2
+
3
+ A Chrome extension that exposes Chrome APIs over a general-purpose RPC bridge. Any process on your machine can connect via TCP and call Chrome APIs like `tabs.query`, `scripting.executeScript`, `storage.local.get`, or subscribe to events like `tabs.onUpdated` — all through a simple `call()` / `subscribe()` interface.
4
+
5
+ ## How It Works
6
+
7
+ ```
8
+ Your Agent ── TCP :9224 ──→ Native Host ── stdin/stdout ──→ Chrome Extension
9
+ │ │
10
+ ChromeServer background.ts
11
+ (TCP proxy) (RPC proxy)
12
+ ```
13
+
14
+ 1. **Chrome extension** installs as a Manifest V3 service worker. On startup, it connects to a native messaging host.
15
+ 2. **Native host** is a Node.js process Chrome launches via the [Native Messaging](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging) protocol. It opens a TCP server on port 9224.
16
+ 3. **Your agent** connects to the TCP server and sends RPC messages. The native host forwards them to Chrome over stdin/stdout. Chrome executes the API call and sends the result back through the same chain.
17
+
18
+ The protocol uses 6 message types: `call`, `subscribe`, `unsubscribe` (agent → Chrome) and `result`, `error`, `event` (Chrome → agent). All messages are length-prefixed JSON, correlated by UUID.
19
+
20
+ ## Setup
21
+
22
+ ### Prerequisites
23
+
24
+ - Chrome browser
25
+ - Node.js 18+
26
+ - pnpm
27
+
28
+ ### Install
29
+
30
+ ```bash
31
+ # Build the extension and native host
32
+ pnpm build
33
+
34
+ # Load the extension in Chrome:
35
+ # 1. Open chrome://extensions
36
+ # 2. Enable "Developer mode"
37
+ # 3. Click "Load unpacked" → select packages/extension/dist/chrome/
38
+ # 4. Copy the extension ID shown on the card
39
+
40
+ # Register the native messaging host
41
+ ./manifests/install-host.sh <extension-id>
42
+
43
+ # Quit and reopen Chrome (required for native host registration)
44
+ ```
45
+
46
+ After this one-time setup, Chrome will automatically launch the native host whenever the extension loads.
47
+
48
+ ### Verify
49
+
50
+ Check the extension's service worker console (`chrome://extensions` → Inspect views → service worker):
51
+
52
+ ```
53
+ [bg] background service worker loaded
54
+ ```
55
+
56
+ No disconnect error means the native host is running and the TCP server is ready on port 9224.
57
+
58
+ ## Usage
59
+
60
+ ### From TypeScript/JavaScript
61
+
62
+ ```ts
63
+ import { connect } from '@ank1015/llm-extension';
64
+
65
+ // Auto-launch Chrome if not running, retry until native host is ready
66
+ const chrome = await connect({ launch: true });
67
+
68
+ // Query tabs
69
+ const tabs = await chrome.call('tabs.query', { active: true, currentWindow: true });
70
+ console.log(tabs);
71
+
72
+ // Execute JavaScript in a tab
73
+ const result = await chrome.call('scripting.executeScript', {
74
+ target: { tabId: tabs[0].id },
75
+ code: 'document.title',
76
+ });
77
+ console.log(result[0].result); // page title
78
+
79
+ // Use storage
80
+ await chrome.call('storage.local.set', { myKey: 'myValue' });
81
+ const data = await chrome.call('storage.local.get', 'myKey');
82
+ console.log(data.myKey); // 'myValue'
83
+
84
+ // Subscribe to events
85
+ const unsubscribe = chrome.subscribe('tabs.onUpdated', (args) => {
86
+ const [tabId, changeInfo, tab] = args;
87
+ console.log(`Tab ${tabId} updated:`, changeInfo);
88
+ });
89
+
90
+ // Later...
91
+ unsubscribe();
92
+ ```
93
+
94
+ ### From Any Language
95
+
96
+ The protocol is language-agnostic. Connect to TCP port 9224 and exchange length-prefixed JSON:
97
+
98
+ ```
99
+ [4 bytes: uint32 LE message length][JSON payload]
100
+ ```
101
+
102
+ Send a call:
103
+
104
+ ```json
105
+ { "id": "uuid-here", "type": "call", "method": "tabs.query", "args": [{ "active": true }] }
106
+ ```
107
+
108
+ Receive the result:
109
+
110
+ ```json
111
+ { "id": "uuid-here", "type": "result", "data": [{ "id": 1, "url": "https://..." }] }
112
+ ```
113
+
114
+ ## API
115
+
116
+ ### `connect(opts?)`
117
+
118
+ Connect to the Chrome RPC server. Returns a `ChromeClient`.
119
+
120
+ | Option | Default | Description |
121
+ | --------------- | ------------- | --------------------------------------------------- |
122
+ | `port` | `9224` | TCP port to connect to |
123
+ | `host` | `'127.0.0.1'` | TCP host to connect to |
124
+ | `launch` | `false` | Launch Chrome automatically if connection fails |
125
+ | `launchTimeout` | `30000` | Max ms to wait for Chrome + native host to be ready |
126
+
127
+ ```ts
128
+ const chrome = await connect();
129
+ const chrome = await connect({ port: 9224, host: '127.0.0.1' });
130
+ const chrome = await connect({ launch: true }); // auto-open Chrome if not running
131
+ const chrome = await connect({ launch: true, launchTimeout: 15000 });
132
+ ```
133
+
134
+ ### `ChromeClient.call(method, ...args)`
135
+
136
+ Call any Chrome API method. The method string maps to `chrome.<method>` in the extension.
137
+
138
+ ```ts
139
+ // chrome.tabs.query({ active: true })
140
+ await chrome.call('tabs.query', { active: true });
141
+
142
+ // chrome.tabs.get(123)
143
+ await chrome.call('tabs.get', 123);
144
+
145
+ // chrome.storage.local.get('key')
146
+ await chrome.call('storage.local.get', 'key');
147
+ ```
148
+
149
+ ### `ChromeClient.call('scripting.executeScript', opts)`
150
+
151
+ Special case: pass a `code` string instead of a function reference. The code runs in the page's main world via `eval`.
152
+
153
+ ```ts
154
+ await chrome.call('scripting.executeScript', {
155
+ target: { tabId: 123 },
156
+ code: 'document.title',
157
+ });
158
+
159
+ await chrome.call('scripting.executeScript', {
160
+ target: { tabId: 123 },
161
+ code: '({ title: document.title, url: location.href })',
162
+ });
163
+ ```
164
+
165
+ ### `ChromeClient.subscribe(event, callback)`
166
+
167
+ Subscribe to a Chrome event. Returns an unsubscribe function.
168
+
169
+ ```ts
170
+ const unsub = chrome.subscribe('tabs.onUpdated', (args) => {
171
+ console.log('Tab updated:', args);
172
+ });
173
+
174
+ // Stop listening
175
+ unsub();
176
+ ```
177
+
178
+ ## Configuration
179
+
180
+ | Variable | Default | Description |
181
+ | ----------------- | ------- | ----------------------------------- |
182
+ | `CHROME_RPC_PORT` | `9224` | TCP port the native host listens on |
183
+
184
+ Set in the wrapper script at `~/.local/share/llm-native-host/run-host.sh` or pass via `connect({ port })`.
185
+
186
+ ## Development
187
+
188
+ ```bash
189
+ pnpm dev # Watch mode (native + chrome)
190
+ pnpm test # Unit tests (25 tests)
191
+ pnpm test:e2e # E2E tests against live Chrome
192
+ pnpm typecheck # Type-check both tsconfigs
193
+ ```
194
+
195
+ ### Project Structure
196
+
197
+ ```
198
+ src/
199
+ protocol/ # Shared message types and constants
200
+ sdk/ # ChromeClient, connect(), createChromeClient()
201
+ native/ # Node.js native host (host.ts, server.ts, stdio.ts)
202
+ chrome/ # Chrome extension (background.ts, manifest.json)
203
+ tests/
204
+ unit/ # Unit tests (stdio, client, server, factory)
205
+ e2e/ # E2E tests against live Chrome
206
+ manifests/ # Native host manifest and install script
207
+ ```
208
+
209
+ ### Two Build Targets
210
+
211
+ The package has two runtime contexts with separate TypeScript configs:
212
+
213
+ - **Node** (`tsconfig.json`): native host + SDK, compiled by `tsc` to `dist/`
214
+ - **Chrome** (`tsconfig.chrome.json`): extension service worker, bundled by `esbuild` to `dist/chrome/`
@@ -0,0 +1,244 @@
1
+ // src/protocol/constants.ts
2
+ var NATIVE_HOST_NAME = "com.ank1015.llm";
3
+ var MAX_HOST_TO_CHROME_MESSAGE_SIZE_BYTES = 1024 * 1024;
4
+ var MAX_CHROME_TO_HOST_MESSAGE_SIZE_BYTES = 64 * 1024 * 1024;
5
+ var MAX_TCP_MESSAGE_SIZE_BYTES = 64 * 1024 * 1024;
6
+
7
+ // src/chrome/background.ts
8
+ var nativePort = null;
9
+ var subscriptions = /* @__PURE__ */ new Map();
10
+ function connectNative() {
11
+ const port = chrome.runtime.connectNative(NATIVE_HOST_NAME);
12
+ port.onMessage.addListener((message) => {
13
+ handleHostMessage(message);
14
+ });
15
+ port.onDisconnect.addListener(() => {
16
+ console.warn("[bg] native host disconnected", chrome.runtime.lastError?.message ?? "");
17
+ nativePort = null;
18
+ subscriptions.clear();
19
+ });
20
+ nativePort = port;
21
+ return port;
22
+ }
23
+ function sendToHost(message) {
24
+ if (!nativePort) {
25
+ connectNative();
26
+ }
27
+ nativePort.postMessage(message);
28
+ }
29
+ function handleHostMessage(message) {
30
+ switch (message.type) {
31
+ case "call":
32
+ handleCall(message);
33
+ break;
34
+ case "subscribe":
35
+ handleSubscribe(message);
36
+ break;
37
+ case "unsubscribe":
38
+ handleUnsubscribe(message);
39
+ break;
40
+ default:
41
+ console.warn("[bg] unknown message type:", message.type);
42
+ }
43
+ }
44
+ async function handleCall(message) {
45
+ try {
46
+ let result;
47
+ if (message.method === "debugger.evaluate") {
48
+ result = await debuggerEvaluate(message.args);
49
+ } else if (message.method === "debugger.attach") {
50
+ result = await debuggerAttach(message.args);
51
+ } else if (message.method === "debugger.sendCommand") {
52
+ result = await debuggerSendCommand(message.args);
53
+ } else if (message.method === "debugger.detach") {
54
+ result = await debuggerDetach(message.args);
55
+ } else if (message.method === "debugger.getEvents") {
56
+ result = debuggerGetEvents(message.args);
57
+ } else if (message.method === "scripting.executeScript" && hasCodeArg(message.args)) {
58
+ result = await executeScriptWithCode(message.args);
59
+ } else {
60
+ const fn = resolveMethod(message.method);
61
+ result = await fn(...message.args);
62
+ }
63
+ sendToHost({ id: message.id, type: "result", data: result });
64
+ } catch (error) {
65
+ sendToHost({
66
+ id: message.id,
67
+ type: "error",
68
+ error: error instanceof Error ? error.message : String(error)
69
+ });
70
+ }
71
+ }
72
+ function hasCodeArg(args2) {
73
+ return args2.length > 0 && typeof args2[0] === "object" && args2[0] !== null && "code" in args2[0];
74
+ }
75
+ async function executeScriptWithCode(args) {
76
+ const { code, target, world, ...rest } = args[0];
77
+ return chrome.scripting.executeScript({
78
+ ...rest,
79
+ target,
80
+ world: world ?? "MAIN",
81
+ // func is serialized by Chrome and executed in the TAB context (not the service worker).
82
+ // eval is allowed in MAIN world under the page's CSP.
83
+ func: (codeStr) => eval(codeStr),
84
+ args: [code]
85
+ });
86
+ }
87
+ async function debuggerEvaluate(args2) {
88
+ const {
89
+ tabId,
90
+ code: code2,
91
+ returnByValue = true,
92
+ awaitPromise = false,
93
+ userGesture = false
94
+ } = args2[0];
95
+ if (typeof tabId !== "number") {
96
+ throw new Error("debugger.evaluate requires a numeric tabId");
97
+ }
98
+ if (typeof code2 !== "string" || !code2) {
99
+ throw new Error("debugger.evaluate requires a non-empty code string");
100
+ }
101
+ let attachedByThisMethod = false;
102
+ try {
103
+ await chrome.debugger.attach({ tabId }, "1.3");
104
+ attachedByThisMethod = true;
105
+ } catch (error) {
106
+ const message = error instanceof Error ? error.message : String(error);
107
+ if (!message.includes("Another debugger is already attached")) {
108
+ throw new Error(`Failed to attach debugger to tab ${tabId}: ${message}`);
109
+ }
110
+ }
111
+ try {
112
+ const response = await chrome.debugger.sendCommand({ tabId }, "Runtime.evaluate", {
113
+ expression: code2,
114
+ returnByValue,
115
+ awaitPromise,
116
+ userGesture
117
+ });
118
+ if (response.exceptionDetails) {
119
+ const detail = response.exceptionDetails.exception?.description ?? response.exceptionDetails.text ?? "Unknown evaluation error";
120
+ throw new Error(detail);
121
+ }
122
+ return { result: response.result?.value, type: response.result?.type };
123
+ } finally {
124
+ if (attachedByThisMethod) {
125
+ try {
126
+ await chrome.debugger.detach({ tabId });
127
+ } catch {
128
+ }
129
+ }
130
+ }
131
+ }
132
+ var debuggerSessions = /* @__PURE__ */ new Map();
133
+ function handleDebuggerEvent(source, method, params) {
134
+ if (source.tabId === void 0) return;
135
+ const session = debuggerSessions.get(source.tabId);
136
+ if (session) {
137
+ session.events.push({ method, params: params ?? {} });
138
+ }
139
+ }
140
+ chrome.debugger.onEvent.addListener(handleDebuggerEvent);
141
+ async function debuggerAttach(args2) {
142
+ const { tabId } = args2[0];
143
+ if (debuggerSessions.has(tabId)) {
144
+ return { alreadyAttached: true };
145
+ }
146
+ await chrome.debugger.attach({ tabId }, "1.3");
147
+ debuggerSessions.set(tabId, { events: [] });
148
+ return { attached: true };
149
+ }
150
+ async function debuggerSendCommand(args2) {
151
+ const { tabId, method, params } = args2[0];
152
+ if (!debuggerSessions.has(tabId)) {
153
+ throw new Error(`No debugger session for tab ${tabId} \u2014 call debugger.attach first`);
154
+ }
155
+ return chrome.debugger.sendCommand({ tabId }, method, params);
156
+ }
157
+ async function debuggerDetach(args2) {
158
+ const { tabId } = args2[0];
159
+ debuggerSessions.delete(tabId);
160
+ try {
161
+ await chrome.debugger.detach({ tabId });
162
+ } catch {
163
+ }
164
+ return { detached: true };
165
+ }
166
+ function debuggerGetEvents(args2) {
167
+ const {
168
+ tabId,
169
+ filter,
170
+ clear = false
171
+ } = args2[0];
172
+ const session = debuggerSessions.get(tabId);
173
+ if (!session) {
174
+ throw new Error(`No debugger session for tab ${tabId}`);
175
+ }
176
+ let events = session.events;
177
+ if (filter) {
178
+ events = events.filter((e) => e.method.startsWith(filter));
179
+ }
180
+ const result = [...events];
181
+ if (clear) {
182
+ if (filter) {
183
+ session.events = session.events.filter((e) => !e.method.startsWith(filter));
184
+ } else {
185
+ session.events = [];
186
+ }
187
+ }
188
+ return result;
189
+ }
190
+ function resolveMethod(method) {
191
+ const parts = method.split(".");
192
+ let target2 = chrome;
193
+ let parent = chrome;
194
+ for (const part of parts) {
195
+ parent = target2;
196
+ target2 = target2[part];
197
+ if (target2 === void 0) {
198
+ throw new Error(`chrome.${method} is not available`);
199
+ }
200
+ }
201
+ if (typeof target2 !== "function") {
202
+ throw new Error(`chrome.${method} is not a function`);
203
+ }
204
+ return target2.bind(parent);
205
+ }
206
+ function handleSubscribe(message) {
207
+ try {
208
+ const parts = message.event.split(".");
209
+ let target2 = chrome;
210
+ for (const part of parts) {
211
+ target2 = target2[part];
212
+ if (target2 === void 0) {
213
+ throw new Error(`chrome.${message.event} is not available`);
214
+ }
215
+ }
216
+ const eventTarget = target2;
217
+ if (typeof eventTarget.addListener !== "function") {
218
+ throw new Error(`chrome.${message.event} is not an event`);
219
+ }
220
+ const listener = (...args2) => {
221
+ sendToHost({ id: message.id, type: "event", data: args2 });
222
+ };
223
+ eventTarget.addListener(listener);
224
+ subscriptions.set(message.id, { target: eventTarget, listener });
225
+ } catch (error) {
226
+ sendToHost({
227
+ id: message.id,
228
+ type: "error",
229
+ error: error instanceof Error ? error.message : String(error)
230
+ });
231
+ }
232
+ }
233
+ function handleUnsubscribe(message) {
234
+ const sub = subscriptions.get(message.id);
235
+ if (sub) {
236
+ sub.target.removeListener(sub.listener);
237
+ subscriptions.delete(message.id);
238
+ }
239
+ }
240
+ chrome.runtime.onStartup.addListener(() => {
241
+ if (!nativePort) connectNative();
242
+ });
243
+ console.warn("[bg] background service worker loaded");
244
+ connectNative();
@@ -0,0 +1,23 @@
1
+ {
2
+ "manifest_version": 3,
3
+ "name": "LLM Extension",
4
+ "version": "0.0.1",
5
+ "description": "Chrome extension with general-purpose native messaging RPC",
6
+ "permissions": [
7
+ "nativeMessaging",
8
+ "scripting",
9
+ "activeTab",
10
+ "tabs",
11
+ "storage",
12
+ "cookies",
13
+ "downloads",
14
+ "debugger",
15
+ "accessibilityFeatures.read",
16
+ "accessibilityFeatures.modify"
17
+ ],
18
+ "host_permissions": ["<all_urls>"],
19
+ "background": {
20
+ "service_worker": "background.js",
21
+ "type": "module"
22
+ }
23
+ }
@@ -0,0 +1,8 @@
1
+ export type { CallMessage, SubscribeMessage, UnsubscribeMessage, HostMessage, ResultMessage, ErrorMessage, EventMessage, ChromeMessage, } from './protocol/types.js';
2
+ export { NATIVE_HOST_NAME, MAX_HOST_TO_CHROME_MESSAGE_SIZE_BYTES, MAX_CHROME_TO_HOST_MESSAGE_SIZE_BYTES, MAX_TCP_MESSAGE_SIZE_BYTES, MAX_MESSAGE_SIZE_BYTES, LENGTH_PREFIX_BYTES, DEFAULT_PORT, } from './protocol/constants.js';
3
+ export { ChromeClient, createChromeClient, connect, Window } from './sdk/index.js';
4
+ export type { ChromeClientOptions, ConnectOptions, ObserveFilter, WindowActionOptions, WindowDownloadOptions, WindowEvaluateOptions, WindowGetPageOptions, WindowObserveOptions, WindowOpenOptions, WindowScrollBehavior, WindowScrollOptions, WindowSemanticFilter, WindowScreenshotOptions, WindowTab, WindowTypeOptions, } from './sdk/index.js';
5
+ export { ChromeServer } from './native/server.js';
6
+ export type { ChromeServerOptions } from './native/server.js';
7
+ export { readMessage, writeMessage } from './native/stdio.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,gBAAgB,EAChB,qCAAqC,EACrC,qCAAqC,EACrC,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,GACb,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACnF,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,SAAS,EACT,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { NATIVE_HOST_NAME, MAX_HOST_TO_CHROME_MESSAGE_SIZE_BYTES, MAX_CHROME_TO_HOST_MESSAGE_SIZE_BYTES, MAX_TCP_MESSAGE_SIZE_BYTES, MAX_MESSAGE_SIZE_BYTES, LENGTH_PREFIX_BYTES, DEFAULT_PORT, } from './protocol/constants.js';
2
+ // SDK
3
+ export { ChromeClient, createChromeClient, connect, Window } from './sdk/index.js';
4
+ // Server
5
+ export { ChromeServer } from './native/server.js';
6
+ // Native host stdio utilities
7
+ export { readMessage, writeMessage } from './native/stdio.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,gBAAgB,EAChB,qCAAqC,EACrC,qCAAqC,EACrC,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,GACb,MAAM,yBAAyB,CAAC;AAEjC,MAAM;AACN,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAmBnF,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,8BAA8B;AAC9B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+ # Chrome launches this script as the native messaging host.
3
+ # It resolves its own directory and invokes the Node.js host.
4
+ #
5
+ # NOTE: This wrapper is only used for local development.
6
+ # The install-host.sh script creates a separate wrapper in
7
+ # ~/.local/share/llm-native-host/ with an absolute node path.
8
+
9
+ DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
11
+ exec node "$DIR/native/host.js"
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/native/host.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { DEFAULT_PORT, MAX_CHROME_TO_HOST_MESSAGE_SIZE_BYTES, MAX_HOST_TO_CHROME_MESSAGE_SIZE_BYTES, } from '../protocol/constants.js';
2
+ import { ChromeClient } from '../sdk/client.js';
3
+ import { ChromeServer } from './server.js';
4
+ function log(msg) {
5
+ process.stderr.write(`[host] ${msg}\n`);
6
+ }
7
+ log(`started (pid=${process.pid})`);
8
+ const client = new ChromeClient({
9
+ maxIncomingMessageSizeBytes: MAX_CHROME_TO_HOST_MESSAGE_SIZE_BYTES,
10
+ maxOutgoingMessageSizeBytes: MAX_HOST_TO_CHROME_MESSAGE_SIZE_BYTES,
11
+ });
12
+ client.run().then(() => {
13
+ log('Chrome disconnected, exiting');
14
+ process.exit(0);
15
+ }, (e) => {
16
+ log(`fatal: ${e instanceof Error ? e.message : String(e)}`);
17
+ process.exit(1);
18
+ });
19
+ const port = process.env.CHROME_RPC_PORT ? parseInt(process.env.CHROME_RPC_PORT, 10) : DEFAULT_PORT;
20
+ new ChromeServer(client, { port });
21
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/native/host.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,qCAAqC,EACrC,qCAAqC,GACtC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,SAAS,GAAG,CAAC,GAAW;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,GAAG,CAAC,gBAAgB,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAEpC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;IAC9B,2BAA2B,EAAE,qCAAqC;IAClE,2BAA2B,EAAE,qCAAqC;CACnE,CAAC,CAAC;AACH,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CACf,GAAG,EAAE;IACH,GAAG,CAAC,8BAA8B,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,EACD,CAAC,CAAC,EAAE,EAAE;IACJ,GAAG,CAAC,UAAU,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC;AAEF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AAEpG,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { ChromeClient } from '../sdk/client.js';
2
+ export interface ChromeServerOptions {
3
+ port?: number;
4
+ host?: string;
5
+ }
6
+ /**
7
+ * TCP server that proxies Chrome API calls from external agents
8
+ * through a ChromeClient connected to Chrome's native messaging.
9
+ *
10
+ * Each TCP connection gets its own read loop and subscription tracking.
11
+ * Multiple agents can connect simultaneously.
12
+ */
13
+ export declare class ChromeServer {
14
+ private server;
15
+ private chromeClient;
16
+ constructor(chromeClient: ChromeClient, opts?: ChromeServerOptions);
17
+ private handleConnection;
18
+ private handleCall;
19
+ private handleSubscribe;
20
+ private handleUnsubscribe;
21
+ private send;
22
+ close(): void;
23
+ get address(): {
24
+ port: number;
25
+ host: string;
26
+ } | null;
27
+ }
28
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/native/server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAe;gBAEvB,YAAY,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,mBAAmB;YAmBpD,gBAAgB;YAuChB,UAAU;IAaxB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,IAAI;IAYZ,KAAK,IAAI,IAAI;IAIb,IAAI,OAAO,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAMnD;CACF"}