@usecrow/client 0.1.36 → 0.1.38

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/dist/browser.cjs CHANGED
@@ -1 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("./PageController-BDcmu8Xe.cjs"),e=require("./browserUse-BjeJDX8x.cjs");e.setPageController(u.PageController);let o=null;function a(){o&&(console.log("[Crow] Stopping active browser-use automation"),o.stop(),o=null)}function c(t,l){return async n=>{const s=n.instruction||n.instruction;if(!s)return{status:"error",error:"Missing instruction parameter for browser_use tool"};const w=window.__crow_browser_callbacks,r=l||w,i=new e.CrowBrowserUse({productId:t.productId,apiUrl:t.apiUrl,onConfirmation:r==null?void 0:r.onConfirmation,onQuestion:r==null?void 0:r.onQuestion,onProgress:r==null?void 0:r.onProgress});o=i;try{return await i.execute(s)}finally{o=null}}}exports.PageController=u.PageController;exports.CrowBrowserUse=e.CrowBrowserUse;exports.createBrowserUseTool=c;exports.stopActiveBrowserUse=a;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("./PageController-Cu6KUkcn.cjs"),i=require("./workflowExecutor-BUc7WzWF.cjs");i.setPageController(p.PageController);let w=null;function f(){w&&(console.log("[Crow] Stopping active browser-use automation"),w.stop(),w=null)}function _(c,a){return async n=>{const u=n.instruction||n.instruction;if(!u)return{status:"error",error:"Missing instruction parameter for browser_use tool"};const t=window.__crow_browser_callbacks,o=a||t,l=new i.CrowBrowserUse({productId:c.productId,apiUrl:c.apiUrl,onConfirmation:o==null?void 0:o.onConfirmation,onQuestion:o==null?void 0:o.onQuestion,onProgress:o==null?void 0:o.onProgress});w=l;try{return await l.execute(u)}finally{w=null}}}function m(c){return async a=>{const n=a.workflow_name||a.workflow_name,u=a.inputs||a.inputs||{};if(!n)return{status:"error",error:"Missing workflow_name parameter for execute_recorded_workflow tool"};console.log(`[Crow] execute_recorded_workflow: Looking up "${n}"...`);try{const t=await fetch(`${c.apiUrl}/api/products/${c.productId}/recorded-workflows`);if(!t.ok)return{status:"error",error:`Failed to fetch recorded workflows: HTTP ${t.status}`};const o=await t.json(),l=o.find(s=>s.name.toLowerCase()===n.toLowerCase()&&s.enabled);if(!l){const s=o.filter(r=>r.enabled).map(r=>r.name);return{status:"error",error:`Workflow "${n}" not found. Available workflows: ${s.join(", ")||"none"}`}}console.log(`[Crow] execute_recorded_workflow: Found "${l.name}" with ${l.steps.length} steps`);const d=new p.PageController;await d.updateTree();const e=await new i.WorkflowExecutor(d,{waitTimeout:5e3,pollInterval:300,stepDelay:500,stopOnFailure:!0,onStepProgress:s=>{const r=s.success?"OK":"FAILED";console.log(`[Crow] Workflow step ${s.step_index+1}: [${r}] ${s.description}`)}}).execute(l,u);if(e.success)return{status:"success",data:{workflow_name:e.workflow_name,total_steps:e.total_steps,completed_steps:e.completed_steps,message:`Workflow "${e.workflow_name}" completed successfully (${e.completed_steps}/${e.total_steps} steps)`}};{const s=e.step_results.filter(r=>!r.success).map(r=>`Step ${r.step_index+1} (${r.step_type}): ${r.message}`);return{status:"error",error:`Workflow "${e.workflow_name}" failed. ${e.completed_steps}/${e.total_steps} steps completed. Failures:
2
+ ${s.join(`
3
+ `)}`}}}catch(t){return console.error("[Crow] execute_recorded_workflow error:",t),{status:"error",error:`Workflow execution error: ${t instanceof Error?t.message:String(t)}`}}}}exports.PageController=p.PageController;exports.CrowBrowserUse=i.CrowBrowserUse;exports.createBrowserUseTool=_;exports.createExecuteRecordedWorkflowTool=m;exports.stopActiveBrowserUse=f;
package/dist/browser.d.ts CHANGED
@@ -69,6 +69,20 @@ declare function cleanUpHighlights(): void;
69
69
  */
70
70
  export declare function createBrowserUseTool(config: BrowserUseToolConfig, callbacks?: BrowserUseCallbacks): (args: BrowserUseToolArgs | Record<string, unknown>) => Promise<ToolResult>;
71
71
 
