@yuandc/aica 0.1.56 → 0.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -7,3 +7,5 @@ Run directly with `npx @yuandc/aica`, or install globally with `npm install -g @
|
|
|
7
7
|
Runtime configuration is stored in `~/.aica` by default and can be overridden with `--aica-home` or `AICA_HOME`.
|
|
8
8
|
|
|
9
9
|
The package does not include local Session storage or better-sqlite3.
|
|
10
|
+
|
|
11
|
+
Interactive terminal support uses the optional node-pty dependency. If it cannot be installed or loaded, other Worker features remain available. Open the terminal in the web UI for an installation command targeting this Worker's persistent directory, then retry without restarting the Worker.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import o from"node:fs";import r from"node:path";import{createRequire as l}from"node:module";import{getAsset as c,isSea as m}from"node:sea";import{getAcaHome as s}from"../paths.js";class p extends Error{code="TERMINAL_DEPENDENCY_UNAVAILABLE";installation;constructor(e){super("终端组件 node-pty 未安装或无法加载。",{cause:e}),this.name="TerminalDependencyError";const t=r.resolve(s(),"terminal-deps"),n=process.platform==="win32"?`'${t.replaceAll("'","''")}'`:`'${t.replaceAll("'","'\\''")}'`;this.installation={command:`npm install --prefix ${n} --no-save --package-lock=false node-pty@1.1.0`,shell:process.platform==="win32"?"PowerShell":"Shell",prerequisites:process.platform==="linux"?"若安装提示编译工具缺失,请先安装 Python 3、make 和 C++ 编译器。Debian/Ubuntu 可由管理员执行:apt-get install -y python3 build-essential。":process.platform==="darwin"?"若安装需要编译,请先安装 Python 3 和 Xcode Command Line Tools(xcode-select --install)。":"若安装需要编译,请先安装 Python 和 Visual Studio 的 C++ 构建工具。"}}}async function x(){const i=l(m()?process.execPath:import.meta.url);try{return m()?d():i("node-pty")}catch(e){const t=r.resolve(s(),"terminal-deps","node_modules","node-pty");try{return i(t)}catch(n){throw new p(o.existsSync(t)?n:e)}}}function d(){const i=JSON.parse(c("terminal-manifest","utf8")),e=r.join(s(),"native",`pty-${i.hash}`);if(!o.existsSync(r.join(e,".ready"))){o.mkdirSync(r.dirname(e),{recursive:!0,mode:448});const t=o.mkdtempSync(`${e}-`);try{for(const n of i.files){const a=r.join(t,n.name);o.mkdirSync(r.dirname(a),{recursive:!0}),o.writeFileSync(a,Buffer.from(c(`terminal/${n.name}`)),{mode:n.executable?448:384})}o.writeFileSync(r.join(t,".ready"),"");try{o.renameSync(t,e)}catch(n){if(!o.existsSync(r.join(e,".ready")))throw n}}finally{o.rmSync(t,{recursive:!0,force:!0})}}return l(r.join(e,"package.json"))(r.join(e,"lib","index.js"))}export{p as TerminalDependencyError,x as loadPty};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as M}from"node:crypto";import p from"node:fs";import u from"node:path";import S from"@xterm/headless";import q from"@xterm/addon-serialize";import{loadPty as D}from"./native.js";import{expandWorkerRuntimePath as E}from"../worker-runtime-paths.js";import{terminalShell as T}from"./shell.js";const y=8,z=1440*6e4;class O{emit;entries=new Map;sweep=setInterval(()=>{for(const[e,t]of this.entries)!t.attachmentId&&Date.now()-t.detachedAt>z&&this.remove(e)},6e4);opening=new Map;epoch=0;disposed=!1;constructor(e){this.emit=e,this.sweep.unref()}async handle(e){const{sessionId:t,attachmentId:i}=e;if(!t||!i||this.disposed)return;const s=this.epoch,n=(this.opening.get(t)||Promise.resolve()).catch(()=>{}).then(async()=>{s!==this.epoch||this.disposed||(e.type==="open"?await this.open(e,s):this.control(e))});this.opening.set(t,n);try{await n}finally{this.opening.get(t)===n&&this.opening.delete(t)}}control(e){const{sessionId:t,attachmentId:i}=e,s=this.entries.get(t);if(!(!s||s.attachmentId!==i))if(e.type==="detach")s.attachmentId=void 0,s.detachedAt=Date.now();else if(e.type==="input"&&s.exitCode===void 0&&typeof e.data=="string"&&e.data.length<=16384)s.pty.write(e.binary?Buffer.from(e.data,"binary"):e.data);else if(e.type==="resize"&&s.exitCode===void 0){const[o,n]=C(e);s.screen.resize(o,n),s.pty.resize(o,n)}else e.type==="end"&&s.exitCode===void 0&&s.pty.kill()}detachAll(){this.epoch++;for(const e of this.entries.values())e.attachmentId&&(e.detachedAt=Date.now()),e.attachmentId=void 0}hasRunningInDirectory(e,t){const i=p.realpathSync(e);return[...this.entries.values()].some(s=>s.exitCode===void 0&&(s.sessionId===t||s.cwd===i||s.cwd.startsWith(i+u.sep)||this.shellIsInside(s,i)))}shellIsInside(e,t){if(process.platform!=="linux")return!1;try{const i=p.realpathSync(`/proc/${e.pty.pid}/cwd`);return i===t||i.startsWith(t+u.sep)}catch{return!1}}dispose(){this.disposed=!0,this.epoch++,clearInterval(this.sweep);for(const e of this.entries.keys())this.remove(e)}async open(e,t){const{sessionId:i,attachmentId:s}=e;let o=this.entries.get(i);if(e.restart&&o?.exitCode!==void 0&&(this.remove(i),o=void 0),!o){if(!e.create){this.emit({type:"missing",sessionId:i,attachmentId:s});return}const d=E(e.cwd||"");if(!d||!u.isAbsolute(d))throw new Error("终端启动目录无效。");const l=p.realpathSync(d);if(!p.statSync(l).isDirectory())throw new Error("终端启动目录不存在。");const A=await
|
|
1
|
+
import{randomUUID as M}from"node:crypto";import p from"node:fs";import u from"node:path";import S from"@xterm/headless";import q from"@xterm/addon-serialize";import{loadPty as D}from"./native.js";import{expandWorkerRuntimePath as E}from"../worker-runtime-paths.js";import{terminalShell as T}from"./shell.js";const y=8,z=1440*6e4;class O{emit;ptyLoader;entries=new Map;sweep=setInterval(()=>{for(const[e,t]of this.entries)!t.attachmentId&&Date.now()-t.detachedAt>z&&this.remove(e)},6e4);opening=new Map;epoch=0;disposed=!1;constructor(e,t=D){this.emit=e,this.ptyLoader=t,this.sweep.unref()}async handle(e){const{sessionId:t,attachmentId:i}=e;if(!t||!i||this.disposed)return;const s=this.epoch,n=(this.opening.get(t)||Promise.resolve()).catch(()=>{}).then(async()=>{s!==this.epoch||this.disposed||(e.type==="open"?await this.open(e,s):this.control(e))});this.opening.set(t,n);try{await n}finally{this.opening.get(t)===n&&this.opening.delete(t)}}control(e){const{sessionId:t,attachmentId:i}=e,s=this.entries.get(t);if(!(!s||s.attachmentId!==i))if(e.type==="detach")s.attachmentId=void 0,s.detachedAt=Date.now();else if(e.type==="input"&&s.exitCode===void 0&&typeof e.data=="string"&&e.data.length<=16384)s.pty.write(e.binary?Buffer.from(e.data,"binary"):e.data);else if(e.type==="resize"&&s.exitCode===void 0){const[o,n]=C(e);s.screen.resize(o,n),s.pty.resize(o,n)}else e.type==="end"&&s.exitCode===void 0&&s.pty.kill()}detachAll(){this.epoch++;for(const e of this.entries.values())e.attachmentId&&(e.detachedAt=Date.now()),e.attachmentId=void 0}hasRunningInDirectory(e,t){const i=p.realpathSync(e);return[...this.entries.values()].some(s=>s.exitCode===void 0&&(s.sessionId===t||s.cwd===i||s.cwd.startsWith(i+u.sep)||this.shellIsInside(s,i)))}shellIsInside(e,t){if(process.platform!=="linux")return!1;try{const i=p.realpathSync(`/proc/${e.pty.pid}/cwd`);return i===t||i.startsWith(t+u.sep)}catch{return!1}}dispose(){this.disposed=!0,this.epoch++,clearInterval(this.sweep);for(const e of this.entries.keys())this.remove(e)}async open(e,t){const{sessionId:i,attachmentId:s}=e;let o=this.entries.get(i);if(e.restart&&o?.exitCode!==void 0&&(this.remove(i),o=void 0),!o){if(!e.create){this.emit({type:"missing",sessionId:i,attachmentId:s});return}const d=E(e.cwd||"");if(!d||!u.isAbsolute(d))throw new Error("终端启动目录无效。");const l=p.realpathSync(d);if(!p.statSync(l).isDirectory())throw new Error("终端启动目录不存在。");const A=await this.ptyLoader();if(this.disposed||t!==this.epoch)return;if(this.entries.size>=y){const a=[...this.entries.values()].find(v=>v.exitCode!==void 0&&!v.attachmentId);a&&this.remove(a.sessionId)}if(this.entries.size>=y)throw new Error("此设备最多保留 8 个终端,请先结束并收起其他终端。");const[w,m]=C(e),I=process.platform==="win32"?process.env.COMSPEC||"powershell.exe":process.env.SHELL||"/bin/sh",g=T(I),c=A.spawn(I,g.args,{name:"xterm-256color",cwd:l,cols:w,rows:m,env:g.env}),f=new S.Terminal({cols:w,rows:m,scrollback:1e3,allowProposedApi:!0}),x=new q.SerializeAddon;f.loadAddon(x),o={id:M(),sessionId:i,cwd:l,pty:c,screen:f,serializer:x,detachedAt:Date.now(),seq:0,pending:"",queued:0},this.entries.set(i,o);const r=o;f.onData(a=>{if(!r.attachmentId&&r.exitCode===void 0)try{c.write(a)}catch{}}),c.onData(a=>{r.pending+=a,r.pending.length>=32768?this.flush(r):r.timer||(r.timer=setTimeout(()=>this.flush(r),24))}),c.onExit(({exitCode:a})=>{this.entries.get(i)===r&&(this.flush(r),r.screen.write("",()=>{r.exitCode=a,r.attachmentId&&this.emit({type:"exit",sessionId:i,attachmentId:r.attachmentId,exitCode:a})}))})}o.attachmentId=void 0,this.flush(o);const n=o;await new Promise(d=>n.screen.write("",()=>{if(this.disposed||t!==this.epoch){d();return}n.attachmentId=s,this.emit({type:"snapshot",sessionId:i,attachmentId:s,terminalId:n.id,seq:n.seq,cwd:n.cwd,cols:n.screen.cols,rows:n.screen.rows,data:n.serializer.serialize(),exitCode:n.exitCode,retentionHours:24}),d()}))}flush(e){if(clearTimeout(e.timer),e.timer=void 0,!e.pending)return;const t=e.pending;e.pending="",e.queued+=t.length,e.queued>256e3&&e.pty.pause(),e.screen.write(t,()=>{this.entries.get(e.sessionId)===e&&(e.queued-=t.length,e.queued<64e3&&e.exitCode===void 0&&e.pty.resume(),e.seq++,e.attachmentId&&this.emit({type:"output",sessionId:e.sessionId,attachmentId:e.attachmentId,seq:e.seq,data:t}))})}remove(e){const t=this.entries.get(e);t&&(this.entries.delete(e),clearTimeout(t.timer),t.exitCode===void 0&&t.pty.kill(),t.screen.dispose())}}function C(h){return[Math.max(20,Math.min(240,Math.floor(Number(h.cols)||80))),Math.max(5,Math.min(80,Math.floor(Number(h.rows)||24)))]}let _;function U(h){_=h}export{O as TerminalService,_ as activeTerminalService,U as setActiveTerminalService};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import u from"ws";import{loadAcaConfig as w}from"../aca-config.js";import{TerminalService as S,setActiveTerminalService as h}from"./service.js";import{loadPty as T,TerminalDependencyError as g}from"./native.js";function E(m,y=T){let n,d=!1,i,f,p=Date.now();const c=new S(r=>{if(n?.readyState===u.OPEN){if(n.bufferedAmount>2e6){n.terminate();return}n.send(JSON.stringify(r))}},y);h(c);function l(){if(d)return;const r=w();if(!r.serverUrl||!r.token){i=setTimeout(l,5e3);return}try{const o=new URL("api/terminal/worker",r.serverUrl.replace(/\/?$/,"/"));o.protocol=o.protocol==="https:"?"wss:":"ws:";const e=new u(o,{headers:{authorization:`Bearer ${r.token}`},rejectUnauthorized:!["1","true","yes"].includes((process.env.ACA_SERVER_INSECURE_TLS||"").toLowerCase()),maxPayload:65536,perMessageDeflate:!1,handshakeTimeout:1e4});n=e,e.on("open",()=>{p=Date.now(),f=setInterval(()=>{Date.now()-p>45e3&&e.terminate()},15e3)}),e.on("ping",()=>{p=Date.now()}),e.on("message",a=>{let t;try{t=JSON.parse(a.toString())}catch{e.close(1008);return}if(!t||typeof t!="object"||typeof t.sessionId!="string"||typeof t.attachmentId!="string"){e.close(1008);return}c.handle(t).catch(s=>{e.readyState===u.OPEN&&e.send(JSON.stringify({type:"error",sessionId:t.sessionId,attachmentId:t.attachmentId,message:s instanceof Error?s.message:"终端操作失败。",...s instanceof g?{code:s.code,installation:s.installation}:{}}))})}),e.on("error",a=>m.warn(`Terminal connection: ${a.message}`)),e.on("close",a=>{clearInterval(f),c.detachAll(),a===4001?m.warn("Terminal channel replaced by another Worker on this machine; restart this Worker to reconnect."):d||(i=setTimeout(l,3e3+Math.random()*2e3))})}catch(o){m.warn(`Terminal connection: ${String(o)}`),i=setTimeout(l,5e3)}}return l(),{stop(){d=!0,clearTimeout(i),clearInterval(f),n?.terminate(),c.dispose(),h(void 0)}}}export{E as startTerminalWorker};
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const o="0.1.
|
|
1
|
+
const o="0.1.58";export{o as AICA_VERSION};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuandc/aica",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.58",
|
|
4
4
|
"description": "AICA remote Agent worker",
|
|
5
5
|
"author": "yuandc",
|
|
6
6
|
"type": "module",
|
|
@@ -32,9 +32,11 @@
|
|
|
32
32
|
"chalk": "^5.4.1",
|
|
33
33
|
"commander": "^12.1.0",
|
|
34
34
|
"diff": "^9.0.0",
|
|
35
|
-
"node-pty": "^1.1.0",
|
|
36
35
|
"undici": "^7.28.0",
|
|
37
36
|
"ws": "^8.22.0",
|
|
38
37
|
"zod": "^3.25.76"
|
|
38
|
+
},
|
|
39
|
+
"optionalDependencies": {
|
|
40
|
+
"node-pty": "^1.1.0"
|
|
39
41
|
}
|
|
40
42
|
}
|