impactus-swarm 0.1.4 → 0.1.8
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.
Potentially problematic release.
This version of impactus-swarm might be problematic. Click here for more details.
- package/package.json +1 -1
- package/server/main.js +2 -2
package/package.json
CHANGED
package/server/main.js
CHANGED
|
@@ -33,7 +33,7 @@ set -gx TERM_PROGRAM impactus-swarm
|
|
|
33
33
|
`.trim();default:return""}}static detectShell(e){return e.includes("zsh")?"zsh":e.includes("bash")?"bash":e.includes("fish")?"fish":"unknown"}static getEnvVars(e){return{TERM_PROGRAM:"impactus-swarm",__IMPACTUS_SHELL_INTEGRATION:"1"}}static async createInjectionEnv(e){if(e==="unknown"||e==="fish")return a.getEnvVars(e);try{let t=K(Us(),"impactus-shell-integration");if(await et(t,{recursive:!0}),await xs(t,448),e==="zsh"){let s=K(t,"zsh");await et(s,{recursive:!0});let r=["# IMPACTUS Swarm Shell Integration","# Source original zshrc",'if [[ -f "$HOME/.zshrc" ]]; then',' ZDOTDIR="$HOME" source "$HOME/.zshrc"',"fi","",a.getInitScript("zsh")].join(`
|
|
34
34
|
`);await tt(K(s,".zshrc"),r,"utf-8");let n=["# Source original zshenv",'if [[ -f "$HOME/.zshenv" ]]; then',' ZDOTDIR="$HOME" source "$HOME/.zshenv"',"fi"].join(`
|
|
35
35
|
`);return await tt(K(s,".zshenv"),n,"utf-8"),{...a.getEnvVars("zsh"),ZDOTDIR:s}}if(e==="bash"){let s=K(t,"bash");await et(s,{recursive:!0});let r=["# IMPACTUS Swarm Shell Integration","# Source original bashrc",'if [[ -f "$HOME/.bashrc" ]]; then',' source "$HOME/.bashrc"',"fi","",a.getInitScript("bash")].join(`
|
|
36
|
-
`),n=K(s,".bashrc_impactus");return await tt(n,r,"utf-8"),{...a.getEnvVars("bash"),BASH_ENV:n}}}catch{}return a.getEnvVars(e)}};var Fs=_s(import.meta.url),Ws=Fs("node-pty");async function kt(a){let e=process.platform==="win32",t=e?process.env.COMSPEC||"cmd.exe":process.env.SHELL||"/bin/zsh",s=e?[]:[],r=te.detectShell(t),n=await te.createInjectionEnv(r);return Ws.spawn(t,s,{name:"xterm-256color",cols:a.cols,rows:a.rows,cwd:a.cwd,env:{...
|
|
36
|
+
`),n=K(s,".bashrc_impactus");return await tt(n,r,"utf-8"),{...a.getEnvVars("bash"),BASH_ENV:n}}}catch{}return a.getEnvVars(e)}};var Fs=_s(import.meta.url),Ws=Fs("node-pty");async function kt(a){let e=process.platform==="win32",t=e?process.env.COMSPEC||"cmd.exe":process.env.SHELL||"/bin/zsh",s=e?[]:[],r=te.detectShell(t),n=await te.createInjectionEnv(r),{PORT:o,IMPACTUS_WEB_DIR:i,RELAY_URL:c,RELAY_ALLOWED_IPS:d,...l}=process.env;return Ws.spawn(t,s,{name:"xterm-256color",cols:a.cols,rows:a.rows,cwd:a.cwd,env:{...l,...n,...a.env}})}import{randomUUID as Bs}from"node:crypto";var se=class a{activeBlocks=new Map;lineCounters=new Map;partialBuffers=new Map;static OSC_PROMPT_START=/\x1b\]133;A(?:\x1b\\|\x07)/g;static OSC_COMMAND_EXEC=/\x1b\]133;C(?:\x1b\\|\x07)/g;static OSC_COMMAND_END=/\x1b\]133;D;?(\d*)(?:\x1b\\|\x07)/g;static PARTIAL_OSC=/\x1b(?:\](?:1(?:3(?:3(?:;(?:[A-D](?:;?\d*)?)?)?)?)?)?)?$/;parse(e,t){let s=[],n=(this.partialBuffers.get(t)||"")+e;this.partialBuffers.delete(t);let o=a.PARTIAL_OSC.exec(n),i;o?(this.partialBuffers.set(t,o[0]),i=n.slice(0,o.index)):i=n;let c=(i.match(/\n/g)||[]).length,d=this.lineCounters.get(t)||0,l=[];a.OSC_PROMPT_START.lastIndex=0,a.OSC_COMMAND_EXEC.lastIndex=0,a.OSC_COMMAND_END.lastIndex=0;let u;for(;(u=a.OSC_PROMPT_START.exec(i))!==null;)l.push({type:"A",index:u.index});for(;(u=a.OSC_COMMAND_EXEC.exec(i))!==null;)l.push({type:"C",index:u.index});for(;(u=a.OSC_COMMAND_END.exec(i))!==null;)l.push({type:"D",index:u.index,exitCode:u[1]?parseInt(u[1],10):0});l.sort((p,m)=>p.index-m.index);for(let p of l)switch(p.type){case"A":{let m={id:Bs(),terminalId:t,status:"prompting",startTime:new Date().toISOString(),lineStart:d};this.activeBlocks.set(t,m),s.push({type:"block-start",terminalId:t,block:{...m}});break}case"C":{let m=this.activeBlocks.get(t);m&&(m.status="executing",s.push({type:"block-executing",terminalId:t,block:{...m}}));break}case"D":{let m=this.activeBlocks.get(t);m&&(m.status="completed",m.exitCode=p.exitCode,m.endTime=new Date().toISOString(),m.lineEnd=d+c,s.push({type:"block-end",terminalId:t,block:{...m}}),this.activeBlocks.delete(t));break}}return this.lineCounters.set(t,d+c),s}static stripOSC133(e){return e.replace(/\x1b\]133;[A-D];?\d*(?:\x1b\\|\x07)/g,"")}getActiveBlock(e){return this.activeBlocks.get(e)}cleanup(e){this.activeBlocks.delete(e),this.lineCounters.delete(e),this.partialBuffers.delete(e)}};var qs=process.platform==="win32",st=new Set(["zsh","bash","sh","fish","dash","ksh","tcsh","csh","ps","grep","rg","cmd.exe","powershell.exe","pwsh.exe","conhost.exe","cmd","powershell","pwsh","conhost"]),me=class{terminals=new Map;pushHandler;commandBlockParser=new se;processDetectionInterval;constructor(e){this.pushHandler=e,this.processDetectionInterval=setInterval(()=>{this.detectProcesses()},3e3)}detectProcesses(){for(let[,e]of this.terminals){let t=this.detectProcessForTerminal(e),s=e.lastProcessInfo;(!s||s.foregroundProcess!==t.foregroundProcess||s.isIdle!==t.isIdle)&&(e.lastProcessInfo=t,this.pushHandler("terminal.process",{id:e.id,process:t}))}}detectProcessForTerminal(e){let t=e.pty.pid,s;try{if(qs){let n=pe(`wmic process where (ParentProcessId=${t}) get Name /format:list`,{stdio:"pipe",timeout:2e3}).toString().trim().split(`
|
|
37
37
|
`).map(o=>o.replace(/^Name=/,"").trim()).filter(o=>o&&!st.has(o)&&!st.has(o.replace(/\.exe$/i,"")));n.length>0&&(s=n[0].replace(/\.exe$/i,""))}else{let r=pe(`ps -p ${t} -o tty= 2>/dev/null`,{stdio:"pipe",timeout:2e3}).toString().trim();if(r&&r!=="?"){let o=pe(`ps -o comm= -t ${r} 2>/dev/null`,{stdio:"pipe",timeout:2e3}).toString().trim().split(`
|
|
38
38
|
`).map(i=>{let c=i.trim();return c.split("/").pop()||c}).filter(i=>i&&!st.has(i));o.length>0&&(s=o[0])}}}catch{}return{id:e.id,pid:t,foregroundProcess:s,isIdle:s===void 0}}dispose(){clearInterval(this.processDetectionInterval)}getProcessInfo(e){let t=this.terminals.get(e);return t?t.lastProcessInfo??this.detectProcessForTerminal(t):null}getAllProcessInfo(){return Array.from(this.terminals.values()).map(e=>e.lastProcessInfo??this.detectProcessForTerminal(e))}async open(e,t){this.terminals.has(e.id)&&this.close(e.id);let s=e.cwd==="~"?bt():e.cwd.replace(/^~\//,bt()+"/"),r;try{r=await kt({cols:e.cols,rows:e.rows,cwd:s,env:e.env})}catch(l){let u=l instanceof Error?l.message:"Failed to spawn PTY";this.pushHandler("terminal.error",{id:e.id,message:u});return}let n=new AbortController,o={pty:r,id:e.id,sequenceAbort:n,outputBuffer:""};this.terminals.set(e.id,o),r.onData(l=>{o.outputBuffer+=l,o.outputBuffer.length>1e5&&(o.outputBuffer=o.outputBuffer.slice(-5e4));let u=this.commandBlockParser.parse(l,e.id);for(let f of u)this.pushHandler("terminal.command-block",{terminalId:e.id,event:f});let p=u.length>0?se.stripOSC133(l):l,m={id:e.id,data:p};this.pushHandler("terminal.output",m)}),r.onExit(({exitCode:l})=>{n.abort();let u={id:e.id,exitCode:l};this.pushHandler("terminal.exited",u),this.terminals.delete(e.id)});let i={id:e.id,pid:r.pid};this.pushHandler("terminal.started",i);let c=new Set(t?.completedSteps||[]),d=[];e.command&&d.push({command:e.command,delay:300}),e.commandSequence&&e.commandSequence.forEach((l,u)=>{l.runOnce&&c.has(u)||d.push({...l,originalIndex:u})}),d.length>0?this.executeSequence(r,d,n.signal,e.id,t?.onStepCompleted).catch(l=>{console.error("[terminal] executeSequence error:",l)}).then(()=>{e.closeAfterCommand&&!n.signal.aborted&&this.scheduleClose(e.id,e.closeDelay??1e3,e.closeWaitFor,n.signal)}):e.closeAfterCommand&&this.scheduleClose(e.id,e.closeDelay??1e3,e.closeWaitFor,n.signal)}async executeSequence(e,t,s,r,n){for(let o of t){if(s.aborted)return;let i=o.delay??500;if(await this.sleep(i,s),s.aborted)return;if(o.waitFor){if(await this.waitForOutput(r||"",o.waitFor,3e4,s),s.aborted)return;let c=o.respond||"",d=c.endsWith("\r")?c:c+"\r";e.write(d),o.runOnce&&o.originalIndex!==void 0&&r&&n&&n(r,o.originalIndex);continue}e.write(o.command+"\r"),o.runOnce&&o.originalIndex!==void 0&&r&&n&&n(r,o.originalIndex)}}async scheduleClose(e,t,s,r){r?.aborted||s&&(await this.waitForOutput(e,s,12e4,r||new AbortController().signal),r?.aborted)||(await this.sleep(Math.max(t,500),r||new AbortController().signal),!r?.aborted&&this.terminals.has(e)&&this.close(e))}sleep(e,t){return new Promise(s=>{let r=setTimeout(s,e);t.addEventListener("abort",()=>{clearTimeout(r),s()},{once:!0})})}stripAnsi(e){return e.replace(/\x1b\[[0-9;?]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\x1b[>=]/g," ").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g,"")}waitForOutput(e,t,s,r){return new Promise(n=>{let o=this.terminals.get(e);if(!o){n();return}let i=o.outputBuffer.length,c=setInterval(()=>{let l=o.outputBuffer;this.stripAnsi(l.slice(i)).includes(t)&&(clearInterval(c),clearTimeout(d),n())},200),d=setTimeout(()=>{clearInterval(c);let l=o.outputBuffer;n()},s);r.addEventListener("abort",()=>{clearInterval(c),clearTimeout(d),n()},{once:!0})})}write(e,t){let s=this.terminals.get(e);if(!s){this.pushHandler("terminal.error",{id:e,message:`Terminal ${e} not found`});return}try{s.pty.write(t)}catch(r){let n=r instanceof Error?r.message:"Failed to write to PTY";this.pushHandler("terminal.error",{id:e,message:n})}}resize(e,t,s){let r=this.terminals.get(e);r&&r.pty.resize(t,s)}close(e){let t=this.terminals.get(e);t&&(t.sequenceAbort?.abort(),t.pty.kill(),this.commandBlockParser.cleanup(e),this.terminals.delete(e))}closeAll(){this.dispose();for(let[e]of this.terminals)this.close(e)}getOutputBuffer(e){let t=this.terminals.get(e);return t?t.outputBuffer:null}outputContains(e,t){let s=this.terminals.get(e);return s?this.stripAnsi(s.outputBuffer).includes(t):!1}has(e){return this.terminals.has(e)}getCwd(e){let t=this.terminals.get(e);if(!t)return null;let s=t.pty.pid;try{if(process.platform==="darwin"){let n=pe(`lsof -a -p ${s} -d cwd -Fn 2>/dev/null`,{stdio:"pipe",timeout:3e3}).toString().trim().split(`
|
|
39
39
|
`);for(let o of n)if(o.startsWith("n"))return o.slice(1)}else if(process.platform==="linux")return $s(`/proc/${s}/cwd`)}catch{}return null}get size(){return this.terminals.size}listTerminals(){let e=[];for(let[t,s]of this.terminals)e.push({id:t,pid:s.pty.pid});return e}};import{randomUUID as Hs}from"node:crypto";var ge=class{db;areaManager;constructor(e,t){this.db=e,this.areaManager=t}list(){return this.db.prepare('SELECT * FROM workspaces ORDER BY "order" ASC, createdAt ASC').all().map(s=>this.hydrateWorkspace(s))}get(e){let s=this.db.prepare("SELECT * FROM workspaces WHERE id = ?").get(e);return s?this.hydrateWorkspace(s):null}create(e){let t=Hs(),s=new Date().toISOString(),r=e.icon||e.name.split(" ").map(p=>p[0]).join("").slice(0,2).toUpperCase(),i=this.db.prepare('SELECT MAX("order") as m FROM workspaces').get()?.m||0;this.db.prepare(`INSERT INTO workspaces (id, name, icon, color, rootDirectory, initGit, defaultCommand, terminalCount, layout, "order", createdAt, updatedAt)
|
|
@@ -565,5 +565,5 @@ You can document your own discoveries for teammates to benefit from.`),r.push(""
|
|
|
565
565
|
`).all();if(t.length===0)return;let s=new Date().toISOString(),r=a.prepare(`
|
|
566
566
|
INSERT INTO areas (id, workspaceId, name, color, directory, useWorktree, defaultCommand, terminalCount, layout, "order", isDefault, createdAt, updatedAt)
|
|
567
567
|
VALUES (?, ?, ?, ?, '', 0, ?, ?, ?, 0, 1, ?, ?)
|
|
568
|
-
`),n=a.prepare("INSERT OR IGNORE INTO area_state (areaId) VALUES (?)"),o=a.prepare("UPDATE terminal_configs SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')"),i=a.prepare("UPDATE saved_layouts SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')"),c=a.prepare("UPDATE swarms SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')");for(let d of t){let l=dn();r.run(l,d.id,"Principal",d.color,d.defaultCommand,d.terminalCount,d.layout,s,s),n.run(l),o.run(l,d.id),i.run(l,d.id),c.run(l,d.id)}}import $ from"ws";var pn=3e4,mn=
|
|
568
|
+
`),n=a.prepare("INSERT OR IGNORE INTO area_state (areaId) VALUES (?)"),o=a.prepare("UPDATE terminal_configs SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')"),i=a.prepare("UPDATE saved_layouts SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')"),c=a.prepare("UPDATE swarms SET areaId = ? WHERE workspaceId = ? AND (areaId IS NULL OR areaId = '')");for(let d of t){let l=dn();r.run(l,d.id,"Principal",d.color,d.defaultCommand,d.terminalCount,d.layout,s,s),n.run(l),o.run(l,d.id),i.run(l,d.id),c.run(l,d.id)}}import $ from"ws";var pn=3e4,mn=3e4,gn=480*60*1e3,ze=class{ws=null;_code=null;relayUrl;allowedIps;reconnectDelay=1e3;maxReconnectDelay=3e4;shouldReconnect=!0;pingTimer=null;sessionTimer=null;connectedAt=null;onMessage;onCodeChange;constructor(e,t=[]){this.relayUrl=e,this.allowedIps=t}get code(){return this._code}get connected(){return this.ws?.readyState===$.OPEN}getStatus(){return{code:this._code,connected:this.connected,connectedAt:this.connectedAt,relayUrl:this.relayUrl}}connect(){return new Promise((e,t)=>{let s=`${this.relayUrl.replace(/^http/,"ws")}/ws/server`;this.ws=new $(s),this.ws.on("open",()=>{this.reconnectDelay=1e3,this.connectedAt=new Date().toISOString(),this.ws.send(JSON.stringify({type:"register",allowed_ips:this.allowedIps})),this.startPing(),this.startSessionTimer()}),this.ws.on("message",r=>{let n=r.toString();try{let o=JSON.parse(n);if(o.type==="registered"&&o.code){this._code=o.code,this.reconnectDelay=1e3,e(o.code),this.onCodeChange?.(o.code);return}if(o.type==="pong")return}catch{}if(this.onMessage&&this.ws){let o=this.createVirtualWs();this.onMessage(n,o)}}),this.ws.on("pong",()=>{}),this.ws.on("close",()=>{this.handleDisconnect()}),this.ws.on("error",r=>{console.error("[relay] Connection error:",r.message)})})}async reconnect(){if(this.stopPing(),this.stopSessionTimer(),this.ws){this.ws.removeAllListeners();try{this.ws.close()}catch{}this.ws=null}return this._code=null,this.connect()}createVirtualWs(){let e=this;return{readyState:$.OPEN,send(t){e.ws?.readyState===$.OPEN&&e.ws.send(t)}}}send(e){this.ws?.readyState===$.OPEN&&this.ws.send(e)}close(){this.shouldReconnect=!1,this.stopPing(),this.stopSessionTimer(),this.ws?.close()}startPing(){this.stopPing(),this.pingTimer=setInterval(()=>{if(this.ws?.readyState===$.OPEN){try{this.ws.ping()}catch{}try{this.ws.send(JSON.stringify({type:"ping"}))}catch{}let e=setTimeout(()=>{this.ws?.readyState===$.OPEN&&(console.log("[relay] Pong timeout \u2014 forcing reconnect"),this.ws.terminate())},mn);this.ws.once("pong",()=>clearTimeout(e))}},pn)}stopPing(){this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null)}startSessionTimer(){this.stopSessionTimer(),this.sessionTimer=setTimeout(()=>{console.log("[relay] Session expired (8h) \u2014 reconnecting"),this.reconnect().then(e=>console.log(`[relay] Reconnected with new code: ${e}`)).catch(()=>console.error("[relay] Session refresh failed"))},gn)}stopSessionTimer(){this.sessionTimer&&(clearTimeout(this.sessionTimer),this.sessionTimer=null)}handleDisconnect(){this._code=null,this.connectedAt=null,this.stopPing(),this.stopSessionTimer(),this.shouldReconnect&&(console.log(`[relay] Disconnected. Reconnecting in ${this.reconnectDelay}ms...`),setTimeout(async()=>{try{let e=await this.connect();console.log(`[relay] Reconnected. New code: ${e}`)}catch{console.error("[relay] Reconnection failed")}},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*2,this.maxReconnectDelay))}};function Is(){return process.env.PORT?parseInt(process.env.PORT):process.env.ELECTRON_RUN_AS_NODE?process.platform==="win32"?"\\\\.\\pipe\\impactus-swarm":"/tmp/impactus-swarm.sock":7773}var wn={".html":"text/html",".js":"application/javascript",".css":"text/css",".json":"application/json",".png":"image/png",".svg":"image/svg+xml",".ico":"image/x-icon"},ie=Is(),Cs=process.env.IMPACTUS_WEB_DIR||St(import.meta.dirname,"../../web/dist"),vt=hn((a,e)=>{let t=a.url||"/",s=St(Cs,t==="/"?"index.html":t);if(As(s)||(s=St(Cs,"index.html")),!As(s)){e.writeHead(404),e.end("Not found");return}if(s.endsWith("index.html")){try{let o=Rs(s,"utf-8"),i=JSON.stringify({relayUrl:process.env.RELAY_URL||null}),c=o.replace("</head>",`<script>window.__IMPACTUS_CONFIG__=${i}</script>
|
|
569
569
|
</head>`);e.writeHead(200,{"Content-Type":"text/html"}),e.end(c)}catch{e.writeHead(500),e.end("Internal server error")}return}let r=fn(s),n=wn[r]||"application/octet-stream";try{let o=Rs(s);e.writeHead(200,{"Content-Type":n}),e.end(o)}catch{e.writeHead(500),e.end("Internal server error")}}),Ns=bs(),{terminalManager:Tn,broadcast:En,externalSenders:yn,services:Ms,routes:Sn}=vs(vt,Ns),Ls=process.env.RELAY_URL,vn=process.env.RELAY_ALLOWED_IPS?process.env.RELAY_ALLOWED_IPS.split(",").map(a=>a.trim()):[],q=null;Ls&&(q=new ze(Ls,vn),Ms.relayClient=q,yn.push(a=>q.send(a)),q.onMessage=(a,e)=>{let t;try{t=JSON.parse(a)}catch{return}Et(t,e,Ms,Sn)},q.onCodeChange=a=>{En("relay.codeChange",{code:a})},q.connect().then(a=>console.log(`[relay] Code: ${a}`)).catch(a=>console.error("[relay] Failed to connect:",a)));function Os(){q?.close(),Tn.closeAll(),Ns.close(),process.exit(0)}process.on("SIGINT",Os);process.on("SIGTERM",Os);var kn=process.argv.includes("--open");typeof ie=="number"?vt.listen(ie,async()=>{let a=`http://localhost:${ie}`;console.log(`Impactus Swarm server running on ${a}`),kn&&(await import("open")).default(a)}):vt.listen(ie,()=>{console.log(`Impactus Swarm server running on ${ie}`)});
|