72
+ /**
73
+ * Create an execute_recorded_workflow tool handler for registration with CrowClient or widget.
74
+ *
75
+ * When the LLM calls this tool, the handler:
76
+ * 1. Fetches the workflow definition from the backend API (by name)
77
+ * 2. Creates a PageController and WorkflowExecutor
78
+ * 3. Executes the workflow steps deterministically (no LLM calls)
79
+ * 4. Returns the result
80
+ *
81
+ * @param config - Configuration with productId and apiUrl
82
+ * @returns Async function that executes recorded workflows
83
+ */
84
+ export declare function createExecuteRecordedWorkflowTool(config: BrowserUseToolConfig): (args: ExecuteRecordedWorkflowToolArgs | Record<string, unknown>) => Promise<ToolResult>;
85
+
72
86
  export declare class CrowBrowserUse {
73
87
  private config;
74
88
  private pageController;
@@ -143,6 +157,11 @@ declare interface ElementDomNode {
143
157
  [key: string]: unknown;
144
158
  }
145
159
 
160
+ export declare interface ExecuteRecordedWorkflowToolArgs {
161
+ workflow_name: string;
162
+ inputs?: Record<string, string | number | boolean>;
163
+ }
164
+
146
165
  /**
147
166
  * Derived from @page-agent/page-controller
148
167
  * Original: https://github.com/alibaba/page-agent
@@ -301,6 +320,71 @@ export declare class PageController extends EventTarget {
301
320
  * Execute arbitrary JavaScript on the page
302
321
  */
303
322
  executeJavascript(script: string): Promise<ActionResult>;
323
+ /**
324
+ * Find an interactive element index by visible text (exact match).
325
+ * Scans the elementTextMap for a match.
326
+ */
327
+ findElementByText(text: string, exact?: boolean): number | null;
328
+ /**
329
+ * Find an interactive element index by CSS selector.
330
+ * Queries the DOM, then reverse-looks up in selectorMap.
331
+ */
332
+ findElementBySelector(cssSelector: string): number | null;
333
+ /**
334
+ * Find an interactive element index by XPath.
335
+ * Evaluates the XPath, then reverse-looks up in selectorMap.
336
+ */
337
+ findElementByXPath(xpath: string): number | null;
338
+ /**
339
+ * Find an interactive element index by aria-label attribute.
340
+ */
341
+ findElementByAriaLabel(label: string): number | null;
342
+ /**
343
+ * Find an interactive element index by placeholder text.
344
+ */
345
+ findElementByPlaceholder(placeholder: string): number | null;
346
+ /**
347
+ * Multi-strategy element finder. Tries strategies in priority order.
348
+ * Returns the index of the first match, or null if nothing found.
349
+ */
350
+ findElementByStrategies(strategies: Array<{
351
+ type: 'text_exact' | 'text_contains' | 'aria_label' | 'placeholder' | 'css' | 'xpath';
352
+ value: string;
353
+ priority: number;
354
+ }>): number | null;
355
+ /**
356
+ * Press a key on an element (or the active element if no index provided).
357
+ */
358
+ pressKey(key: string, index?: number): Promise<ActionResult>;
359
+ /**
360
+ * Navigate to a URL. Restricts to same-origin http(s) URLs for security.
361
+ */
362
+ navigateToUrl(url: string): Promise<ActionResult>;
363
+ /**
364
+ * Go back in browser history.
365
+ */
366
+ goBack(): Promise<ActionResult>;
367
+ /**
368
+ * Go forward in browser history.
369
+ */
370
+ goForward(): Promise<ActionResult>;
371
+ /**
372
+ * Wait until an element matching the given strategies appears in the DOM,
373
+ * or until the timeout is reached. Refreshes the DOM tree on each poll.
374
+ */
375
+ waitForElement(strategies: Array<{
376
+ type: 'text_exact' | 'text_contains' | 'aria_label' | 'placeholder' | 'css' | 'xpath';
377
+ value: string;
378
+ priority: number;
379
+ }>, timeoutMs?: number, pollIntervalMs?: number): Promise<number | null>;
380
+ /**
381
+ * Get the current selectorMap (for external use like WorkflowExecutor).
382
+ */
383
+ getSelectorMap(): Map<number, InteractiveElementDomNode>;
384
+ /**
385
+ * Get the current elementTextMap (for external use like WorkflowExecutor).
386
+ */
387
+ getElementTextMap(): Map<number, string>;
304
388
  /**
305
389
  * Show the visual mask overlay.
306
390
  * Only works after mask is setup.
package/dist/browser.js CHANGED
@@ -1,36 +1,107 @@
1
- import { PageController as l } from "./PageController-BweWYS-Z.js";
2
- import { C as w, s as a } from "./browserUse-Btg7osSj.js";
3
- a(l);
4
- let r = null;
5
- function m() {
6
- r && (console.log("[Crow] Stopping active browser-use automation"), r.stop(), r = null);
1
+ import { PageController as p } from "./PageController-D3uwrwlG.js";
2
+ import { C as d, W as f, s as m } from "./workflowExecutor-DgghvBIA.js";
3
+ m(p);
4
+ let w = null;
5
+ function x() {
6
+ w && (console.log("[Crow] Stopping active browser-use automation"), w.stop(), w = null);
7
7
  }
8
- function U(n, i) {
9
- return async (t) => {
10
- const s = t.instruction || t.instruction;
11
- if (!s)
8
+ function g(c, a) {
9
+ return async (n) => {
10
+ const u = n.instruction || n.instruction;
11
+ if (!u)
12
12
  return {
13
13
  status: "error",
14
14
  error: "Missing instruction parameter for browser_use tool"
15
15
  };
16
- const u = window.__crow_browser_callbacks, o = i || u, e = new w({
17
- productId: n.productId,
18
- apiUrl: n.apiUrl,
16
+ const t = window.__crow_browser_callbacks, o = a || t, l = new d({
17
+ productId: c.productId,
18
+ apiUrl: c.apiUrl,
19
19
  onConfirmation: o == null ? void 0 : o.onConfirmation,
20
20
  onQuestion: o == null ? void 0 : o.onQuestion,
21
21
  onProgress: o == null ? void 0 : o.onProgress
22
22
  });
23
- r = e;
23
+ w = l;
24
24
  try {
25
- return await e.execute(s);
25
+ return await l.execute(u);
26
26
  } finally {
27
- r = null;
27
+ w = null;
28
+ }
29
+ };
30
+ }
31
+ function C(c) {
32
+ return async (a) => {
33
+ const n = a.workflow_name || a.workflow_name, u = a.inputs || a.inputs || {};
34
+ if (!n)
35
+ return {
36
+ status: "error",
37
+ error: "Missing workflow_name parameter for execute_recorded_workflow tool"
38
+ };
39
+ console.log(`[Crow] execute_recorded_workflow: Looking up "${n}"...`);
40
+ try {
41
+ const t = await fetch(
42
+ `${c.apiUrl}/api/products/${c.productId}/recorded-workflows`
43
+ );
44
+ if (!t.ok)
45
+ return {
46
+ status: "error",
47
+ error: `Failed to fetch recorded workflows: HTTP ${t.status}`
48
+ };
49
+ const o = await t.json(), l = o.find(
50
+ (s) => s.name.toLowerCase() === n.toLowerCase() && s.enabled
51
+ );
52
+ if (!l) {
53
+ const s = o.filter((r) => r.enabled).map((r) => r.name);
54
+ return {
55
+ status: "error",
56
+ error: `Workflow "${n}" not found. Available workflows: ${s.join(", ") || "none"}`
57
+ };
58
+ }
59
+ console.log(`[Crow] execute_recorded_workflow: Found "${l.name}" with ${l.steps.length} steps`);
60
+ const i = new p();
61
+ await i.updateTree();
62
+ const e = await new f(i, {
63
+ waitTimeout: 5e3,
64
+ pollInterval: 300,
65
+ stepDelay: 500,
66
+ stopOnFailure: !0,
67
+ onStepProgress: (s) => {
68
+ const r = s.success ? "OK" : "FAILED";
69
+ console.log(
70
+ `[Crow] Workflow step ${s.step_index + 1}: [${r}] ${s.description}`
71
+ );
72
+ }
73
+ }).execute(l, u);
74
+ if (e.success)
75
+ return {
76
+ status: "success",
77
+ data: {
78
+ workflow_name: e.workflow_name,
79
+ total_steps: e.total_steps,
80
+ completed_steps: e.completed_steps,
81
+ message: `Workflow "${e.workflow_name}" completed successfully (${e.completed_steps}/${e.total_steps} steps)`
82
+ }
83
+ };
84
+ {
85
+ const s = e.step_results.filter((r) => !r.success).map((r) => `Step ${r.step_index + 1} (${r.step_type}): ${r.message}`);
86
+ return {
87
+ status: "error",
88
+ error: `Workflow "${e.workflow_name}" failed. ${e.completed_steps}/${e.total_steps} steps completed. Failures:
89
+ ${s.join(`
90
+ `)}`
91
+ };
92
+ }
93
+ } catch (t) {
94
+ return console.error("[Crow] execute_recorded_workflow error:", t), {
95
+ status: "error",
96
+ error: `Workflow execution error: ${t instanceof Error ? t.message : String(t)}`
97
+ };
28
98
  }
29
99
  };
30
100
  }
31
101
  export {
32
- w as CrowBrowserUse,
33
- l as PageController,
34
- U as createBrowserUseTool,
35
- m as stopActiveBrowserUse
102
+ d as CrowBrowserUse,
103
+ p as PageController,
104
+ g as createBrowserUseTool,
105
+ C as createExecuteRecordedWorkflowTool,
106
+ x as stopActiveBrowserUse
36
107
  };
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("./browserUse-BjeJDX8x.cjs");class _{constructor(){this.state={token:null,metadata:{},isVerified:!1},this.listeners=new Set}identify(e){const{token:t,...s}=e;this.state={token:t,metadata:s,isVerified:!1},this.notify(),console.log("[Crow] User identified")}setVerified(e){this.state={...this.state,isVerified:e},this.notify()}reset(){this.state={token:null,metadata:{},isVerified:!1},this.notify(),console.log("[Crow] User reset")}getToken(){return this.state.token}getState(){return{...this.state}}isIdentified(){return this.state.token!==null}isVerified(){return this.state.isVerified}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){const e=this.getState();for(const t of this.listeners)t(e)}}class k{constructor(){this.handlers={}}register(e){for(const[t,s]of Object.entries(e))typeof s=="function"?(this.handlers[t]=s,console.log(`[Crow] Registered client tool: ${t}`)):console.warn(`[Crow] Skipping ${t}: handler is not a function`)}unregister(e){delete this.handlers[e],console.log(`[Crow] Unregistered client tool: ${e}`)}has(e){return e in this.handlers}getRegisteredTools(){return Object.keys(this.handlers)}async execute(e,t){const s=this.handlers[e];if(!s)return console.warn(`[Crow] No handler registered for tool: ${e}`),{status:"error",error:`No handler registered for tool: ${e}`};try{console.log(`[Crow] Executing client tool: ${e}`,t);const r=await s(t);return console.log(`[Crow] Tool ${e} completed:`,r),r}catch(r){const n=r instanceof Error?r.message:String(r);return console.error(`[Crow] Tool ${e} failed:`,r),{status:"error",error:n}}}}const E="crow_conv_";class v{constructor(e,t){this.currentId=null,this.productId=e,this.apiUrl=t,this.currentId=this.loadFromStorage()}getStorageKey(){return`${E}${this.productId}`}loadFromStorage(){try{return localStorage.getItem(this.getStorageKey())}catch{return null}}saveToStorage(e){try{localStorage.setItem(this.getStorageKey(),e)}catch{}}clearStorage(){try{localStorage.removeItem(this.getStorageKey())}catch{}}getCurrentId(){return this.currentId}setCurrentId(e){this.currentId=e,e?this.saveToStorage(e):this.clearStorage()}hasRestoredConversation(){return this.currentId!==null}clear(){this.currentId=null,this.clearStorage()}async getConversations(e){try{const t=await fetch(`${this.apiUrl}/api/chat/conversations?product_id=${this.productId}&identity_token=${encodeURIComponent(e)}`);if(!t.ok)throw new Error(`HTTP error: ${t.status}`);return(await t.json()).conversations||[]}catch(t){return console.error("[Crow] Failed to load conversations:",t),[]}}async loadHistory(e,t){try{const s=await fetch(`${this.apiUrl}/api/chat/conversations/${e}/history?product_id=${this.productId}&identity_token=${encodeURIComponent(t)}`);if(!s.ok)throw new Error(`HTTP error: ${s.status}`);const r=await s.json();return this.parseHistoryMessages(r.messages||[])}catch(s){return console.error("[Crow] Failed to load conversation history:",s),[]}}async loadAnonymousHistory(e){try{const t=await fetch(`${this.apiUrl}/api/chat/conversations/${e}/history/anonymous?product_id=${this.productId}`);if(!t.ok)throw new Error(`HTTP error: ${t.status}`);const s=await t.json();return this.parseHistoryMessages(s.messages||[])}catch(t){return console.error("[Crow] Failed to load anonymous conversation history:",t),[]}}parseHistoryMessages(e){return e.filter(t=>t.role!=="tool"&&!t.content.startsWith("[Client Tool Result:")).map((t,s)=>({id:`history-${s}`,content:this.parseContent(t.content),role:t.role==="assistant"?"assistant":"user",timestamp:new Date}))}parseContent(e){try{const t=JSON.parse(e);if(Array.isArray(t)){const s=t.find(r=>r.type==="text");return(s==null?void 0:s.text)||e}}catch{}if(e.includes("'type': 'text'")){const t=e.match(/\{'text':\s*'((?:[^'\\]|\\.)*)'\s*,\s*'type':\s*'text'/);if(t)return t[1].replace(/\\n/g,`
2
- `).replace(/\\'/g,"'")}return e}}function C(o){if(o==="[DONE]")return{type:"done"};try{const e=JSON.parse(o);switch(e.type){case"verification_status":return{type:"verification_status",isVerified:e.is_verified===!0};case"conversation_id":return{type:"conversation_id",conversationId:e.conversation_id};case"thinking":return e.status==="complete"?{type:"thinking_complete"}:null;case"thinking_token":return{type:"thinking",content:e.content||""};case"content":return{type:"content",text:e.content||"",accumulated:""};case"citations":return{type:"citations",citations:e.citations};case"error":return{type:"error",message:e.message||"Unknown error"};case"tool_call_start":return{type:"tool_call_start",toolName:e.tool_name,displayName:e.display_name||void 0,arguments:e.arguments||{}};case"tool_call_complete":return{type:"tool_call_complete",toolName:e.tool_name,displayName:e.display_name||void 0,success:e.success};case"client_tool_call":return{type:"client_tool_call",toolName:e.tool_name,displayName:e.display_name||void 0,arguments:e.arguments||{}};case"workflow_started":return{type:"workflow_started",name:e.name,todos:e.todos};case"todo_updated":return{type:"workflow_todo_updated",todoId:e.id,status:e.status};case"workflow_ended":return{type:"workflow_ended"};case"workflow_complete_prompt":return{type:"workflow_complete_prompt"};default:return null}}catch{return console.error("[Crow] Failed to parse SSE data:",o),null}}function*b(o){const e=o.split(`
3
- `);for(const t of e)t.startsWith("data: ")&&(yield t.slice(6).trim())}async function*M(o,e){var n;const t=(n=o.body)==null?void 0:n.getReader();if(!t)throw new Error("Response body is not readable");const s=new TextDecoder;let r="";try{for(;;){if(e!=null&&e.aborted){t.cancel();return}const{done:i,value:d}=await t.read();if(i)break;const h=s.decode(d);for(const u of b(h)){const l=C(u);if(l&&(l.type==="content"?(r+=l.text,yield{...l,accumulated:r}):yield l,l.type==="done"))return}}}finally{t.releaseLock()}}async function L(){try{return window.location.reload(),{status:"success",data:{refreshed:!0}}}catch(o){return{status:"error",error:o instanceof Error?o.message:"Failed to refresh page"}}}async function $(){var o;try{const e=document.title,t=window.location.href,s=window.location.pathname,r=(((o=document.body)==null?void 0:o.innerText)||"").slice(0,2e3).trim();return{status:"success",data:{title:e,url:t,pathname:s,visibleText:r}}}catch(e){return{status:"error",error:e instanceof Error?e.message:"Failed to read screen"}}}const g={refreshPage:L,whatsOnScreen:$},S=Object.keys(g),U="https://api.usecrow.org",x="claude-sonnet-4-20250514";class O{constructor(e){this.context={},this.abortController=null,this.callbacks={},this._messages=[],this.messageListeners=new Set,this._isLoading=!1,this.loadingListeners=new Set,this.config={productId:e.productId,apiUrl:e.apiUrl||U,model:e.model||x},this.identity=new _,this.tools=new k,this.conversations=new v(this.config.productId,this.config.apiUrl),this.tools.register(g),console.log("[Crow] Default tools registered:",S.join(", ")),this.identity.subscribe(t=>{var s,r;(r=(s=this.callbacks).onVerificationStatus)==null||r.call(s,t.isVerified)})}get productId(){return this.config.productId}get apiUrl(){return this.config.apiUrl}get model(){return this.config.model}set model(e){this.config.model=e}on(e){this.callbacks={...this.callbacks,...e}}identify(e){this.identity.identify(e)}resetUser(){this.identity.reset(),this.clearMessages()}isIdentified(){return this.identity.isIdentified()}isVerified(){return this.identity.isVerified()}registerTools(e){this.tools.register(e)}unregisterTool(e){this.tools.unregister(e)}getRegisteredTools(){return this.tools.getRegisteredTools()}setContext(e){this.context={...this.context,...e}}clearContext(){this.context={}}get messages(){return[...this._messages]}get isLoading(){return this._isLoading}onMessages(e){return this.messageListeners.add(e),()=>this.messageListeners.delete(e)}onLoading(e){return this.loadingListeners.add(e),()=>this.loadingListeners.delete(e)}clearMessages(){this._messages=[],this.conversations.clear(),this.notifyMessages()}loadMessages(e){this._messages=e,this.notifyMessages()}notifyMessages(){const e=this.messages;for(const t of this.messageListeners)t(e)}setLoading(e){this._isLoading=e;for(const t of this.loadingListeners)t(e)}addMessage(e){var t,s;this._messages=[...this._messages,e],this.notifyMessages(),(s=(t=this.callbacks).onMessage)==null||s.call(t,e)}updateMessage(e,t){var s,r;this._messages=this._messages.map(n=>n.id===e?{...n,...t}:n),this.notifyMessages(),(r=(s=this.callbacks).onMessageUpdate)==null||r.call(s,e,t)}generateMessageId(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`}get conversationId(){return this.conversations.getCurrentId()}set conversationId(e){this.conversations.setCurrentId(e)}async getConversations(){const e=this.identity.getToken();return e?this.conversations.getConversations(e):(console.warn("[Crow] Cannot get conversations: user not identified"),[])}async loadHistory(e){const t=this.identity.getToken();return t?this.conversations.loadHistory(e,t):this.conversations.loadAnonymousHistory(e)}async switchConversation(e){const t=await this.loadHistory(e);this.conversations.setCurrentId(e),this.loadMessages(t)}async*sendMessage(e){var i,d,h,u,l,f,p,y,m,w;if(!e.trim())return;const t=this.generateMessageId("user");this.addMessage({id:t,content:e,role:"user",timestamp:new Date});const s=this.generateMessageId("assistant");this.addMessage({id:s,content:"",role:"assistant",timestamp:new Date}),this.setLoading(!0),this.abortController=new AbortController;let r="",n="";try{const c=await fetch(`${this.config.apiUrl}/api/chat/message`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({product_id:this.config.productId,message:e,conversation_id:this.conversations.getCurrentId(),identity_token:this.identity.getToken(),model:this.config.model,context:Object.keys(this.context).length>0?this.context:void 0}),signal:this.abortController.signal});if(!c.ok)throw new Error(`HTTP error: ${c.status}`);for await(const a of M(c,this.abortController.signal)){switch(a.type){case"content":r=a.accumulated,this.updateMessage(s,{content:r});break;case"thinking":n+=a.content,this.updateMessage(s,{thinking:n});break;case"thinking_complete":this.updateMessage(s,{thinkingComplete:!0});break;case"citations":this.updateMessage(s,{citations:a.citations});break;case"verification_status":this.identity.setVerified(a.isVerified);break;case"conversation_id":this.conversations.setCurrentId(a.conversationId);break;case"client_tool_call":await this.tools.execute(a.toolName,a.arguments),(d=(i=this.callbacks).onToolCall)==null||d.call(i,a);break;case"tool_call_start":case"tool_call_complete":(u=(h=this.callbacks).onToolCall)==null||u.call(h,a);break;case"workflow_started":case"workflow_todo_updated":case"workflow_ended":case"workflow_complete_prompt":(f=(l=this.callbacks).onWorkflow)==null||f.call(l,a);break;case"error":this.updateMessage(s,{content:a.message}),(y=(p=this.callbacks).onError)==null||y.call(p,new Error(a.message));break}yield a}}catch(c){if(c instanceof Error&&c.name==="AbortError"){r?this.updateMessage(s,{content:r}):(this._messages=this._messages.filter(a=>a.id!==s),this.notifyMessages());return}console.error("[Crow] Error:",c),this.updateMessage(s,{content:"Sorry, I encountered an error. Please try again."}),(w=(m=this.callbacks).onError)==null||w.call(m,c instanceof Error?c:new Error(String(c)))}finally{this.setLoading(!1),this.abortController=null}}async send(e){let t=null;for await(const r of this.sendMessage(e))if(r.type==="done")break;const s=this.messages;return s.length>0&&(t=s[s.length-1],t.role==="assistant")?t:null}stop(){this.abortController&&(this.abortController.abort(),this.setLoading(!1))}destroy(){this.stop(),this.messageListeners.clear(),this.loadingListeners.clear()}}function T(o,e,t){const s=o.find(n=>n.name.toLowerCase()===e.toLowerCase());if(!s)return null;let r=s.path;if(t)for(const[n,i]of Object.entries(t))r=r.replace(`:${n}`,String(i));return r}function A(o,e){return async t=>{try{const s=t.page,r=t.params,n=t.url;let i=null;if(s){if(i=T(o,s,r),!i)return{status:"error",error:`Unknown page: "${s}". Available pages: ${o.map(h=>h.name).join(", ")}`}}else if(n)i=n;else return{status:"error",error:'Either "page" or "url" parameter is required'};const d=i.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return d?{status:"error",error:`Missing parameters: ${d.join(", ")}. Please provide values for these parameters.`}:e?(e(i),{status:"success",data:{navigated_to:i,page:s||void 0,method:"spa_router"}}):(window.location.href=i,{status:"success",data:{navigated_to:i,page:s||void 0,method:"full_navigation"}})}catch(s){return{status:"error",error:String(s)}}}}exports.CrowBrowserUse=I.CrowBrowserUse;exports.ConversationManager=v;exports.CrowClient=O;exports.DEFAULT_TOOLS=g;exports.DEFAULT_TOOL_NAMES=S;exports.IdentityManager=_;exports.ToolManager=k;exports.createNavigateToPageTool=A;exports.parseSSEChunk=b;exports.parseSSEData=C;exports.resolveRoute=T;exports.streamResponse=M;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./workflowExecutor-BUc7WzWF.cjs");class k{constructor(){this.state={token:null,metadata:{},isVerified:!1},this.listeners=new Set}identify(e){const{token:t,...s}=e;this.state={token:t,metadata:s,isVerified:!1},this.notify(),console.log("[Crow] User identified")}setVerified(e){this.state={...this.state,isVerified:e},this.notify()}reset(){this.state={token:null,metadata:{},isVerified:!1},this.notify(),console.log("[Crow] User reset")}getToken(){return this.state.token}getState(){return{...this.state}}isIdentified(){return this.state.token!==null}isVerified(){return this.state.isVerified}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){const e=this.getState();for(const t of this.listeners)t(e)}}class v{constructor(){this.handlers={}}register(e){for(const[t,s]of Object.entries(e))typeof s=="function"?(this.handlers[t]=s,console.log(`[Crow] Registered client tool: ${t}`)):console.warn(`[Crow] Skipping ${t}: handler is not a function`)}unregister(e){delete this.handlers[e],console.log(`[Crow] Unregistered client tool: ${e}`)}has(e){return e in this.handlers}getRegisteredTools(){return Object.keys(this.handlers)}async execute(e,t){const s=this.handlers[e];if(!s)return console.warn(`[Crow] No handler registered for tool: ${e}`),{status:"error",error:`No handler registered for tool: ${e}`};try{console.log(`[Crow] Executing client tool: ${e}`,t);const r=await s(t);return console.log(`[Crow] Tool ${e} completed:`,r),r}catch(r){const n=r instanceof Error?r.message:String(r);return console.error(`[Crow] Tool ${e} failed:`,r),{status:"error",error:n}}}}const E="crow_conv_";class C{constructor(e,t){this.currentId=null,this.productId=e,this.apiUrl=t,this.currentId=this.loadFromStorage()}getStorageKey(){return`${E}${this.productId}`}loadFromStorage(){try{return localStorage.getItem(this.getStorageKey())}catch{return null}}saveToStorage(e){try{localStorage.setItem(this.getStorageKey(),e)}catch{}}clearStorage(){try{localStorage.removeItem(this.getStorageKey())}catch{}}getCurrentId(){return this.currentId}setCurrentId(e){this.currentId=e,e?this.saveToStorage(e):this.clearStorage()}hasRestoredConversation(){return this.currentId!==null}clear(){this.currentId=null,this.clearStorage()}async getConversations(e){try{const t=await fetch(`${this.apiUrl}/api/chat/conversations?product_id=${this.productId}&identity_token=${encodeURIComponent(e)}`);if(!t.ok)throw new Error(`HTTP error: ${t.status}`);return(await t.json()).conversations||[]}catch(t){return console.error("[Crow] Failed to load conversations:",t),[]}}async loadHistory(e,t){try{const s=await fetch(`${this.apiUrl}/api/chat/conversations/${e}/history?product_id=${this.productId}&identity_token=${encodeURIComponent(t)}`);if(!s.ok)throw new Error(`HTTP error: ${s.status}`);const r=await s.json();return this.parseHistoryMessages(r.messages||[])}catch(s){return console.error("[Crow] Failed to load conversation history:",s),[]}}async loadAnonymousHistory(e){try{const t=await fetch(`${this.apiUrl}/api/chat/conversations/${e}/history/anonymous?product_id=${this.productId}`);if(!t.ok)throw new Error(`HTTP error: ${t.status}`);const s=await t.json();return this.parseHistoryMessages(s.messages||[])}catch(t){return console.error("[Crow] Failed to load anonymous conversation history:",t),[]}}parseHistoryMessages(e){return e.filter(t=>t.role!=="tool"&&!t.content.startsWith("[Client Tool Result:")).map((t,s)=>({id:`history-${s}`,content:this.parseContent(t.content),role:t.role==="assistant"?"assistant":"user",timestamp:new Date}))}parseContent(e){try{const t=JSON.parse(e);if(Array.isArray(t)){const s=t.find(r=>r.type==="text");return(s==null?void 0:s.text)||e}}catch{}if(e.includes("'type': 'text'")){const t=e.match(/\{'text':\s*'((?:[^'\\]|\\.)*)'\s*,\s*'type':\s*'text'/);if(t)return t[1].replace(/\\n/g,`
2
+ `).replace(/\\'/g,"'")}return e}}function b(o){if(o==="[DONE]")return{type:"done"};try{const e=JSON.parse(o);switch(e.type){case"verification_status":return{type:"verification_status",isVerified:e.is_verified===!0};case"conversation_id":return{type:"conversation_id",conversationId:e.conversation_id};case"thinking":return e.status==="complete"?{type:"thinking_complete"}:null;case"thinking_token":return{type:"thinking",content:e.content||""};case"content":return{type:"content",text:e.content||"",accumulated:""};case"citations":return{type:"citations",citations:e.citations};case"error":return{type:"error",message:e.message||"Unknown error"};case"tool_call_start":return{type:"tool_call_start",toolName:e.tool_name,displayName:e.display_name||void 0,arguments:e.arguments||{}};case"tool_call_complete":return{type:"tool_call_complete",toolName:e.tool_name,displayName:e.display_name||void 0,success:e.success};case"client_tool_call":return{type:"client_tool_call",toolName:e.tool_name,displayName:e.display_name||void 0,arguments:e.arguments||{}};case"workflow_started":return{type:"workflow_started",name:e.name,todos:e.todos};case"todo_updated":return{type:"workflow_todo_updated",todoId:e.id,status:e.status};case"workflow_ended":return{type:"workflow_ended"};case"workflow_complete_prompt":return{type:"workflow_complete_prompt"};default:return null}}catch{return console.error("[Crow] Failed to parse SSE data:",o),null}}function*M(o){const e=o.split(`
3
+ `);for(const t of e)t.startsWith("data: ")&&(yield t.slice(6).trim())}async function*S(o,e){var n;const t=(n=o.body)==null?void 0:n.getReader();if(!t)throw new Error("Response body is not readable");const s=new TextDecoder;let r="";try{for(;;){if(e!=null&&e.aborted){t.cancel();return}const{done:i,value:d}=await t.read();if(i)break;const u=s.decode(d);for(const h of M(u)){const l=b(h);if(l&&(l.type==="content"?(r+=l.text,yield{...l,accumulated:r}):yield l,l.type==="done"))return}}}finally{t.releaseLock()}}async function L(){try{return window.location.reload(),{status:"success",data:{refreshed:!0}}}catch(o){return{status:"error",error:o instanceof Error?o.message:"Failed to refresh page"}}}async function $(){var o;try{const e=document.title,t=window.location.href,s=window.location.pathname,r=(((o=document.body)==null?void 0:o.innerText)||"").slice(0,2e3).trim();return{status:"success",data:{title:e,url:t,pathname:s,visibleText:r}}}catch(e){return{status:"error",error:e instanceof Error?e.message:"Failed to read screen"}}}const g={refreshPage:L,whatsOnScreen:$},T=Object.keys(g),U="https://api.usecrow.org",x="claude-sonnet-4-20250514";class O{constructor(e){this.context={},this.abortController=null,this.callbacks={},this._messages=[],this.messageListeners=new Set,this._isLoading=!1,this.loadingListeners=new Set,this.config={productId:e.productId,apiUrl:e.apiUrl||U,model:e.model||x},this.identity=new k,this.tools=new v,this.conversations=new C(this.config.productId,this.config.apiUrl),this.tools.register(g),console.log("[Crow] Default tools registered:",T.join(", ")),this.identity.subscribe(t=>{var s,r;(r=(s=this.callbacks).onVerificationStatus)==null||r.call(s,t.isVerified)})}get productId(){return this.config.productId}get apiUrl(){return this.config.apiUrl}get model(){return this.config.model}set model(e){this.config.model=e}on(e){this.callbacks={...this.callbacks,...e}}identify(e){this.identity.identify(e)}resetUser(){this.identity.reset(),this.clearMessages()}isIdentified(){return this.identity.isIdentified()}isVerified(){return this.identity.isVerified()}registerTools(e){this.tools.register(e)}unregisterTool(e){this.tools.unregister(e)}getRegisteredTools(){return this.tools.getRegisteredTools()}setContext(e){this.context={...this.context,...e}}clearContext(){this.context={}}get messages(){return[...this._messages]}get isLoading(){return this._isLoading}onMessages(e){return this.messageListeners.add(e),()=>this.messageListeners.delete(e)}onLoading(e){return this.loadingListeners.add(e),()=>this.loadingListeners.delete(e)}clearMessages(){this._messages=[],this.conversations.clear(),this.notifyMessages()}loadMessages(e){this._messages=e,this.notifyMessages()}notifyMessages(){const e=this.messages;for(const t of this.messageListeners)t(e)}setLoading(e){this._isLoading=e;for(const t of this.loadingListeners)t(e)}addMessage(e){var t,s;this._messages=[...this._messages,e],this.notifyMessages(),(s=(t=this.callbacks).onMessage)==null||s.call(t,e)}updateMessage(e,t){var s,r;this._messages=this._messages.map(n=>n.id===e?{...n,...t}:n),this.notifyMessages(),(r=(s=this.callbacks).onMessageUpdate)==null||r.call(s,e,t)}generateMessageId(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`}get conversationId(){return this.conversations.getCurrentId()}set conversationId(e){this.conversations.setCurrentId(e)}async getConversations(){const e=this.identity.getToken();return e?this.conversations.getConversations(e):(console.warn("[Crow] Cannot get conversations: user not identified"),[])}async loadHistory(e){const t=this.identity.getToken();return t?this.conversations.loadHistory(e,t):this.conversations.loadAnonymousHistory(e)}async switchConversation(e){const t=await this.loadHistory(e);this.conversations.setCurrentId(e),this.loadMessages(t)}async*sendMessage(e){var i,d,u,h,l,f,p,y,m,w;if(!e.trim())return;const t=this.generateMessageId("user");this.addMessage({id:t,content:e,role:"user",timestamp:new Date});const s=this.generateMessageId("assistant");this.addMessage({id:s,content:"",role:"assistant",timestamp:new Date}),this.setLoading(!0),this.abortController=new AbortController;let r="",n="";try{const c=await fetch(`${this.config.apiUrl}/api/chat/message`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({product_id:this.config.productId,message:e,conversation_id:this.conversations.getCurrentId(),identity_token:this.identity.getToken(),model:this.config.model,context:Object.keys(this.context).length>0?this.context:void 0}),signal:this.abortController.signal});if(!c.ok)throw new Error(`HTTP error: ${c.status}`);for await(const a of S(c,this.abortController.signal)){switch(a.type){case"content":r=a.accumulated,this.updateMessage(s,{content:r});break;case"thinking":n+=a.content,this.updateMessage(s,{thinking:n});break;case"thinking_complete":this.updateMessage(s,{thinkingComplete:!0});break;case"citations":this.updateMessage(s,{citations:a.citations});break;case"verification_status":this.identity.setVerified(a.isVerified);break;case"conversation_id":this.conversations.setCurrentId(a.conversationId);break;case"client_tool_call":await this.tools.execute(a.toolName,a.arguments),(d=(i=this.callbacks).onToolCall)==null||d.call(i,a);break;case"tool_call_start":case"tool_call_complete":(h=(u=this.callbacks).onToolCall)==null||h.call(u,a);break;case"workflow_started":case"workflow_todo_updated":case"workflow_ended":case"workflow_complete_prompt":(f=(l=this.callbacks).onWorkflow)==null||f.call(l,a);break;case"error":this.updateMessage(s,{content:a.message}),(y=(p=this.callbacks).onError)==null||y.call(p,new Error(a.message));break}yield a}}catch(c){if(c instanceof Error&&c.name==="AbortError"){r?this.updateMessage(s,{content:r}):(this._messages=this._messages.filter(a=>a.id!==s),this.notifyMessages());return}console.error("[Crow] Error:",c),this.updateMessage(s,{content:"Sorry, I encountered an error. Please try again."}),(w=(m=this.callbacks).onError)==null||w.call(m,c instanceof Error?c:new Error(String(c)))}finally{this.setLoading(!1),this.abortController=null}}async send(e){let t=null;for await(const r of this.sendMessage(e))if(r.type==="done")break;const s=this.messages;return s.length>0&&(t=s[s.length-1],t.role==="assistant")?t:null}stop(){this.abortController&&(this.abortController.abort(),this.setLoading(!1))}destroy(){this.stop(),this.messageListeners.clear(),this.loadingListeners.clear()}}function I(o,e,t){const s=o.find(n=>n.name.toLowerCase()===e.toLowerCase());if(!s)return null;let r=s.path;if(t)for(const[n,i]of Object.entries(t))r=r.replace(`:${n}`,String(i));return r}function A(o,e){return async t=>{try{const s=t.page,r=t.params,n=t.url;let i=null;if(s){if(i=I(o,s,r),!i)return{status:"error",error:`Unknown page: "${s}". Available pages: ${o.map(u=>u.name).join(", ")}`}}else if(n)i=n;else return{status:"error",error:'Either "page" or "url" parameter is required'};const d=i.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return d?{status:"error",error:`Missing parameters: ${d.join(", ")}. Please provide values for these parameters.`}:e?(e(i),{status:"success",data:{navigated_to:i,page:s||void 0,method:"spa_router"}}):(window.location.href=i,{status:"success",data:{navigated_to:i,page:s||void 0,method:"full_navigation"}})}catch(s){return{status:"error",error:String(s)}}}}exports.CrowBrowserUse=_.CrowBrowserUse;exports.WorkflowExecutor=_.WorkflowExecutor;exports.ConversationManager=C;exports.CrowClient=O;exports.DEFAULT_TOOLS=g;exports.DEFAULT_TOOL_NAMES=T;exports.IdentityManager=k;exports.ToolManager=v;exports.createNavigateToPageTool=A;exports.parseSSEChunk=M;exports.parseSSEData=b;exports.resolveRoute=I;exports.streamResponse=S;