@gui-chat-plugin/browse 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @gui-chat-plugin/browse
2
+
3
+ [![npm version](https://badge.fury.io/js/%40gui-chat-plugin%2Fbrowse.svg)](https://www.npmjs.com/package/@gui-chat-plugin/browse)
4
+
5
+ Web browsing plugin for GUI Chat applications. Browse and extract content from web pages.
6
+
7
+ ## Features
8
+
9
+ - Extract content from any web page URL
10
+ - Twitter/X post embedding support
11
+ - Article content parsing (title, byline, excerpt, body)
12
+ - Clean, readable content display
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ yarn add @gui-chat-plugin/browse
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Vue Integration
23
+
24
+ ```typescript
25
+ // In src/tools/index.ts
26
+ import BrowsePlugin from "@gui-chat-plugin/browse/vue";
27
+
28
+ const pluginList = [
29
+ // ... other plugins
30
+ BrowsePlugin,
31
+ ];
32
+
33
+ // In src/main.ts
34
+ import "@gui-chat-plugin/browse/style.css";
35
+ ```
36
+
37
+ ### Core-only Usage
38
+
39
+ ```typescript
40
+ import { executeBrowse, TOOL_DEFINITION } from "@gui-chat-plugin/browse";
41
+
42
+ // Browse a webpage
43
+ const result = await executeBrowse(context, {
44
+ url: "https://example.com/article",
45
+ });
46
+ ```
47
+
48
+ ## API
49
+
50
+ ### BrowseArgs
51
+
52
+ ```typescript
53
+ interface BrowseArgs {
54
+ url: string; // The URL of the webpage to browse
55
+ }
56
+ ```
57
+
58
+ ### BrowseToolData
59
+
60
+ ```typescript
61
+ interface BrowseToolData {
62
+ url: string;
63
+ twitterEmbedHtml?: string | null;
64
+ }
65
+ ```
66
+
67
+ ### BrowseJsonData
68
+
69
+ ```typescript
70
+ interface BrowseJsonData {
71
+ data: {
72
+ title?: string;
73
+ description?: string;
74
+ content?: string;
75
+ textContent?: string;
76
+ text?: string;
77
+ byline?: string;
78
+ excerpt?: string;
79
+ };
80
+ }
81
+ ```
82
+
83
+ ## Development
84
+
85
+ ```bash
86
+ # Install dependencies
87
+ yarn install
88
+
89
+ # Run demo
90
+ yarn dev
91
+
92
+ # Build
93
+ yarn build
94
+
95
+ # Lint
96
+ yarn lint
97
+ ```
98
+
99
+ ## Test Prompts
100
+
101
+ Try these prompts to test the plugin:
102
+
103
+ 1. "Browse the Wikipedia page about artificial intelligence and tell me the key points"
104
+ 2. "Show me what's on the Hacker News homepage"
105
+ 3. "Read this article and summarize it: https://example.com/article"
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,17 @@
1
+ export declare const TOOL_NAME = "browse";
2
+ export declare const TOOL_DEFINITION: {
3
+ type: "function";
4
+ name: string;
5
+ description: string;
6
+ parameters: {
7
+ type: "object";
8
+ properties: {
9
+ url: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ };
14
+ required: string[];
15
+ };
16
+ };
17
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/core/definition.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,WAAW,CAAC;AAElC,eAAO,MAAM,eAAe;;;;;;;;;;;;;;CAgB3B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from "./types";
2
+ export * from "./definition";
3
+ export * from "./plugin";
4
+ export { samples } from "./samples";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ToolContext, ToolPluginCore } from "gui-chat-protocol";
2
+ import type { BrowseToolData, BrowseJsonData, BrowseArgs, BrowseResult } from "./types";
3
+ import { TOOL_NAME, TOOL_DEFINITION } from "./definition";
4
+ declare function isTwitterUrl(url: string): boolean;
5
+ export declare const browse: (context: ToolContext, args: BrowseArgs) => Promise<BrowseResult>;
6
+ export { isTwitterUrl };
7
+ export declare const pluginCore: ToolPluginCore<BrowseToolData, BrowseJsonData, BrowseArgs>;
8
+ export { TOOL_NAME, TOOL_DEFINITION };
9
+ export declare const executeBrowse: (context: ToolContext, args: BrowseArgs) => Promise<BrowseResult>;
10
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/core/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI1D,iBAAS,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAY1C;AAgBD,eAAO,MAAM,MAAM,GACjB,SAAS,WAAW,EACpB,MAAM,UAAU,KACf,OAAO,CAAC,YAAY,CA8CtB,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,cAAc,EAAE,cAAc,EAAE,UAAU,CAQjF,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;AACtC,eAAO,MAAM,aAAa,YA/Df,WAAW,QACd,UAAU,KACf,OAAO,CAAC,YAAY,CA6DY,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolSample } from "gui-chat-protocol";
2
+ export declare const samples: ToolSample[];
3
+ //# sourceMappingURL=samples.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"samples.d.ts","sourceRoot":"","sources":["../../src/core/samples.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,eAAO,MAAM,OAAO,EAAE,UAAU,EAa/B,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { ToolResult } from "gui-chat-protocol";
2
+ export interface BrowseToolData {
3
+ url: string;
4
+ twitterEmbedHtml?: string | null;
5
+ }
6
+ export interface BrowseJsonData {
7
+ data: {
8
+ title?: string;
9
+ description?: string;
10
+ content?: string;
11
+ textContent?: string;
12
+ text?: string;
13
+ byline?: string;
14
+ excerpt?: string;
15
+ [key: string]: unknown;
16
+ };
17
+ [key: string]: unknown;
18
+ }
19
+ export interface BrowseArgs {
20
+ url: string;
21
+ }
22
+ export type BrowseResult = ToolResult<BrowseToolData, BrowseJsonData>;
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC"}
package/dist/core.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o="browse",c={type:"function",name:o,description:"Browse and extract content from a web page using the provided URL.",parameters:{type:"object",properties:{url:{type:"string",description:"The URL of the webpage to browse and extract content from"}},required:["url"]}},n={};function r(e){try{const a=new URL(e);return a.hostname==="twitter.com"||a.hostname==="www.twitter.com"||a.hostname==="x.com"||a.hostname==="www.x.com"}catch{return!1}}async function l(e,a){if(!r(e)||e in n)return;const t=await a.app?.getTwitterEmbed?.(e);t&&(n[e]=t)}const i=async(e,a)=>{const{url:t}=a;if(r(t)&&await l(t,e),!e.app?.browseUrl)return{message:"browseUrl function not available",instructions:"Acknowledge that the webpage browsing failed."};try{const s=await e.app.browseUrl(t);if(s.success&&s.data){const w={url:t,twitterEmbedHtml:r(t)?n[t]||null:void 0};return{message:"Successfully browsed the webpage",title:s.data.title||"Untitled",jsonData:{data:s.data},instructions:"Acknowledge that the webpage was successfully browsed and give a ONE-SENTENCE summary of the content if it is available.",data:w}}else return{message:s.error||"Failed to browse webpage",instructions:"Acknowledge that the webpage browsing failed."}}catch(s){return{message:`Failed to browse webpage: ${s instanceof Error?s.message:"Unknown error"}`,instructions:"Acknowledge that the webpage browsing failed."}}},b={toolDefinition:c,execute:i,generatingMessage:"Browsing webpage...",waitingMessage:"Tell the user to that you are accessing the specified web page.",isEnabled:()=>!0,delayAfterExecution:3e3,backends:["browse"]},g=i,d=[{name:"Wikipedia Article",args:{url:"https://en.wikipedia.org/wiki/Artificial_intelligence"}},{name:"News Article",args:{url:"https://www.bbc.com/news"}}];exports.TOOL_DEFINITION=c;exports.TOOL_NAME=o;exports.browse=i;exports.executeBrowse=g;exports.isTwitterUrl=r;exports.pluginCore=b;exports.samples=d;
package/dist/core.js ADDED
@@ -0,0 +1,92 @@
1
+ const c = "browse", w = {
2
+ type: "function",
3
+ name: c,
4
+ description: "Browse and extract content from a web page using the provided URL.",
5
+ parameters: {
6
+ type: "object",
7
+ properties: {
8
+ url: {
9
+ type: "string",
10
+ description: "The URL of the webpage to browse and extract content from"
11
+ }
12
+ },
13
+ required: ["url"]
14
+ }
15
+ }, r = {};
16
+ function n(e) {
17
+ try {
18
+ const a = new URL(e);
19
+ return a.hostname === "twitter.com" || a.hostname === "www.twitter.com" || a.hostname === "x.com" || a.hostname === "www.x.com";
20
+ } catch {
21
+ return !1;
22
+ }
23
+ }
24
+ async function l(e, a) {
25
+ if (!n(e) || e in r)
26
+ return;
27
+ const t = await a.app?.getTwitterEmbed?.(e);
28
+ t && (r[e] = t);
29
+ }
30
+ const i = async (e, a) => {
31
+ const { url: t } = a;
32
+ if (n(t) && await l(t, e), !e.app?.browseUrl)
33
+ return {
34
+ message: "browseUrl function not available",
35
+ instructions: "Acknowledge that the webpage browsing failed."
36
+ };
37
+ try {
38
+ const s = await e.app.browseUrl(t);
39
+ if (s.success && s.data) {
40
+ const o = {
41
+ url: t,
42
+ twitterEmbedHtml: n(t) ? r[t] || null : void 0
43
+ };
44
+ return {
45
+ message: "Successfully browsed the webpage",
46
+ title: s.data.title || "Untitled",
47
+ jsonData: { data: s.data },
48
+ instructions: "Acknowledge that the webpage was successfully browsed and give a ONE-SENTENCE summary of the content if it is available.",
49
+ data: o
50
+ };
51
+ } else
52
+ return {
53
+ message: s.error || "Failed to browse webpage",
54
+ instructions: "Acknowledge that the webpage browsing failed."
55
+ };
56
+ } catch (s) {
57
+ return {
58
+ message: `Failed to browse webpage: ${s instanceof Error ? s.message : "Unknown error"}`,
59
+ instructions: "Acknowledge that the webpage browsing failed."
60
+ };
61
+ }
62
+ }, b = {
63
+ toolDefinition: w,
64
+ execute: i,
65
+ generatingMessage: "Browsing webpage...",
66
+ waitingMessage: "Tell the user to that you are accessing the specified web page.",
67
+ isEnabled: () => !0,
68
+ delayAfterExecution: 3e3,
69
+ backends: ["browse"]
70
+ }, d = i, g = [
71
+ {
72
+ name: "Wikipedia Article",
73
+ args: {
74
+ url: "https://en.wikipedia.org/wiki/Artificial_intelligence"
75
+ }
76
+ },
77
+ {
78
+ name: "News Article",
79
+ args: {
80
+ url: "https://www.bbc.com/news"
81
+ }
82
+ }
83
+ ];
84
+ export {
85
+ w as TOOL_DEFINITION,
86
+ c as TOOL_NAME,
87
+ i as browse,
88
+ d as executeBrowse,
89
+ n as isTwitterUrl,
90
+ b as pluginCore,
91
+ g as samples
92
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs");exports.TOOL_DEFINITION=e.TOOL_DEFINITION;exports.TOOL_NAME=e.TOOL_NAME;exports.browse=e.browse;exports.executeBrowse=e.executeBrowse;exports.isTwitterUrl=e.isTwitterUrl;exports.pluginCore=e.pluginCore;exports.samples=e.samples;
@@ -0,0 +1,2 @@
1
+ export * from "./core";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { TOOL_DEFINITION as o, TOOL_NAME as s, browse as O, executeBrowse as t, isTwitterUrl as T, pluginCore as i, samples as l } from "./core.js";
2
+ export {
3
+ o as TOOL_DEFINITION,
4
+ s as TOOL_NAME,
5
+ O as browse,
6
+ t as executeBrowse,
7
+ T as isTwitterUrl,
8
+ i as pluginCore,
9
+ l as samples
10
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-blue-50:oklch(97% .014 254.604);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-bold:700;--leading-relaxed:1.625;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.flex{display:flex}.inline-block{display:inline-block}.h-8{height:calc(var(--spacing)*8)}.h-full{height:100%}.w-8{width:calc(var(--spacing)*8)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.animate-spin{animation:var(--animate-spin)}.items-center{align-items:center}.justify-center{justify-content:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-blue-200{border-color:var(--color-blue-200)}.border-blue-500{border-color:var(--color-blue-500)}.border-blue-600{border-color:var(--color-blue-600)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-white{background-color:var(--color-white)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-2{padding-block:calc(var(--spacing)*2)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-blue-600{color:var(--color-blue-600)}.text-blue-800{color:var(--color-blue-800)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-white{color:var(--color-white)}.italic{font-style:italic}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:underline:hover{text-decoration-line:underline}}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
@@ -0,0 +1,9 @@
1
+ import type { ToolResult } from "gui-chat-protocol";
2
+ import type { BrowseToolData } from "../core/types";
3
+ type __VLS_Props = {
4
+ result: ToolResult<BrowseToolData>;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ //# sourceMappingURL=Preview.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Preview.vue.d.ts","sourceRoot":"","sources":["../../src/vue/Preview.vue"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;CACpC,CAAC;AAwCF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,9 @@
1
+ import type { ToolResult } from "gui-chat-protocol";
2
+ import type { BrowseToolData, BrowseJsonData } from "../core/types";
3
+ type __VLS_Props = {
4
+ selectedResult: ToolResult<BrowseToolData, BrowseJsonData> | null;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ //# sourceMappingURL=View.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"View.vue.d.ts","sourceRoot":"","sources":["../../src/vue/View.vue"],"names":[],"mappings":"AA8IA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpE,KAAK,WAAW,GAAG;IACjB,cAAc,EAAE,UAAU,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,IAAI,CAAC;CACnE,CAAC;AAsOF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,15 @@
1
+ import "../style.css";
2
+ import type { ToolPlugin } from "gui-chat-protocol/vue";
3
+ import type { BrowseToolData, BrowseJsonData, BrowseArgs } from "../core/types";
4
+ import View from "./View.vue";
5
+ import Preview from "./Preview.vue";
6
+ export declare const plugin: ToolPlugin<BrowseToolData, BrowseJsonData, BrowseArgs>;
7
+ export type { BrowseToolData, BrowseJsonData, BrowseArgs } from "../core/types";
8
+ export { TOOL_NAME, TOOL_DEFINITION, executeBrowse, pluginCore, isTwitterUrl, } from "../core/plugin";
9
+ export { samples } from "../core/samples";
10
+ export { View, Preview };
11
+ declare const _default: {
12
+ plugin: ToolPlugin<BrowseToolData, BrowseJsonData, BrowseArgs, import("gui-chat-protocol/vue").InputHandler, Record<string, unknown>>;
13
+ };
14
+ export default _default;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhF,OAAO,IAAI,MAAM,YAAY,CAAC;AAC9B,OAAO,OAAO,MAAM,eAAe,CAAC;AAEpC,eAAO,MAAM,MAAM,EAAE,UAAU,CAAC,cAAc,EAAE,cAAc,EAAE,UAAU,CAKzE,CAAC;AAEF,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhF,OAAO,EACL,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,EACV,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;;;AAEzB,wBAA0B"}
package/dist/vue.cjs ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("./core.cjs"),e=require("vue"),v={class:"w-full h-full"},g={key:0,class:"overflow-auto p-4 bg-white h-full"},E=["innerHTML"],h={key:1,class:"h-full flex items-center justify-center"},k={class:"text-center"},f=["href"],_={key:2,class:"h-full flex items-center justify-center"},w={key:1,class:"w-full h-full overflow-auto p-6 bg-white"},y={class:"max-w-4xl mx-auto"},N={class:"mb-4 p-3 bg-blue-50 border border-blue-200 rounded"},B={class:"text-sm text-blue-800"},V=["href"],D={class:"text-3xl font-bold mb-3 text-gray-900"},T={key:0,class:"text-sm text-gray-600 mb-2"},R={key:1,class:"text-lg text-gray-700 mb-4 italic border-l-4 border-blue-500 pl-4"},j={class:"text-gray-800 leading-relaxed"},i=e.defineComponent({__name:"View",props:{selectedResult:{}},setup(t){const s=t,r=e.computed(()=>s.selectedResult?.jsonData?.data?.title||s.selectedResult?.title||"Untitled"),c=e.computed(()=>s.selectedResult?.jsonData?.data?.byline||""),d=e.computed(()=>s.selectedResult?.jsonData?.data?.excerpt||""),b=e.computed(()=>{const l=s.selectedResult?.jsonData,o=l?.data?.textContent||l?.data?.text;return o||"No content available."}),p=e.computed(()=>{const l=b.value;return l==="No content available."?[l]:(l.includes(`
2
+
3
+ `)?l.split(`
4
+
5
+ `):l.split(`
6
+ `)).map(a=>a.trim()).filter(a=>a.length>0)});return(l,o)=>(e.openBlock(),e.createElementBlock("div",v,[t.selectedResult?.data?.url&&e.unref(n.isTwitterUrl)(t.selectedResult.data.url)?(e.openBlock(),e.createElementBlock("div",g,[t.selectedResult.data.twitterEmbedHtml?(e.openBlock(),e.createElementBlock("div",{key:0,innerHTML:t.selectedResult.data.twitterEmbedHtml},null,8,E)):t.selectedResult.data.twitterEmbedHtml===null?(e.openBlock(),e.createElementBlock("div",h,[e.createElementVNode("div",k,[o[0]||(o[0]=e.createElementVNode("div",{class:"text-gray-600 mb-4"},"Unable to load Twitter embed",-1)),e.createElementVNode("a",{href:t.selectedResult.data.url,target:"_blank",class:"inline-block px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"}," Open on Twitter/X ",8,f)])])):(e.openBlock(),e.createElementBlock("div",_,[...o[1]||(o[1]=[e.createElementVNode("div",{class:"text-center"},[e.createElementVNode("div",{class:"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-2"}),e.createElementVNode("div",{class:"text-gray-600"},"Loading Twitter embed...")],-1)])]))])):e.createCommentVNode("",!0),t.selectedResult?.data?.url&&!e.unref(n.isTwitterUrl)(t.selectedResult.data.url)?(e.openBlock(),e.createElementBlock("div",w,[e.createElementVNode("div",y,[e.createElementVNode("div",N,[e.createElementVNode("div",B,[e.createElementVNode("a",{href:t.selectedResult.data.url,target:"_blank",class:"text-blue-600 hover:underline"}," Open original page → ",8,V)])]),e.createElementVNode("article",null,[e.createElementVNode("h1",D,e.toDisplayString(r.value),1),c.value?(e.openBlock(),e.createElementBlock("div",T," By "+e.toDisplayString(c.value),1)):e.createCommentVNode("",!0),d.value?(e.openBlock(),e.createElementBlock("div",R,e.toDisplayString(d.value),1)):e.createCommentVNode("",!0),e.createElementVNode("div",j,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(p.value,(a,x)=>(e.openBlock(),e.createElementBlock("div",{key:x,class:"mb-4"},e.toDisplayString(a),1))),128))])])])])):e.createCommentVNode("",!0)]))}}),C={class:"text-center p-4 bg-blue-50 rounded"},O={class:"text-xs text-gray-600 mt-1 truncate"},u=e.defineComponent({__name:"Preview",props:{result:{}},setup(t){return(s,r)=>(e.openBlock(),e.createElementBlock("div",C,[r[0]||(r[0]=e.createElementVNode("div",{class:"text-blue-600 font-medium"},"Web Page",-1)),e.createElementVNode("div",O,e.toDisplayString(t.result.title||t.result.data?.url),1)]))}}),m={...n.pluginCore,viewComponent:i,previewComponent:u,samples:n.samples},L={plugin:m};exports.TOOL_DEFINITION=n.TOOL_DEFINITION;exports.TOOL_NAME=n.TOOL_NAME;exports.executeBrowse=n.executeBrowse;exports.isTwitterUrl=n.isTwitterUrl;exports.pluginCore=n.pluginCore;exports.samples=n.samples;exports.Preview=u;exports.View=i;exports.default=L;exports.plugin=m;
package/dist/vue.js ADDED
@@ -0,0 +1,115 @@
1
+ import { isTwitterUrl as x, samples as w, pluginCore as p } from "./core.js";
2
+ import { TOOL_DEFINITION as K, TOOL_NAME as Q, executeBrowse as Y } from "./core.js";
3
+ import { defineComponent as h, computed as d, createElementBlock as l, openBlock as n, createCommentVNode as u, unref as v, createElementVNode as e, toDisplayString as i, Fragment as y, renderList as R } from "vue";
4
+ const j = { class: "w-full h-full" }, k = {
5
+ key: 0,
6
+ class: "overflow-auto p-4 bg-white h-full"
7
+ }, D = ["innerHTML"], T = {
8
+ key: 1,
9
+ class: "h-full flex items-center justify-center"
10
+ }, C = { class: "text-center" }, E = ["href"], N = {
11
+ key: 2,
12
+ class: "h-full flex items-center justify-center"
13
+ }, O = {
14
+ key: 1,
15
+ class: "w-full h-full overflow-auto p-6 bg-white"
16
+ }, L = { class: "max-w-4xl mx-auto" }, B = { class: "mb-4 p-3 bg-blue-50 border border-blue-200 rounded" }, H = { class: "text-sm text-blue-800" }, V = ["href"], I = { class: "text-3xl font-bold mb-3 text-gray-900" }, M = {
17
+ key: 0,
18
+ class: "text-sm text-gray-600 mb-2"
19
+ }, P = {
20
+ key: 1,
21
+ class: "text-lg text-gray-700 mb-4 italic border-l-4 border-blue-500 pl-4"
22
+ }, U = { class: "text-gray-800 leading-relaxed" }, $ = /* @__PURE__ */ h({
23
+ __name: "View",
24
+ props: {
25
+ selectedResult: {}
26
+ },
27
+ setup(t) {
28
+ const o = t, c = d(() => o.selectedResult?.jsonData?.data?.title || o.selectedResult?.title || "Untitled"), m = d(() => o.selectedResult?.jsonData?.data?.byline || ""), b = d(() => o.selectedResult?.jsonData?.data?.excerpt || ""), f = d(() => {
29
+ const s = o.selectedResult?.jsonData, a = s?.data?.textContent || s?.data?.text;
30
+ return a || "No content available.";
31
+ }), g = d(() => {
32
+ const s = f.value;
33
+ return s === "No content available." ? [s] : (s.includes(`
34
+
35
+ `) ? s.split(`
36
+
37
+ `) : s.split(`
38
+ `)).map((r) => r.trim()).filter((r) => r.length > 0);
39
+ });
40
+ return (s, a) => (n(), l("div", j, [
41
+ t.selectedResult?.data?.url && v(x)(t.selectedResult.data.url) ? (n(), l("div", k, [
42
+ t.selectedResult.data.twitterEmbedHtml ? (n(), l("div", {
43
+ key: 0,
44
+ innerHTML: t.selectedResult.data.twitterEmbedHtml
45
+ }, null, 8, D)) : t.selectedResult.data.twitterEmbedHtml === null ? (n(), l("div", T, [
46
+ e("div", C, [
47
+ a[0] || (a[0] = e("div", { class: "text-gray-600 mb-4" }, "Unable to load Twitter embed", -1)),
48
+ e("a", {
49
+ href: t.selectedResult.data.url,
50
+ target: "_blank",
51
+ class: "inline-block px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
52
+ }, " Open on Twitter/X ", 8, E)
53
+ ])
54
+ ])) : (n(), l("div", N, [...a[1] || (a[1] = [
55
+ e("div", { class: "text-center" }, [
56
+ e("div", { class: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-2" }),
57
+ e("div", { class: "text-gray-600" }, "Loading Twitter embed...")
58
+ ], -1)
59
+ ])]))
60
+ ])) : u("", !0),
61
+ t.selectedResult?.data?.url && !v(x)(t.selectedResult.data.url) ? (n(), l("div", O, [
62
+ e("div", L, [
63
+ e("div", B, [
64
+ e("div", H, [
65
+ e("a", {
66
+ href: t.selectedResult.data.url,
67
+ target: "_blank",
68
+ class: "text-blue-600 hover:underline"
69
+ }, " Open original page → ", 8, V)
70
+ ])
71
+ ]),
72
+ e("article", null, [
73
+ e("h1", I, i(c.value), 1),
74
+ m.value ? (n(), l("div", M, " By " + i(m.value), 1)) : u("", !0),
75
+ b.value ? (n(), l("div", P, i(b.value), 1)) : u("", !0),
76
+ e("div", U, [
77
+ (n(!0), l(y, null, R(g.value, (r, _) => (n(), l("div", {
78
+ key: _,
79
+ class: "mb-4"
80
+ }, i(r), 1))), 128))
81
+ ])
82
+ ])
83
+ ])
84
+ ])) : u("", !0)
85
+ ]));
86
+ }
87
+ }), F = { class: "text-center p-4 bg-blue-50 rounded" }, A = { class: "text-xs text-gray-600 mt-1 truncate" }, S = /* @__PURE__ */ h({
88
+ __name: "Preview",
89
+ props: {
90
+ result: {}
91
+ },
92
+ setup(t) {
93
+ return (o, c) => (n(), l("div", F, [
94
+ c[0] || (c[0] = e("div", { class: "text-blue-600 font-medium" }, "Web Page", -1)),
95
+ e("div", A, i(t.result.title || t.result.data?.url), 1)
96
+ ]));
97
+ }
98
+ }), W = {
99
+ ...p,
100
+ viewComponent: $,
101
+ previewComponent: S,
102
+ samples: w
103
+ }, z = { plugin: W };
104
+ export {
105
+ S as Preview,
106
+ K as TOOL_DEFINITION,
107
+ Q as TOOL_NAME,
108
+ $ as View,
109
+ z as default,
110
+ Y as executeBrowse,
111
+ x as isTwitterUrl,
112
+ W as plugin,
113
+ p as pluginCore,
114
+ w as samples
115
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@gui-chat-plugin/browse",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Web browsing plugin for GUI Chat applications",
6
+ "author": "snakajima",
7
+ "license": "MIT",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./vue": {
18
+ "types": "./dist/vue/index.d.ts",
19
+ "import": "./dist/vue.js",
20
+ "require": "./dist/vue.cjs"
21
+ },
22
+ "./style.css": "./dist/style.css"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "dev": "vite",
29
+ "build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
30
+ "typecheck": "vue-tsc --noEmit",
31
+ "lint": "eslint src"
32
+ },
33
+ "dependencies": {
34
+ "gui-chat-protocol": "^0.0.1"
35
+ },
36
+ "devDependencies": {
37
+ "@tailwindcss/vite": "^4.1.0",
38
+ "@vitejs/plugin-vue": "^6.0.0",
39
+ "eslint": "^9.0.0",
40
+ "tailwindcss": "^4.1.0",
41
+ "typescript": "^5.8.0",
42
+ "vite": "^7.0.0",
43
+ "vue": "^3.5.0",
44
+ "vue-tsc": "^3.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "vue": "^3.5.0"
48
+ }
49
+ }