@iflow-ai/iflow-cli-sdk 0.1.5 → 0.1.6

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/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("fs"),t=require("path"),o=require("ws"),s=require("fs/promises"),i=require("os"),r=require("net"),n=require("child_process");function l(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(o){if("default"!==o){var s=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,s.get?s:{enumerable:!0,get:function(){return e[o]}})}}),t.default=e,Object.freeze(t)}var a,c,d,h,u,p,g,f,w,y,m,v,S,T=l(e),E=l(t),I=l(s),x=l(i),A=l(r),P=l(n);class O extends Error{constructor(e,t){super(e),this.name="IFlowError",this.details=t||{}}}class _ extends O{constructor(e,t){super(e,t),this.name="TimeoutError"}}class R extends O{constructor(e,t){super(e,{rawData:t}),this.name="JSONDecodeError",this.rawData=t}}class C extends O{constructor(e,t){super(e,t),this.name="IFlowNotInstalledError"}}class N extends O{constructor(e,t){super(e,t),this.name="IFlowProcessError"}}class L extends O{constructor(e,t){super(e,t),this.name="PortNotAvailableError"}}class M extends O{constructor(e,t){super(e,t),this.name="ConnectionError"}}class F extends O{constructor(e,t){super(e,t),this.name="TransportError"}}class $ extends O{constructor(e,t){super(e,t),this.name="PermissionError"}}class b extends O{constructor(e,t){super(e,t),this.name="ValidationError"}}class D extends O{constructor(e,t){super(e,t),this.name="ProtocolError"}}class k extends O{constructor(e,t){super(e,t),this.name="AuthenticationError"}}function U(e,t,o,s){return new(o||(o=Promise))(function(i,r){function n(e){try{a(s.next(e))}catch(e){r(e)}}function l(e){try{a(s.throw(e))}catch(e){r(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof o?t:new o(function(e){e(t)})).then(n,l)}a((s=s.apply(e,t||[])).next())})}function j(e){var t="function"==typeof Symbol&&Symbol.iterator,o=t&&e[t],s=0;if(o)return o.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&s>=e.length&&(e=void 0),{value:e&&e[s++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function H(e){return this instanceof H?(this.v=e,this):new H(e)}function W(e,t,o){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var s,i=o.apply(e,t||[]),r=[];return s=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),n("next"),n("throw"),n("return",function(e){return function(t){return Promise.resolve(t).then(e,c)}}),s[Symbol.asyncIterator]=function(){return this},s;function n(e,t){i[e]&&(s[e]=function(t){return new Promise(function(o,s){r.push([e,t,o,s])>1||l(e,t)})},t&&(s[e]=t(s[e])))}function l(e,t){try{(o=i[e](t)).value instanceof H?Promise.resolve(o.value.v).then(a,c):d(r[0][2],o)}catch(e){d(r[0][3],e)}var o}function a(e){l("next",e)}function c(e){l("throw",e)}function d(e,t){e(t),r.shift(),r.length&&l(r[0][0],r[0][1])}}function q(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,o=e[Symbol.asyncIterator];return o?o.call(e):(e=j(e),t={},s("next"),s("throw"),s("return"),t[Symbol.asyncIterator]=function(){return this},t);function s(o){t[o]=e[o]&&function(t){return new Promise(function(s,i){(function(e,t,o,s){Promise.resolve(s).then(function(t){e({value:t,done:o})},t)})(s,i,(t=e[o](t)).done,t.value)})}}}exports.LogLevel=void 0,(a=exports.LogLevel||(exports.LogLevel={}))[a.DEBUG=0]="DEBUG",a[a.INFO=1]="INFO",a[a.WARN=2]="WARN",a[a.ERROR=3]="ERROR",exports.PermissionMode=void 0,(c=exports.PermissionMode||(exports.PermissionMode={})).AUTO="auto",c.MANUAL="manual",c.SELECTIVE="selective",exports.ApprovalMode=void 0,(d=exports.ApprovalMode||(exports.ApprovalMode={})).DEFAULT="default",d.AUTO_EDIT="autoEdit",d.YOLO="yolo",d.PLAN="plan",exports.HookEventType=void 0,(h=exports.HookEventType||(exports.HookEventType={})).PRE_TOOL_USE="PreToolUse",h.POST_TOOL_USE="PostToolUse",h.STOP="Stop",h.SUBAGENT_STOP="SubagentStop",h.SET_UP_ENVIRONMENT="SetUpEnvironment",exports.PlanPriority=void 0,(u=exports.PlanPriority||(exports.PlanPriority={})).HIGH="high",u.MEDIUM="medium",u.LOW="low",exports.PlanStatus=void 0,(p=exports.PlanStatus||(exports.PlanStatus={})).PENDING="pending",p.IN_PROGRESS="in_progress",p.COMPLETED="completed",exports.StopReason=void 0,(g=exports.StopReason||(exports.StopReason={})).END_TURN="end_turn",g.MAX_TOKENS="max_tokens",g.REFUSAL="refusal",g.CANCELLED="cancelled",exports.ToolCallStatus=void 0,(f=exports.ToolCallStatus||(exports.ToolCallStatus={})).PENDING="pending",f.IN_PROGRESS="in_progress",f.COMPLETED="completed",f.FAILED="failed",exports.ToolCallContentType=void 0,(w=exports.ToolCallContentType||(exports.ToolCallContentType={})).DIFF="diff",w.MARKDOWN="markdown",exports.ToolCallConfirmationType=void 0,(y=exports.ToolCallConfirmationType||(exports.ToolCallConfirmationType={})).EDIT="edit",y.EXECUTE="execute",y.MCP="mcp",y.FETCH="fetch",y.OTHER="other",exports.ToolCallConfirmationOutcome=void 0,(m=exports.ToolCallConfirmationOutcome||(exports.ToolCallConfirmationOutcome={})).ALLOW="allow",m.ALWAYS_ALLOW="alwaysAllow",m.ALWAYS_ALLOW_TOOL="alwaysAllowTool",m.ALWAYS_ALLOW_MCP_SERVER="alwaysAllowMcpServer",m.REJECT="reject",exports.ToolCallIconType=void 0,(v=exports.ToolCallIconType||(exports.ToolCallIconType={})).URL="url",v.EMOJI="emoji",exports.MessageType=void 0,(S=exports.MessageType||(exports.MessageType={})).PLAN="plan",S.USER="user",S.ASSISTANT="assistant",S.TOOL_CALL="tool_call",S.ERROR="error",S.TASK_FINISH="task_finish","function"==typeof SuppressedError&&SuppressedError;const z="2.0";var G,Q,K;function J(e){return e instanceof Error?e.message:e?String(e):"unknown error"}!function(e){e.INITIALIZE="initialize",e.AUTHENTICATE="authenticate",e.SESSION_NEW="session/new",e.SESSION_LOAD="session/load",e.SESSION_PROMPT="session/prompt",e.SESSION_CANCEL="session/cancel"}(G||(G={})),function(e){e.SESSION_UPDATE="session/update",e.SESSION_REQUEST_PERMISSION="session/request_permission",e.FS_READ_TEXT_FILE="fs/read_text_file",e.FS_WRITE_TEXT_FILE="fs/write_text_file",e.PUSH_TOOL_CALL="pushToolCall",e.UPDATE_TOOL_CALL="updateToolCall",e.NOTIFY_TASK_FINISH="notifyTaskFinish"}(Q||(Q={})),function(e){e.PLAN="plan",e.TOOL_CALL="tool_call",e.TOOL_CALL_UPDATE="tool_call_update",e.USER_MESSAGE_CHUNK="user_message_chunk",e.AGENT_MESSAGE_CHUNK="agent_message_chunk",e.AGENT_THOUGHT_CHUNK="agent_thought_chunk"}(K||(K={}));class V{constructor(e={}){const t=e.level||"INFO";this.level=exports.LogLevel[t]}debug(e){this.log(exports.LogLevel.DEBUG,e)}info(e){this.log(exports.LogLevel.INFO,e)}warn(e){this.log(exports.LogLevel.WARN,e)}error(e,t){this.log(exports.LogLevel.ERROR,e,t)}log(e,t,o){if(e<this.level)return;const s=`[${(new Date).toLocaleString("sv-SE").replace("T"," ")}] ${exports.LogLevel[e]}: ${t}${o?`\n${o.stack}`:""}`;switch(e){case exports.LogLevel.DEBUG:console.debug(s);break;case exports.LogLevel.INFO:console.info(s);break;case exports.LogLevel.WARN:console.warn(s);break;case exports.LogLevel.ERROR:console.error(s)}}}const X=new V;function Y(e){return!!e&&"id"in e&&"result"in e&&null!=e.result}function B(e){return!!e&&"id"in e&&"error"in e&&null!=e.error}function Z(e){return!!e&&"method"in e&&!("result"in e)&&!("error"in e)}class ee{constructor(e){this.requestId=0,this.initialized=!1,this.authenticated=!1,this.logger=e.logger||X,this.transport=e.transport,this.fileHandler=e.fileHandler,this.permissionMode=e.permissionMode||exports.PermissionMode.AUTO,this.autoApproveTypes=e.autoApproveTypes||["read","fetch","list"]}nextRequestId(){return++this.requestId}checkAuthenticated(){if(!this.initialized)throw new D("Protocol not initialized. Call initialize() first.");if(!this.authenticated)throw new D("Not authenticated. Call authenticate() first.")}sendResult(e,t){return U(this,void 0,void 0,function*(){const o={jsonrpc:z,id:e,result:t};yield this.transport.send(o)})}sendError(e,t,o){return U(this,void 0,void 0,function*(){const s={jsonrpc:z,id:e,error:{code:t,message:o}};yield this.transport.send(s)})}waitForReadySignal(){return U(this,void 0,void 0,function*(){var e,t,o,s;try{for(var i,r=!0,n=q(this.transport.receive());!(e=(i=yield n.next()).done);r=!0){s=i.value,r=!1;const e=s.trim();if("//ready"===e){this.logger.info("Received //ready signal");break}e.startsWith("//")&&this.logger.debug(`Control message: ${e}`)}}catch(e){t={error:e}}finally{try{r||e||!(o=n.return)||(yield o.call(n))}finally{if(t)throw t.error}}})}waitForMessageResponse(e,t,o){return U(this,void 0,void 0,function*(){var s,i,r,n;const{timeout:l,timeoutMsg:a=`Timeout after ${l} seconds`}=o||{},c=Date.now();try{for(var d,h=!0,u=q(this.transport.receive());!(s=(d=yield u.next()).done);h=!0){n=d.value,h=!1;const o=n;if(o.trim().startsWith("//")){this.logger.debug(`Control message: ${o.trim()}`);continue}let s;try{s=JSON.parse(o.trim())}catch(e){this.logger.error(`Failed to parse response: ${J(e)}`);continue}if(s.id===e){const e=t(s);if(void 0!==e)return e}if(l&&l>0&&Date.now()-c>l)throw new _(a)}}catch(e){i={error:e}}finally{try{h||s||!(r=u.return)||(yield r.call(u))}finally{if(i)throw i.error}}})}initialize(){return U(this,arguments,void 0,function*(e={}){if(this.initialized)return this.logger.warn("Protocol already initialized"),{protocolVersion:1,isAuthenticated:this.authenticated};this.logger.info("Waiting for //ready signal..."),yield this.waitForReadySignal();const t=this.nextRequestId(),o={jsonrpc:z,id:t,method:G.INITIALIZE,params:Object.assign({protocolVersion:1,clientCapabilities:{fs:{readTextFile:!0,writeTextFile:!0}}},e)};yield this.transport.send(o),this.logger.info("Sent initialize request");const s=yield this.waitForMessageResponse(t,e=>{var t;if("error"in e)throw new D(`Initialize failed: ${null===(t=e.error)||void 0===t?void 0:t.message}`,e.error);const o=e.result||{};return this.initialized=!0,this.authenticated=o.isAuthenticated||!1,this.logger.info(`Initialized with protocol version: ${o.protocolVersion}, authenticated: ${this.authenticated}`),o},{timeout:1e4,timeoutMsg:"Initialize timeout after 10 seconds"});if(s)return s;throw new D("Connection closed during initialization")})}authenticate(){return U(this,arguments,void 0,function*(e={}){const t=e.methodId||"iflow";if(this.authenticated)return void this.logger.warn("Already authenticated");const o=this.nextRequestId(),s={jsonrpc:z,id:o,method:G.AUTHENTICATE,params:Object.assign(Object.assign({},e),{methodId:t})};yield this.transport.send(s),this.logger.info(`Sent authenticate request with method: ${s.params.methodId}`);if(!(yield this.waitForMessageResponse(o,e=>{var o;if("error"in e)throw new k(`Authentication failed: ${null===(o=e.error)||void 0===o?void 0:o.message}`,e.error);const s=e.result||{};return s.methodId===t?(this.authenticated=!0,this.logger.info(`Authentication successful with method: ${s.methodId}`),!0):(this.authenticated=!0,this.logger.warn(`Unexpected methodId in response: ${s.methodId} (expected ${t})`),!0)},{timeout:1e4,timeoutMsg:"Authentication timeout after 10 seconds"})))throw new k("Connection closed during authentication")})}createSession(){return U(this,arguments,void 0,function*(e={}){this.checkAuthenticated();const t=this.nextRequestId(),o={jsonrpc:z,id:t,method:G.SESSION_NEW,params:Object.assign(Object.assign({},e),{cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]})};yield this.transport.send(o),this.logger.info(`Sent session/new request with cwd: ${e.cwd}`);const s=yield this.waitForMessageResponse(t,e=>{var t;if("error"in e)throw new D(`session/new failed: ${null===(t=e.error)||void 0===t?void 0:t.message}`,e.error);const o=e.result||{};if(o.sessionId)return this.logger.info(`Created session: ${o.sessionId}`),o.sessionId;throw new D(`Invalid session/new response: ${JSON.stringify(o)}`)},{timeout:1e4,timeoutMsg:"Session creation timeout after 10 seconds"});if(s)return s;throw new D("Connection closed while waiting for session/new response")})}loadSession(e){return U(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),o={jsonrpc:z,id:t,method:G.SESSION_LOAD,params:Object.assign(Object.assign({},e),{cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]})};yield this.transport.send(o),this.logger.info(`Sent session/load request for session: ${e.sessionId}`);if(!(yield this.waitForMessageResponse(t,t=>{var o;if("error"in t){if(-32601===t.error.code)throw new D("session/load is not supported by the current iFlow version. Use session/new to create a new session instead.",t.error);throw new D(`session/load failed: ${null===(o=t.error)||void 0===o?void 0:o.message}`,t.error)}return this.logger.info(`Session loaded successfully: ${e.sessionId}`),!0},{timeout:1e4,timeoutMsg:"Session load timeout after 10 seconds"})))throw new D("Connection closed while waiting for session/load response")})}sendPrompt(e){return U(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),o={jsonrpc:z,id:t,method:G.SESSION_PROMPT,params:e};return yield this.transport.send(o),this.logger.info(`Sent prompt with ${e.prompt.length} content blocks`),t})}cancelSession(e){return U(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),o={jsonrpc:z,id:t,method:G.SESSION_CANCEL,params:e};yield this.transport.send(o),this.logger.info("Sent session/cancel request")})}handleMessages(){return W(this,arguments,function*(){var e,t,o,s;try{for(var i,r=!0,n=q(this.transport.receive());!(e=(i=yield H(n.next())).done);r=!0){s=i.value,r=!1;const e=s;if(e.trim().startsWith("//")){this.logger.debug(`Control message: ${e.trim()}`);continue}let t;try{t=JSON.parse(e.trim())}catch(t){throw this.logger.error(`Failed to parse message: ${J(t)}`),new R("Invalid JSON received",e)}Z(t)?yield yield H(yield H(this.handleClientMessage(t))):Y(t)?yield yield H({type:"response",id:t.id,result:t.result}):B(t)&&(yield yield H({type:"error",code:t.error.code,error:t.error.message}))}}catch(e){t={error:e}}finally{try{r||e||!(o=n.return)||(yield H(o.call(n)))}finally{if(t)throw t.error}}})}handleClientMessage(e){return U(this,void 0,void 0,function*(){const{method:t}=e;switch(t){case Q.FS_READ_TEXT_FILE:return yield this.handleReadTextFile(e);case Q.FS_WRITE_TEXT_FILE:return yield this.handleWriteTextFile(e);case Q.SESSION_UPDATE:return yield this.handleSessionUpdate(e);case Q.SESSION_REQUEST_PERMISSION:return yield this.handleRequestPermission(e);case Q.PUSH_TOOL_CALL:return yield this.handlePushToolCall(e);case Q.UPDATE_TOOL_CALL:return yield this.handleUpdateToolCall(e);case Q.NOTIFY_TASK_FINISH:return yield this.handleNotifyTaskFinish(e);default:return yield this.handleUnknownMessage(e)}})}handleReadTextFile(e){return U(this,void 0,void 0,function*(){const{id:t,method:o,params:s}=e,{path:i,limit:r,line:n}=s||{};let l;if(this.logger.info(`fs/read_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&(yield this.sendError(t,-32603,e)),{type:"error",code:-32603,error:e,method:o}}try{l=yield this.fileHandler.readFile(i,n,r)}catch(e){const s=J(e);return this.logger.error(`Error reading file ${i}: ${s}`),void 0!==t&&(yield this.sendError(t,-32603,s)),{type:"error",code:-32603,error:s,method:o}}return void 0!==t&&(yield this.sendResult(t,{content:l})),{type:"file_read",path:i,content:l}})}handleWriteTextFile(e){return U(this,void 0,void 0,function*(){const{id:t,method:o,params:s}=e,{path:i,content:r}=s||{};if(this.logger.info(`fs/write_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&(yield this.sendError(t,-32603,e)),{type:"error",code:-32603,error:e,method:o}}try{yield this.fileHandler.writeFile(i,r)}catch(e){const s=J(e);return this.logger.error(`Error writing file ${i}: ${s}`),void 0!==t&&(yield this.sendError(t,-32603,s)),{type:"error",code:-32603,error:s,method:o}}return void 0!==t&&(yield this.sendResult(t,{success:!0})),{type:"file_write",path:i,content:r}})}handleSessionUpdate(e){return U(this,void 0,void 0,function*(){const{params:t}=e,{sessionId:o,update:s}=t;return{type:"session_update",sessionId:o,updateData:s}})}handleRequestPermission(e){return U(this,void 0,void 0,function*(){const{id:t,params:o}=e,s=o.toolCall||{},i=o.options||[];let r,n;if(r=this.permissionMode===exports.PermissionMode.AUTO||this.permissionMode!==exports.PermissionMode.MANUAL&&this.autoApproveTypes.includes(s.type||""),r){let e;for(const t of i){const o=t.optionId||"";if("proceed_once"===o){e=o;break}"proceed_always"===o&&(e=o)}!e&&i.length>0&&(e=i[0].optionId||"proceed_once"),n={outcome:{outcome:"selected",optionId:e}}}else n={outcome:{outcome:"cancelled"}};return void 0!==t&&(yield this.sendResult(t,n)),this.logger.info(`Permission request for tool '${s.title||"unknown"}' - Response: ${n.outcome.outcome}`),{type:"tool_confirmation",params:o,response:n}})}handlePushToolCall(e){return U(this,void 0,void 0,function*(){const{id:t,params:o}=e,s=`tool_${this.nextRequestId()}`,i={id:s};return void 0!==t&&(yield this.sendResult(t,i)),{type:"tool_call",id:s,params:o}})}handleUpdateToolCall(e){return U(this,void 0,void 0,function*(){const{id:t,params:o}=e;return void 0!==t&&(yield this.sendResult(t,null)),{type:"tool_update",params:o}})}handleNotifyTaskFinish(e){return U(this,void 0,void 0,function*(){const{id:t,params:o}=e;return void 0!==t&&(yield this.sendResult(t,null)),{type:"task_finish",params:o}})}handleUnknownMessage(e){return U(this,void 0,void 0,function*(){const{id:t,method:o,params:s}=e;return this.logger.warn(`Unknown method: ${o}`),void 0!==t&&(yield this.sendError(t,-32601,"Method not found")),{type:"unknown",method:o,params:s}})}}class te{constructor(e){this.ws=null,this.connected=!1,this.url=e.url,this.logger=e.logger||X,this.timeout=e.timeout||3e5}get isConnected(){return!!this.ws&&this.connected}checkConnected(){if(!this.isConnected)throw new M("Not connected")}connect(){return U(this,void 0,void 0,function*(){if(this.connected)this.logger.warn(`Already connected to ${this.url}`);else try{this.logger.info(`Connecting to ${this.url}`),this.ws=yield new Promise((e,t)=>{const s=new o(this.url),i=setTimeout(()=>{s.close(),t(new _(`Connected to ${this.url} timeout after ${this.timeout/1e3}s`))},this.timeout);s.on("open",()=>{clearTimeout(i),this.connected=!0,this.logger.info(`Connected to ${this.url} succesfully`),e(s)}),s.on("error",e=>{clearTimeout(i),this.connected=!1,t(e)}),s.on("close",(e,o)=>{clearTimeout(i),this.connected=!1,t(new Error(`${o} (code: ${e})`))})})}catch(e){if(e instanceof _)throw e;throw new M(`Failed to connect to ${this.url}: ${J(e)}`)}})}close(){return U(this,void 0,void 0,function*(){if(this.ws&&this.connected)try{this.ws.close(),this.logger.info("Connection closed")}catch(e){this.logger.warn(`Error closing connection: ${J(e)}`)}this.ws=null,this.connected=!1})}send(e){return U(this,void 0,void 0,function*(){this.checkConnected();try{const t="string"==typeof e?e:JSON.stringify(e);yield new Promise((e,o)=>{this.ws.send(t,s=>{s?o(s):(this.logger.debug(`Sent message: ${t}`),e())})})}catch(e){throw this.connected=!1,new F(`Failed to send message: ${J(e)}`)}})}receive(){return W(this,arguments,function*(){for(this.checkConnected();this.isConnected;)try{const e=yield H(this.receiveRawData());this.logger.debug(`Received message: ${e}`),yield yield H(e)}catch(e){if(this.connected=!1,e instanceof M&&e.details.isClosed){this.logger.info("Connection closed");break}throw new F(`Failed to receive message: ${J(e)}`)}})}receiveRawData(){return new Promise((e,t)=>{if(!this.isConnected)return void t(new M("Not connected"));const o=()=>{this.ws&&(this.ws.off("close",s),this.ws.off("error",i),this.ws.off("message",r))},s=()=>{o(),this.connected=!1,t(new M("Connection closed",{isClosed:!0}))},i=e=>{o(),this.connected=!1,t(e)},r=t=>{o(),e(t.toString())};this.ws&&(this.ws.on("close",s),this.ws.on("error",i),this.ws.on("message",r))})}}class oe{constructor(e={}){this.cwd=e.cwd||process.cwd(),this.logger=e.logger||X,this.readOnly=e.readOnly||!1,this.maxFileSize=e.maxFileSize||10485760,e.allowedDirs?this.allowedDirs=new Set(e.allowedDirs.map(e=>E.resolve(this.cwd,e))):this.allowedDirs=new Set([this.cwd]),this.logger.info(`File handler initialized with ${this.allowedDirs.size} allowed directories`);for(const e of this.allowedDirs)this.logger.debug(` Allowed: ${e}`)}isPathAllowed(e){try{const t=E.resolve(this.cwd,e);for(const e of this.allowedDirs)if(t.startsWith(e))return!0;return this.logger.warn(`Path not in allowed directories: ${t}`),!1}catch(e){return e instanceof Error&&this.logger.error(`Error checking path: ${e.message}`,e),!1}}readFile(e,t,o){return U(this,void 0,void 0,function*(){if(!this.isPathAllowed(e))throw new $(`Access denied: ${e}`);const s=E.resolve(this.cwd,e);try{if(!T.existsSync(s))throw new b(`File not found: ${e}`);try{yield I.access(s,T.constants.R_OK)}catch(t){throw new $(`Permission denied: ${e}`)}const i=yield I.stat(s);if(!i.isFile())throw new b(`Not a file: ${e}`);if(i.size>this.maxFileSize)throw new b(`File too large: ${i.size} bytes (max: ${this.maxFileSize})`);const r=yield I.readFile(s,"utf-8");if(void 0!==t||void 0!==o){const s=r.split("\n"),i=t?t-1:0,n=o?i+o:s.length,l=Math.max(0,i),a=Math.min(s.length,n);return this.logger.debug(`Read ${a-l} lines from ${e}`),s.slice(l,a).join("\n")}return this.logger.debug(`Read ${r.length} bytes from ${e}`),r}catch(e){if(e instanceof b||e instanceof $)throw e;throw new b(`Failed to read file: ${J(e)}`)}})}writeFile(e,t){return U(this,void 0,void 0,function*(){if(this.readOnly)throw new $("File system is in read-only mode");if(!this.isPathAllowed(e))throw new $(`Access denied: ${e}`);const o=E.resolve(this.cwd,e);try{yield I.mkdir(E.dirname(o),{recursive:!0}),yield I.writeFile(o,t,"utf-8"),this.logger.debug(`Wrote ${t.length} bytes to ${e}`)}catch(e){throw new b(`Failed to write file: ${J(e)}`)}})}addAllowedDir(e){return U(this,void 0,void 0,function*(){const t=E.resolve(this.cwd,e);try{if(!T.existsSync(t))throw new b(`Directory does not exist: ${t}`);if(!(yield I.stat(t)).isDirectory())throw new b(`Not a directory: ${t}`);this.allowedDirs.add(t),this.logger.info(`Added allowed directory: ${t}`)}catch(e){if(e instanceof b)throw e;throw new b(`Failed to add ${t} as allowed directory: ${J(e)}`)}})}removeAllowedDir(e){const t=E.resolve(this.cwd,e);this.allowedDirs.delete(t),this.logger.info(`Removed allowed directory: ${t}`)}}class se{constructor(e={}){this.port=null,this.process=null,this.iflowPath=null,this.logger=e.logger||X,this.startPort=e.startPort||8090}get url(){if(!this.port)throw new N("iFlow process not started");return`ws://localhost:${this.port}/acp`}isRunning(){return!!this.process&&!this.process.killed&&null===this.process.exitCode}which(e){try{return P.execSync(`which ${e}`,{encoding:"utf-8"}).trim()}catch(e){return null}}fileExists(e){try{return T.existsSync(e)&&T.statSync(e).isFile()}catch(e){return!1}}findIflowPath(){const e=this.which("iflow");if(e)return this.logger.debug(`Found iflow at: ${e}`),e;const t=x.homedir(),o=[E.join(t,".npm-global","bin","iflow"),"/usr/local/bin/iflow",E.join(t,".local","bin","iflow"),E.join(t,"node_modules",".bin","iflow"),E.join(t,".yarn","bin","iflow"),E.join(t,"AppData","Roaming","npm","iflow.cmd"),E.join("C:","Program Files","nodejs","iflow.cmd")];for(const e of o)if(this.fileExists(e))return this.logger.debug(`Found iflow at: ${e}`),e;const s=null!==this.which("npm"),i=null!==this.which("node");let r;throw r="win32"===x.platform()?s||i?"iFlow CLI not found. Please use the following command to install:\n npm install -g @iflow-ai/iflow-cli@latest":"iFlow requires Node.js, but it is not installed in the system.\n\nPlease install Node.js first: https://nodejs.org/\n\nAfter installing Node.js, use the following command to install iFlow:\n npm install -g @iflow-ai/iflow-cli@latest":'iFlow CLI not found. Please use the following command to install:\n\nšŸŽ Mac/Linux/Ubuntu users:\n bash -c "$(curl -fsSL https://cloud.iflow.cn/iflow-cli/install.sh)"\n\n🪟 Windows users:\n npm install -g @iflow-ai/iflow-cli@latest',new C(r)}isPortAvailable(e){return new Promise(t=>{const o=A.createServer();o.listen(e,"localhost",()=>{o.once("close",()=>{t(!0)}),o.close()}),o.once("error",()=>{t(!1)})})}findAvailablePort(){return U(this,void 0,void 0,function*(){for(let e=0;e<100;e++){const t=this.startPort+e;if(yield this.isPortAvailable(t))return this.logger.debug(`Found available port: ${t}`),t}throw new L(`No available port found in range ${this.startPort}-${this.startPort+100}`)})}start(){return U(this,void 0,void 0,function*(){if(this.isRunning())return this.url;this.iflowPath=this.findIflowPath(),this.port=yield this.findAvailablePort();const e=[this.iflowPath,"--experimental-acp","--port",this.port.toString()];this.logger.info(`Starting iFlow process: ${e.join(" ")}`);try{if(this.process=P.spawn(e[0],e.slice(1),{stdio:["ignore","pipe","pipe"],detached:!1}),yield this.onSpawn(),!this.isRunning()){let e="iFlow process exited immediately";if(this.process.stderr){const t=this.process.stderr.read();t&&(e+=`: ${t.toString("utf-8")}`)}throw new Error(e)}return this.logger.info(`iFlow process started on port ${this.port} (PID: ${this.process.pid})`),this.url}catch(e){throw this.port=null,this.process=null,new N(`Failed to start iFlow process: ${J(e)}`)}})}stop(){return U(this,void 0,void 0,function*(){if(this.process){if(!this.isRunning())return this.port=null,void(this.process=null);this.logger.info(`Stopping iFlow process (PID: ${this.process.pid})`);try{this.process.kill("SIGTERM"),yield Promise.race([new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()}),new Promise(e=>setTimeout(()=>e(),5e3))]),this.isRunning()?(this.logger.warn("iFlow process did not terminate gracefully, forcing kill"),this.process.kill("SIGKILL"),yield new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()})):this.logger.info("iFlow process terminated gracefully")}catch(e){this.logger.error(`Error stopping iFlow process: ${J(e)}`)}finally{this.port=null,this.process=null}}})}onSpawn(){return U(this,arguments,void 0,function*(e=5e3){return new Promise((t,o)=>{if(!this.process)return void o(new Error("Process not initialized"));const s=setTimeout(()=>{o(new Error(`Process spawn timeout after ${e}ms`))},e);this.process.once("spawn",()=>{clearTimeout(s),setTimeout(t,2e3)})})})}}var ie;!function(e){e.ERROR="error",e.RESPONSE="response",e.FILE_READ="file_read",e.FILE_WRITE="file_write",e.SESSION_UPDATE="session_update",e.TOOL_CALL="tool_call",e.TOOL_UPDATE="tool_update",e.TOOL_CONFIRMATION="tool_confirmation",e.TASK_FINISH="task_finish",e.UNKNOWN="unknown"}(ie||(ie={}));class re{constructor(e={}){this.protocol=null,this.transport=null,this.connected=!1,this.authenticated=!1,this.messageTask=null,this.messageQueue=[],this.pendingToolCalls=new Map,this.url=null,this.sessionId=null,this.processManager=null,this.processStarted=!1,this.options=Object.assign({url:"ws://localhost:8090/acp",cwd:process.cwd(),timeout:3e4,logLevel:"INFO",fileMaxSize:10485760,permissionMode:exports.PermissionMode.AUTO,autoApproveTypes:["read","fetch","list"],authMethodId:"iflow",autoStartProcess:!0,processStartPort:8090},e),this.logger=new V({level:this.options.logLevel})}connect(){return U(this,void 0,void 0,function*(){var e,t;if(this.connected)this.logger.warn("Already connected");else try{if(this.options.autoStartProcess&&((null===(e=this.options.url)||void 0===e?void 0:e.startsWith("ws://localhost:"))||(null===(t=this.options.url)||void 0===t?void 0:t.startsWith("ws://127.0.0.1:")))){const e=new te({url:this.options.url,logger:this.logger,timeout:2e3});try{yield e.connect(),yield e.close(),this.url=this.options.url,this.logger.info(`iFlow already running at ${this.options.url}`)}catch(e){this.logger.info("iFlow not running, starting process..."),this.processManager=new se({logger:this.logger,startPort:this.options.processStartPort});try{const e=yield this.processManager.start();this.url=e,this.processStarted=!0,this.logger.info(`Started iFlow process at ${e}`),yield new Promise(e=>setTimeout(e,1e3))}catch(e){throw e instanceof C?(this.logger.error("iFlow not installed"),C):(this.logger.error(`Failed to start iFlow process: ${J(e)}`),new M(`Failed to start iFlow process: ${J(e)}`))}}}let o=null;this.options.fileAccess&&(o=new oe({cwd:this.options.cwd,logger:this.logger,readOnly:this.options.fileReadOnly,maxFileSize:this.options.fileMaxSize,allowedDirs:this.options.fileAllowedDirs}),this.logger.info(`File system access enabled with ${this.options.fileReadOnly?"read-only":"read-write"} mode`)),this.transport=new te({url:this.options.url,logger:this.logger,timeout:this.options.timeout}),this.protocol=new ee({logger:this.logger,transport:this.transport,fileHandler:o,permissionMode:this.options.permissionMode,autoApproveTypes:this.options.autoApproveTypes}),yield this.transport.connect();const s=yield this.protocol.initialize({mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents});this.authenticated=s.isAuthenticated||!1,this.authenticated||(yield this.protocol.authenticate({methodId:this.options.authMethodId,methodInfo:this.options.authMethodInfo}),this.authenticated=!0),this.sessionId=yield this.protocol.createSession({cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents,settings:this.options.sessionSettings}),this.connected=!0,this.messageTask=this.handleMessages(),this.logger.info("Connected to iFlow")}catch(e){throw yield this.disconnect(),new M(`Failed to connect: ${J(e)}`)}})}loadSession(e){return U(this,void 0,void 0,function*(){if(!this.connected||!this.protocol)throw new M("Not connected. Call connect() first.");yield this.protocol.loadSession({sessionId:e,cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers}),this.sessionId=e,this.logger.info(`Loaded session: ${e}`)})}disconnect(){return U(this,void 0,void 0,function*(){this.connected=!1,this.transport&&(yield this.transport.close()),this.processManager&&this.processStarted&&(yield this.processManager.stop()),this.url=null,this.protocol=null,this.transport=null,this.messageTask=null,this.authenticated=!1,this.processManager=null,this.processStarted=!1,this.logger.info("Disconnected from iFlow")})}sendMessage(e,t){return U(this,void 0,void 0,function*(){if(!this.connected||!this.protocol||!this.sessionId)throw new M("Not connected. Call connect() first.");const o=[{type:"text",text:e}];if(null==t?void 0:t.length)for(const e of t){const t=E.resolve(this.options.cwd||process.cwd(),e),s=E.parse(e);if(!T.existsSync(t)){this.logger.warn(`File not found, skipping: ${t}`);continue}const i=s.ext.toLowerCase();if([".png",".jpg",".jpeg",".gif",".bmp",".webp",".svg"].includes(i))try{const e=T.readFileSync(t).toString("base64"),r={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".bmp":"image/bmp",".webp":"image/webp",".svg":"image/svg+xml"};o.push({type:"image",data:e,mimeType:r[i]||"image/unknown"}),this.logger.debug(`Added image file: ${s.base}`)}catch(e){this.logger.error(`Failed to read image file ${t}: ${J(e)}`);continue}else if([".mp3",".wav",".m4a",".ogg",".flac"].includes(i))try{const e=T.readFileSync(t).toString("base64"),r={".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".ogg":"audio/ogg",".flac":"audio/flac"};o.push({type:"audio",data:e,mimeType:r[i]||"audio/unknown"}),this.logger.debug(`Added audio file: ${s.base}`)}catch(e){this.logger.error(`Failed to read audio file ${t}: ${J(e)}`);continue}else{const e=T.statSync(t);o.push({type:"resource_link",uri:`file://${t}`,name:s.base,title:s.name,size:e.size}),this.logger.debug(`Added resource link: ${s.base}`)}}yield this.protocol.sendPrompt({sessionId:this.sessionId,prompt:o})})}interrupt(){return U(this,void 0,void 0,function*(){if(!this.connected||!this.protocol||!this.sessionId)throw new M("Not connected");yield this.protocol.cancelSession({sessionId:this.sessionId}),this.logger.info("Sent interrupt signal")})}receiveMessages(){return W(this,arguments,function*(){if(!this.connected)throw new M("Not connected");for(;this.connected;)try{this.messageQueue.length>0?yield yield H(this.messageQueue.shift()):yield H(new Promise(e=>setTimeout(e,100)))}catch(e){continue}})}approveToolCall(e){return U(this,arguments,void 0,function*(e,t=exports.ToolCallConfirmationOutcome.ALLOW){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Approved tool call ${e} with outcome ${t}`),this.pendingToolCalls.delete(e)})}rejectToolCall(e){return U(this,void 0,void 0,function*(){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Rejected tool call ${e}`),this.pendingToolCalls.delete(e)})}handleMessages(){return U(this,void 0,void 0,function*(){var e,t,o,s;if(this.protocol)try{try{for(var i,r=!0,n=q(this.protocol.handleMessages());!(e=(i=yield n.next()).done);r=!0){s=i.value,r=!1;const e=s,t=this.processProtocolMessage(e);t&&this.messageQueue.push(t)}}catch(e){t={error:e}}finally{try{r||e||!(o=n.return)||(yield o.call(n))}finally{if(t)throw t.error}}}catch(e){this.logger.error(`Error in message handler: ${J(e)}`);const t={type:exports.MessageType.ERROR,code:-1,message:String(J(e))};this.messageQueue.push(t)}})}processProtocolMessage(e){var t,o,s;switch(e.type){case ie.SESSION_UPDATE:{const{updateData:i}=e;let r,n;switch("agentId"in i&&i.agentId&&(r=i.agentId,n=function(e){const t=e.split("-");return"subagent"!==t[0]||t.length<4?{agentId:e}:4===t.length?{agentId:e,taskId:["null","undefined"].includes(t[1])?void 0:t[1],agentIndex:parseInt(t[2])||void 0,timestamp:parseInt(t[3])||void 0}:{agentId:e,taskId:t.slice(1,-2).join("-"),agentIndex:parseInt(t[t.length-2])||void 0,timestamp:parseInt(t[t.length-1])||void 0}}(r)),i.sessionUpdate){case K.PLAN:{const e=null===(t=i.entries)||void 0===t?void 0:t.map(e=>({content:e.content||"",status:e.status||exports.PlanStatus.PENDING,priority:e.priority||exports.PlanPriority.MEDIUM}));return e&&(null==e?void 0:e.length)>0?{type:exports.MessageType.PLAN,entries:e}:null}case K.TOOL_CALL:{const e={type:exports.MessageType.TOOL_CALL,id:i.toolCallId||"",label:i.title||"Tool",icon:{type:exports.ToolCallIconType.EMOJI,value:"šŸ”§"},status:i.status||exports.ToolCallStatus.IN_PROGRESS,toolName:i.toolName};return r&&(e.agentId=r,e.agentInfo=n),this.pendingToolCalls.set(e.id,e),e}case K.TOOL_CALL_UPDATE:{const e=i.toolCallId;let t;if(this.pendingToolCalls.has(e)?(t=this.pendingToolCalls.get(e),t.status=i.status||exports.ToolCallStatus.COMPLETED,i.toolName&&(t.toolName=i.toolName),!t.agentId&&r&&(t.agentId=r),!t.agentInfo&&n&&(t.agentInfo=n)):(t={type:exports.MessageType.TOOL_CALL,id:e,label:i.title||"Tool",icon:{type:exports.ToolCallIconType.EMOJI,value:"šŸ”§"},status:i.status||exports.ToolCallStatus.COMPLETED,toolName:i.toolName},r&&(t.agentId=r,t.agentInfo=n),this.pendingToolCalls.set(e,t)),i.content&&(null===(o=i.content)||void 0===o?void 0:o.length)>0){let e;const o=[];for(const t of i.content)"args"in t&&(e=t.args),"content"===t.type&&"text"===(null===(s=t.content)||void 0===s?void 0:s.type)&&o.push(t.content.text||"");void 0!==e&&(t.args=e),o.length>0&&(t.output=o.join("\n"))}return t}case K.USER_MESSAGE_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t)return{type:exports.MessageType.USER,chunks:[{text:t}]}}return null}case K.AGENT_MESSAGE_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t){const e={type:exports.MessageType.ASSISTANT,chunk:{text:t}};return r&&(e.agentId=r,e.agentInfo=n),e}}return null}case K.AGENT_THOUGHT_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t){const e={type:exports.MessageType.ASSISTANT,chunk:{thought:t}};return r&&(e.agentId=r,e.agentInfo=n),e}}}default:return null}}case ie.RESPONSE:return"stopReason"in(e.result||{})?{type:exports.MessageType.TASK_FINISH,stopReason:e.result.stopReason}:null;case ie.ERROR:return{type:exports.MessageType.ERROR,code:e.code||-1,message:e.error||"Unknown error"};default:return null}}}function ne(e){let t,o=!1,s="text";if(e.startsWith("//"))o=!0,s="control";else try{t=JSON.parse(e),t&&"method"in t?s=`method:${t.method}`:t&&("result"in t||"error"in t)?s="response":t&&"type"in t&&(s=t.type)}catch(e){}return{isControl:o,messageType:s,rawData:e,jsonData:t,timestamp:Date.now()}}exports.AuthenticationError=k,exports.ConnectionError=M,exports.IFlowClient=re,exports.IFlowError=O,exports.IFlowNotInstalledError=C,exports.IFlowProcessError=N,exports.JSONDecodeError=R,exports.PermissionError=$,exports.PortNotAvailableError=L,exports.ProtocolError=D,exports.RawDataClient=class extends re{constructor(e,t=!0){super(e),this.rawQueue=[],this.rawHistory=[],this.rawQueueResolvers=[],this.messageQueueResolvers=[],this.captureRaw=t}handleMessages(){const e=Object.create(null,{handleMessages:{get:()=>super.handleMessages}});return U(this,void 0,void 0,function*(){if(this.protocol)try{if(this.captureRaw&&this.transport){const e=this.captureRawStream(),t=this.handleParsedStream();yield Promise.all([e,t])}else yield e.handleMessages.call(this)}catch(e){this.logger.error(`Error in message handler: ${J(e)}`)}})}captureRawStream(){return U(this,void 0,void 0,function*(){var e,t,o,s;if(this.transport)try{try{for(var i,r=!0,n=q(this.transport.receive());!(e=(i=yield n.next()).done);r=!0){s=i.value,r=!1;const e=s,t=ne("string"==typeof e?e:JSON.stringify(e));this.rawQueue.push(t),this.rawHistory.push(t);const o=this.rawQueueResolvers.shift();o&&o(t)}}catch(e){t={error:e}}finally{try{r||e||!(o=n.return)||(yield o.call(n))}finally{if(t)throw t.error}}}catch(e){this.logger.error(`Error capturing raw stream: ${J(e)}`)}})}handleParsedStream(){return U(this,void 0,void 0,function*(){var e,t,o,s;if(this.protocol)try{for(var i,r=!0,n=q(this.protocol.handleMessages());!(e=(i=yield n.next()).done);r=!0){s=i.value,r=!1;const e=s,t=this.processProtocolMessage(e);if(t){const e=this.messageQueueResolvers.shift();e&&e(t)}}}catch(e){t={error:e}}finally{try{r||e||!(o=n.return)||(yield o.call(n))}finally{if(t)throw t.error}}})}receiveRawMessages(){return W(this,arguments,function*(){for(;this.connected||this.rawQueue.length>0;)try{if(this.rawQueue.length>0)yield yield H(this.rawQueue.shift());else{const e=yield H(Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),100)})]));yield yield H(e)}}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}})}receiveDualStream(){return W(this,arguments,function*(){const e=[],t=[];for(;this.connected||this.rawQueue.length>0||e.length>0||t.length>0;)try{let e,t;e=this.rawQueue.length>0?this.rawQueue.shift():yield H(Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]));try{t=yield H(Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]))}catch(e){}e.parsedMessage=t,yield yield H([e,t])}catch(e){if(!(e instanceof Error&&"Timeout"===e.message))throw e;try{const e=yield H(Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})])),t=ne("<no-raw-data>");t.messageType="parsed_only",yield yield H([t,e])}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}})}getRawHistory(){return[...this.rawHistory]}getProtocolStats(){const e={totalMessages:this.rawHistory.length,messageTypes:{},controlMessages:0,jsonMessages:0,textMessages:0,errors:0};for(const t of this.rawHistory)t.messageType&&(e.messageTypes[t.messageType]=(e.messageTypes[t.messageType]||0)+1),t.isControl?e.controlMessages++:t.jsonData?e.jsonMessages++:e.textMessages++,t.jsonData&&"error"in t.jsonData&&e.errors++;return e}sendRaw(e){return U(this,void 0,void 0,function*(){if(!this.transport)throw new Error("Not connected");yield this.transport.send(e);const t="string"==typeof e?e:JSON.stringify(e).substring(0,100);this.logger.info(`Sent raw data: ${t}`)})}},exports.TimeoutError=_,exports.TransportError=F,exports.ValidationError=b,exports.query=function(e,t,o){return U(this,void 0,void 0,function*(){var s,i,r,n;const l=[],a=new re(o);yield a.connect();try{yield a.sendMessage(e,t);try{for(var c,d=!0,h=q(a.receiveMessages());!(s=(c=yield h.next()).done);d=!0){n=c.value,d=!1;const e=n;if(e.type===exports.MessageType.ASSISTANT&&e.chunk.text)l.push(e.chunk.text);else if(e.type===exports.MessageType.TASK_FINISH)break}}catch(e){i={error:e}}finally{try{d||s||!(r=h.return)||(yield r.call(h))}finally{if(i)throw i.error}}}finally{yield a.disconnect()}return l.join("")})},exports.queryStream=function(e,t,o){return W(this,arguments,function*(){var s,i,r,n;const l=new re(o);yield H(l.connect());try{yield H(l.sendMessage(e,t));try{for(var a,c=!0,d=q(l.receiveMessages());!(s=(a=yield H(d.next())).done);c=!0){n=a.value,c=!1;const e=n;if(e.type===exports.MessageType.ASSISTANT&&e.chunk.text)yield yield H(e.chunk.text);else if(e.type===exports.MessageType.TASK_FINISH)break}}catch(e){i={error:e}}finally{try{c||s||!(r=d.return)||(yield H(r.call(d)))}finally{if(i)throw i.error}}}finally{yield H(l.disconnect())}})};
1
+ "use strict";var e=require("fs"),t=require("path"),s=require("ws"),o=require("fs/promises"),i=require("os"),r=require("net"),n=require("child_process");function a(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(s){if("default"!==s){var o=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,o.get?o:{enumerable:!0,get:function(){return e[s]}})}}),t.default=e,Object.freeze(t)}var l,c,h,d,p,u,g,w,f,m,y,S,T,E=a(e),I=a(t),x=a(o),A=a(i),v=a(r),P=a(n);class _ extends Error{constructor(e,t){super(e),this.name="IFlowError",this.details=t||{}}}class O extends _{constructor(e,t){super(e,t),this.name="TimeoutError"}}class R extends _{constructor(e,t){super(e,{rawData:t}),this.name="JSONDecodeError",this.rawData=t}}class C extends _{constructor(e,t){super(e,t),this.name="IFlowNotInstalledError"}}class N extends _{constructor(e,t){super(e,t),this.name="IFlowProcessError"}}class L extends _{constructor(e,t){super(e,t),this.name="PortNotAvailableError"}}class F extends _{constructor(e,t){super(e,t),this.name="ConnectionError"}}class $ extends _{constructor(e,t){super(e,t),this.name="TransportError"}}class M extends _{constructor(e,t){super(e,t),this.name="PermissionError"}}class D extends _{constructor(e,t){super(e,t),this.name="ValidationError"}}class b extends _{constructor(e,t){super(e,t),this.name="ProtocolError"}}class k extends _{constructor(e,t){super(e,t),this.name="AuthenticationError"}}exports.LogLevel=void 0,(l=exports.LogLevel||(exports.LogLevel={}))[l.DEBUG=0]="DEBUG",l[l.INFO=1]="INFO",l[l.WARN=2]="WARN",l[l.ERROR=3]="ERROR",exports.PermissionMode=void 0,(c=exports.PermissionMode||(exports.PermissionMode={})).AUTO="auto",c.MANUAL="manual",c.SELECTIVE="selective",exports.ApprovalMode=void 0,(h=exports.ApprovalMode||(exports.ApprovalMode={})).DEFAULT="default",h.AUTO_EDIT="autoEdit",h.YOLO="yolo",h.PLAN="plan",exports.HookEventType=void 0,(d=exports.HookEventType||(exports.HookEventType={})).PRE_TOOL_USE="PreToolUse",d.POST_TOOL_USE="PostToolUse",d.STOP="Stop",d.SUBAGENT_STOP="SubagentStop",d.SET_UP_ENVIRONMENT="SetUpEnvironment",exports.PlanPriority=void 0,(p=exports.PlanPriority||(exports.PlanPriority={})).HIGH="high",p.MEDIUM="medium",p.LOW="low",exports.PlanStatus=void 0,(u=exports.PlanStatus||(exports.PlanStatus={})).PENDING="pending",u.IN_PROGRESS="in_progress",u.COMPLETED="completed",exports.StopReason=void 0,(g=exports.StopReason||(exports.StopReason={})).END_TURN="end_turn",g.MAX_TOKENS="max_tokens",g.REFUSAL="refusal",g.CANCELLED="cancelled",exports.ToolCallStatus=void 0,(w=exports.ToolCallStatus||(exports.ToolCallStatus={})).PENDING="pending",w.IN_PROGRESS="in_progress",w.COMPLETED="completed",w.FAILED="failed",exports.ToolCallContentType=void 0,(f=exports.ToolCallContentType||(exports.ToolCallContentType={})).DIFF="diff",f.MARKDOWN="markdown",exports.ToolCallConfirmationType=void 0,(m=exports.ToolCallConfirmationType||(exports.ToolCallConfirmationType={})).EDIT="edit",m.EXECUTE="execute",m.MCP="mcp",m.FETCH="fetch",m.OTHER="other",exports.ToolCallConfirmationOutcome=void 0,(y=exports.ToolCallConfirmationOutcome||(exports.ToolCallConfirmationOutcome={})).ALLOW="allow",y.ALWAYS_ALLOW="alwaysAllow",y.ALWAYS_ALLOW_TOOL="alwaysAllowTool",y.ALWAYS_ALLOW_MCP_SERVER="alwaysAllowMcpServer",y.REJECT="reject",exports.ToolCallIconType=void 0,(S=exports.ToolCallIconType||(exports.ToolCallIconType={})).URL="url",S.EMOJI="emoji",exports.MessageType=void 0,(T=exports.MessageType||(exports.MessageType={})).PLAN="plan",T.USER="user",T.ASSISTANT="assistant",T.TOOL_CALL="tool_call",T.ERROR="error",T.TASK_FINISH="task_finish";const U="2.0";var j,H,W;function q(e){return e instanceof Error?e.message:e?String(e):"unknown error"}!function(e){e.INITIALIZE="initialize",e.AUTHENTICATE="authenticate",e.SESSION_NEW="session/new",e.SESSION_LOAD="session/load",e.SESSION_PROMPT="session/prompt",e.SESSION_CANCEL="session/cancel"}(j||(j={})),function(e){e.SESSION_UPDATE="session/update",e.SESSION_REQUEST_PERMISSION="session/request_permission",e.FS_READ_TEXT_FILE="fs/read_text_file",e.FS_WRITE_TEXT_FILE="fs/write_text_file",e.PUSH_TOOL_CALL="pushToolCall",e.UPDATE_TOOL_CALL="updateToolCall",e.NOTIFY_TASK_FINISH="notifyTaskFinish"}(H||(H={})),function(e){e.PLAN="plan",e.TOOL_CALL="tool_call",e.TOOL_CALL_UPDATE="tool_call_update",e.USER_MESSAGE_CHUNK="user_message_chunk",e.AGENT_MESSAGE_CHUNK="agent_message_chunk",e.AGENT_THOUGHT_CHUNK="agent_thought_chunk"}(W||(W={}));class z{constructor(e={}){const t=e.level||"INFO";this.level=exports.LogLevel[t]}debug(e){this.log(exports.LogLevel.DEBUG,e)}info(e){this.log(exports.LogLevel.INFO,e)}warn(e){this.log(exports.LogLevel.WARN,e)}error(e,t){this.log(exports.LogLevel.ERROR,e,t)}log(e,t,s){if(e<this.level)return;const o=`[${(new Date).toLocaleString("sv-SE").replace("T"," ")}] ${exports.LogLevel[e]}: ${t}${s?`\n${s.stack}`:""}`;switch(e){case exports.LogLevel.DEBUG:console.debug(o);break;case exports.LogLevel.INFO:console.info(o);break;case exports.LogLevel.WARN:console.warn(o);break;case exports.LogLevel.ERROR:console.error(o)}}}const G=new z;function Q(e){return!!e&&"id"in e&&"result"in e&&null!=e.result}function K(e){return!!e&&"id"in e&&"error"in e&&null!=e.error}function J(e){return!!e&&"method"in e&&!("result"in e)&&!("error"in e)}class V{constructor(e){this.requestId=0,this.initialized=!1,this.authenticated=!1,this.logger=e.logger||G,this.transport=e.transport,this.fileHandler=e.fileHandler,this.permissionMode=e.permissionMode||exports.PermissionMode.AUTO,this.autoApproveTypes=e.autoApproveTypes||["read","fetch","list"]}nextRequestId(){return++this.requestId}checkAuthenticated(){if(!this.initialized)throw new b("Protocol not initialized. Call initialize() first.");if(!this.authenticated)throw new b("Not authenticated. Call authenticate() first.")}async sendResult(e,t){const s={jsonrpc:U,id:e,result:t};await this.transport.send(s)}async sendError(e,t,s){const o={jsonrpc:U,id:e,error:{code:t,message:s}};await this.transport.send(o)}async waitForReadySignal(){for await(const e of this.transport.receive()){const t=e.trim();if("//ready"===t){this.logger.info("Received //ready signal");break}t.startsWith("//")&&this.logger.debug(`Control message: ${t}`)}}async waitForMessageResponse(e,t,s){const{timeout:o,timeoutMsg:i=`Timeout after ${o} seconds`}=s||{},r=Date.now();for await(const s of this.transport.receive()){if(s.trim().startsWith("//")){this.logger.debug(`Control message: ${s.trim()}`);continue}let n;try{n=JSON.parse(s.trim())}catch(e){this.logger.error(`Failed to parse response: ${q(e)}`);continue}if(n.id===e){const e=t(n);if(void 0!==e)return e}if(o&&o>0&&Date.now()-r>o)throw new O(i)}}async initialize(e={}){if(this.initialized)return this.logger.warn("Protocol already initialized"),{protocolVersion:1,isAuthenticated:this.authenticated};this.logger.info("Waiting for //ready signal..."),await this.waitForReadySignal();const t=this.nextRequestId(),s={jsonrpc:U,id:t,method:j.INITIALIZE,params:{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!0,writeTextFile:!0}},...e}};await this.transport.send(s),this.logger.info("Sent initialize request");const o=await this.waitForMessageResponse(t,e=>{if("error"in e)throw new b(`Initialize failed: ${e.error?.message}`,e.error);const t=e.result||{};return this.initialized=!0,this.authenticated=t.isAuthenticated||!1,this.logger.info(`Initialized with protocol version: ${t.protocolVersion}, authenticated: ${this.authenticated}`),t},{timeout:1e4,timeoutMsg:"Initialize timeout after 10 seconds"});if(o)return o;throw new b("Connection closed during initialization")}async authenticate(e={}){const t=e.methodId||"iflow";if(this.authenticated)return void this.logger.warn("Already authenticated");const s=this.nextRequestId(),o={jsonrpc:U,id:s,method:j.AUTHENTICATE,params:{...e,methodId:t}};await this.transport.send(o),this.logger.info(`Sent authenticate request with method: ${o.params.methodId}`);if(!await this.waitForMessageResponse(s,e=>{if("error"in e)throw new k(`Authentication failed: ${e.error?.message}`,e.error);const s=e.result||{};return s.methodId===t?(this.authenticated=!0,this.logger.info(`Authentication successful with method: ${s.methodId}`),!0):(this.authenticated=!0,this.logger.warn(`Unexpected methodId in response: ${s.methodId} (expected ${t})`),!0)},{timeout:1e4,timeoutMsg:"Authentication timeout after 10 seconds"}))throw new k("Connection closed during authentication")}async createSession(e={}){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:U,id:t,method:j.SESSION_NEW,params:{...e,cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]}};await this.transport.send(s),this.logger.info(`Sent session/new request with cwd: ${e.cwd}`);const o=await this.waitForMessageResponse(t,e=>{if("error"in e)throw new b(`session/new failed: ${e.error?.message}`,e.error);const t=e.result||{};if(t.sessionId)return this.logger.info(`Created session: ${t.sessionId}`),t.sessionId;throw new b(`Invalid session/new response: ${JSON.stringify(t)}`)},{timeout:1e4,timeoutMsg:"Session creation timeout after 10 seconds"});if(o)return o;throw new b("Connection closed while waiting for session/new response")}async loadSession(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:U,id:t,method:j.SESSION_LOAD,params:{...e,cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]}};await this.transport.send(s),this.logger.info(`Sent session/load request for session: ${e.sessionId}`);if(!await this.waitForMessageResponse(t,t=>{if("error"in t){if(-32601===t.error.code)throw new b("session/load is not supported by the current iFlow version. Use session/new to create a new session instead.",t.error);throw new b(`session/load failed: ${t.error?.message}`,t.error)}return this.logger.info(`Session loaded successfully: ${e.sessionId}`),!0},{timeout:1e4,timeoutMsg:"Session load timeout after 10 seconds"}))throw new b("Connection closed while waiting for session/load response")}async sendPrompt(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:U,id:t,method:j.SESSION_PROMPT,params:e};return await this.transport.send(s),this.logger.info(`Sent prompt with ${e.prompt.length} content blocks`),t}async cancelSession(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:U,id:t,method:j.SESSION_CANCEL,params:e};await this.transport.send(s),this.logger.info("Sent session/cancel request")}async*handleMessages(){for await(const e of this.transport.receive()){if(e.trim().startsWith("//")){this.logger.debug(`Control message: ${e.trim()}`);continue}let t;try{t=JSON.parse(e.trim())}catch(t){throw this.logger.error(`Failed to parse message: ${q(t)}`),new R("Invalid JSON received",e)}J(t)?yield await this.handleClientMessage(t):Q(t)?yield{type:"response",id:t.id,result:t.result}:K(t)&&(yield{type:"error",code:t.error.code,error:t.error.message})}}async handleClientMessage(e){const{method:t}=e;switch(t){case H.FS_READ_TEXT_FILE:return await this.handleReadTextFile(e);case H.FS_WRITE_TEXT_FILE:return await this.handleWriteTextFile(e);case H.SESSION_UPDATE:return await this.handleSessionUpdate(e);case H.SESSION_REQUEST_PERMISSION:return await this.handleRequestPermission(e);case H.PUSH_TOOL_CALL:return await this.handlePushToolCall(e);case H.UPDATE_TOOL_CALL:return await this.handleUpdateToolCall(e);case H.NOTIFY_TASK_FINISH:return await this.handleNotifyTaskFinish(e);default:return await this.handleUnknownMessage(e)}}async handleReadTextFile(e){const{id:t,method:s,params:o}=e,{path:i,limit:r,line:n}=o||{};let a;if(this.logger.info(`fs/read_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&await this.sendError(t,-32603,e),{type:"error",code:-32603,error:e,method:s}}try{a=await this.fileHandler.readFile(i,n,r)}catch(e){const o=q(e);return this.logger.error(`Error reading file ${i}: ${o}`),void 0!==t&&await this.sendError(t,-32603,o),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&await this.sendResult(t,{content:a}),{type:"file_read",path:i,content:a}}async handleWriteTextFile(e){const{id:t,method:s,params:o}=e,{path:i,content:r}=o||{};if(this.logger.info(`fs/write_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&await this.sendError(t,-32603,e),{type:"error",code:-32603,error:e,method:s}}try{await this.fileHandler.writeFile(i,r)}catch(e){const o=q(e);return this.logger.error(`Error writing file ${i}: ${o}`),void 0!==t&&await this.sendError(t,-32603,o),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&await this.sendResult(t,{success:!0}),{type:"file_write",path:i,content:r}}async handleSessionUpdate(e){const{params:t}=e,{sessionId:s,update:o}=t;return{type:"session_update",sessionId:s,updateData:o}}async handleRequestPermission(e){const{id:t,params:s}=e,o=s.toolCall||{},i=s.options||[];let r,n;if(r=this.permissionMode===exports.PermissionMode.AUTO||this.permissionMode!==exports.PermissionMode.MANUAL&&this.autoApproveTypes.includes(o.type||""),r){let e;for(const t of i){const s=t.optionId||"";if("proceed_once"===s){e=s;break}"proceed_always"===s&&(e=s)}!e&&i.length>0&&(e=i[0].optionId||"proceed_once"),n={outcome:{outcome:"selected",optionId:e}}}else n={outcome:{outcome:"cancelled"}};return void 0!==t&&await this.sendResult(t,n),this.logger.info(`Permission request for tool '${o.title||"unknown"}' - Response: ${n.outcome.outcome}`),{type:"tool_confirmation",params:s,response:n}}async handlePushToolCall(e){const{id:t,params:s}=e,o=`tool_${this.nextRequestId()}`,i={id:o};return void 0!==t&&await this.sendResult(t,i),{type:"tool_call",id:o,params:s}}async handleUpdateToolCall(e){const{id:t,params:s}=e;return void 0!==t&&await this.sendResult(t,null),{type:"tool_update",params:s}}async handleNotifyTaskFinish(e){const{id:t,params:s}=e;return void 0!==t&&await this.sendResult(t,null),{type:"task_finish",params:s}}async handleUnknownMessage(e){const{id:t,method:s,params:o}=e;return this.logger.warn(`Unknown method: ${s}`),void 0!==t&&await this.sendError(t,-32601,"Method not found"),{type:"unknown",method:s,params:o}}}class X{constructor(e){this.ws=null,this.connected=!1,this.url=e.url,this.logger=e.logger||G,this.timeout=e.timeout||3e5}get isConnected(){return!!this.ws&&this.connected}checkConnected(){if(!this.isConnected)throw new F("Not connected")}async connect(){if(this.connected)this.logger.warn(`Already connected to ${this.url}`);else try{this.logger.info(`Connecting to ${this.url}`),this.ws=await new Promise((e,t)=>{const o=new s(this.url),i=setTimeout(()=>{o.close(),t(new O(`Connected to ${this.url} timeout after ${this.timeout/1e3}s`))},this.timeout);o.on("open",()=>{clearTimeout(i),this.connected=!0,this.logger.info(`Connected to ${this.url} succesfully`),e(o)}),o.on("error",e=>{clearTimeout(i),this.connected=!1,t(e)}),o.on("close",(e,s)=>{clearTimeout(i),this.connected=!1,t(new Error(`${s} (code: ${e})`))})})}catch(e){if(e instanceof O)throw e;throw new F(`Failed to connect to ${this.url}: ${q(e)}`)}}async close(){if(this.ws&&this.connected)try{this.ws.close(),this.logger.info("Connection closed")}catch(e){this.logger.warn(`Error closing connection: ${q(e)}`)}this.ws=null,this.connected=!1}async send(e){this.checkConnected();try{const t="string"==typeof e?e:JSON.stringify(e);await new Promise((e,s)=>{this.ws.send(t,o=>{o?s(o):(this.logger.debug(`Sent message: ${t}`),e())})})}catch(e){throw this.connected=!1,new $(`Failed to send message: ${q(e)}`)}}async*receive(){for(this.checkConnected();this.isConnected;)try{const e=await this.receiveRawData();this.logger.debug(`Received message: ${e}`),yield e}catch(e){if(this.connected=!1,e instanceof F&&e.details.isClosed){this.logger.info("Connection closed");break}throw new $(`Failed to receive message: ${q(e)}`)}}receiveRawData(){return new Promise((e,t)=>{if(!this.isConnected)return void t(new F("Not connected"));const s=()=>{this.ws&&(this.ws.off("close",o),this.ws.off("error",i),this.ws.off("message",r))},o=()=>{s(),this.connected=!1,t(new F("Connection closed",{isClosed:!0}))},i=e=>{s(),this.connected=!1,t(e)},r=t=>{s(),e(t.toString())};this.ws&&(this.ws.on("close",o),this.ws.on("error",i),this.ws.on("message",r))})}}class Y{constructor(e={}){this.cwd=e.cwd||process.cwd(),this.logger=e.logger||G,this.readOnly=e.readOnly||!1,this.maxFileSize=e.maxFileSize||10485760,e.allowedDirs?this.allowedDirs=new Set(e.allowedDirs.map(e=>I.resolve(this.cwd,e))):this.allowedDirs=new Set([this.cwd]),this.logger.info(`File handler initialized with ${this.allowedDirs.size} allowed directories`);for(const e of this.allowedDirs)this.logger.debug(` Allowed: ${e}`)}isPathAllowed(e){try{const t=I.resolve(this.cwd,e);for(const e of this.allowedDirs)if(t.startsWith(e))return!0;return this.logger.warn(`Path not in allowed directories: ${t}`),!1}catch(e){return e instanceof Error&&this.logger.error(`Error checking path: ${e.message}`,e),!1}}async readFile(e,t,s){if(!this.isPathAllowed(e))throw new M(`Access denied: ${e}`);const o=I.resolve(this.cwd,e);try{if(!E.existsSync(o))throw new D(`File not found: ${e}`);try{await x.access(o,E.constants.R_OK)}catch{throw new M(`Permission denied: ${e}`)}const i=await x.stat(o);if(!i.isFile())throw new D(`Not a file: ${e}`);if(i.size>this.maxFileSize)throw new D(`File too large: ${i.size} bytes (max: ${this.maxFileSize})`);const r=await x.readFile(o,"utf-8");if(void 0!==t||void 0!==s){const o=r.split("\n"),i=t?t-1:0,n=s?i+s:o.length,a=Math.max(0,i),l=Math.min(o.length,n);return this.logger.debug(`Read ${l-a} lines from ${e}`),o.slice(a,l).join("\n")}return this.logger.debug(`Read ${r.length} bytes from ${e}`),r}catch(e){if(e instanceof D||e instanceof M)throw e;throw new D(`Failed to read file: ${q(e)}`)}}async writeFile(e,t){if(this.readOnly)throw new M("File system is in read-only mode");if(!this.isPathAllowed(e))throw new M(`Access denied: ${e}`);const s=I.resolve(this.cwd,e);try{await x.mkdir(I.dirname(s),{recursive:!0}),await x.writeFile(s,t,"utf-8"),this.logger.debug(`Wrote ${t.length} bytes to ${e}`)}catch(e){throw new D(`Failed to write file: ${q(e)}`)}}async addAllowedDir(e){const t=I.resolve(this.cwd,e);try{if(!E.existsSync(t))throw new D(`Directory does not exist: ${t}`);if(!(await x.stat(t)).isDirectory())throw new D(`Not a directory: ${t}`);this.allowedDirs.add(t),this.logger.info(`Added allowed directory: ${t}`)}catch(e){if(e instanceof D)throw e;throw new D(`Failed to add ${t} as allowed directory: ${q(e)}`)}}removeAllowedDir(e){const t=I.resolve(this.cwd,e);this.allowedDirs.delete(t),this.logger.info(`Removed allowed directory: ${t}`)}}class B{constructor(e={}){this.port=null,this.process=null,this.iflowPath=null,this.logger=e.logger||G,this.startPort=e.startPort||8090}get url(){if(!this.port)throw new N("iFlow process not started");return`ws://localhost:${this.port}/acp`}isRunning(){return!!this.process&&!this.process.killed&&null===this.process.exitCode}which(e){try{return P.execSync(`which ${e}`,{encoding:"utf-8"}).trim()}catch{return null}}fileExists(e){try{return E.existsSync(e)&&E.statSync(e).isFile()}catch{return!1}}findIflowPath(){const e=this.which("iflow");if(e)return this.logger.debug(`Found iflow at: ${e}`),e;const t=A.homedir(),s=[I.join(t,".npm-global","bin","iflow"),"/usr/local/bin/iflow",I.join(t,".local","bin","iflow"),I.join(t,"node_modules",".bin","iflow"),I.join(t,".yarn","bin","iflow"),I.join(t,"AppData","Roaming","npm","iflow.cmd"),I.join("C:","Program Files","nodejs","iflow.cmd")];for(const e of s)if(this.fileExists(e))return this.logger.debug(`Found iflow at: ${e}`),e;const o=null!==this.which("npm"),i=null!==this.which("node");let r;throw r="win32"===A.platform()?o||i?"iFlow CLI not found. Please use the following command to install:\n npm install -g @iflow-ai/iflow-cli@latest":"iFlow requires Node.js, but it is not installed in the system.\n\nPlease install Node.js first: https://nodejs.org/\n\nAfter installing Node.js, use the following command to install iFlow:\n npm install -g @iflow-ai/iflow-cli@latest":'iFlow CLI not found. Please use the following command to install:\n\nšŸŽ Mac/Linux/Ubuntu users:\n bash -c "$(curl -fsSL https://cloud.iflow.cn/iflow-cli/install.sh)"\n\n🪟 Windows users:\n npm install -g @iflow-ai/iflow-cli@latest',new C(r)}isPortAvailable(e){return new Promise(t=>{const s=v.createServer();s.listen(e,"localhost",()=>{s.once("close",()=>{t(!0)}),s.close()}),s.once("error",()=>{t(!1)})})}async findAvailablePort(){for(let e=0;e<100;e++){const t=this.startPort+e;if(await this.isPortAvailable(t))return this.logger.debug(`Found available port: ${t}`),t}throw new L(`No available port found in range ${this.startPort}-${this.startPort+100}`)}async start(){if(this.isRunning())return this.url;this.iflowPath=this.findIflowPath(),this.port=await this.findAvailablePort();const e=[this.iflowPath,"--experimental-acp","--port",this.port.toString()];this.logger.info(`Starting iFlow process: ${e.join(" ")}`);try{if(this.process=P.spawn(e[0],e.slice(1),{stdio:["ignore","pipe","pipe"],detached:!1}),await this.onSpawn(),!this.isRunning()){let e="iFlow process exited immediately";if(this.process.stderr){const t=this.process.stderr.read();t&&(e+=`: ${t.toString("utf-8")}`)}throw new Error(e)}return this.logger.info(`iFlow process started on port ${this.port} (PID: ${this.process.pid})`),this.url}catch(e){throw this.port=null,this.process=null,new N(`Failed to start iFlow process: ${q(e)}`)}}async stop(){if(this.process){if(!this.isRunning())return this.port=null,void(this.process=null);this.logger.info(`Stopping iFlow process (PID: ${this.process.pid})`);try{this.process.kill("SIGTERM"),await Promise.race([new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()}),new Promise(e=>setTimeout(()=>e(),5e3))]),this.isRunning()?(this.logger.warn("iFlow process did not terminate gracefully, forcing kill"),this.process.kill("SIGKILL"),await new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()})):this.logger.info("iFlow process terminated gracefully")}catch(e){this.logger.error(`Error stopping iFlow process: ${q(e)}`)}finally{this.port=null,this.process=null}}}async onSpawn(e=5e3){return new Promise((t,s)=>{if(!this.process)return void s(new Error("Process not initialized"));const o=setTimeout(()=>{s(new Error(`Process spawn timeout after ${e}ms`))},e);this.process.once("spawn",()=>{clearTimeout(o),setTimeout(t,2e3)})})}}var Z;!function(e){e.ERROR="error",e.RESPONSE="response",e.FILE_READ="file_read",e.FILE_WRITE="file_write",e.SESSION_UPDATE="session_update",e.TOOL_CALL="tool_call",e.TOOL_UPDATE="tool_update",e.TOOL_CONFIRMATION="tool_confirmation",e.TASK_FINISH="task_finish",e.UNKNOWN="unknown"}(Z||(Z={}));class ee{constructor(e={}){this.protocol=null,this.transport=null,this.connected=!1,this.authenticated=!1,this.messageTask=null,this.messageQueue=[],this.pendingToolCalls=new Map,this.url=null,this.sessionId=null,this.processManager=null,this.processStarted=!1,this.options={url:"ws://localhost:8090/acp",cwd:process.cwd(),timeout:3e4,logLevel:"INFO",fileMaxSize:10485760,permissionMode:exports.PermissionMode.AUTO,autoApproveTypes:["read","fetch","list"],authMethodId:"iflow",autoStartProcess:!0,processStartPort:8090,...e},this.logger=new z({level:this.options.logLevel})}async connect(){if(this.connected)this.logger.warn("Already connected");else try{if(this.options.autoStartProcess&&(this.options.url?.startsWith("ws://localhost:")||this.options.url?.startsWith("ws://127.0.0.1:"))){const e=new X({url:this.options.url,logger:this.logger,timeout:2e3});try{await e.connect(),await e.close(),this.url=this.options.url,this.logger.info(`iFlow already running at ${this.options.url}`)}catch{this.logger.info("iFlow not running, starting process..."),this.processManager=new B({logger:this.logger,startPort:this.options.processStartPort});try{const e=await this.processManager.start();this.url=e,this.processStarted=!0,this.logger.info(`Started iFlow process at ${e}`),await new Promise(e=>setTimeout(e,1e3))}catch(e){throw e instanceof C?(this.logger.error("iFlow not installed"),C):(this.logger.error(`Failed to start iFlow process: ${q(e)}`),new F(`Failed to start iFlow process: ${q(e)}`))}}}let e=null;this.options.fileAccess&&(e=new Y({cwd:this.options.cwd,logger:this.logger,readOnly:this.options.fileReadOnly,maxFileSize:this.options.fileMaxSize,allowedDirs:this.options.fileAllowedDirs}),this.logger.info(`File system access enabled with ${this.options.fileReadOnly?"read-only":"read-write"} mode`)),this.transport=new X({url:this.options.url,logger:this.logger,timeout:this.options.timeout}),this.protocol=new V({logger:this.logger,transport:this.transport,fileHandler:e,permissionMode:this.options.permissionMode,autoApproveTypes:this.options.autoApproveTypes}),await this.transport.connect();const t=await this.protocol.initialize({mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents});this.authenticated=t.isAuthenticated||!1,this.authenticated||(await this.protocol.authenticate({methodId:this.options.authMethodId,methodInfo:this.options.authMethodInfo}),this.authenticated=!0),this.sessionId=await this.protocol.createSession({cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents,settings:this.options.sessionSettings}),this.connected=!0,this.messageTask=this.handleMessages(),this.logger.info("Connected to iFlow")}catch(e){throw await this.disconnect(),new F(`Failed to connect: ${q(e)}`)}}async loadSession(e){if(!this.connected||!this.protocol)throw new F("Not connected. Call connect() first.");await this.protocol.loadSession({sessionId:e,cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers}),this.sessionId=e,this.logger.info(`Loaded session: ${e}`)}async disconnect(){this.connected=!1,this.transport&&await this.transport.close(),this.processManager&&this.processStarted&&await this.processManager.stop(),this.url=null,this.protocol=null,this.transport=null,this.messageTask=null,this.authenticated=!1,this.processManager=null,this.processStarted=!1,this.logger.info("Disconnected from iFlow")}async sendMessage(e,t){if(!this.connected||!this.protocol||!this.sessionId)throw new F("Not connected. Call connect() first.");const s=[{type:"text",text:e}];if(t?.length)for(const e of t){const t=I.resolve(this.options.cwd||process.cwd(),e),o=I.parse(e);if(!E.existsSync(t)){this.logger.warn(`File not found, skipping: ${t}`);continue}const i=o.ext.toLowerCase();if([".png",".jpg",".jpeg",".gif",".bmp",".webp",".svg"].includes(i))try{const e=E.readFileSync(t).toString("base64"),r={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".bmp":"image/bmp",".webp":"image/webp",".svg":"image/svg+xml"};s.push({type:"image",data:e,mimeType:r[i]||"image/unknown"}),this.logger.debug(`Added image file: ${o.base}`)}catch(e){this.logger.error(`Failed to read image file ${t}: ${q(e)}`);continue}else if([".mp3",".wav",".m4a",".ogg",".flac"].includes(i))try{const e=E.readFileSync(t).toString("base64"),r={".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".ogg":"audio/ogg",".flac":"audio/flac"};s.push({type:"audio",data:e,mimeType:r[i]||"audio/unknown"}),this.logger.debug(`Added audio file: ${o.base}`)}catch(e){this.logger.error(`Failed to read audio file ${t}: ${q(e)}`);continue}else{const e=E.statSync(t);s.push({type:"resource_link",uri:`file://${t}`,name:o.base,title:o.name,size:e.size}),this.logger.debug(`Added resource link: ${o.base}`)}}await this.protocol.sendPrompt({sessionId:this.sessionId,prompt:s})}async interrupt(){if(!this.connected||!this.protocol||!this.sessionId)throw new F("Not connected");await this.protocol.cancelSession({sessionId:this.sessionId}),this.logger.info("Sent interrupt signal")}async*receiveMessages(){if(!this.connected)throw new F("Not connected");for(;this.connected;)try{this.messageQueue.length>0?yield this.messageQueue.shift():await new Promise(e=>setTimeout(e,100))}catch{continue}}async approveToolCall(e,t=exports.ToolCallConfirmationOutcome.ALLOW){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Approved tool call ${e} with outcome ${t}`),this.pendingToolCalls.delete(e)}async rejectToolCall(e){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Rejected tool call ${e}`),this.pendingToolCalls.delete(e)}async handleMessages(){if(this.protocol)try{for await(const e of this.protocol.handleMessages()){const t=this.processProtocolMessage(e);t&&this.messageQueue.push(t)}}catch(e){this.logger.error(`Error in message handler: ${q(e)}`);const t={type:exports.MessageType.ERROR,code:-1,message:String(q(e))};this.messageQueue.push(t)}}processProtocolMessage(e){switch(e.type){case Z.SESSION_UPDATE:{const{updateData:t}=e;let s,o;switch("agentId"in t&&t.agentId&&(s=t.agentId,o=function(e){const t=e.split("-");return"subagent"!==t[0]||t.length<4?{agentId:e}:4===t.length?{agentId:e,taskId:["null","undefined"].includes(t[1])?void 0:t[1],agentIndex:parseInt(t[2])||void 0,timestamp:parseInt(t[3])||void 0}:{agentId:e,taskId:t.slice(1,-2).join("-"),agentIndex:parseInt(t[t.length-2])||void 0,timestamp:parseInt(t[t.length-1])||void 0}}(s)),t.sessionUpdate){case W.PLAN:{const e=t.entries?.map(e=>({content:e.content||"",status:e.status||exports.PlanStatus.PENDING,priority:e.priority||exports.PlanPriority.MEDIUM}));return e&&e?.length>0?{type:exports.MessageType.PLAN,entries:e}:null}case W.TOOL_CALL:{const e={type:exports.MessageType.TOOL_CALL,id:t.toolCallId||"",label:t.title||"Tool",icon:{type:exports.ToolCallIconType.EMOJI,value:"šŸ”§"},status:t.status||exports.ToolCallStatus.IN_PROGRESS,toolName:t.toolName};return s&&(e.agentId=s,e.agentInfo=o),this.pendingToolCalls.set(e.id,e),{...e}}case W.TOOL_CALL_UPDATE:{const e=t.toolCallId;let i;if(this.pendingToolCalls.has(e)?(i=this.pendingToolCalls.get(e),i.status=t.status||exports.ToolCallStatus.COMPLETED,t.toolName&&(i.toolName=t.toolName),!i.agentId&&s&&(i.agentId=s),!i.agentInfo&&o&&(i.agentInfo=o)):(i={type:exports.MessageType.TOOL_CALL,id:e,label:t.title||"Tool",icon:{type:exports.ToolCallIconType.EMOJI,value:"šŸ”§"},status:t.status||exports.ToolCallStatus.COMPLETED,toolName:t.toolName},s&&(i.agentId=s,i.agentInfo=o),this.pendingToolCalls.set(e,i)),t.content&&t.content?.length>0){let e;const s=[];for(const o of t.content)"args"in o&&(e=o.args),"content"===o.type&&"text"===o.content?.type&&s.push(o.content.text||"");void 0!==e&&(i.args=e),s.length>0&&(i.output=s.join("\n"))}return{...i}}case W.USER_MESSAGE_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t)return{type:exports.MessageType.USER,chunks:[{text:t}]}}return null}case W.AGENT_MESSAGE_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t){const e={type:exports.MessageType.ASSISTANT,chunk:{text:t}};return s&&(e.agentId=s,e.agentInfo=o),e}}return null}case W.AGENT_THOUGHT_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t){const e={type:exports.MessageType.ASSISTANT,chunk:{thought:t}};return s&&(e.agentId=s,e.agentInfo=o),e}}}default:return null}}case Z.RESPONSE:return"stopReason"in(e.result||{})?{type:exports.MessageType.TASK_FINISH,stopReason:e.result.stopReason}:null;case Z.ERROR:return{type:exports.MessageType.ERROR,code:e.code||-1,message:e.error||"Unknown error"};default:return null}}}function te(e){let t,s=!1,o="text";if(e.startsWith("//"))s=!0,o="control";else try{t=JSON.parse(e),t&&"method"in t?o=`method:${t.method}`:t&&("result"in t||"error"in t)?o="response":t&&"type"in t&&(o=t.type)}catch{}return{isControl:s,messageType:o,rawData:e,jsonData:t,timestamp:Date.now()}}exports.AuthenticationError=k,exports.ConnectionError=F,exports.IFlowClient=ee,exports.IFlowError=_,exports.IFlowNotInstalledError=C,exports.IFlowProcessError=N,exports.JSONDecodeError=R,exports.PermissionError=M,exports.PortNotAvailableError=L,exports.ProtocolError=b,exports.RawDataClient=class extends ee{constructor(e,t=!0){super(e),this.rawQueue=[],this.rawHistory=[],this.rawQueueResolvers=[],this.messageQueueResolvers=[],this.captureRaw=t}async handleMessages(){if(this.protocol)try{if(this.captureRaw&&this.transport){const e=this.captureRawStream(),t=this.handleParsedStream();await Promise.all([e,t])}else await super.handleMessages()}catch(e){this.logger.error(`Error in message handler: ${q(e)}`)}}async captureRawStream(){if(this.transport)try{for await(const e of this.transport.receive()){const t=te("string"==typeof e?e:JSON.stringify(e));this.rawQueue.push(t),this.rawHistory.push(t);const s=this.rawQueueResolvers.shift();s&&s(t)}}catch(e){this.logger.error(`Error capturing raw stream: ${q(e)}`)}}async handleParsedStream(){if(this.protocol)for await(const e of this.protocol.handleMessages()){const t=this.processProtocolMessage(e);if(t){const e=this.messageQueueResolvers.shift();e&&e(t)}}}async*receiveRawMessages(){for(;this.connected||this.rawQueue.length>0;)try{if(this.rawQueue.length>0)yield this.rawQueue.shift();else{const e=await Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),100)})]);yield e}}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}async*receiveDualStream(){const e=[],t=[];for(;this.connected||this.rawQueue.length>0||e.length>0||t.length>0;)try{let e,t;e=this.rawQueue.length>0?this.rawQueue.shift():await Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]);try{t=await Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})])}catch{}e.parsedMessage=t,yield[e,t]}catch(e){if(!(e instanceof Error&&"Timeout"===e.message))throw e;try{const e=await Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]),t=te("<no-raw-data>");t.messageType="parsed_only",yield[t,e]}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}}getRawHistory(){return[...this.rawHistory]}getProtocolStats(){const e={totalMessages:this.rawHistory.length,messageTypes:{},controlMessages:0,jsonMessages:0,textMessages:0,errors:0};for(const t of this.rawHistory)t.messageType&&(e.messageTypes[t.messageType]=(e.messageTypes[t.messageType]||0)+1),t.isControl?e.controlMessages++:t.jsonData?e.jsonMessages++:e.textMessages++,t.jsonData&&"error"in t.jsonData&&e.errors++;return e}async sendRaw(e){if(!this.transport)throw new Error("Not connected");await this.transport.send(e);const t="string"==typeof e?e:JSON.stringify(e).substring(0,100);this.logger.info(`Sent raw data: ${t}`)}},exports.TimeoutError=O,exports.TransportError=$,exports.ValidationError=D,exports.query=async function(e,t,s){const o=[],i=new ee(s);await i.connect();try{await i.sendMessage(e,t);for await(const e of i.receiveMessages())if(e.type===exports.MessageType.ASSISTANT&&e.chunk.text)o.push(e.chunk.text);else if(e.type===exports.MessageType.TASK_FINISH)break}finally{await i.disconnect()}return o.join("")},exports.queryStream=async function*(e,t,s){const o=new ee(s);await o.connect();try{await o.sendMessage(e,t);for await(const e of o.receiveMessages())if(e.type===exports.MessageType.ASSISTANT&&e.chunk.text)yield e.chunk.text;else if(e.type===exports.MessageType.TASK_FINISH)break}finally{await o.disconnect()}};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import*as e from"fs";import*as t from"path";import s from"ws";import*as o from"fs/promises";import*as i from"os";import*as n from"net";import*as r from"child_process";class l extends Error{constructor(e,t){super(e),this.name="IFlowError",this.details=t||{}}}class a extends l{constructor(e,t){super(e,t),this.name="TimeoutError"}}class c extends l{constructor(e,t){super(e,{rawData:t}),this.name="JSONDecodeError",this.rawData=t}}class d extends l{constructor(e,t){super(e,t),this.name="IFlowNotInstalledError"}}class h extends l{constructor(e,t){super(e,t),this.name="IFlowProcessError"}}class u extends l{constructor(e,t){super(e,t),this.name="PortNotAvailableError"}}class p extends l{constructor(e,t){super(e,t),this.name="ConnectionError"}}class g extends l{constructor(e,t){super(e,t),this.name="TransportError"}}class f extends l{constructor(e,t){super(e,t),this.name="PermissionError"}}class w extends l{constructor(e,t){super(e,t),this.name="ValidationError"}}class m extends l{constructor(e,t){super(e,t),this.name="ProtocolError"}}class y extends l{constructor(e,t){super(e,t),this.name="AuthenticationError"}}var v,S,E,I,T,A,_,O,R,N,P,$,F;function L(e,t,s,o){return new(s||(s=Promise))(function(i,n){function r(e){try{a(o.next(e))}catch(e){n(e)}}function l(e){try{a(o.throw(e))}catch(e){n(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof s?t:new s(function(e){e(t)})).then(r,l)}a((o=o.apply(e,t||[])).next())})}function x(e){var t="function"==typeof Symbol&&Symbol.iterator,s=t&&e[t],o=0;if(s)return s.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&o>=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function C(e){return this instanceof C?(this.v=e,this):new C(e)}function M(e,t,s){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var o,i=s.apply(e,t||[]),n=[];return o=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),r("next"),r("throw"),r("return",function(e){return function(t){return Promise.resolve(t).then(e,c)}}),o[Symbol.asyncIterator]=function(){return this},o;function r(e,t){i[e]&&(o[e]=function(t){return new Promise(function(s,o){n.push([e,t,s,o])>1||l(e,t)})},t&&(o[e]=t(o[e])))}function l(e,t){try{(s=i[e](t)).value instanceof C?Promise.resolve(s.value.v).then(a,c):d(n[0][2],s)}catch(e){d(n[0][3],e)}var s}function a(e){l("next",e)}function c(e){l("throw",e)}function d(e,t){e(t),n.shift(),n.length&&l(n[0][0],n[0][1])}}function b(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,s=e[Symbol.asyncIterator];return s?s.call(e):(e=x(e),t={},o("next"),o("throw"),o("return"),t[Symbol.asyncIterator]=function(){return this},t);function o(s){t[s]=e[s]&&function(t){return new Promise(function(o,i){(function(e,t,s,o){Promise.resolve(o).then(function(t){e({value:t,done:s})},t)})(o,i,(t=e[s](t)).done,t.value)})}}}!function(e){e[e.DEBUG=0]="DEBUG",e[e.INFO=1]="INFO",e[e.WARN=2]="WARN",e[e.ERROR=3]="ERROR"}(v||(v={})),function(e){e.AUTO="auto",e.MANUAL="manual",e.SELECTIVE="selective"}(S||(S={})),function(e){e.DEFAULT="default",e.AUTO_EDIT="autoEdit",e.YOLO="yolo",e.PLAN="plan"}(E||(E={})),function(e){e.PRE_TOOL_USE="PreToolUse",e.POST_TOOL_USE="PostToolUse",e.STOP="Stop",e.SUBAGENT_STOP="SubagentStop",e.SET_UP_ENVIRONMENT="SetUpEnvironment"}(I||(I={})),function(e){e.HIGH="high",e.MEDIUM="medium",e.LOW="low"}(T||(T={})),function(e){e.PENDING="pending",e.IN_PROGRESS="in_progress",e.COMPLETED="completed"}(A||(A={})),function(e){e.END_TURN="end_turn",e.MAX_TOKENS="max_tokens",e.REFUSAL="refusal",e.CANCELLED="cancelled"}(_||(_={})),function(e){e.PENDING="pending",e.IN_PROGRESS="in_progress",e.COMPLETED="completed",e.FAILED="failed"}(O||(O={})),function(e){e.DIFF="diff",e.MARKDOWN="markdown"}(R||(R={})),function(e){e.EDIT="edit",e.EXECUTE="execute",e.MCP="mcp",e.FETCH="fetch",e.OTHER="other"}(N||(N={})),function(e){e.ALLOW="allow",e.ALWAYS_ALLOW="alwaysAllow",e.ALWAYS_ALLOW_TOOL="alwaysAllowTool",e.ALWAYS_ALLOW_MCP_SERVER="alwaysAllowMcpServer",e.REJECT="reject"}(P||(P={})),function(e){e.URL="url",e.EMOJI="emoji"}($||($={})),function(e){e.PLAN="plan",e.USER="user",e.ASSISTANT="assistant",e.TOOL_CALL="tool_call",e.ERROR="error",e.TASK_FINISH="task_finish"}(F||(F={})),"function"==typeof SuppressedError&&SuppressedError;const D="2.0";var U,k,j;function H(e){return e instanceof Error?e.message:e?String(e):"unknown error"}!function(e){e.INITIALIZE="initialize",e.AUTHENTICATE="authenticate",e.SESSION_NEW="session/new",e.SESSION_LOAD="session/load",e.SESSION_PROMPT="session/prompt",e.SESSION_CANCEL="session/cancel"}(U||(U={})),function(e){e.SESSION_UPDATE="session/update",e.SESSION_REQUEST_PERMISSION="session/request_permission",e.FS_READ_TEXT_FILE="fs/read_text_file",e.FS_WRITE_TEXT_FILE="fs/write_text_file",e.PUSH_TOOL_CALL="pushToolCall",e.UPDATE_TOOL_CALL="updateToolCall",e.NOTIFY_TASK_FINISH="notifyTaskFinish"}(k||(k={})),function(e){e.PLAN="plan",e.TOOL_CALL="tool_call",e.TOOL_CALL_UPDATE="tool_call_update",e.USER_MESSAGE_CHUNK="user_message_chunk",e.AGENT_MESSAGE_CHUNK="agent_message_chunk",e.AGENT_THOUGHT_CHUNK="agent_thought_chunk"}(j||(j={}));class W{constructor(e={}){const t=e.level||"INFO";this.level=v[t]}debug(e){this.log(v.DEBUG,e)}info(e){this.log(v.INFO,e)}warn(e){this.log(v.WARN,e)}error(e,t){this.log(v.ERROR,e,t)}log(e,t,s){if(e<this.level)return;const o=`[${(new Date).toLocaleString("sv-SE").replace("T"," ")}] ${v[e]}: ${t}${s?`\n${s.stack}`:""}`;switch(e){case v.DEBUG:console.debug(o);break;case v.INFO:console.info(o);break;case v.WARN:console.warn(o);break;case v.ERROR:console.error(o)}}}const z=new W;function G(e){return!!e&&"id"in e&&"result"in e&&null!=e.result}function Q(e){return!!e&&"id"in e&&"error"in e&&null!=e.error}function q(e){return!!e&&"method"in e&&!("result"in e)&&!("error"in e)}class K{constructor(e){this.requestId=0,this.initialized=!1,this.authenticated=!1,this.logger=e.logger||z,this.transport=e.transport,this.fileHandler=e.fileHandler,this.permissionMode=e.permissionMode||S.AUTO,this.autoApproveTypes=e.autoApproveTypes||["read","fetch","list"]}nextRequestId(){return++this.requestId}checkAuthenticated(){if(!this.initialized)throw new m("Protocol not initialized. Call initialize() first.");if(!this.authenticated)throw new m("Not authenticated. Call authenticate() first.")}sendResult(e,t){return L(this,void 0,void 0,function*(){const s={jsonrpc:D,id:e,result:t};yield this.transport.send(s)})}sendError(e,t,s){return L(this,void 0,void 0,function*(){const o={jsonrpc:D,id:e,error:{code:t,message:s}};yield this.transport.send(o)})}waitForReadySignal(){return L(this,void 0,void 0,function*(){var e,t,s,o;try{for(var i,n=!0,r=b(this.transport.receive());!(e=(i=yield r.next()).done);n=!0){o=i.value,n=!1;const e=o.trim();if("//ready"===e){this.logger.info("Received //ready signal");break}e.startsWith("//")&&this.logger.debug(`Control message: ${e}`)}}catch(e){t={error:e}}finally{try{n||e||!(s=r.return)||(yield s.call(r))}finally{if(t)throw t.error}}})}waitForMessageResponse(e,t,s){return L(this,void 0,void 0,function*(){var o,i,n,r;const{timeout:l,timeoutMsg:c=`Timeout after ${l} seconds`}=s||{},d=Date.now();try{for(var h,u=!0,p=b(this.transport.receive());!(o=(h=yield p.next()).done);u=!0){r=h.value,u=!1;const s=r;if(s.trim().startsWith("//")){this.logger.debug(`Control message: ${s.trim()}`);continue}let o;try{o=JSON.parse(s.trim())}catch(e){this.logger.error(`Failed to parse response: ${H(e)}`);continue}if(o.id===e){const e=t(o);if(void 0!==e)return e}if(l&&l>0&&Date.now()-d>l)throw new a(c)}}catch(e){i={error:e}}finally{try{u||o||!(n=p.return)||(yield n.call(p))}finally{if(i)throw i.error}}})}initialize(){return L(this,arguments,void 0,function*(e={}){if(this.initialized)return this.logger.warn("Protocol already initialized"),{protocolVersion:1,isAuthenticated:this.authenticated};this.logger.info("Waiting for //ready signal..."),yield this.waitForReadySignal();const t=this.nextRequestId(),s={jsonrpc:D,id:t,method:U.INITIALIZE,params:Object.assign({protocolVersion:1,clientCapabilities:{fs:{readTextFile:!0,writeTextFile:!0}}},e)};yield this.transport.send(s),this.logger.info("Sent initialize request");const o=yield this.waitForMessageResponse(t,e=>{var t;if("error"in e)throw new m(`Initialize failed: ${null===(t=e.error)||void 0===t?void 0:t.message}`,e.error);const s=e.result||{};return this.initialized=!0,this.authenticated=s.isAuthenticated||!1,this.logger.info(`Initialized with protocol version: ${s.protocolVersion}, authenticated: ${this.authenticated}`),s},{timeout:1e4,timeoutMsg:"Initialize timeout after 10 seconds"});if(o)return o;throw new m("Connection closed during initialization")})}authenticate(){return L(this,arguments,void 0,function*(e={}){const t=e.methodId||"iflow";if(this.authenticated)return void this.logger.warn("Already authenticated");const s=this.nextRequestId(),o={jsonrpc:D,id:s,method:U.AUTHENTICATE,params:Object.assign(Object.assign({},e),{methodId:t})};yield this.transport.send(o),this.logger.info(`Sent authenticate request with method: ${o.params.methodId}`);if(!(yield this.waitForMessageResponse(s,e=>{var s;if("error"in e)throw new y(`Authentication failed: ${null===(s=e.error)||void 0===s?void 0:s.message}`,e.error);const o=e.result||{};return o.methodId===t?(this.authenticated=!0,this.logger.info(`Authentication successful with method: ${o.methodId}`),!0):(this.authenticated=!0,this.logger.warn(`Unexpected methodId in response: ${o.methodId} (expected ${t})`),!0)},{timeout:1e4,timeoutMsg:"Authentication timeout after 10 seconds"})))throw new y("Connection closed during authentication")})}createSession(){return L(this,arguments,void 0,function*(e={}){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:D,id:t,method:U.SESSION_NEW,params:Object.assign(Object.assign({},e),{cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]})};yield this.transport.send(s),this.logger.info(`Sent session/new request with cwd: ${e.cwd}`);const o=yield this.waitForMessageResponse(t,e=>{var t;if("error"in e)throw new m(`session/new failed: ${null===(t=e.error)||void 0===t?void 0:t.message}`,e.error);const s=e.result||{};if(s.sessionId)return this.logger.info(`Created session: ${s.sessionId}`),s.sessionId;throw new m(`Invalid session/new response: ${JSON.stringify(s)}`)},{timeout:1e4,timeoutMsg:"Session creation timeout after 10 seconds"});if(o)return o;throw new m("Connection closed while waiting for session/new response")})}loadSession(e){return L(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:D,id:t,method:U.SESSION_LOAD,params:Object.assign(Object.assign({},e),{cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]})};yield this.transport.send(s),this.logger.info(`Sent session/load request for session: ${e.sessionId}`);if(!(yield this.waitForMessageResponse(t,t=>{var s;if("error"in t){if(-32601===t.error.code)throw new m("session/load is not supported by the current iFlow version. Use session/new to create a new session instead.",t.error);throw new m(`session/load failed: ${null===(s=t.error)||void 0===s?void 0:s.message}`,t.error)}return this.logger.info(`Session loaded successfully: ${e.sessionId}`),!0},{timeout:1e4,timeoutMsg:"Session load timeout after 10 seconds"})))throw new m("Connection closed while waiting for session/load response")})}sendPrompt(e){return L(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:D,id:t,method:U.SESSION_PROMPT,params:e};return yield this.transport.send(s),this.logger.info(`Sent prompt with ${e.prompt.length} content blocks`),t})}cancelSession(e){return L(this,void 0,void 0,function*(){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:D,id:t,method:U.SESSION_CANCEL,params:e};yield this.transport.send(s),this.logger.info("Sent session/cancel request")})}handleMessages(){return M(this,arguments,function*(){var e,t,s,o;try{for(var i,n=!0,r=b(this.transport.receive());!(e=(i=yield C(r.next())).done);n=!0){o=i.value,n=!1;const e=o;if(e.trim().startsWith("//")){this.logger.debug(`Control message: ${e.trim()}`);continue}let t;try{t=JSON.parse(e.trim())}catch(t){throw this.logger.error(`Failed to parse message: ${H(t)}`),new c("Invalid JSON received",e)}q(t)?yield yield C(yield C(this.handleClientMessage(t))):G(t)?yield yield C({type:"response",id:t.id,result:t.result}):Q(t)&&(yield yield C({type:"error",code:t.error.code,error:t.error.message}))}}catch(e){t={error:e}}finally{try{n||e||!(s=r.return)||(yield C(s.call(r)))}finally{if(t)throw t.error}}})}handleClientMessage(e){return L(this,void 0,void 0,function*(){const{method:t}=e;switch(t){case k.FS_READ_TEXT_FILE:return yield this.handleReadTextFile(e);case k.FS_WRITE_TEXT_FILE:return yield this.handleWriteTextFile(e);case k.SESSION_UPDATE:return yield this.handleSessionUpdate(e);case k.SESSION_REQUEST_PERMISSION:return yield this.handleRequestPermission(e);case k.PUSH_TOOL_CALL:return yield this.handlePushToolCall(e);case k.UPDATE_TOOL_CALL:return yield this.handleUpdateToolCall(e);case k.NOTIFY_TASK_FINISH:return yield this.handleNotifyTaskFinish(e);default:return yield this.handleUnknownMessage(e)}})}handleReadTextFile(e){return L(this,void 0,void 0,function*(){const{id:t,method:s,params:o}=e,{path:i,limit:n,line:r}=o||{};let l;if(this.logger.info(`fs/read_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&(yield this.sendError(t,-32603,e)),{type:"error",code:-32603,error:e,method:s}}try{l=yield this.fileHandler.readFile(i,r,n)}catch(e){const o=H(e);return this.logger.error(`Error reading file ${i}: ${o}`),void 0!==t&&(yield this.sendError(t,-32603,o)),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&(yield this.sendResult(t,{content:l})),{type:"file_read",path:i,content:l}})}handleWriteTextFile(e){return L(this,void 0,void 0,function*(){const{id:t,method:s,params:o}=e,{path:i,content:n}=o||{};if(this.logger.info(`fs/write_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&(yield this.sendError(t,-32603,e)),{type:"error",code:-32603,error:e,method:s}}try{yield this.fileHandler.writeFile(i,n)}catch(e){const o=H(e);return this.logger.error(`Error writing file ${i}: ${o}`),void 0!==t&&(yield this.sendError(t,-32603,o)),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&(yield this.sendResult(t,{success:!0})),{type:"file_write",path:i,content:n}})}handleSessionUpdate(e){return L(this,void 0,void 0,function*(){const{params:t}=e,{sessionId:s,update:o}=t;return{type:"session_update",sessionId:s,updateData:o}})}handleRequestPermission(e){return L(this,void 0,void 0,function*(){const{id:t,params:s}=e,o=s.toolCall||{},i=s.options||[];let n,r;if(n=this.permissionMode===S.AUTO||this.permissionMode!==S.MANUAL&&this.autoApproveTypes.includes(o.type||""),n){let e;for(const t of i){const s=t.optionId||"";if("proceed_once"===s){e=s;break}"proceed_always"===s&&(e=s)}!e&&i.length>0&&(e=i[0].optionId||"proceed_once"),r={outcome:{outcome:"selected",optionId:e}}}else r={outcome:{outcome:"cancelled"}};return void 0!==t&&(yield this.sendResult(t,r)),this.logger.info(`Permission request for tool '${o.title||"unknown"}' - Response: ${r.outcome.outcome}`),{type:"tool_confirmation",params:s,response:r}})}handlePushToolCall(e){return L(this,void 0,void 0,function*(){const{id:t,params:s}=e,o=`tool_${this.nextRequestId()}`,i={id:o};return void 0!==t&&(yield this.sendResult(t,i)),{type:"tool_call",id:o,params:s}})}handleUpdateToolCall(e){return L(this,void 0,void 0,function*(){const{id:t,params:s}=e;return void 0!==t&&(yield this.sendResult(t,null)),{type:"tool_update",params:s}})}handleNotifyTaskFinish(e){return L(this,void 0,void 0,function*(){const{id:t,params:s}=e;return void 0!==t&&(yield this.sendResult(t,null)),{type:"task_finish",params:s}})}handleUnknownMessage(e){return L(this,void 0,void 0,function*(){const{id:t,method:s,params:o}=e;return this.logger.warn(`Unknown method: ${s}`),void 0!==t&&(yield this.sendError(t,-32601,"Method not found")),{type:"unknown",method:s,params:o}})}}class J{constructor(e){this.ws=null,this.connected=!1,this.url=e.url,this.logger=e.logger||z,this.timeout=e.timeout||3e5}get isConnected(){return!!this.ws&&this.connected}checkConnected(){if(!this.isConnected)throw new p("Not connected")}connect(){return L(this,void 0,void 0,function*(){if(this.connected)this.logger.warn(`Already connected to ${this.url}`);else try{this.logger.info(`Connecting to ${this.url}`),this.ws=yield new Promise((e,t)=>{const o=new s(this.url),i=setTimeout(()=>{o.close(),t(new a(`Connected to ${this.url} timeout after ${this.timeout/1e3}s`))},this.timeout);o.on("open",()=>{clearTimeout(i),this.connected=!0,this.logger.info(`Connected to ${this.url} succesfully`),e(o)}),o.on("error",e=>{clearTimeout(i),this.connected=!1,t(e)}),o.on("close",(e,s)=>{clearTimeout(i),this.connected=!1,t(new Error(`${s} (code: ${e})`))})})}catch(e){if(e instanceof a)throw e;throw new p(`Failed to connect to ${this.url}: ${H(e)}`)}})}close(){return L(this,void 0,void 0,function*(){if(this.ws&&this.connected)try{this.ws.close(),this.logger.info("Connection closed")}catch(e){this.logger.warn(`Error closing connection: ${H(e)}`)}this.ws=null,this.connected=!1})}send(e){return L(this,void 0,void 0,function*(){this.checkConnected();try{const t="string"==typeof e?e:JSON.stringify(e);yield new Promise((e,s)=>{this.ws.send(t,o=>{o?s(o):(this.logger.debug(`Sent message: ${t}`),e())})})}catch(e){throw this.connected=!1,new g(`Failed to send message: ${H(e)}`)}})}receive(){return M(this,arguments,function*(){for(this.checkConnected();this.isConnected;)try{const e=yield C(this.receiveRawData());this.logger.debug(`Received message: ${e}`),yield yield C(e)}catch(e){if(this.connected=!1,e instanceof p&&e.details.isClosed){this.logger.info("Connection closed");break}throw new g(`Failed to receive message: ${H(e)}`)}})}receiveRawData(){return new Promise((e,t)=>{if(!this.isConnected)return void t(new p("Not connected"));const s=()=>{this.ws&&(this.ws.off("close",o),this.ws.off("error",i),this.ws.off("message",n))},o=()=>{s(),this.connected=!1,t(new p("Connection closed",{isClosed:!0}))},i=e=>{s(),this.connected=!1,t(e)},n=t=>{s(),e(t.toString())};this.ws&&(this.ws.on("close",o),this.ws.on("error",i),this.ws.on("message",n))})}}class V{constructor(e={}){this.cwd=e.cwd||process.cwd(),this.logger=e.logger||z,this.readOnly=e.readOnly||!1,this.maxFileSize=e.maxFileSize||10485760,e.allowedDirs?this.allowedDirs=new Set(e.allowedDirs.map(e=>t.resolve(this.cwd,e))):this.allowedDirs=new Set([this.cwd]),this.logger.info(`File handler initialized with ${this.allowedDirs.size} allowed directories`);for(const e of this.allowedDirs)this.logger.debug(` Allowed: ${e}`)}isPathAllowed(e){try{const s=t.resolve(this.cwd,e);for(const e of this.allowedDirs)if(s.startsWith(e))return!0;return this.logger.warn(`Path not in allowed directories: ${s}`),!1}catch(e){return e instanceof Error&&this.logger.error(`Error checking path: ${e.message}`,e),!1}}readFile(s,i,n){return L(this,void 0,void 0,function*(){if(!this.isPathAllowed(s))throw new f(`Access denied: ${s}`);const r=t.resolve(this.cwd,s);try{if(!e.existsSync(r))throw new w(`File not found: ${s}`);try{yield o.access(r,e.constants.R_OK)}catch(e){throw new f(`Permission denied: ${s}`)}const t=yield o.stat(r);if(!t.isFile())throw new w(`Not a file: ${s}`);if(t.size>this.maxFileSize)throw new w(`File too large: ${t.size} bytes (max: ${this.maxFileSize})`);const l=yield o.readFile(r,"utf-8");if(void 0!==i||void 0!==n){const e=l.split("\n"),t=i?i-1:0,o=n?t+n:e.length,r=Math.max(0,t),a=Math.min(e.length,o);return this.logger.debug(`Read ${a-r} lines from ${s}`),e.slice(r,a).join("\n")}return this.logger.debug(`Read ${l.length} bytes from ${s}`),l}catch(e){if(e instanceof w||e instanceof f)throw e;throw new w(`Failed to read file: ${H(e)}`)}})}writeFile(e,s){return L(this,void 0,void 0,function*(){if(this.readOnly)throw new f("File system is in read-only mode");if(!this.isPathAllowed(e))throw new f(`Access denied: ${e}`);const i=t.resolve(this.cwd,e);try{yield o.mkdir(t.dirname(i),{recursive:!0}),yield o.writeFile(i,s,"utf-8"),this.logger.debug(`Wrote ${s.length} bytes to ${e}`)}catch(e){throw new w(`Failed to write file: ${H(e)}`)}})}addAllowedDir(s){return L(this,void 0,void 0,function*(){const i=t.resolve(this.cwd,s);try{if(!e.existsSync(i))throw new w(`Directory does not exist: ${i}`);if(!(yield o.stat(i)).isDirectory())throw new w(`Not a directory: ${i}`);this.allowedDirs.add(i),this.logger.info(`Added allowed directory: ${i}`)}catch(e){if(e instanceof w)throw e;throw new w(`Failed to add ${i} as allowed directory: ${H(e)}`)}})}removeAllowedDir(e){const s=t.resolve(this.cwd,e);this.allowedDirs.delete(s),this.logger.info(`Removed allowed directory: ${s}`)}}class X{constructor(e={}){this.port=null,this.process=null,this.iflowPath=null,this.logger=e.logger||z,this.startPort=e.startPort||8090}get url(){if(!this.port)throw new h("iFlow process not started");return`ws://localhost:${this.port}/acp`}isRunning(){return!!this.process&&!this.process.killed&&null===this.process.exitCode}which(e){try{return r.execSync(`which ${e}`,{encoding:"utf-8"}).trim()}catch(e){return null}}fileExists(t){try{return e.existsSync(t)&&e.statSync(t).isFile()}catch(e){return!1}}findIflowPath(){const e=this.which("iflow");if(e)return this.logger.debug(`Found iflow at: ${e}`),e;const s=i.homedir(),o=[t.join(s,".npm-global","bin","iflow"),"/usr/local/bin/iflow",t.join(s,".local","bin","iflow"),t.join(s,"node_modules",".bin","iflow"),t.join(s,".yarn","bin","iflow"),t.join(s,"AppData","Roaming","npm","iflow.cmd"),t.join("C:","Program Files","nodejs","iflow.cmd")];for(const e of o)if(this.fileExists(e))return this.logger.debug(`Found iflow at: ${e}`),e;const n=null!==this.which("npm"),r=null!==this.which("node");let l;throw l="win32"===i.platform()?n||r?"iFlow CLI not found. Please use the following command to install:\n npm install -g @iflow-ai/iflow-cli@latest":"iFlow requires Node.js, but it is not installed in the system.\n\nPlease install Node.js first: https://nodejs.org/\n\nAfter installing Node.js, use the following command to install iFlow:\n npm install -g @iflow-ai/iflow-cli@latest":'iFlow CLI not found. Please use the following command to install:\n\nšŸŽ Mac/Linux/Ubuntu users:\n bash -c "$(curl -fsSL https://cloud.iflow.cn/iflow-cli/install.sh)"\n\n🪟 Windows users:\n npm install -g @iflow-ai/iflow-cli@latest',new d(l)}isPortAvailable(e){return new Promise(t=>{const s=n.createServer();s.listen(e,"localhost",()=>{s.once("close",()=>{t(!0)}),s.close()}),s.once("error",()=>{t(!1)})})}findAvailablePort(){return L(this,void 0,void 0,function*(){for(let e=0;e<100;e++){const t=this.startPort+e;if(yield this.isPortAvailable(t))return this.logger.debug(`Found available port: ${t}`),t}throw new u(`No available port found in range ${this.startPort}-${this.startPort+100}`)})}start(){return L(this,void 0,void 0,function*(){if(this.isRunning())return this.url;this.iflowPath=this.findIflowPath(),this.port=yield this.findAvailablePort();const e=[this.iflowPath,"--experimental-acp","--port",this.port.toString()];this.logger.info(`Starting iFlow process: ${e.join(" ")}`);try{if(this.process=r.spawn(e[0],e.slice(1),{stdio:["ignore","pipe","pipe"],detached:!1}),yield this.onSpawn(),!this.isRunning()){let e="iFlow process exited immediately";if(this.process.stderr){const t=this.process.stderr.read();t&&(e+=`: ${t.toString("utf-8")}`)}throw new Error(e)}return this.logger.info(`iFlow process started on port ${this.port} (PID: ${this.process.pid})`),this.url}catch(e){throw this.port=null,this.process=null,new h(`Failed to start iFlow process: ${H(e)}`)}})}stop(){return L(this,void 0,void 0,function*(){if(this.process){if(!this.isRunning())return this.port=null,void(this.process=null);this.logger.info(`Stopping iFlow process (PID: ${this.process.pid})`);try{this.process.kill("SIGTERM"),yield Promise.race([new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()}),new Promise(e=>setTimeout(()=>e(),5e3))]),this.isRunning()?(this.logger.warn("iFlow process did not terminate gracefully, forcing kill"),this.process.kill("SIGKILL"),yield new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()})):this.logger.info("iFlow process terminated gracefully")}catch(e){this.logger.error(`Error stopping iFlow process: ${H(e)}`)}finally{this.port=null,this.process=null}}})}onSpawn(){return L(this,arguments,void 0,function*(e=5e3){return new Promise((t,s)=>{if(!this.process)return void s(new Error("Process not initialized"));const o=setTimeout(()=>{s(new Error(`Process spawn timeout after ${e}ms`))},e);this.process.once("spawn",()=>{clearTimeout(o),setTimeout(t,2e3)})})})}}var Y;!function(e){e.ERROR="error",e.RESPONSE="response",e.FILE_READ="file_read",e.FILE_WRITE="file_write",e.SESSION_UPDATE="session_update",e.TOOL_CALL="tool_call",e.TOOL_UPDATE="tool_update",e.TOOL_CONFIRMATION="tool_confirmation",e.TASK_FINISH="task_finish",e.UNKNOWN="unknown"}(Y||(Y={}));class B{constructor(e={}){this.protocol=null,this.transport=null,this.connected=!1,this.authenticated=!1,this.messageTask=null,this.messageQueue=[],this.pendingToolCalls=new Map,this.url=null,this.sessionId=null,this.processManager=null,this.processStarted=!1,this.options=Object.assign({url:"ws://localhost:8090/acp",cwd:process.cwd(),timeout:3e4,logLevel:"INFO",fileMaxSize:10485760,permissionMode:S.AUTO,autoApproveTypes:["read","fetch","list"],authMethodId:"iflow",autoStartProcess:!0,processStartPort:8090},e),this.logger=new W({level:this.options.logLevel})}connect(){return L(this,void 0,void 0,function*(){var e,t;if(this.connected)this.logger.warn("Already connected");else try{if(this.options.autoStartProcess&&((null===(e=this.options.url)||void 0===e?void 0:e.startsWith("ws://localhost:"))||(null===(t=this.options.url)||void 0===t?void 0:t.startsWith("ws://127.0.0.1:")))){const e=new J({url:this.options.url,logger:this.logger,timeout:2e3});try{yield e.connect(),yield e.close(),this.url=this.options.url,this.logger.info(`iFlow already running at ${this.options.url}`)}catch(e){this.logger.info("iFlow not running, starting process..."),this.processManager=new X({logger:this.logger,startPort:this.options.processStartPort});try{const e=yield this.processManager.start();this.url=e,this.processStarted=!0,this.logger.info(`Started iFlow process at ${e}`),yield new Promise(e=>setTimeout(e,1e3))}catch(e){throw e instanceof d?(this.logger.error("iFlow not installed"),d):(this.logger.error(`Failed to start iFlow process: ${H(e)}`),new p(`Failed to start iFlow process: ${H(e)}`))}}}let s=null;this.options.fileAccess&&(s=new V({cwd:this.options.cwd,logger:this.logger,readOnly:this.options.fileReadOnly,maxFileSize:this.options.fileMaxSize,allowedDirs:this.options.fileAllowedDirs}),this.logger.info(`File system access enabled with ${this.options.fileReadOnly?"read-only":"read-write"} mode`)),this.transport=new J({url:this.options.url,logger:this.logger,timeout:this.options.timeout}),this.protocol=new K({logger:this.logger,transport:this.transport,fileHandler:s,permissionMode:this.options.permissionMode,autoApproveTypes:this.options.autoApproveTypes}),yield this.transport.connect();const o=yield this.protocol.initialize({mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents});this.authenticated=o.isAuthenticated||!1,this.authenticated||(yield this.protocol.authenticate({methodId:this.options.authMethodId,methodInfo:this.options.authMethodInfo}),this.authenticated=!0),this.sessionId=yield this.protocol.createSession({cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents,settings:this.options.sessionSettings}),this.connected=!0,this.messageTask=this.handleMessages(),this.logger.info("Connected to iFlow")}catch(e){throw yield this.disconnect(),new p(`Failed to connect: ${H(e)}`)}})}loadSession(e){return L(this,void 0,void 0,function*(){if(!this.connected||!this.protocol)throw new p("Not connected. Call connect() first.");yield this.protocol.loadSession({sessionId:e,cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers}),this.sessionId=e,this.logger.info(`Loaded session: ${e}`)})}disconnect(){return L(this,void 0,void 0,function*(){this.connected=!1,this.transport&&(yield this.transport.close()),this.processManager&&this.processStarted&&(yield this.processManager.stop()),this.url=null,this.protocol=null,this.transport=null,this.messageTask=null,this.authenticated=!1,this.processManager=null,this.processStarted=!1,this.logger.info("Disconnected from iFlow")})}sendMessage(s,o){return L(this,void 0,void 0,function*(){if(!this.connected||!this.protocol||!this.sessionId)throw new p("Not connected. Call connect() first.");const i=[{type:"text",text:s}];if(null==o?void 0:o.length)for(const s of o){const o=t.resolve(this.options.cwd||process.cwd(),s),n=t.parse(s);if(!e.existsSync(o)){this.logger.warn(`File not found, skipping: ${o}`);continue}const r=n.ext.toLowerCase();if([".png",".jpg",".jpeg",".gif",".bmp",".webp",".svg"].includes(r))try{const t=e.readFileSync(o).toString("base64"),s={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".bmp":"image/bmp",".webp":"image/webp",".svg":"image/svg+xml"};i.push({type:"image",data:t,mimeType:s[r]||"image/unknown"}),this.logger.debug(`Added image file: ${n.base}`)}catch(e){this.logger.error(`Failed to read image file ${o}: ${H(e)}`);continue}else if([".mp3",".wav",".m4a",".ogg",".flac"].includes(r))try{const t=e.readFileSync(o).toString("base64"),s={".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".ogg":"audio/ogg",".flac":"audio/flac"};i.push({type:"audio",data:t,mimeType:s[r]||"audio/unknown"}),this.logger.debug(`Added audio file: ${n.base}`)}catch(e){this.logger.error(`Failed to read audio file ${o}: ${H(e)}`);continue}else{const t=e.statSync(o);i.push({type:"resource_link",uri:`file://${o}`,name:n.base,title:n.name,size:t.size}),this.logger.debug(`Added resource link: ${n.base}`)}}yield this.protocol.sendPrompt({sessionId:this.sessionId,prompt:i})})}interrupt(){return L(this,void 0,void 0,function*(){if(!this.connected||!this.protocol||!this.sessionId)throw new p("Not connected");yield this.protocol.cancelSession({sessionId:this.sessionId}),this.logger.info("Sent interrupt signal")})}receiveMessages(){return M(this,arguments,function*(){if(!this.connected)throw new p("Not connected");for(;this.connected;)try{this.messageQueue.length>0?yield yield C(this.messageQueue.shift()):yield C(new Promise(e=>setTimeout(e,100)))}catch(e){continue}})}approveToolCall(e){return L(this,arguments,void 0,function*(e,t=P.ALLOW){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Approved tool call ${e} with outcome ${t}`),this.pendingToolCalls.delete(e)})}rejectToolCall(e){return L(this,void 0,void 0,function*(){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Rejected tool call ${e}`),this.pendingToolCalls.delete(e)})}handleMessages(){return L(this,void 0,void 0,function*(){var e,t,s,o;if(this.protocol)try{try{for(var i,n=!0,r=b(this.protocol.handleMessages());!(e=(i=yield r.next()).done);n=!0){o=i.value,n=!1;const e=o,t=this.processProtocolMessage(e);t&&this.messageQueue.push(t)}}catch(e){t={error:e}}finally{try{n||e||!(s=r.return)||(yield s.call(r))}finally{if(t)throw t.error}}}catch(e){this.logger.error(`Error in message handler: ${H(e)}`);const t={type:F.ERROR,code:-1,message:String(H(e))};this.messageQueue.push(t)}})}processProtocolMessage(e){var t,s,o;switch(e.type){case Y.SESSION_UPDATE:{const{updateData:i}=e;let n,r;switch("agentId"in i&&i.agentId&&(n=i.agentId,r=function(e){const t=e.split("-");return"subagent"!==t[0]||t.length<4?{agentId:e}:4===t.length?{agentId:e,taskId:["null","undefined"].includes(t[1])?void 0:t[1],agentIndex:parseInt(t[2])||void 0,timestamp:parseInt(t[3])||void 0}:{agentId:e,taskId:t.slice(1,-2).join("-"),agentIndex:parseInt(t[t.length-2])||void 0,timestamp:parseInt(t[t.length-1])||void 0}}(n)),i.sessionUpdate){case j.PLAN:{const e=null===(t=i.entries)||void 0===t?void 0:t.map(e=>({content:e.content||"",status:e.status||A.PENDING,priority:e.priority||T.MEDIUM}));return e&&(null==e?void 0:e.length)>0?{type:F.PLAN,entries:e}:null}case j.TOOL_CALL:{const e={type:F.TOOL_CALL,id:i.toolCallId||"",label:i.title||"Tool",icon:{type:$.EMOJI,value:"šŸ”§"},status:i.status||O.IN_PROGRESS,toolName:i.toolName};return n&&(e.agentId=n,e.agentInfo=r),this.pendingToolCalls.set(e.id,e),e}case j.TOOL_CALL_UPDATE:{const e=i.toolCallId;let t;if(this.pendingToolCalls.has(e)?(t=this.pendingToolCalls.get(e),t.status=i.status||O.COMPLETED,i.toolName&&(t.toolName=i.toolName),!t.agentId&&n&&(t.agentId=n),!t.agentInfo&&r&&(t.agentInfo=r)):(t={type:F.TOOL_CALL,id:e,label:i.title||"Tool",icon:{type:$.EMOJI,value:"šŸ”§"},status:i.status||O.COMPLETED,toolName:i.toolName},n&&(t.agentId=n,t.agentInfo=r),this.pendingToolCalls.set(e,t)),i.content&&(null===(s=i.content)||void 0===s?void 0:s.length)>0){let e;const s=[];for(const t of i.content)"args"in t&&(e=t.args),"content"===t.type&&"text"===(null===(o=t.content)||void 0===o?void 0:o.type)&&s.push(t.content.text||"");void 0!==e&&(t.args=e),s.length>0&&(t.output=s.join("\n"))}return t}case j.USER_MESSAGE_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t)return{type:F.USER,chunks:[{text:t}]}}return null}case j.AGENT_MESSAGE_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t){const e={type:F.ASSISTANT,chunk:{text:t}};return n&&(e.agentId=n,e.agentInfo=r),e}}return null}case j.AGENT_THOUGHT_CHUNK:{const e=i.content;if("text"===(null==e?void 0:e.type)){const t=e.text||"";if(t){const e={type:F.ASSISTANT,chunk:{thought:t}};return n&&(e.agentId=n,e.agentInfo=r),e}}}default:return null}}case Y.RESPONSE:return"stopReason"in(e.result||{})?{type:F.TASK_FINISH,stopReason:e.result.stopReason}:null;case Y.ERROR:return{type:F.ERROR,code:e.code||-1,message:e.error||"Unknown error"};default:return null}}}function Z(e){let t,s=!1,o="text";if(e.startsWith("//"))s=!0,o="control";else try{t=JSON.parse(e),t&&"method"in t?o=`method:${t.method}`:t&&("result"in t||"error"in t)?o="response":t&&"type"in t&&(o=t.type)}catch(e){}return{isControl:s,messageType:o,rawData:e,jsonData:t,timestamp:Date.now()}}class ee extends B{constructor(e,t=!0){super(e),this.rawQueue=[],this.rawHistory=[],this.rawQueueResolvers=[],this.messageQueueResolvers=[],this.captureRaw=t}handleMessages(){const e=Object.create(null,{handleMessages:{get:()=>super.handleMessages}});return L(this,void 0,void 0,function*(){if(this.protocol)try{if(this.captureRaw&&this.transport){const e=this.captureRawStream(),t=this.handleParsedStream();yield Promise.all([e,t])}else yield e.handleMessages.call(this)}catch(e){this.logger.error(`Error in message handler: ${H(e)}`)}})}captureRawStream(){return L(this,void 0,void 0,function*(){var e,t,s,o;if(this.transport)try{try{for(var i,n=!0,r=b(this.transport.receive());!(e=(i=yield r.next()).done);n=!0){o=i.value,n=!1;const e=o,t=Z("string"==typeof e?e:JSON.stringify(e));this.rawQueue.push(t),this.rawHistory.push(t);const s=this.rawQueueResolvers.shift();s&&s(t)}}catch(e){t={error:e}}finally{try{n||e||!(s=r.return)||(yield s.call(r))}finally{if(t)throw t.error}}}catch(e){this.logger.error(`Error capturing raw stream: ${H(e)}`)}})}handleParsedStream(){return L(this,void 0,void 0,function*(){var e,t,s,o;if(this.protocol)try{for(var i,n=!0,r=b(this.protocol.handleMessages());!(e=(i=yield r.next()).done);n=!0){o=i.value,n=!1;const e=o,t=this.processProtocolMessage(e);if(t){const e=this.messageQueueResolvers.shift();e&&e(t)}}}catch(e){t={error:e}}finally{try{n||e||!(s=r.return)||(yield s.call(r))}finally{if(t)throw t.error}}})}receiveRawMessages(){return M(this,arguments,function*(){for(;this.connected||this.rawQueue.length>0;)try{if(this.rawQueue.length>0)yield yield C(this.rawQueue.shift());else{const e=yield C(Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),100)})]));yield yield C(e)}}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}})}receiveDualStream(){return M(this,arguments,function*(){const e=[],t=[];for(;this.connected||this.rawQueue.length>0||e.length>0||t.length>0;)try{let e,t;e=this.rawQueue.length>0?this.rawQueue.shift():yield C(Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]));try{t=yield C(Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]))}catch(e){}e.parsedMessage=t,yield yield C([e,t])}catch(e){if(!(e instanceof Error&&"Timeout"===e.message))throw e;try{const e=yield C(Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})])),t=Z("<no-raw-data>");t.messageType="parsed_only",yield yield C([t,e])}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}})}getRawHistory(){return[...this.rawHistory]}getProtocolStats(){const e={totalMessages:this.rawHistory.length,messageTypes:{},controlMessages:0,jsonMessages:0,textMessages:0,errors:0};for(const t of this.rawHistory)t.messageType&&(e.messageTypes[t.messageType]=(e.messageTypes[t.messageType]||0)+1),t.isControl?e.controlMessages++:t.jsonData?e.jsonMessages++:e.textMessages++,t.jsonData&&"error"in t.jsonData&&e.errors++;return e}sendRaw(e){return L(this,void 0,void 0,function*(){if(!this.transport)throw new Error("Not connected");yield this.transport.send(e);const t="string"==typeof e?e:JSON.stringify(e).substring(0,100);this.logger.info(`Sent raw data: ${t}`)})}}function te(e,t,s){return L(this,void 0,void 0,function*(){var o,i,n,r;const l=[],a=new B(s);yield a.connect();try{yield a.sendMessage(e,t);try{for(var c,d=!0,h=b(a.receiveMessages());!(o=(c=yield h.next()).done);d=!0){r=c.value,d=!1;const e=r;if(e.type===F.ASSISTANT&&e.chunk.text)l.push(e.chunk.text);else if(e.type===F.TASK_FINISH)break}}catch(e){i={error:e}}finally{try{d||o||!(n=h.return)||(yield n.call(h))}finally{if(i)throw i.error}}}finally{yield a.disconnect()}return l.join("")})}function se(e,t,s){return M(this,arguments,function*(){var o,i,n,r;const l=new B(s);yield C(l.connect());try{yield C(l.sendMessage(e,t));try{for(var a,c=!0,d=b(l.receiveMessages());!(o=(a=yield C(d.next())).done);c=!0){r=a.value,c=!1;const e=r;if(e.type===F.ASSISTANT&&e.chunk.text)yield yield C(e.chunk.text);else if(e.type===F.TASK_FINISH)break}}catch(e){i={error:e}}finally{try{c||o||!(n=d.return)||(yield C(n.call(d)))}finally{if(i)throw i.error}}}finally{yield C(l.disconnect())}})}export{E as ApprovalMode,y as AuthenticationError,p as ConnectionError,I as HookEventType,B as IFlowClient,l as IFlowError,d as IFlowNotInstalledError,h as IFlowProcessError,c as JSONDecodeError,v as LogLevel,F as MessageType,f as PermissionError,S as PermissionMode,T as PlanPriority,A as PlanStatus,u as PortNotAvailableError,m as ProtocolError,ee as RawDataClient,_ as StopReason,a as TimeoutError,P as ToolCallConfirmationOutcome,N as ToolCallConfirmationType,R as ToolCallContentType,$ as ToolCallIconType,O as ToolCallStatus,g as TransportError,w as ValidationError,te as query,se as queryStream};
1
+ import*as e from"fs";import*as t from"path";import s from"ws";import*as o from"fs/promises";import*as i from"os";import*as n from"net";import*as r from"child_process";class a extends Error{constructor(e,t){super(e),this.name="IFlowError",this.details=t||{}}}class l extends a{constructor(e,t){super(e,t),this.name="TimeoutError"}}class c extends a{constructor(e,t){super(e,{rawData:t}),this.name="JSONDecodeError",this.rawData=t}}class h extends a{constructor(e,t){super(e,t),this.name="IFlowNotInstalledError"}}class d extends a{constructor(e,t){super(e,t),this.name="IFlowProcessError"}}class u extends a{constructor(e,t){super(e,t),this.name="PortNotAvailableError"}}class p extends a{constructor(e,t){super(e,t),this.name="ConnectionError"}}class g extends a{constructor(e,t){super(e,t),this.name="TransportError"}}class w extends a{constructor(e,t){super(e,t),this.name="PermissionError"}}class f extends a{constructor(e,t){super(e,t),this.name="ValidationError"}}class m extends a{constructor(e,t){super(e,t),this.name="ProtocolError"}}class y extends a{constructor(e,t){super(e,t),this.name="AuthenticationError"}}var S,E,T,I,A,_,R,N,O,P,$,F,v;!function(e){e[e.DEBUG=0]="DEBUG",e[e.INFO=1]="INFO",e[e.WARN=2]="WARN",e[e.ERROR=3]="ERROR"}(S||(S={})),function(e){e.AUTO="auto",e.MANUAL="manual",e.SELECTIVE="selective"}(E||(E={})),function(e){e.DEFAULT="default",e.AUTO_EDIT="autoEdit",e.YOLO="yolo",e.PLAN="plan"}(T||(T={})),function(e){e.PRE_TOOL_USE="PreToolUse",e.POST_TOOL_USE="PostToolUse",e.STOP="Stop",e.SUBAGENT_STOP="SubagentStop",e.SET_UP_ENVIRONMENT="SetUpEnvironment"}(I||(I={})),function(e){e.HIGH="high",e.MEDIUM="medium",e.LOW="low"}(A||(A={})),function(e){e.PENDING="pending",e.IN_PROGRESS="in_progress",e.COMPLETED="completed"}(_||(_={})),function(e){e.END_TURN="end_turn",e.MAX_TOKENS="max_tokens",e.REFUSAL="refusal",e.CANCELLED="cancelled"}(R||(R={})),function(e){e.PENDING="pending",e.IN_PROGRESS="in_progress",e.COMPLETED="completed",e.FAILED="failed"}(N||(N={})),function(e){e.DIFF="diff",e.MARKDOWN="markdown"}(O||(O={})),function(e){e.EDIT="edit",e.EXECUTE="execute",e.MCP="mcp",e.FETCH="fetch",e.OTHER="other"}(P||(P={})),function(e){e.ALLOW="allow",e.ALWAYS_ALLOW="alwaysAllow",e.ALWAYS_ALLOW_TOOL="alwaysAllowTool",e.ALWAYS_ALLOW_MCP_SERVER="alwaysAllowMcpServer",e.REJECT="reject"}($||($={})),function(e){e.URL="url",e.EMOJI="emoji"}(F||(F={})),function(e){e.PLAN="plan",e.USER="user",e.ASSISTANT="assistant",e.TOOL_CALL="tool_call",e.ERROR="error",e.TASK_FINISH="task_finish"}(v||(v={}));const L="2.0";var C,M,x;function D(e){return e instanceof Error?e.message:e?String(e):"unknown error"}!function(e){e.INITIALIZE="initialize",e.AUTHENTICATE="authenticate",e.SESSION_NEW="session/new",e.SESSION_LOAD="session/load",e.SESSION_PROMPT="session/prompt",e.SESSION_CANCEL="session/cancel"}(C||(C={})),function(e){e.SESSION_UPDATE="session/update",e.SESSION_REQUEST_PERMISSION="session/request_permission",e.FS_READ_TEXT_FILE="fs/read_text_file",e.FS_WRITE_TEXT_FILE="fs/write_text_file",e.PUSH_TOOL_CALL="pushToolCall",e.UPDATE_TOOL_CALL="updateToolCall",e.NOTIFY_TASK_FINISH="notifyTaskFinish"}(M||(M={})),function(e){e.PLAN="plan",e.TOOL_CALL="tool_call",e.TOOL_CALL_UPDATE="tool_call_update",e.USER_MESSAGE_CHUNK="user_message_chunk",e.AGENT_MESSAGE_CHUNK="agent_message_chunk",e.AGENT_THOUGHT_CHUNK="agent_thought_chunk"}(x||(x={}));class U{constructor(e={}){const t=e.level||"INFO";this.level=S[t]}debug(e){this.log(S.DEBUG,e)}info(e){this.log(S.INFO,e)}warn(e){this.log(S.WARN,e)}error(e,t){this.log(S.ERROR,e,t)}log(e,t,s){if(e<this.level)return;const o=`[${(new Date).toLocaleString("sv-SE").replace("T"," ")}] ${S[e]}: ${t}${s?`\n${s.stack}`:""}`;switch(e){case S.DEBUG:console.debug(o);break;case S.INFO:console.info(o);break;case S.WARN:console.warn(o);break;case S.ERROR:console.error(o)}}}const k=new U;function b(e){return!!e&&"id"in e&&"result"in e&&null!=e.result}function j(e){return!!e&&"id"in e&&"error"in e&&null!=e.error}function H(e){return!!e&&"method"in e&&!("result"in e)&&!("error"in e)}class W{constructor(e){this.requestId=0,this.initialized=!1,this.authenticated=!1,this.logger=e.logger||k,this.transport=e.transport,this.fileHandler=e.fileHandler,this.permissionMode=e.permissionMode||E.AUTO,this.autoApproveTypes=e.autoApproveTypes||["read","fetch","list"]}nextRequestId(){return++this.requestId}checkAuthenticated(){if(!this.initialized)throw new m("Protocol not initialized. Call initialize() first.");if(!this.authenticated)throw new m("Not authenticated. Call authenticate() first.")}async sendResult(e,t){const s={jsonrpc:L,id:e,result:t};await this.transport.send(s)}async sendError(e,t,s){const o={jsonrpc:L,id:e,error:{code:t,message:s}};await this.transport.send(o)}async waitForReadySignal(){for await(const e of this.transport.receive()){const t=e.trim();if("//ready"===t){this.logger.info("Received //ready signal");break}t.startsWith("//")&&this.logger.debug(`Control message: ${t}`)}}async waitForMessageResponse(e,t,s){const{timeout:o,timeoutMsg:i=`Timeout after ${o} seconds`}=s||{},n=Date.now();for await(const s of this.transport.receive()){if(s.trim().startsWith("//")){this.logger.debug(`Control message: ${s.trim()}`);continue}let r;try{r=JSON.parse(s.trim())}catch(e){this.logger.error(`Failed to parse response: ${D(e)}`);continue}if(r.id===e){const e=t(r);if(void 0!==e)return e}if(o&&o>0&&Date.now()-n>o)throw new l(i)}}async initialize(e={}){if(this.initialized)return this.logger.warn("Protocol already initialized"),{protocolVersion:1,isAuthenticated:this.authenticated};this.logger.info("Waiting for //ready signal..."),await this.waitForReadySignal();const t=this.nextRequestId(),s={jsonrpc:L,id:t,method:C.INITIALIZE,params:{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!0,writeTextFile:!0}},...e}};await this.transport.send(s),this.logger.info("Sent initialize request");const o=await this.waitForMessageResponse(t,e=>{if("error"in e)throw new m(`Initialize failed: ${e.error?.message}`,e.error);const t=e.result||{};return this.initialized=!0,this.authenticated=t.isAuthenticated||!1,this.logger.info(`Initialized with protocol version: ${t.protocolVersion}, authenticated: ${this.authenticated}`),t},{timeout:1e4,timeoutMsg:"Initialize timeout after 10 seconds"});if(o)return o;throw new m("Connection closed during initialization")}async authenticate(e={}){const t=e.methodId||"iflow";if(this.authenticated)return void this.logger.warn("Already authenticated");const s=this.nextRequestId(),o={jsonrpc:L,id:s,method:C.AUTHENTICATE,params:{...e,methodId:t}};await this.transport.send(o),this.logger.info(`Sent authenticate request with method: ${o.params.methodId}`);if(!await this.waitForMessageResponse(s,e=>{if("error"in e)throw new y(`Authentication failed: ${e.error?.message}`,e.error);const s=e.result||{};return s.methodId===t?(this.authenticated=!0,this.logger.info(`Authentication successful with method: ${s.methodId}`),!0):(this.authenticated=!0,this.logger.warn(`Unexpected methodId in response: ${s.methodId} (expected ${t})`),!0)},{timeout:1e4,timeoutMsg:"Authentication timeout after 10 seconds"}))throw new y("Connection closed during authentication")}async createSession(e={}){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:L,id:t,method:C.SESSION_NEW,params:{...e,cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]}};await this.transport.send(s),this.logger.info(`Sent session/new request with cwd: ${e.cwd}`);const o=await this.waitForMessageResponse(t,e=>{if("error"in e)throw new m(`session/new failed: ${e.error?.message}`,e.error);const t=e.result||{};if(t.sessionId)return this.logger.info(`Created session: ${t.sessionId}`),t.sessionId;throw new m(`Invalid session/new response: ${JSON.stringify(t)}`)},{timeout:1e4,timeoutMsg:"Session creation timeout after 10 seconds"});if(o)return o;throw new m("Connection closed while waiting for session/new response")}async loadSession(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:L,id:t,method:C.SESSION_LOAD,params:{...e,cwd:e.cwd||process.cwd(),mcpServers:e.mcpServers||[]}};await this.transport.send(s),this.logger.info(`Sent session/load request for session: ${e.sessionId}`);if(!await this.waitForMessageResponse(t,t=>{if("error"in t){if(-32601===t.error.code)throw new m("session/load is not supported by the current iFlow version. Use session/new to create a new session instead.",t.error);throw new m(`session/load failed: ${t.error?.message}`,t.error)}return this.logger.info(`Session loaded successfully: ${e.sessionId}`),!0},{timeout:1e4,timeoutMsg:"Session load timeout after 10 seconds"}))throw new m("Connection closed while waiting for session/load response")}async sendPrompt(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:L,id:t,method:C.SESSION_PROMPT,params:e};return await this.transport.send(s),this.logger.info(`Sent prompt with ${e.prompt.length} content blocks`),t}async cancelSession(e){this.checkAuthenticated();const t=this.nextRequestId(),s={jsonrpc:L,id:t,method:C.SESSION_CANCEL,params:e};await this.transport.send(s),this.logger.info("Sent session/cancel request")}async*handleMessages(){for await(const e of this.transport.receive()){if(e.trim().startsWith("//")){this.logger.debug(`Control message: ${e.trim()}`);continue}let t;try{t=JSON.parse(e.trim())}catch(t){throw this.logger.error(`Failed to parse message: ${D(t)}`),new c("Invalid JSON received",e)}H(t)?yield await this.handleClientMessage(t):b(t)?yield{type:"response",id:t.id,result:t.result}:j(t)&&(yield{type:"error",code:t.error.code,error:t.error.message})}}async handleClientMessage(e){const{method:t}=e;switch(t){case M.FS_READ_TEXT_FILE:return await this.handleReadTextFile(e);case M.FS_WRITE_TEXT_FILE:return await this.handleWriteTextFile(e);case M.SESSION_UPDATE:return await this.handleSessionUpdate(e);case M.SESSION_REQUEST_PERMISSION:return await this.handleRequestPermission(e);case M.PUSH_TOOL_CALL:return await this.handlePushToolCall(e);case M.UPDATE_TOOL_CALL:return await this.handleUpdateToolCall(e);case M.NOTIFY_TASK_FINISH:return await this.handleNotifyTaskFinish(e);default:return await this.handleUnknownMessage(e)}}async handleReadTextFile(e){const{id:t,method:s,params:o}=e,{path:i,limit:n,line:r}=o||{};let a;if(this.logger.info(`fs/read_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&await this.sendError(t,-32603,e),{type:"error",code:-32603,error:e,method:s}}try{a=await this.fileHandler.readFile(i,r,n)}catch(e){const o=D(e);return this.logger.error(`Error reading file ${i}: ${o}`),void 0!==t&&await this.sendError(t,-32603,o),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&await this.sendResult(t,{content:a}),{type:"file_read",path:i,content:a}}async handleWriteTextFile(e){const{id:t,method:s,params:o}=e,{path:i,content:n}=o||{};if(this.logger.info(`fs/write_text_file request for: ${i}`),!this.fileHandler){const e="File system access not configured";return void 0!==t&&await this.sendError(t,-32603,e),{type:"error",code:-32603,error:e,method:s}}try{await this.fileHandler.writeFile(i,n)}catch(e){const o=D(e);return this.logger.error(`Error writing file ${i}: ${o}`),void 0!==t&&await this.sendError(t,-32603,o),{type:"error",code:-32603,error:o,method:s}}return void 0!==t&&await this.sendResult(t,{success:!0}),{type:"file_write",path:i,content:n}}async handleSessionUpdate(e){const{params:t}=e,{sessionId:s,update:o}=t;return{type:"session_update",sessionId:s,updateData:o}}async handleRequestPermission(e){const{id:t,params:s}=e,o=s.toolCall||{},i=s.options||[];let n,r;if(n=this.permissionMode===E.AUTO||this.permissionMode!==E.MANUAL&&this.autoApproveTypes.includes(o.type||""),n){let e;for(const t of i){const s=t.optionId||"";if("proceed_once"===s){e=s;break}"proceed_always"===s&&(e=s)}!e&&i.length>0&&(e=i[0].optionId||"proceed_once"),r={outcome:{outcome:"selected",optionId:e}}}else r={outcome:{outcome:"cancelled"}};return void 0!==t&&await this.sendResult(t,r),this.logger.info(`Permission request for tool '${o.title||"unknown"}' - Response: ${r.outcome.outcome}`),{type:"tool_confirmation",params:s,response:r}}async handlePushToolCall(e){const{id:t,params:s}=e,o=`tool_${this.nextRequestId()}`,i={id:o};return void 0!==t&&await this.sendResult(t,i),{type:"tool_call",id:o,params:s}}async handleUpdateToolCall(e){const{id:t,params:s}=e;return void 0!==t&&await this.sendResult(t,null),{type:"tool_update",params:s}}async handleNotifyTaskFinish(e){const{id:t,params:s}=e;return void 0!==t&&await this.sendResult(t,null),{type:"task_finish",params:s}}async handleUnknownMessage(e){const{id:t,method:s,params:o}=e;return this.logger.warn(`Unknown method: ${s}`),void 0!==t&&await this.sendError(t,-32601,"Method not found"),{type:"unknown",method:s,params:o}}}class z{constructor(e){this.ws=null,this.connected=!1,this.url=e.url,this.logger=e.logger||k,this.timeout=e.timeout||3e5}get isConnected(){return!!this.ws&&this.connected}checkConnected(){if(!this.isConnected)throw new p("Not connected")}async connect(){if(this.connected)this.logger.warn(`Already connected to ${this.url}`);else try{this.logger.info(`Connecting to ${this.url}`),this.ws=await new Promise((e,t)=>{const o=new s(this.url),i=setTimeout(()=>{o.close(),t(new l(`Connected to ${this.url} timeout after ${this.timeout/1e3}s`))},this.timeout);o.on("open",()=>{clearTimeout(i),this.connected=!0,this.logger.info(`Connected to ${this.url} succesfully`),e(o)}),o.on("error",e=>{clearTimeout(i),this.connected=!1,t(e)}),o.on("close",(e,s)=>{clearTimeout(i),this.connected=!1,t(new Error(`${s} (code: ${e})`))})})}catch(e){if(e instanceof l)throw e;throw new p(`Failed to connect to ${this.url}: ${D(e)}`)}}async close(){if(this.ws&&this.connected)try{this.ws.close(),this.logger.info("Connection closed")}catch(e){this.logger.warn(`Error closing connection: ${D(e)}`)}this.ws=null,this.connected=!1}async send(e){this.checkConnected();try{const t="string"==typeof e?e:JSON.stringify(e);await new Promise((e,s)=>{this.ws.send(t,o=>{o?s(o):(this.logger.debug(`Sent message: ${t}`),e())})})}catch(e){throw this.connected=!1,new g(`Failed to send message: ${D(e)}`)}}async*receive(){for(this.checkConnected();this.isConnected;)try{const e=await this.receiveRawData();this.logger.debug(`Received message: ${e}`),yield e}catch(e){if(this.connected=!1,e instanceof p&&e.details.isClosed){this.logger.info("Connection closed");break}throw new g(`Failed to receive message: ${D(e)}`)}}receiveRawData(){return new Promise((e,t)=>{if(!this.isConnected)return void t(new p("Not connected"));const s=()=>{this.ws&&(this.ws.off("close",o),this.ws.off("error",i),this.ws.off("message",n))},o=()=>{s(),this.connected=!1,t(new p("Connection closed",{isClosed:!0}))},i=e=>{s(),this.connected=!1,t(e)},n=t=>{s(),e(t.toString())};this.ws&&(this.ws.on("close",o),this.ws.on("error",i),this.ws.on("message",n))})}}class G{constructor(e={}){this.cwd=e.cwd||process.cwd(),this.logger=e.logger||k,this.readOnly=e.readOnly||!1,this.maxFileSize=e.maxFileSize||10485760,e.allowedDirs?this.allowedDirs=new Set(e.allowedDirs.map(e=>t.resolve(this.cwd,e))):this.allowedDirs=new Set([this.cwd]),this.logger.info(`File handler initialized with ${this.allowedDirs.size} allowed directories`);for(const e of this.allowedDirs)this.logger.debug(` Allowed: ${e}`)}isPathAllowed(e){try{const s=t.resolve(this.cwd,e);for(const e of this.allowedDirs)if(s.startsWith(e))return!0;return this.logger.warn(`Path not in allowed directories: ${s}`),!1}catch(e){return e instanceof Error&&this.logger.error(`Error checking path: ${e.message}`,e),!1}}async readFile(s,i,n){if(!this.isPathAllowed(s))throw new w(`Access denied: ${s}`);const r=t.resolve(this.cwd,s);try{if(!e.existsSync(r))throw new f(`File not found: ${s}`);try{await o.access(r,e.constants.R_OK)}catch{throw new w(`Permission denied: ${s}`)}const t=await o.stat(r);if(!t.isFile())throw new f(`Not a file: ${s}`);if(t.size>this.maxFileSize)throw new f(`File too large: ${t.size} bytes (max: ${this.maxFileSize})`);const a=await o.readFile(r,"utf-8");if(void 0!==i||void 0!==n){const e=a.split("\n"),t=i?i-1:0,o=n?t+n:e.length,r=Math.max(0,t),l=Math.min(e.length,o);return this.logger.debug(`Read ${l-r} lines from ${s}`),e.slice(r,l).join("\n")}return this.logger.debug(`Read ${a.length} bytes from ${s}`),a}catch(e){if(e instanceof f||e instanceof w)throw e;throw new f(`Failed to read file: ${D(e)}`)}}async writeFile(e,s){if(this.readOnly)throw new w("File system is in read-only mode");if(!this.isPathAllowed(e))throw new w(`Access denied: ${e}`);const i=t.resolve(this.cwd,e);try{await o.mkdir(t.dirname(i),{recursive:!0}),await o.writeFile(i,s,"utf-8"),this.logger.debug(`Wrote ${s.length} bytes to ${e}`)}catch(e){throw new f(`Failed to write file: ${D(e)}`)}}async addAllowedDir(s){const i=t.resolve(this.cwd,s);try{if(!e.existsSync(i))throw new f(`Directory does not exist: ${i}`);if(!(await o.stat(i)).isDirectory())throw new f(`Not a directory: ${i}`);this.allowedDirs.add(i),this.logger.info(`Added allowed directory: ${i}`)}catch(e){if(e instanceof f)throw e;throw new f(`Failed to add ${i} as allowed directory: ${D(e)}`)}}removeAllowedDir(e){const s=t.resolve(this.cwd,e);this.allowedDirs.delete(s),this.logger.info(`Removed allowed directory: ${s}`)}}class Q{constructor(e={}){this.port=null,this.process=null,this.iflowPath=null,this.logger=e.logger||k,this.startPort=e.startPort||8090}get url(){if(!this.port)throw new d("iFlow process not started");return`ws://localhost:${this.port}/acp`}isRunning(){return!!this.process&&!this.process.killed&&null===this.process.exitCode}which(e){try{return r.execSync(`which ${e}`,{encoding:"utf-8"}).trim()}catch{return null}}fileExists(t){try{return e.existsSync(t)&&e.statSync(t).isFile()}catch{return!1}}findIflowPath(){const e=this.which("iflow");if(e)return this.logger.debug(`Found iflow at: ${e}`),e;const s=i.homedir(),o=[t.join(s,".npm-global","bin","iflow"),"/usr/local/bin/iflow",t.join(s,".local","bin","iflow"),t.join(s,"node_modules",".bin","iflow"),t.join(s,".yarn","bin","iflow"),t.join(s,"AppData","Roaming","npm","iflow.cmd"),t.join("C:","Program Files","nodejs","iflow.cmd")];for(const e of o)if(this.fileExists(e))return this.logger.debug(`Found iflow at: ${e}`),e;const n=null!==this.which("npm"),r=null!==this.which("node");let a;throw a="win32"===i.platform()?n||r?"iFlow CLI not found. Please use the following command to install:\n npm install -g @iflow-ai/iflow-cli@latest":"iFlow requires Node.js, but it is not installed in the system.\n\nPlease install Node.js first: https://nodejs.org/\n\nAfter installing Node.js, use the following command to install iFlow:\n npm install -g @iflow-ai/iflow-cli@latest":'iFlow CLI not found. Please use the following command to install:\n\nšŸŽ Mac/Linux/Ubuntu users:\n bash -c "$(curl -fsSL https://cloud.iflow.cn/iflow-cli/install.sh)"\n\n🪟 Windows users:\n npm install -g @iflow-ai/iflow-cli@latest',new h(a)}isPortAvailable(e){return new Promise(t=>{const s=n.createServer();s.listen(e,"localhost",()=>{s.once("close",()=>{t(!0)}),s.close()}),s.once("error",()=>{t(!1)})})}async findAvailablePort(){for(let e=0;e<100;e++){const t=this.startPort+e;if(await this.isPortAvailable(t))return this.logger.debug(`Found available port: ${t}`),t}throw new u(`No available port found in range ${this.startPort}-${this.startPort+100}`)}async start(){if(this.isRunning())return this.url;this.iflowPath=this.findIflowPath(),this.port=await this.findAvailablePort();const e=[this.iflowPath,"--experimental-acp","--port",this.port.toString()];this.logger.info(`Starting iFlow process: ${e.join(" ")}`);try{if(this.process=r.spawn(e[0],e.slice(1),{stdio:["ignore","pipe","pipe"],detached:!1}),await this.onSpawn(),!this.isRunning()){let e="iFlow process exited immediately";if(this.process.stderr){const t=this.process.stderr.read();t&&(e+=`: ${t.toString("utf-8")}`)}throw new Error(e)}return this.logger.info(`iFlow process started on port ${this.port} (PID: ${this.process.pid})`),this.url}catch(e){throw this.port=null,this.process=null,new d(`Failed to start iFlow process: ${D(e)}`)}}async stop(){if(this.process){if(!this.isRunning())return this.port=null,void(this.process=null);this.logger.info(`Stopping iFlow process (PID: ${this.process.pid})`);try{this.process.kill("SIGTERM"),await Promise.race([new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()}),new Promise(e=>setTimeout(()=>e(),5e3))]),this.isRunning()?(this.logger.warn("iFlow process did not terminate gracefully, forcing kill"),this.process.kill("SIGKILL"),await new Promise(e=>{this.process?this.process.once("exit",()=>e()):e()})):this.logger.info("iFlow process terminated gracefully")}catch(e){this.logger.error(`Error stopping iFlow process: ${D(e)}`)}finally{this.port=null,this.process=null}}}async onSpawn(e=5e3){return new Promise((t,s)=>{if(!this.process)return void s(new Error("Process not initialized"));const o=setTimeout(()=>{s(new Error(`Process spawn timeout after ${e}ms`))},e);this.process.once("spawn",()=>{clearTimeout(o),setTimeout(t,2e3)})})}}var q;!function(e){e.ERROR="error",e.RESPONSE="response",e.FILE_READ="file_read",e.FILE_WRITE="file_write",e.SESSION_UPDATE="session_update",e.TOOL_CALL="tool_call",e.TOOL_UPDATE="tool_update",e.TOOL_CONFIRMATION="tool_confirmation",e.TASK_FINISH="task_finish",e.UNKNOWN="unknown"}(q||(q={}));class K{constructor(e={}){this.protocol=null,this.transport=null,this.connected=!1,this.authenticated=!1,this.messageTask=null,this.messageQueue=[],this.pendingToolCalls=new Map,this.url=null,this.sessionId=null,this.processManager=null,this.processStarted=!1,this.options={url:"ws://localhost:8090/acp",cwd:process.cwd(),timeout:3e4,logLevel:"INFO",fileMaxSize:10485760,permissionMode:E.AUTO,autoApproveTypes:["read","fetch","list"],authMethodId:"iflow",autoStartProcess:!0,processStartPort:8090,...e},this.logger=new U({level:this.options.logLevel})}async connect(){if(this.connected)this.logger.warn("Already connected");else try{if(this.options.autoStartProcess&&(this.options.url?.startsWith("ws://localhost:")||this.options.url?.startsWith("ws://127.0.0.1:"))){const e=new z({url:this.options.url,logger:this.logger,timeout:2e3});try{await e.connect(),await e.close(),this.url=this.options.url,this.logger.info(`iFlow already running at ${this.options.url}`)}catch{this.logger.info("iFlow not running, starting process..."),this.processManager=new Q({logger:this.logger,startPort:this.options.processStartPort});try{const e=await this.processManager.start();this.url=e,this.processStarted=!0,this.logger.info(`Started iFlow process at ${e}`),await new Promise(e=>setTimeout(e,1e3))}catch(e){throw e instanceof h?(this.logger.error("iFlow not installed"),h):(this.logger.error(`Failed to start iFlow process: ${D(e)}`),new p(`Failed to start iFlow process: ${D(e)}`))}}}let e=null;this.options.fileAccess&&(e=new G({cwd:this.options.cwd,logger:this.logger,readOnly:this.options.fileReadOnly,maxFileSize:this.options.fileMaxSize,allowedDirs:this.options.fileAllowedDirs}),this.logger.info(`File system access enabled with ${this.options.fileReadOnly?"read-only":"read-write"} mode`)),this.transport=new z({url:this.options.url,logger:this.logger,timeout:this.options.timeout}),this.protocol=new W({logger:this.logger,transport:this.transport,fileHandler:e,permissionMode:this.options.permissionMode,autoApproveTypes:this.options.autoApproveTypes}),await this.transport.connect();const t=await this.protocol.initialize({mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents});this.authenticated=t.isAuthenticated||!1,this.authenticated||(await this.protocol.authenticate({methodId:this.options.authMethodId,methodInfo:this.options.authMethodInfo}),this.authenticated=!0),this.sessionId=await this.protocol.createSession({cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers,hooks:this.options.hooks,commands:this.options.commands,agents:this.options.agents,settings:this.options.sessionSettings}),this.connected=!0,this.messageTask=this.handleMessages(),this.logger.info("Connected to iFlow")}catch(e){throw await this.disconnect(),new p(`Failed to connect: ${D(e)}`)}}async loadSession(e){if(!this.connected||!this.protocol)throw new p("Not connected. Call connect() first.");await this.protocol.loadSession({sessionId:e,cwd:this.options.cwd||process.cwd(),mcpServers:this.options.mcpServers}),this.sessionId=e,this.logger.info(`Loaded session: ${e}`)}async disconnect(){this.connected=!1,this.transport&&await this.transport.close(),this.processManager&&this.processStarted&&await this.processManager.stop(),this.url=null,this.protocol=null,this.transport=null,this.messageTask=null,this.authenticated=!1,this.processManager=null,this.processStarted=!1,this.logger.info("Disconnected from iFlow")}async sendMessage(s,o){if(!this.connected||!this.protocol||!this.sessionId)throw new p("Not connected. Call connect() first.");const i=[{type:"text",text:s}];if(o?.length)for(const s of o){const o=t.resolve(this.options.cwd||process.cwd(),s),n=t.parse(s);if(!e.existsSync(o)){this.logger.warn(`File not found, skipping: ${o}`);continue}const r=n.ext.toLowerCase();if([".png",".jpg",".jpeg",".gif",".bmp",".webp",".svg"].includes(r))try{const t=e.readFileSync(o).toString("base64"),s={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".bmp":"image/bmp",".webp":"image/webp",".svg":"image/svg+xml"};i.push({type:"image",data:t,mimeType:s[r]||"image/unknown"}),this.logger.debug(`Added image file: ${n.base}`)}catch(e){this.logger.error(`Failed to read image file ${o}: ${D(e)}`);continue}else if([".mp3",".wav",".m4a",".ogg",".flac"].includes(r))try{const t=e.readFileSync(o).toString("base64"),s={".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".ogg":"audio/ogg",".flac":"audio/flac"};i.push({type:"audio",data:t,mimeType:s[r]||"audio/unknown"}),this.logger.debug(`Added audio file: ${n.base}`)}catch(e){this.logger.error(`Failed to read audio file ${o}: ${D(e)}`);continue}else{const t=e.statSync(o);i.push({type:"resource_link",uri:`file://${o}`,name:n.base,title:n.name,size:t.size}),this.logger.debug(`Added resource link: ${n.base}`)}}await this.protocol.sendPrompt({sessionId:this.sessionId,prompt:i})}async interrupt(){if(!this.connected||!this.protocol||!this.sessionId)throw new p("Not connected");await this.protocol.cancelSession({sessionId:this.sessionId}),this.logger.info("Sent interrupt signal")}async*receiveMessages(){if(!this.connected)throw new p("Not connected");for(;this.connected;)try{this.messageQueue.length>0?yield this.messageQueue.shift():await new Promise(e=>setTimeout(e,100))}catch{continue}}async approveToolCall(e,t=$.ALLOW){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Approved tool call ${e} with outcome ${t}`),this.pendingToolCalls.delete(e)}async rejectToolCall(e){if(!this.pendingToolCalls.has(e))throw new Error(`Unknown tool call: ${e}`);this.logger.info(`Rejected tool call ${e}`),this.pendingToolCalls.delete(e)}async handleMessages(){if(this.protocol)try{for await(const e of this.protocol.handleMessages()){const t=this.processProtocolMessage(e);t&&this.messageQueue.push(t)}}catch(e){this.logger.error(`Error in message handler: ${D(e)}`);const t={type:v.ERROR,code:-1,message:String(D(e))};this.messageQueue.push(t)}}processProtocolMessage(e){switch(e.type){case q.SESSION_UPDATE:{const{updateData:t}=e;let s,o;switch("agentId"in t&&t.agentId&&(s=t.agentId,o=function(e){const t=e.split("-");return"subagent"!==t[0]||t.length<4?{agentId:e}:4===t.length?{agentId:e,taskId:["null","undefined"].includes(t[1])?void 0:t[1],agentIndex:parseInt(t[2])||void 0,timestamp:parseInt(t[3])||void 0}:{agentId:e,taskId:t.slice(1,-2).join("-"),agentIndex:parseInt(t[t.length-2])||void 0,timestamp:parseInt(t[t.length-1])||void 0}}(s)),t.sessionUpdate){case x.PLAN:{const e=t.entries?.map(e=>({content:e.content||"",status:e.status||_.PENDING,priority:e.priority||A.MEDIUM}));return e&&e?.length>0?{type:v.PLAN,entries:e}:null}case x.TOOL_CALL:{const e={type:v.TOOL_CALL,id:t.toolCallId||"",label:t.title||"Tool",icon:{type:F.EMOJI,value:"šŸ”§"},status:t.status||N.IN_PROGRESS,toolName:t.toolName};return s&&(e.agentId=s,e.agentInfo=o),this.pendingToolCalls.set(e.id,e),{...e}}case x.TOOL_CALL_UPDATE:{const e=t.toolCallId;let i;if(this.pendingToolCalls.has(e)?(i=this.pendingToolCalls.get(e),i.status=t.status||N.COMPLETED,t.toolName&&(i.toolName=t.toolName),!i.agentId&&s&&(i.agentId=s),!i.agentInfo&&o&&(i.agentInfo=o)):(i={type:v.TOOL_CALL,id:e,label:t.title||"Tool",icon:{type:F.EMOJI,value:"šŸ”§"},status:t.status||N.COMPLETED,toolName:t.toolName},s&&(i.agentId=s,i.agentInfo=o),this.pendingToolCalls.set(e,i)),t.content&&t.content?.length>0){let e;const s=[];for(const o of t.content)"args"in o&&(e=o.args),"content"===o.type&&"text"===o.content?.type&&s.push(o.content.text||"");void 0!==e&&(i.args=e),s.length>0&&(i.output=s.join("\n"))}return{...i}}case x.USER_MESSAGE_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t)return{type:v.USER,chunks:[{text:t}]}}return null}case x.AGENT_MESSAGE_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t){const e={type:v.ASSISTANT,chunk:{text:t}};return s&&(e.agentId=s,e.agentInfo=o),e}}return null}case x.AGENT_THOUGHT_CHUNK:{const e=t.content;if("text"===e?.type){const t=e.text||"";if(t){const e={type:v.ASSISTANT,chunk:{thought:t}};return s&&(e.agentId=s,e.agentInfo=o),e}}}default:return null}}case q.RESPONSE:return"stopReason"in(e.result||{})?{type:v.TASK_FINISH,stopReason:e.result.stopReason}:null;case q.ERROR:return{type:v.ERROR,code:e.code||-1,message:e.error||"Unknown error"};default:return null}}}function J(e){let t,s=!1,o="text";if(e.startsWith("//"))s=!0,o="control";else try{t=JSON.parse(e),t&&"method"in t?o=`method:${t.method}`:t&&("result"in t||"error"in t)?o="response":t&&"type"in t&&(o=t.type)}catch{}return{isControl:s,messageType:o,rawData:e,jsonData:t,timestamp:Date.now()}}class V extends K{constructor(e,t=!0){super(e),this.rawQueue=[],this.rawHistory=[],this.rawQueueResolvers=[],this.messageQueueResolvers=[],this.captureRaw=t}async handleMessages(){if(this.protocol)try{if(this.captureRaw&&this.transport){const e=this.captureRawStream(),t=this.handleParsedStream();await Promise.all([e,t])}else await super.handleMessages()}catch(e){this.logger.error(`Error in message handler: ${D(e)}`)}}async captureRawStream(){if(this.transport)try{for await(const e of this.transport.receive()){const t=J("string"==typeof e?e:JSON.stringify(e));this.rawQueue.push(t),this.rawHistory.push(t);const s=this.rawQueueResolvers.shift();s&&s(t)}}catch(e){this.logger.error(`Error capturing raw stream: ${D(e)}`)}}async handleParsedStream(){if(this.protocol)for await(const e of this.protocol.handleMessages()){const t=this.processProtocolMessage(e);if(t){const e=this.messageQueueResolvers.shift();e&&e(t)}}}async*receiveRawMessages(){for(;this.connected||this.rawQueue.length>0;)try{if(this.rawQueue.length>0)yield this.rawQueue.shift();else{const e=await Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),100)})]);yield e}}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}async*receiveDualStream(){const e=[],t=[];for(;this.connected||this.rawQueue.length>0||e.length>0||t.length>0;)try{let e,t;e=this.rawQueue.length>0?this.rawQueue.shift():await Promise.race([new Promise(e=>{this.rawQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]);try{t=await Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})])}catch{}e.parsedMessage=t,yield[e,t]}catch(e){if(!(e instanceof Error&&"Timeout"===e.message))throw e;try{const e=await Promise.race([new Promise(e=>{this.messageQueueResolvers.push(e)}),new Promise((e,t)=>{setTimeout(()=>t(new Error("Timeout")),10)})]),t=J("<no-raw-data>");t.messageType="parsed_only",yield[t,e]}catch(e){if(e instanceof Error&&"Timeout"===e.message)continue;throw e}}}getRawHistory(){return[...this.rawHistory]}getProtocolStats(){const e={totalMessages:this.rawHistory.length,messageTypes:{},controlMessages:0,jsonMessages:0,textMessages:0,errors:0};for(const t of this.rawHistory)t.messageType&&(e.messageTypes[t.messageType]=(e.messageTypes[t.messageType]||0)+1),t.isControl?e.controlMessages++:t.jsonData?e.jsonMessages++:e.textMessages++,t.jsonData&&"error"in t.jsonData&&e.errors++;return e}async sendRaw(e){if(!this.transport)throw new Error("Not connected");await this.transport.send(e);const t="string"==typeof e?e:JSON.stringify(e).substring(0,100);this.logger.info(`Sent raw data: ${t}`)}}async function X(e,t,s){const o=[],i=new K(s);await i.connect();try{await i.sendMessage(e,t);for await(const e of i.receiveMessages())if(e.type===v.ASSISTANT&&e.chunk.text)o.push(e.chunk.text);else if(e.type===v.TASK_FINISH)break}finally{await i.disconnect()}return o.join("")}async function*Y(e,t,s){const o=new K(s);await o.connect();try{await o.sendMessage(e,t);for await(const e of o.receiveMessages())if(e.type===v.ASSISTANT&&e.chunk.text)yield e.chunk.text;else if(e.type===v.TASK_FINISH)break}finally{await o.disconnect()}}export{T as ApprovalMode,y as AuthenticationError,p as ConnectionError,I as HookEventType,K as IFlowClient,a as IFlowError,h as IFlowNotInstalledError,d as IFlowProcessError,c as JSONDecodeError,S as LogLevel,v as MessageType,w as PermissionError,E as PermissionMode,A as PlanPriority,_ as PlanStatus,u as PortNotAvailableError,m as ProtocolError,V as RawDataClient,R as StopReason,l as TimeoutError,$ as ToolCallConfirmationOutcome,P as ToolCallConfirmationType,O as ToolCallContentType,F as ToolCallIconType,N as ToolCallStatus,g as TransportError,f as ValidationError,X as query,Y as queryStream};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iflow-ai/iflow-cli-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "TypeScript SDK for iFlow CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",