@postqode/browser 0.7.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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/session.ts"],
4
+ "sourcesContent": ["import type { Browser, BrowserContext, ConsoleMessage, Dialog, Page, Request, Response, Route } from \"playwright-core\"\nimport { chromium } from \"playwright-core\"\n\n/** Configuration for a browser session. */\nexport interface BrowserSessionConfig {\n\t/** Launch headless (default true). */\n\theadless?: boolean\n\t/** Default timeout for every operation, in ms. Default 30000. */\n\tdefaultTimeoutMs?: number\n\t/** Viewport size. Default { width: 1280, height: 800 }. */\n\tviewport?: { width: number; height: number }\n\t/** User-agent override. */\n\tuserAgent?: string\n\t/** Additional launch args (passed to chromium.launch). */\n\tlaunchArgs?: string[]\n\t/** Max console messages retained per page (FIFO). Default 200. */\n\tconsoleBufferSize?: number\n\t/** Max network entries retained per page (FIFO). Default 200. */\n\tnetworkBufferSize?: number\n}\n\n/** Captured console message in plain-data form. */\nexport interface ConsoleEntry {\n\ttype: string\n\ttext: string\n\tlocation?: { url: string; lineNumber: number; columnNumber: number }\n\ttimestamp: number\n}\n\n/** Captured network request in plain-data form. */\nexport interface NetworkEntry {\n\turl: string\n\tmethod: string\n\tresourceType: string\n\tstatus?: number\n\tstatusText?: string\n\tfailed?: boolean\n\tfailureText?: string\n\tfromCache?: boolean\n\ttimestamp: number\n}\n\n/** Pre-registered dialog policy. The next dialog `page.on('dialog')` fires will be handled per this policy. */\nexport interface DialogPolicy {\n\t/** Accept the dialog. If false, dismiss it. */\n\taccept: boolean\n\t/** Optional response for window.prompt(). */\n\tpromptText?: string\n}\n\n/** Registered network route. */\nexport interface RouteEntry {\n\tpattern: string\n\taction: \"abort\" | \"fulfill\" | \"continue\"\n\tstatus?: number\n\tbody?: string\n\tcontentType?: string\n\thandler: (route: Route) => Promise<void>\n}\n\ninterface PageState {\n\tpage: Page\n\tconsole: ConsoleEntry[]\n\tnetwork: NetworkEntry[]\n}\n\n/**\n * Long-lived browser session shared across tool calls.\n *\n * Call `start()` once per conversation; tools created with\n * {@link createBrowserTools} bound to this session reuse the same\n * {@link Page}. Call `close()` to release the browser.\n *\n * Errors on a closed session throw \u2014 consumers should guard with\n * `session.isOpen()` or call `start()` again to reopen.\n */\nexport class BrowserSession {\n\tprivate browser: Browser | undefined\n\tprivate context: BrowserContext | undefined\n\tprivate states: PageState[] = []\n\tprivate activeIndex = 0\n\tprivate dialogPolicy: DialogPolicy = { accept: false }\n\tprivate routes = new Map<string, RouteEntry>()\n\tprivate tracingActive = false\n\tprivate offline = false\n\tprivate readonly config: Required<Omit<BrowserSessionConfig, \"userAgent\" | \"launchArgs\">> & Pick<BrowserSessionConfig, \"userAgent\" | \"launchArgs\">\n\n\tconstructor(config: BrowserSessionConfig = {}) {\n\t\tthis.config = {\n\t\t\theadless: config.headless ?? true,\n\t\t\tdefaultTimeoutMs: config.defaultTimeoutMs ?? 30_000,\n\t\t\tviewport: config.viewport ?? { width: 1280, height: 800 },\n\t\t\tuserAgent: config.userAgent,\n\t\t\tlaunchArgs: config.launchArgs,\n\t\t\tconsoleBufferSize: config.consoleBufferSize ?? 200,\n\t\t\tnetworkBufferSize: config.networkBufferSize ?? 200,\n\t\t}\n\t}\n\n\tasync start(): Promise<void> {\n\t\tif (this.browser) return\n\t\tthis.browser = await chromium.launch({\n\t\t\theadless: this.config.headless,\n\t\t\targs: this.config.launchArgs,\n\t\t})\n\t\tthis.context = await this.browser.newContext({\n\t\t\tviewport: this.config.viewport,\n\t\t\tuserAgent: this.config.userAgent,\n\t\t})\n\t\tthis.context.setDefaultTimeout(this.config.defaultTimeoutMs)\n\t\tthis.context.on(\"page\", (p) => this.attachPage(p))\n\t\tconst firstPage = await this.context.newPage()\n\t\t// firstPage already created via newPage will not have fired the \"page\" event in some\n\t\t// playwright versions when no listener was set yet; ensure it's attached exactly once.\n\t\tif (!this.states.find((s) => s.page === firstPage)) this.attachPage(firstPage)\n\t\tthis.activeIndex = 0\n\t}\n\n\tprivate attachPage(page: Page): void {\n\t\tconst state: PageState = { page, console: [], network: [] }\n\t\tthis.states.push(state)\n\n\t\tpage.on(\"console\", (msg: ConsoleMessage) => {\n\t\t\tconst loc = msg.location()\n\t\t\tstate.console.push({\n\t\t\t\ttype: msg.type(),\n\t\t\t\ttext: msg.text(),\n\t\t\t\tlocation: loc ? { url: loc.url, lineNumber: loc.lineNumber, columnNumber: loc.columnNumber } : undefined,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t\tif (state.console.length > this.config.consoleBufferSize) state.console.shift()\n\t\t})\n\n\t\tpage.on(\"pageerror\", (err) => {\n\t\t\tstate.console.push({ type: \"error\", text: err.message, timestamp: Date.now() })\n\t\t\tif (state.console.length > this.config.consoleBufferSize) state.console.shift()\n\t\t})\n\n\t\tpage.on(\"request\", (req: Request) => {\n\t\t\tstate.network.push({\n\t\t\t\turl: req.url(),\n\t\t\t\tmethod: req.method(),\n\t\t\t\tresourceType: req.resourceType(),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t\tif (state.network.length > this.config.networkBufferSize) state.network.shift()\n\t\t})\n\n\t\tpage.on(\"response\", (res: Response) => {\n\t\t\tconst entry = [...state.network].reverse().find((n) => n.url === res.url() && n.status === undefined)\n\t\t\tif (entry) {\n\t\t\t\tentry.status = res.status()\n\t\t\t\tentry.statusText = res.statusText()\n\t\t\t\tentry.fromCache = res.fromServiceWorker()\n\t\t\t}\n\t\t})\n\n\t\tpage.on(\"requestfailed\", (req: Request) => {\n\t\t\tconst entry = [...state.network].reverse().find((n) => n.url === req.url() && n.status === undefined)\n\t\t\tif (entry) {\n\t\t\t\tentry.failed = true\n\t\t\t\tentry.failureText = req.failure()?.errorText\n\t\t\t}\n\t\t})\n\n\t\tpage.on(\"dialog\", (dialog: Dialog) => {\n\t\t\tconst policy = this.dialogPolicy\n\t\t\tconst finish = policy.accept ? dialog.accept(policy.promptText) : dialog.dismiss()\n\t\t\tfinish.catch(() => {})\n\t\t})\n\n\t\tpage.on(\"close\", () => {\n\t\t\tconst idx = this.states.findIndex((s) => s.page === page)\n\t\t\tif (idx >= 0) {\n\t\t\t\tthis.states.splice(idx, 1)\n\t\t\t\tif (this.activeIndex >= this.states.length) this.activeIndex = Math.max(0, this.states.length - 1)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync getPage(): Promise<Page> {\n\t\tif (this.states.length === 0) {\n\t\t\tawait this.start()\n\t\t}\n\t\tconst state = this.states[this.activeIndex]\n\t\tif (!state) throw new Error(\"BrowserSession failed to initialize a page\")\n\t\treturn state.page\n\t}\n\n\tasync getContext(): Promise<BrowserContext> {\n\t\tif (!this.context) await this.start()\n\t\tif (!this.context) throw new Error(\"BrowserSession failed to initialize a context\")\n\t\treturn this.context\n\t}\n\n\tlistPages(): { index: number; url: string; title?: string; active: boolean }[] {\n\t\treturn this.states.map((s, i) => ({\n\t\t\tindex: i,\n\t\t\turl: s.page.url(),\n\t\t\tactive: i === this.activeIndex,\n\t\t}))\n\t}\n\n\tasync listPagesWithTitles(): Promise<{ index: number; url: string; title: string; active: boolean }[]> {\n\t\treturn Promise.all(\n\t\t\tthis.states.map(async (s, i) => ({\n\t\t\t\tindex: i,\n\t\t\t\turl: s.page.url(),\n\t\t\t\ttitle: await s.page.title().catch(() => \"\"),\n\t\t\t\tactive: i === this.activeIndex,\n\t\t\t})),\n\t\t)\n\t}\n\n\tasync switchTab(index: number): Promise<Page> {\n\t\tif (index < 0 || index >= this.states.length) {\n\t\t\tthrow new Error(`tab index ${index} out of range (0..${this.states.length - 1})`)\n\t\t}\n\t\tthis.activeIndex = index\n\t\tconst page = this.states[index]!.page\n\t\tawait page.bringToFront().catch(() => {})\n\t\treturn page\n\t}\n\n\tasync newTab(): Promise<Page> {\n\t\tconst context = await this.getContext()\n\t\tconst page = await context.newPage()\n\t\t// attachPage runs via the context \"page\" event; switch active to the new tab.\n\t\tthis.activeIndex = this.states.findIndex((s) => s.page === page)\n\t\tif (this.activeIndex < 0) {\n\t\t\t// Fallback if the event didn't fire in this playwright version.\n\t\t\tthis.attachPage(page)\n\t\t\tthis.activeIndex = this.states.length - 1\n\t\t}\n\t\treturn page\n\t}\n\n\tasync closeTab(index: number): Promise<void> {\n\t\tif (index < 0 || index >= this.states.length) {\n\t\t\tthrow new Error(`tab index ${index} out of range (0..${this.states.length - 1})`)\n\t\t}\n\t\tawait this.states[index]!.page.close().catch(() => {})\n\t}\n\n\tgetConsole(): ConsoleEntry[] {\n\t\treturn this.states[this.activeIndex]?.console.slice() ?? []\n\t}\n\n\tclearConsole(): void {\n\t\tconst s = this.states[this.activeIndex]\n\t\tif (s) s.console.length = 0\n\t}\n\n\tgetNetwork(): NetworkEntry[] {\n\t\treturn this.states[this.activeIndex]?.network.slice() ?? []\n\t}\n\n\tclearNetwork(): void {\n\t\tconst s = this.states[this.activeIndex]\n\t\tif (s) s.network.length = 0\n\t}\n\n\tsetDialogPolicy(policy: DialogPolicy): void {\n\t\tthis.dialogPolicy = policy\n\t}\n\n\tgetRoutes(): RouteEntry[] {\n\t\treturn Array.from(this.routes.values())\n\t}\n\n\tasync addRoute(entry: RouteEntry): Promise<void> {\n\t\tconst context = await this.getContext()\n\t\tthis.routes.set(entry.pattern, entry)\n\t\tawait context.route(entry.pattern, entry.handler)\n\t}\n\n\tasync removeRoute(pattern: string): Promise<boolean> {\n\t\tconst entry = this.routes.get(pattern)\n\t\tif (!entry) return false\n\t\tconst context = await this.getContext()\n\t\tawait context.unroute(pattern, entry.handler).catch(() => {})\n\t\tthis.routes.delete(pattern)\n\t\treturn true\n\t}\n\n\tasync setOffline(value: boolean): Promise<void> {\n\t\tconst context = await this.getContext()\n\t\tawait context.setOffline(value)\n\t\tthis.offline = value\n\t}\n\n\tisOffline(): boolean {\n\t\treturn this.offline\n\t}\n\n\tisTracing(): boolean {\n\t\treturn this.tracingActive\n\t}\n\n\tasync startTracing(options?: { screenshots?: boolean; snapshots?: boolean; sources?: boolean }): Promise<void> {\n\t\tconst context = await this.getContext()\n\t\tawait context.tracing.start({\n\t\t\tscreenshots: options?.screenshots ?? true,\n\t\t\tsnapshots: options?.snapshots ?? true,\n\t\t\tsources: options?.sources ?? false,\n\t\t})\n\t\tthis.tracingActive = true\n\t}\n\n\tasync stopTracing(outputPath?: string): Promise<void> {\n\t\tconst context = await this.getContext()\n\t\tawait context.tracing.stop(outputPath ? { path: outputPath } : undefined)\n\t\tthis.tracingActive = false\n\t}\n\n\tisOpen(): boolean {\n\t\treturn this.browser !== undefined && this.states.length > 0\n\t}\n\n\tasync close(): Promise<void> {\n\t\tconst b = this.browser\n\t\tthis.states = []\n\t\tthis.activeIndex = 0\n\t\tthis.context = undefined\n\t\tthis.browser = undefined\n\t\tthis.routes.clear()\n\t\tthis.tracingActive = false\n\t\tthis.offline = false\n\t\tif (b) await b.close().catch(() => {})\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["config", "p", "firstPage", "s", "page", "state", "msg", "loc", "err", "req", "res", "entry", "dialog", "policy", "idx", "i", "index", "context", "pattern", "value", "options", "outputPath", "b"]
7
+ }
@@ -0,0 +1,49 @@
1
+ import type { Tool } from "@postqode/agent";
2
+ import type { BrowserSession } from "./session";
3
+ export interface BrowserNavigateAndReadInput {
4
+ url: string;
5
+ /** Max time to wait for load, in ms. Default 30000. */
6
+ timeoutMs?: number;
7
+ /** Max characters of visible text returned. Default 8000. */
8
+ maxChars?: number;
9
+ }
10
+ /**
11
+ * Navigate to a URL and return the visible text content of the resulting page.
12
+ *
13
+ * Stateless per call: launches chromium, navigates, extracts, closes. Fine
14
+ * for one-off page reads during research; for interactive flows (click,
15
+ * type, screenshot) use the per-session API in a follow-up commit.
16
+ */
17
+ export declare const browserNavigateAndReadTool: Tool<BrowserNavigateAndReadInput>;
18
+ export interface CreateBrowserToolsOptions {
19
+ /** When supplied, returns the session-bound tool set (navigate, read,
20
+ * click, type, wait, screenshot, eval, close). When omitted, returns
21
+ * the single stateless `browser_navigate_and_read` tool. */
22
+ session?: BrowserSession;
23
+ }
24
+ /**
25
+ * Returns a browser tool pack for @postqode/agent.
26
+ *
27
+ * Stateless (one Chrome per call):
28
+ * ```ts
29
+ * createBrowserTools() // [browser_navigate_and_read]
30
+ * ```
31
+ *
32
+ * Session-based (one shared Chrome instance across calls):
33
+ * ```ts
34
+ * import { BrowserSession, createBrowserTools } from "@postqode/browser"
35
+ *
36
+ * const session = new BrowserSession({ headless: true })
37
+ * const agent = createCodingAgent({
38
+ * api,
39
+ * extraTools: createBrowserTools({ session }),
40
+ * })
41
+ * try {
42
+ * await agent.run("Fill the login form at example.com and screenshot the dashboard")
43
+ * } finally {
44
+ * await session.close()
45
+ * }
46
+ * ```
47
+ */
48
+ export declare function createBrowserTools(options?: CreateBrowserToolsOptions): Tool[];
49
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAG3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAG/C,MAAM,WAAW,2BAA2B;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,EAAE,IAAI,CAAC,2BAA2B,CA2ExE,CAAA;AAED,MAAM,WAAW,yBAAyB;IACzC;;iEAE6D;IAC7D,OAAO,CAAC,EAAE,cAAc,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,IAAI,EAAE,CAGlF"}
package/dist/tools.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.browserNavigateAndReadTool=void 0,exports.createBrowserTools=createBrowserTools;const playwright_core_1=require("playwright-core"),session_tools_1=require("./session-tools");exports.browserNavigateAndReadTool={name:"browser_navigate_and_read",description:"Open a web page and return its visible text. Stateless per call \u2014 no session kept between invocations.",inputSchema:{type:"object",properties:{url:{type:"string",description:"URL to navigate to."},timeoutMs:{type:"integer",minimum:1,description:"Max milliseconds to wait for the page to load. Default 30000."},maxChars:{type:"integer",minimum:100,description:"Truncate the returned text at this many characters. Default 8000."}},required:["url"]},async execute({url:e,timeoutMs:l,maxChars:d},u){const a=d??8e3;let r;try{r=await playwright_core_1.chromium.launch({headless:!0});const t=await r.newPage(),s=()=>{t.close().catch(()=>{})};u.signal.addEventListener("abort",s,{once:!0});const c=await t.goto(e,{waitUntil:"domcontentloaded",timeout:l??3e4}),n=await t.title().catch(()=>""),o=await t.evaluate(()=>document.body?.innerText??""),i=o.length>a,p=i?o.slice(0,a):o;return{content:[`URL: ${e}`,`Status: ${c?.status()??"unknown"}`,n?`Title: ${n}`:"","",p,i?`
2
+ [truncated ${o.length-a} characters]`:""].filter(Boolean).join(`
3
+ `),details:{url:e,status:c?.status(),title:n,length:o.length,truncated:i}}}catch(t){const s=t instanceof Error?t.message:String(t);return{content:`Failed to fetch ${e}: ${s}`,isError:!0,details:{url:e,error:s}}}finally{r&&await r.close().catch(()=>{})}}};function createBrowserTools(e={}){return e.session?(0,session_tools_1.createSessionTools)(e.session):[exports.browserNavigateAndReadTool]}
4
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tools.ts"],
4
+ "sourcesContent": ["import type { Tool } from \"@postqode/agent\"\nimport { chromium, type Browser, type Page } from \"playwright-core\"\n\nimport type { BrowserSession } from \"./session\"\nimport { createSessionTools } from \"./session-tools\"\n\nexport interface BrowserNavigateAndReadInput {\n\turl: string\n\t/** Max time to wait for load, in ms. Default 30000. */\n\ttimeoutMs?: number\n\t/** Max characters of visible text returned. Default 8000. */\n\tmaxChars?: number\n}\n\n/**\n * Navigate to a URL and return the visible text content of the resulting page.\n *\n * Stateless per call: launches chromium, navigates, extracts, closes. Fine\n * for one-off page reads during research; for interactive flows (click,\n * type, screenshot) use the per-session API in a follow-up commit.\n */\nexport const browserNavigateAndReadTool: Tool<BrowserNavigateAndReadInput> = {\n\tname: \"browser_navigate_and_read\",\n\tdescription:\n\t\t\"Open a web page and return its visible text. Stateless per call \u2014 no session kept between invocations.\",\n\tinputSchema: {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\turl: { type: \"string\", description: \"URL to navigate to.\" },\n\t\t\ttimeoutMs: {\n\t\t\t\ttype: \"integer\",\n\t\t\t\tminimum: 1,\n\t\t\t\tdescription: \"Max milliseconds to wait for the page to load. Default 30000.\",\n\t\t\t},\n\t\t\tmaxChars: {\n\t\t\t\ttype: \"integer\",\n\t\t\t\tminimum: 100,\n\t\t\t\tdescription: \"Truncate the returned text at this many characters. Default 8000.\",\n\t\t\t},\n\t\t},\n\t\trequired: [\"url\"],\n\t},\n\tasync execute({ url, timeoutMs, maxChars }, ctx) {\n\t\tconst cap = maxChars ?? 8000\n\t\tlet browser: Browser | undefined\n\t\ttry {\n\t\t\tbrowser = await chromium.launch({ headless: true })\n\t\t\tconst page: Page = await browser.newPage()\n\n\t\t\t// Relay the agent's abort signal to the page navigation.\n\t\t\tconst abortHandler = () => {\n\t\t\t\tpage.close().catch(() => {})\n\t\t\t}\n\t\t\tctx.signal.addEventListener(\"abort\", abortHandler, { once: true })\n\n\t\t\tconst response = await page.goto(url, {\n\t\t\t\twaitUntil: \"domcontentloaded\",\n\t\t\t\ttimeout: timeoutMs ?? 30_000,\n\t\t\t})\n\t\t\tconst title = await page.title().catch(() => \"\")\n\t\t\tconst text = await page.evaluate(() => document.body?.innerText ?? \"\")\n\t\t\tconst truncated = text.length > cap\n\t\t\tconst body = truncated ? text.slice(0, cap) : text\n\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t`URL: ${url}`,\n\t\t\t\t\t`Status: ${response?.status() ?? \"unknown\"}`,\n\t\t\t\t\ttitle ? `Title: ${title}` : \"\",\n\t\t\t\t\t\"\",\n\t\t\t\t\tbody,\n\t\t\t\t\ttruncated ? `\\n[truncated ${text.length - cap} characters]` : \"\",\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\"\\n\"),\n\t\t\t\tdetails: {\n\t\t\t\t\turl,\n\t\t\t\t\tstatus: response?.status(),\n\t\t\t\t\ttitle,\n\t\t\t\t\tlength: text.length,\n\t\t\t\t\ttruncated,\n\t\t\t\t},\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\treturn {\n\t\t\t\tcontent: `Failed to fetch ${url}: ${message}`,\n\t\t\t\tisError: true,\n\t\t\t\tdetails: { url, error: message },\n\t\t\t}\n\t\t} finally {\n\t\t\tif (browser) {\n\t\t\t\tawait browser.close().catch(() => {})\n\t\t\t}\n\t\t}\n\t},\n}\n\nexport interface CreateBrowserToolsOptions {\n\t/** When supplied, returns the session-bound tool set (navigate, read,\n\t * click, type, wait, screenshot, eval, close). When omitted, returns\n\t * the single stateless `browser_navigate_and_read` tool. */\n\tsession?: BrowserSession\n}\n\n/**\n * Returns a browser tool pack for @postqode/agent.\n *\n * Stateless (one Chrome per call):\n * ```ts\n * createBrowserTools() // [browser_navigate_and_read]\n * ```\n *\n * Session-based (one shared Chrome instance across calls):\n * ```ts\n * import { BrowserSession, createBrowserTools } from \"@postqode/browser\"\n *\n * const session = new BrowserSession({ headless: true })\n * const agent = createCodingAgent({\n * api,\n * extraTools: createBrowserTools({ session }),\n * })\n * try {\n * await agent.run(\"Fill the login form at example.com and screenshot the dashboard\")\n * } finally {\n * await session.close()\n * }\n * ```\n */\nexport function createBrowserTools(options: CreateBrowserToolsOptions = {}): Tool[] {\n\tif (options.session) return createSessionTools(options.session)\n\treturn [browserNavigateAndReadTool]\n}\n"],
5
+ "mappings": "8GAiIA,QAAA,mBAAA,mBAhIA,MAAA,kBAAA,QAAA,iBAAA,EAGA,gBAAA,QAAA,iBAAA,EAiBa,QAAA,2BAAgE,CAC5E,KAAM,4BACN,YACC,8GACD,YAAa,CACZ,KAAM,SACN,WAAY,CACX,IAAK,CAAE,KAAM,SAAU,YAAa,qBAAqB,EACzD,UAAW,CACV,KAAM,UACN,QAAS,EACT,YAAa,iEAEd,SAAU,CACT,KAAM,UACN,QAAS,IACT,YAAa,sEAGf,SAAU,CAAC,KAAK,GAEjB,MAAM,QAAQ,CAAE,IAAAA,EAAK,UAAAC,EAAW,SAAAC,CAAQ,EAAIC,EAAG,CAC9C,MAAMC,EAAMF,GAAY,IACxB,IAAIG,EACJ,GAAI,CACHA,EAAU,MAAM,kBAAA,SAAS,OAAO,CAAE,SAAU,EAAI,CAAE,EAClD,MAAMC,EAAa,MAAMD,EAAQ,QAAO,EAGlCE,EAAe,IAAK,CACzBD,EAAK,MAAK,EAAG,MAAM,IAAK,CAAE,CAAC,CAC5B,EACAH,EAAI,OAAO,iBAAiB,QAASI,EAAc,CAAE,KAAM,EAAI,CAAE,EAEjE,MAAMC,EAAW,MAAMF,EAAK,KAAKN,EAAK,CACrC,UAAW,mBACX,QAASC,GAAa,IACtB,EACKQ,EAAQ,MAAMH,EAAK,MAAK,EAAG,MAAM,IAAM,EAAE,EACzCI,EAAO,MAAMJ,EAAK,SAAS,IAAM,SAAS,MAAM,WAAa,EAAE,EAC/DK,EAAYD,EAAK,OAASN,EAC1BQ,EAAOD,EAAYD,EAAK,MAAM,EAAGN,CAAG,EAAIM,EAE9C,MAAO,CACN,QAAS,CACR,QAAQV,CAAG,GACX,WAAWQ,GAAU,OAAM,GAAM,SAAS,GAC1CC,EAAQ,UAAUA,CAAK,GAAK,GAC5B,GACAG,EACAD,EAAY;aAAgBD,EAAK,OAASN,CAAG,eAAiB,IAE7D,OAAO,OAAO,EACd,KAAK;CAAI,EACX,QAAS,CACR,IAAAJ,EACA,OAAQQ,GAAU,OAAM,EACxB,MAAAC,EACA,OAAQC,EAAK,OACb,UAAAC,GAGH,OAASE,EAAK,CACb,MAAMC,EAAUD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,EAC/D,MAAO,CACN,QAAS,mBAAmBb,CAAG,KAAKc,CAAO,GAC3C,QAAS,GACT,QAAS,CAAE,IAAAd,EAAK,MAAOc,CAAO,EAEhC,SACKT,GACH,MAAMA,EAAQ,MAAK,EAAG,MAAM,IAAK,CAAE,CAAC,CAEtC,CACD,GAkCD,SAAgB,mBAAmBU,EAAqC,CAAA,EAAE,CACzE,OAAIA,EAAQ,WAAgB,gBAAA,oBAAmBA,EAAQ,OAAO,EACvD,CAAC,QAAA,0BAA0B,CACnC",
6
+ "names": ["url", "timeoutMs", "maxChars", "ctx", "cap", "browser", "page", "abortHandler", "response", "title", "text", "truncated", "body", "err", "message", "options"]
7
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@postqode/browser",
3
+ "version": "0.7.1",
4
+ "private": false,
5
+ "description": "Browser automation tools for @postqode/agent. Stateless one-shot navigation plus a shared BrowserSession with 34 session-bound tools — full primitive parity with the in-extension postqode_browser_agent, with related primitives collapsed into action-discriminator tools (cookies, localStorage, sessionStorage, state, route, tracing, mouse, key) to keep prompt overhead at ~2.5K tokens. Playwright-core under the hood.",
6
+ "license": "SEE LICENSE IN ../../LICENSE",
7
+ "author": "ElevenXN Technologies Pvt. Ltd",
8
+ "homepage": "https://postqode.ai/",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/postqode/postqode-extension",
12
+ "directory": "packages/postqode-browser"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20.11.0"
30
+ },
31
+ "scripts": {
32
+ "clean": "rm -rf dist",
33
+ "build": "tsc -p tsconfig.build.json",
34
+ "prepublishOnly": "npm run clean && npm run build && node ../../scripts/minify-packages.js"
35
+ },
36
+ "dependencies": {
37
+ "@postqode/agent": "*"
38
+ },
39
+ "peerDependencies": {
40
+ "playwright-core": ">=1.58.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^18.0.0",
44
+ "playwright-core": "~1.58.2",
45
+ "typescript": "^5.3.3",
46
+ "vitest": "^2.1.3"
47
+ },
48
+ "publishConfig": {
49
+ "registry": "https://registry.npmjs.org/",
50
+ "access": "public"
51
+ }
52
+ }