env-ai
Version:
AI Assistant for Your Local Environment
236 lines (170 loc) • 31.9 kB
JavaScript
import k from"ollama";import{OllamaEmbedding as Z,Ollama as H}from"@llamaindex/ollama";import{JSONReader as Q}from"@llamaindex/readers/json";import{Settings as E,Document as D,VectorStoreIndex as X,ContextChatEngine as tt}from"llamaindex";import{globby as et}from"globby";import{readFile as st,writeFile as it,stat as rt}from"node:fs/promises";import{join as P,isAbsolute as x,basename as ot,extname as A,resolve as at}from"node:path";import{pathToFileURL as nt}from"node:url";import{parse as ct}from"smol-toml";import lt from"yaml";import p,{stdout as v,argv as ut,cwd as ht}from"node:process";import{z as I}from"zod";import u from"picocolors";import*as pt from"@clack/prompts";import{block as dt}from"@clack/core";import mt from"is-unicode-supported";import{cursor as j,erase as $}from"sisteransi";function gt(r,t){for(var e=0;e<t.length;e++){const s=t[e];if(typeof s!="string"&&!Array.isArray(s))for(const i in s)i!=="default"&&!(i in r)&&(r[i]=s[i])}return r}const ft="env-ai",wt="0.4.2",yt="AI Assistant for Your Local Environment",_t={url:"https://github.com/pigeonposse/env-ai/issues"},bt=yt,vt=_t.url,Et=ft,L={always:"always",ask:"ask",last:"last"},f={custom:"custom",explain:"explain",docs:"docs",fix:"fix",performance:"performance",refactor:"refactor",test:"tests"},xt={custom:"Adapt the system to your needs.",explain:"Provide clear explanations of code and functionality.",docs:"Generate user guides and technical documentation.",fix:"Identify and resolve bugs for accurate output.",performance:"Improve the efficiency of your code and reduce response times.",refactor:"Improve code structure for better readability and maintainability.",test:"Create tests and ensure quality."},Ct={CONTENT:"content"},M={__proto__:null,PROMPT_VARS:Ct,bugsUrl:vt,overwrite:L,projectDesc:bt,projectName:Et,theme:f,themeDesc:xt,version:wt},N=r=>{if((x(r)||/^(\.\/|\.\.\/|[A-Za-z]:\\|\/)/.test(r))&&(x(r)||/^(\.\/|\.\.\/|[A-Za-z]:\\|\/)/.test(r))){if(/\s(?!\\)/.test(r)&&!/\\\s/.test(r))return!1;try{return P(r)!==""}catch{return!1}}return!1};class F{path={resolve:at,extname:A,basename:ot,isAbsolute:x,join:P};readFile=st;writeFile=it;isAbsolute=x;join=P;isPath=N;getPaths=et;extname=A;async existsFile(t){try{return(await rt(t)).isFile()}catch{return!1}}async readConfigFile(t){const e=this.extname(t),s=await this.readFile(t,"utf8");let i;if(e===".json")i=JSON.parse(s);else if(e===".yml"||e===".yaml")i=lt.parse(s);else if(e===".toml"||e===".tml")i=ct(s);else if(e===".js"||e===".mjs")i=(await import(nt(t).href)).default;else throw new Error(`Unsupported file extension: ${e}`);return i}}const Rt=async(r,t,e)=>{const s=/{{\s*([\w:/.-]+)\s*(?:\(\s*['"]([^'"]+)['"]\s*\))?\s*}}/g,i=[];let a;for(;(a=s.exec(r))!==null;){const[o,n,l]=a;i.push({placeholder:o,key:n,arg:l})}for(const{placeholder:o,key:n,arg:l}of i){const c=t[n];let h="";typeof c=="function"?h=await c(l||""):c!==void 0?h=c:e?h=await e(n):h=o,r=r.replace(o,h)}return r},U=r=>{const t={code:r?.code,name:r?.name,message:r?.message,stack:r?.stack?r.stack.split(`
`):[],...r instanceof Object?r:{}};return Array.isArray(t.stack)&&t.stack.length>0?t.stack.map(e=>` ${e}`).join(`
`):JSON.stringify(t,null," ")},Ot=r=>r,Dt=async r=>{try{const t=await fetch(r);if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);return await t.text()}catch(t){throw new Error(`Failed to fetch URL [${r}]: ${t?.message||"Unexpected error"}`)}},G=r=>Pt(r)?"url":N(r)?"path":"text",Pt=r=>{try{return new URL(r),!0}catch{return!1}},It={__proto__:null,getStringType:G,getTextPlainFromURL:Dt,replacePlaceholders:Rt,sanitizeContent:Ot,setErrorString:U};class Lt{#t;#s;#i;#r;#e;constructor(t){this.#t=new Z({model:"nomic-embed-text"}),this.#i=new F,this.#r=t.system,this.#s=new H({model:t.model,options:{temperature:.5}}),this.#e=void 0,E.embedModel=this.#t,E.llm=this.#s,E.chunkSize=300,E.chunkOverlap=20}async#o(t){const e=new TextEncoder().encode(t);return await new Q({levelsBack:0}).loadDataAsContent(e)}async generateChat(t){if(t.length==0){const o=new D({id_:"default_doc",text:"There are no documents loaded.Starting chat without documentation.",metadata:{file_path:"default",file_name:"default"}});t.push({content:o.text,path:o.id_})}const e=o=>{try{const n=JSON.parse(o);return typeof n=="object"&&n!==null}catch{return!1}},s=t.map(async o=>{const n=G(o.path)==="url",l=n&&e(o.content),c=o.path.endsWith(".json")||l,h={id_:o.path,metadata:{is_url:n,is_JSON_content:c,is_local_path:!n,file_path:n?o.path:this.#i.path.resolve(o.path),file_name:n?o.path:this.#i.path.basename(o.path)}};if(c){const _={...(await this.#o(o.content))[0],...h};return new D(_)}return new D({text:o.content,id_:o.path,...h})}),i=await Promise.all(s),a=(await X.fromDocuments(i)).asRetriever({similarityTopK:3});this.#e&&this.#e.reset(),this.#e=new tt({retriever:a,chatModel:this.#s,systemPrompt:this.#r})}async chat(t){return this.#e?await this.#e.chat({message:t,stream:!0}):void 0}async resetChatEngine(){this.#e&&this.#e.reset()}}class St{#t;error={NO_MODELS:"no-models"};constructor(){this.#t=k}async getModels(){const t=await this.#t.list();if(!t.models||t.models.length===0)throw new Error(this.error.NO_MODELS);return t.models.map(e=>e.name)}async installModel(t){return await k.pull({model:t,stream:!0})}async chatVectored(t){const e=new Lt({model:t.model,system:t.system});return await e.generateChat(t.docs),{send:e.chat.bind(e),reset:e.resetChatEngine.bind(e)}}async chat(t){const e=this.#t,s=[{role:"system",content:t.system}];return{send:async i=>(s.push({role:"user",content:i}),await e.chat({stream:!0,model:t.model,messages:s,options:{temperature:0}})),addAssistantMessage:i=>s.push({role:"assistant",content:i})}}}const Tt=async r=>r.then(t=>[void 0,t]).catch(t=>[t]);class kt extends Error{data;constructor(t,e){super(t),this.data=e,Error.captureStackTrace(this,this.constructor)}}const At=r=>p.on("SIGINT",r),jt=r=>p.exit(r),z=()=>{p.noDeprecation=!0},$t=async({fn:r,on:t})=>{const e=v.write;v.write=async(s,...i)=>{const a=s.toString();await t(a)&&e.call(v,s,...i)};try{return await r()}finally{v.write=e}},Mt={__proto__:null,argv:ut,cwd:ht,exit:jt,onOutputWrite:$t,onSIGNIT:At,rmDeprecationAlerts:z,stdout:v},g=I,Y=r=>I.union(r.map(t=>I.literal(t))),Nt=Y(Object.values(L)),Ft=Y(Object.values(f)),Ut=g.object({output:g.string().optional(),input:g.array(g.string()).optional(),overwrite:Nt.optional(),model:g.string().optional(),prompt:g.string().optional(),system:g.string().optional(),theme:Ft.optional(),single:g.boolean().optional(),debug:g.boolean().optional(),config:g.string().optional()}),Gt=class extends kt{};class y{_c;_p;_argv;_sys=new F;_ai=new St;_string=It;_const=M;_process=Mt;_catchError=Tt;Error=Gt;ERROR_ID={CANCELLED:"CANCELLED",RESPONSE_CANCELLED:"RESPONSE_CANCELLED"};title="core";description;argvSceham=Ut;constructor({argv:t,c:e,p:s}){this._c=e,this._p=s,this._argv=t}_successRes(t,e,s=!1){const i=t+(e!==""?`
`+this._c.gray(e):"");if(s)return i;this._p.log.success(t+`
`+this._c.gray(e))}_errorRes(t,e,s=!1){const i=t+(e!==""?`
`+this._c.gray(e):"");if(s)return i;this._p.log.error(i)}_setDebug(t){this._p.log.debug(this._c.section(this.title.toUpperCase()),t)}_setTitle(){const t=this.description?`
`+this._c.gray(this.description):"";this._p.log.info(this._c.section(this.title.toUpperCase())+t)}_setErrorMessage(t,e="Unexpected error"){return t instanceof Error?t.message:e}cancel(t){this._p.log.warn(this._c.warn(t)),this.exit()}exit(t=0){console.log(""),t==="error"?this._process.exit(1):this._process.exit(t)}async _textPrompt(t){const e=await this._p.text({message:t.message,placeholder:t.placeholder,validate(s){if(!s||s.trim()==="")return"No empty value is allowed."}});if(this._p.isCancel(e))throw new this.Error(this.ERROR_ID.CANCELLED);return e}async _confirmPrompt(t){const e=await this._p.confirm({message:t.message});if(this._p.isCancel(e))throw new this.Error(this.ERROR_ID.CANCELLED);return e}async _selectPrompt(t){const e=await this._p.select({message:t.message,options:t.opts.map(s=>({value:s.value,label:s.title,hint:s.desc}))});if(this._p.isCancel(e))throw new this.Error(this.ERROR_ID.CANCELLED);return e}_setProcessPath(t){return this._sys.path.resolve(this._process.cwd(),t)}async _validateContent(t){const e=async o=>{const n=this._setProcessPath(o);if(!await this._sys.existsFile(n))throw new this.Error(`Path "${o}" doesn't exist or is not found.`);const l=await this._sys.readFile(n,"utf-8");if(l&&typeof l=="string")return l;throw new this.Error(`Path "${o}" has unexpected content type: ${typeof l}`)},s=async o=>{const n=await this._string.getTextPlainFromURL(o);if(n&&typeof n=="string")return n;throw new this.Error(`URL "${o}" has unexpected content type: ${typeof n}`)},i=async o=>{const n=this._string.getStringType(o);return n==="path"?await e(o):n==="url"?await s(o):o},a=await i(t);return await this._string.replacePlaceholders(a,{url:async o=>await s(o),path:async o=>await e(o)},async o=>await i(o))}}class zt extends y{validateProperties(t){return this.argvSceham.parse(t)}async set(){const t=this._argv,e=t.config;if(e)try{const s=await this._sys.readConfigFile(e),i=await this.validateProperties(s);for(const a in i)t[a]||(t[a]=i[a])}catch(s){this._p.log.warn("Error setting config properties: "+this._setErrorMessage(s))}}}class Yt extends y{title="Input";description="Inputs to add context to your chat. This in not required.";errorTitle=this._c.error(this.title);async _getDataContent(t,e){e=e??"path";const s=this._p.spinner();s.start("Preparing inputs...");let i=[];if(e==="url"){s.message("Reading and sanitizing url...");const a={};for(const o of t){const[n,l]=await this._catchError((async()=>{s.message("Reading "+o);const c=await this._string.getTextPlainFromURL(o.toString());return this._string.sanitizeContent(c)})());if(n)throw s.stop("Error reading url: "+this._c.gray(o.toString()),1),n;a[o.toString()]=l}s.message("Getting source for all urls..."),i=[...i,...Object.entries(a).map(([o,n])=>({content:n,path:o}))],s.stop("Source urls obtained!")}if(e==="path"){s.message("Reading and sanitizing files...");const a={};for(const o of t){s.message("Reading "+o);const n=await this._sys.readFile(o,"utf-8");a[o.toString()]=this._string.sanitizeContent(n)}s.message("Getting source for all files..."),i=[...i,...Object.entries(a).map(([o,n])=>({content:n,path:o}))],s.stop("Source files obtained!")}return i}async getContent(t){const e=()=>this._errorRes(this.errorTitle,"Unexpected error! Missing required arguments. Please provide all required arguments.");if(!t)return e(),t=await this.getInputs(void 0,void 0),await this.getContent(t);try{const s=!t.urls||!t.urls.length?void 0:await this._getDataContent(t.urls,"url"),i=!t.paths||!t.paths.length?void 0:await this._getDataContent(t.paths,"path");return s&&i?[...s,...i]:s||i||[]}catch{return t=await this.getInputs(void 0,void 0),await this.getContent(t)}}#t(t){const e=[],s=[];for(const i of t)this._string.getStringType(i)==="url"?e.push(new URL(i)):s.push(i);if(!(!s.length&&!e.length))return{urls:e,paths:s}}async#s(t){return(await this._textPrompt({message:"Enter path patterns or URLs to be processed (comma-separated):",placeholder:t})).split(",").map(e=>e.trim())}async getInputs(t,e){const s=t?(this._successRes("Inputs selected:",t.length?t.join(", "):"none"),t):await this.#s(e);let i=this.#t(s);const a=()=>this._errorRes("No files or urls were found matching the inclusion patterns in:",s.join(", "));return i?(i.paths=await this._sys.getPaths(i.paths),(!i||!i.paths.length&&!i.urls.length)&&(a(),i=await this.getInputs(void 0,s.join(", ")))):i={urls:[],paths:[]},i}async get(){this._setTitle();const t=await this.getInputs(this._argv.input||[]),e=await this.getContent(t);return this._setDebug(JSON.stringify(e,null,2)),e}}class Bt extends y{title="Model";description="LLM model to use for your chat.";async installModel(t){const e=this._p.spinner(),s=i=>`[${t}] Installation: `+i;try{e.start(s("Initializing..."));const i=await this._ai.installModel(t);if(i[Symbol.asyncIterator]){this._process.onSIGNIT(()=>{this._process.stdout.write(`
`),this.cancel("Exit from installation")});for await(const a of i)e.message(s(a.status));e.stop(s("Model installed successfully! \u2728"))}else throw new this.Error("Response is not iterable")}catch(i){throw e.stop(s("Error installing model"),1),new Error(`Error installing [${t}] model: ${this._setErrorMessage(i)}`)}}async get(){const t=this._argv.model,{gray:e}=this._c;this._setTitle();const s=async()=>{const[l,c]=await this._catchError(this._ai.getModels());if(l){const h=`
For more information about Ollama please visit ${this._c.gray("https://ollama.com/")}`;throw this._errorRes("Error retrieving model from Ollama.",""),l instanceof Error&&l.message===this._ai.error.NO_MODELS?new this.Error(`No Ollama models found.
Please download at least one model.`+h):new this.Error(`Ollama is not installed or is not running.
Please install/start Ollama to use this tool.`+h)}else return c},i="Select a LLM model:",a=await s();if(t&&a.includes(t))return this._p.log.success(`${i}
${e(t)}`),t;t&&!a.includes(t)&&this._p.log.error(`Model [${t}] not exists or is not installed.`);const o="nomic-embed-text";if(!a.some(l=>l.startsWith(o))){if(this._p.log.warn(`Model [${o}] must be installed for create embeddings`),await this._confirmPrompt({message:`Do you want to install [${o}] model now?`})===!1)throw new this.Error(`Model [${o}] must be installed.
Read more about it at https://ollama.com/library/nomic-embed-text`);if(await this.installModel(o),!(await s()).some(l=>l.startsWith(o)))throw new this.Error(`Model [${o}] failed to install unexpectedly`)}const n=await this._selectPrompt({message:i,opts:a.filter(l=>!l.startsWith(o)).map(l=>({value:l,title:l}))});return this._setDebug(n),n}}class Wt extends y{title="Output";description="Output configuration for save the generated content.";async getOverwrite(){const t=this._argv.overwrite,{ask:e,...s}=this._const.overwrite,i="Select overwrite type:";if(t&&t!==e){if(t==="always"||t==="last")return this._successRes(i,t),t;this._errorRes("Invalid overwrite type: ",t)}return await this._selectPrompt({message:i,opts:Object.values(s).map(a=>({value:a,title:a}))})}async getSingle(){const t=this._argv.single;return!t||t!==!0?!1:(this._successRes("Response type:","Single"),t)}async getPath(){const t=async(s,i)=>{const a=s?(this._successRes("Output path:",s),s):await this._textPrompt({message:"Enter output path:",placeholder:i});return this._setProcessPath(a)},e=this._argv.output;return e?await t(e):void 0}async get(){this._setTitle();const t=await this.getPath(),e=await this.getSingle(),s=t?await this.getOverwrite():void 0,i={path:t,overwrite:s,single:e};return!t&&!e&&this._p.log.success("No output path provided"),this._setDebug(JSON.stringify(i,null,2)),i}}const qt={[f.docs]:{system:`You are a helpful assistant explaining how to use the provided code library and provide detailed documentation.
Generate a complete and user-oriented README in Markdown format for the provided code library.
Assume the documentation will be viewed by end-users who seek a clear understanding of how to install, configure, and use the library effectively.
If a package.json file is provided, extract relevant information such as project name, description, installation steps, available binaries, author(s), contributor(s), license, exports, and dependencies, integrating these details seamlessly into the documentation.
Include examples and details for each aspect of the library, aiming to cover both beginners and advanced users.
structure:
# Project Title
> A concise project description explaining the library's purpose and main features.
## Table of Contents
- Overview
- Installation
- Usage
- Setup & Configuration
- API Reference
- Code Examples
- Additional Information
- Author & Contributors
- Contributing
- License
## Overview
Provide a high-level explanation of the library's functionality, its key advantages, and core use cases.
## Installation
Explain installation in detail:
1. List prerequisites, if any.
2. Provide step-by-step installation instructions using npm/yarn or other methods, based on package.json information.
## Usage
### Setup & Configuration
Outline any configuration steps required post-installation, using examples if needed.
### API Reference
Document all exposed functions, classes, or modules:
- **Function/Class Name**: Describe its purpose and main use.
- **Parameters**: Detail expected parameters with types and optional/default values.
- **Return Value**: Describe the return type and any specific details.
- **Examples**: Provide clear, context-rich examples.
### Code Examples
Include multiple examples showcasing the library in action, covering different scenarios.
## Additional Information
### Author
List the main author as found in package.json.
### Contributors
Provide a contributors list, if available.
### Contributing
Explain how to contribute, with links to contributing guidelines if they exist.
### License
Detail the license information as specified in package.json.
---
The output should be written in strict Markdown format and provide a comprehensive, user-friendly guide.
`},[f.fix]:{system:`You are a helpful assistant explaining how to identify and fix issues in the provided code library.
Analyze the provided code library and generate a detailed report in Markdown format on common issues and their solutions.
If a package.json file is provided, extract relevant information such as project name, description, and installation steps, integrating these details seamlessly into the report.
Include examples and details for each aspect of the library, aiming to cover both simple and complex issues.
structure:
# Project Title
> A concise project description explaining the library's purpose and main features.
## Table of Contents
- Overview of Common Issues
- Solutions
- Additional Information
## Overview of Common Issues
Provide a summary of typical problems encountered when using the library.
## Solutions
Outline solutions to each identified issue, with step-by-step instructions and code examples.
## Additional Information
### Author
List the main author as found in package.json.
### Contributors
Provide a contributors list, if available.
### License
Detail the license information as specified in package.json.
---
The output should be written in strict Markdown format and provide a comprehensive guide to troubleshooting the library.`},[f.performance]:{system:"You are a helpful assistant explaining how to optimize the performance of the provided code library."},[f.refactor]:{system:`You are a helpful assistant explaining how to refactor code for the provided code library.
Generate a detailed guide in Markdown format on how to refactor the provided code library.
Include best practices and principles for writing clean, maintainable code.
structure:
# Project Title
> A concise project description explaining the library's purpose and main features.
## Table of Contents
- Overview of Refactoring
- Refactoring Techniques
- Example Refactorings
- Additional Information
## Overview of Refactoring
Discuss what refactoring is and its importance in software development.
## Refactoring Techniques
Describe common refactoring techniques, providing examples for each.
## Example Refactorings
Provide concrete examples of code refactorings applied to the library, with before and after comparisons.
## Additional Information
### Author
List the main author as found in package.json.
### Contributors
Provide a contributors list, if available.
### License
Detail the license information as specified in package.json.
---
The output should be written in strict Markdown format and provide a comprehensive guide to code refactoring.`},[f.explain]:{system:`You are a helpful assistant providing explanations for the provided code library.
Create a detailed explanation in Markdown format for the provided code library, focusing on its design, structure, and functionality.
Include examples to illustrate key concepts and usage.
structure:
# Project Title
> A concise project description explaining the library's purpose and main features.
## Table of Contents
- Overview of the Code Library
- Key Components
- Detailed Explanations
- Additional Information
## Overview of the Code Library
Provide an overview of the library, including its main features and intended use cases.
## Key Components
Describe the key components of the library, explaining their roles and how they interact.
## Detailed Explanations
Provide detailed explanations of important concepts, including code snippets to clarify usage.
## Additional Information
### Author
List the main author as found in package.json.
### Contributors
Provide a contributors list, if available.
### License
Detail the license information as specified in package.json.
---
The output should be written in strict Markdown format and provide a comprehensive guide to understanding the library.`},[f.test]:{system:`You are a helpful assistant guiding users on testing the provided code library.
Develop a detailed guide in Markdown format on testing the provided code library.
Assume the audience consists of developers who want to ensure their code is well-tested.
structure:
# Project Title
> A concise project description explaining the library's purpose and main features.
## Table of Contents
- Overview of Testing
- Testing Frameworks and Tools
- Test Cases and Examples
- Additional Information
## Overview of Testing
Discuss the importance of testing in software development and provide an overview of the library's testing approach.
## Testing Frameworks and Tools
Describe the testing frameworks and tools available for use with the library, providing examples of how to set them up.
## Test Cases and Examples
Provide examples of test cases, including unit tests and integration tests, demonstrating how to write and run tests.
## Additional Information
### Author
List the main author as found in package.json.
### Contributors
Provide a contributors list, if available.
### License
Detail the license information as specified in package.json.
---
The output should be written in strict Markdown format and provide a comprehensive guide to testing the library.`}};class Jt extends y{title="Prompt";description="The prompt configuration for your chat.";defaults=qt;async#t(t){const e=`System prompt ${this._c.italic("(Enter text path or url)")}:`,s=async(a,o)=>{let n,l;try{if(a?n=await this._validateContent(a):(l=await this._textPrompt({message:e,placeholder:o||"You are an expert code programmer with extensive knowledge of the content of this library"}),n=await this._validateContent(l)),!n)throw new Error}catch(c){if(c instanceof this.Error&&c.message===this.ERROR_ID.CANCELLED)throw new this.Error(this.ERROR_ID.CANCELLED);this._errorRes("System prompt error:",this._setErrorMessage(c)),n=await s(void 0,n||l)}return n},i=this._argv.system;return i?(this._successRes(e,i),await s(i)):t||await s(void 0)}async getTheme(){const t=this._argv.theme,e="Select theme:";return t?(this._successRes(e,t),t):await this._selectPrompt({message:e,opts:Object.entries(this._const.theme).map(([s,i])=>({value:i,title:i,desc:this._const.themeDesc[s]||void 0}))})}async get(){this._setTitle();const t=await this.getTheme(),e=await this.#t(t!=="custom"?this.defaults[t].system:void 0),s={theme:t,system:e};return this._setDebug(JSON.stringify(s,null,2)),s}}class Vt extends y{title="Chat";#t;#s="\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";async#i(t){this._setDebug(t);const e=this.#s,s="Assistant:",i=()=>(console.log(`
`),this._p.intro(e)),a=()=>(this._p.outro(e),console.log(`
`)),o=this._p.spinnerCustom();let n="",l=!1;if(!this.#t)throw new this.Error("Chat not initialized");o.start(s+" Thinking...");const c=await this.#t.send(t);if(o.message(s+" Thinking..."),c&&c[Symbol.asyncIterator]){o.stop(s),a(),this._process.onSIGNIT(async()=>l=!0);for await(const h of c){if(l)throw this._process.stdout.write(`
`),i(),new this.Error(this.ERROR_ID.RESPONSE_CANCELLED);this._process.stdout.write(h.message.content.toString()),n+=h.message.content}i()}else throw o.stop(s+"There has been an error in the chat process"),new this.Error("Chat unexpeted error");return n}async#r({system:t,model:e,docs:s}){const i=this._p.spinner();i.start("starting...");try{const a="Generating chat";i.message(a);const o=[];this.#t=await this._process.onOutputWrite({fn:async()=>await this._ai.chatVectored({system:t,model:e,docs:s}),on:async n=>{if(!n.includes(a)&&!n.includes("\x1B[999D")&&!n.includes("\x1B[J"))o.push(n);else return n}}),i.stop("Chat successfully generated! \u2728"),o.length||o.join(`
`).trim()!==""?this._p.note(o.join(`
`),"Notifications"):this._p.log.message(this.#s)}catch(a){throw this._p.log.error("Error generating repsonse: "+this._setErrorMessage(a)),a}}async#e(t=void 0){const e=t?.first;let s="";try{const i=t?.prompt&&e?(this._successRes("You:",t.prompt),t.prompt):await this._textPrompt({message:"You:",placeholder:e?"Write your first prompt here":"Write your next prompt here"});s=await this._validateContent(i),s=await this.#i(s)}catch(i){if(i instanceof this.Error&&i.message===this.ERROR_ID.CANCELLED)throw new this.Error(this.ERROR_ID.CANCELLED);i instanceof this.Error&&i.message===this.ERROR_ID.RESPONSE_CANCELLED&&await this.#e(),this._errorRes(this.title,this._setErrorMessage(i)),s=await this.#e()}return s}async#o(t,e,s){if(s==="last"&&await this._sys.existsFile(t)){const i=await this._sys.readFile(t,"utf-8");e=`${i===""?"":i+`
---
`}${e}`}await this._sys.writeFile(t,e),this._successRes("Response saved in:",t)}async#a(t,e){const s=await this.#e();t&&await this.#o(t,s,e||"last"),await this.#a(t,e)}async get({system:t,model:e,docs:s,output:i}){this._setTitle(),await this.#r({system:t,model:e,docs:s});const a=this._argv.prompt,o=await this.#e({first:!0,prompt:a});i.path&&i.overwrite&&await this.#o(i.path,o,i.overwrite),i.single||await this.#a(i?.path,i?.overwrite)}}const Kt={};class Zt{prompt;model;config;input;response;output;Error;ERROR_ID;exit;cancel;constructor(t){this.config=new zt(t),this.prompt=new Jt(t),this.model=new Bt(t),this.input=new Yt(t),this.output=new Wt(t),this.response=new Vt(t),this.Error=this.input.Error,this.ERROR_ID=this.input.ERROR_ID,this.exit=this.input.exit.bind(this.input),this.cancel=this.input.cancel.bind(this.input)}}const Ht=async(r,t)=>{const{group:e}=r.p,{onCancel:s,onError:i}=t;return{list:async a=>{try{await e(a,{onCancel:async()=>await s()})}catch(o){await i(o)}}}},Qt=u.green,B=u.italic,Xt=u.yellow,S=u.red,W=u.magenta,q=u.cyan,J=u.underline,V=u.gray,te=u.black,ee=r=>u.gray(u.dim(r)),C=r=>u.black(u.bold(r)),se=r=>u.bgCyan(C(` ${r} `)),ie=r=>u.bgRed(` ${r} `),re=r=>u.bgYellow(C(` ${r} `)),oe=r=>u.bgGreen(C(` ${r} `)),ae=r=>u.bgWhite(u.black(` ${r} `)),ne=r=>u.bgBlue(u.white(` ${r} `)),ce=r=>J(B(r)),le={__proto__:null,black:te,blackBold:C,blue:q,debug:ae,error:ie,gray:ee,grayBright:V,green:Qt,introColor:se,italic:B,link:ce,magenta:W,red:S,section:ne,success:oe,underline:J,warn:re,yellow:Xt},T=mt(),R=(r,t)=>T?r:t,ue=R("\u25A0","x"),he=R("\u25B2","x"),pe=R("\u25C7","o"),de=R("\u2502","|"),me=()=>{const r=T?["\u25D2","\u25D0","\u25D3","\u25D1"]:["\u2022","o","O","0"],t=T?80:120;let e,s,i=!1,a="";const o=m=>{const d=m>1?"Something went wrong":"Canceled";i&&b(d,m)},n=()=>o(2),l=()=>o(1),c=()=>{p.on("uncaughtExceptionMonitor",n),p.on("unhandledRejection",n),p.on("SIGINT",l),p.on("SIGTERM",l),p.on("exit",o)},h=()=>{p.removeListener("uncaughtExceptionMonitor",n),p.removeListener("unhandledRejection",n),p.removeListener("SIGINT",l),p.removeListener("SIGTERM",l),p.removeListener("exit",o)},_=(m="")=>{i=!0,e=dt(),a=m.replace(/\.+$/,""),p.stdout.write(`${V(de)}
`);let d=0,w=0;c(),s=setInterval(()=>{const O=W(r[d]),K=".".repeat(Math.floor(w)).slice(0,3);p.stdout.write(j.move(-999,0)),p.stdout.write($.down(1)),p.stdout.write(`${O} ${a}${K}`),d=d+1<r.length?d+1:0,w=w<r.length?w+.125:0},t)},b=(m="",d=0)=>{a=m??a,i=!1,clearInterval(s);const w=d===0?q(pe):S(d===1?ue:he);p.stdout.write(j.move(-999,0)),p.stdout.write($.down(1)),p.stdout.write(`${w} ${a}
`),h(),e()};return{start:_,stop:b,message:(m="")=>{a=m??a}}},ge=gt({__proto__:null,spinnerCustom:me},[pt]);class fe{#t;c=le;p=ge;_const=M;name="";desc="";options={input:{alias:"i",describe:"Path patterns or URLs to be processed",type:"array"},model:{alias:"m",describe:"Ollama LLM model name",type:"string"},system:{alias:"s",describe:"System message (text, path or url)",type:"string"},prompt:{alias:"p",describe:"Fist prompt to generate a response (text, path or url)",type:"string"},theme:{alias:"t",describe:"Set a theme for your chat.",choices:Object.values(f)},output:{alias:"o",describe:"Output path for the generated response",type:"string"},overwrite:{describe:"Behavior when output file exists",choices:Object.values(L)},single:{describe:"Only one response",type:"boolean"},config:{alias:"c",describe:"Path to config file. Files supported: [.mjs|.js|.json|.yml|.yaml|.toml|.tml]",type:"string"},debug:{describe:"Debug mode",type:"boolean"}};message={intro:"Line execution",outro:"Operation completed!",cancel:"Operation cancelled",error:{general:"Error",debug:"Debug Error",debugFlag:t=>`You can debug the error with flag: ${t}`,debugContact:t=>`Or contact developers at: ${t}`,unexpected:"Unexpected error"},...Kt};constructor(t){this.#t=t}async fn(t){return await this.#s(t)}async#s(t){const e=this.p,s=this.c;this.#t;const i={...e,log:{...e.log,debug:(c,h)=>{t.debug&&e.log.info(s.debug("DEBUG")+" "+s.gray(c)+`
`+h)}}},a=new Zt({argv:t,c:s,p:i}),o=()=>a.cancel(this.message.cancel),{list:n}=await Ht({p:i},{onCancel:async()=>o(),onError:async c=>{const h=typeof c=="string"?c:U(c),_=c instanceof a.Error,b=c instanceof Error?c.message:typeof c=="string"?c:this.message.error.unexpected,m=t.debug,d=(w,O)=>(e.log.step(""),e.log.error(s.error(w.toUpperCase())),e.log.step(""),e.cancel(O));_?c.message===a.ERROR_ID.CANCELLED?o():d(this.message.error.general,b):m?d(this.message.error.debug,h.trim()):d(this.message.error.general,`${b}
${this.message.error.debugFlag(s.italic("--debug"))}
${this.message.error.debugContact(s.link(this._const.bugsUrl))}`),a.exit("error")}}),l=new Error(this.message.error.unexpected);await n({intro:async()=>e.intro(s.introColor(this.message.intro.toUpperCase())),config:async()=>await a.config.set(),model:async()=>await a.model.get(),content:async()=>await a.input.get(),ai:async()=>await a.prompt.get(),output:async()=>await a.output.get(),response:async({results:c})=>{if(!c.ai||!c.output||!c.model||!c.content)throw l;return await a.response.get({system:c.ai.system,model:c.model,docs:c.content,output:c.output})},outro:async()=>(e.log.step(""),e.outro(s.success(this.message.outro.toUpperCase())))})}run(){return{command:this.name,describe:this.desc,builder:t=>t.options(this.options),handler:this.#s.bind(this)}}}class we extends fe{constructor(t){super(t);const e=this._const.projectName;this.name="chat",this.desc=`Chat with the ${e} assistant`,this.message.intro=`${e} assistant`,this.message.cancel=`${e} assistant cancelled!`,this.message.outro=`${e} assistant completed!`}}export{we as e,z as r};