@openduo/duoduo 0.2.0 → 0.2.1
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/release/cli.js +1 -1
- package/package.json +2 -2
package/dist/release/cli.js
CHANGED
|
@@ -853,7 +853,7 @@ React keys must be passed directly to JSX without using spread:
|
|
|
853
853
|
let props = %s;
|
|
854
854
|
<%s key={someKey} {...props} />`,be,ve,Pe,ve),Fl[ve+be]=!0}}return ae===n?wa(Rn):Hn(Rn),Rn}}function gf(ae,Ye,vt){return sa(ae,Ye,vt,!0)}function nl(ae,Ye,vt){return sa(ae,Ye,vt,!1)}var wo=nl,il=gf;Bz.Fragment=n,Bz.jsx=wo,Bz.jsxs=il})()});var ud=q((Vrr,uQ)=>{"use strict";process.env.NODE_ENV==="production"?uQ.exports=D2e():uQ.exports=T2e()});import{createInterface as PAt}from"node:readline/promises";ta();V0();import{promises as zu}from"node:fs";import Eze from"node:os";import gl from"node:path";import{execFile as xze,spawn as kze}from"node:child_process";import{promisify as Dze}from"node:util";var Tze=Dze(xze);function Rze(e=process.env){let t=zd({},e);return gl.join(t.runtimeDir,"plugins","channels")}function p6(e,t){return gl.join(e,t)}function ire(e,t){return gl.join(p6(e,t),"manifest.json")}function m6(e,t){return gl.join(p6(e,t),"run")}function h6(e,t){return gl.join(m6(e,t),"pid.json")}function nre(e,t){return gl.join(m6(e,t),"plugin.log")}function Ny(e){if(!Number.isFinite(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}function Cze(e){let t=e.aladuo,r=t&&typeof t=="object"?t.channel:void 0;if(!r||typeof r!="object")throw new Error("Invalid plugin package: missing package.json aladuo.channel metadata");let n=r,i=typeof n.type=="string"?n.type.trim():"",o=typeof n.bin=="string"?n.bin.trim():"";if(!i||!o)throw new Error("Invalid plugin package: aladuo.channel.type/bin is required");let s=Array.isArray(n.envAllowlist)?n.envAllowlist.filter(f=>typeof f=="string"):[],a=Array.isArray(n.args)?n.args.filter(f=>typeof f=="string"):[],u=typeof n.healthCheck=="string"?n.healthCheck:void 0;return{type:i,bin:o,envAllowlist:s,args:a,healthCheck:u}}async function f6(e,t){try{let r=await zu.readFile(ire(e,t),"utf8");return JSON.parse(r)}catch{return null}}async function Oze(e,t){let r=ire(e,t.channelType);await sr(gl.dirname(r)),await zu.writeFile(r,JSON.stringify(t,null,2)+`
|
|
855
855
|
`,"utf8")}async function sk(e,t){try{let r=await zu.readFile(h6(e,t),"utf8"),n=JSON.parse(r);return typeof n.pid=="number"?n.pid:void 0}catch{return}}async function $ze(e,t,r){let n=h6(e,t);await sr(gl.dirname(n)),await zu.writeFile(n,JSON.stringify({pid:r,startedAt:new Date().toISOString()},null,2)+`
|
|
856
|
-
`,"utf8")}async function t$(e,t){await zu.rm(h6(e,t),{force:!0})}async function d6(e,t,r="SIGTERM",n=1500){let i=await sk(e,t);if(typeof i!="number"||!Ny(i)){await t$(e,t);return}try{process.kill(i,r)}catch{}let o=Date.now()+n;for(;Date.now()<o&&Ny(i);)await new Promise(s=>setTimeout(s,50));if(Ny(i)&&r!=="SIGKILL"){await d6(e,t,"SIGKILL",250);return}await t$(e,t)}function Ize(e,t,r){let n={ALADUO_DAEMON_URL:t},i=["PATH","HOME","USER","LOGNAME","SHELL","TMPDIR","TMP","TEMP","LANG","LC_ALL","TZ","TERM","NO_COLOR","NODE_OPTIONS"];for(let o of i)o in r&&(n[o]=r[o]);for(let o of e)!o||!(o in r)||(n[o]=r[o]);return n}function ore(e={}){let t=e.env??process.env,r=e.rootDir??Rze(t);return{async installFromTarball(n){let i=gl.resolve(n);await zu.access(i);let o=await zu.mkdtemp(gl.join(Eze.tmpdir(),"aladuo-channel-plugin-"));try{await Tze("tar",["-xzf",i,"-C",o]);let s=gl.join(o,"package"),a=await zu.readFile(gl.join(s,"package.json"),"utf8"),u=JSON.parse(a),f=typeof u.name=="string"?u.name:"unknown",m=typeof u.version=="string"?u.version:"0.0.0",h=Cze(u),v=p6(r,h.type),y=gl.join(v,"package");await d6(r,h.type),await zu.rm(v,{recursive:!0,force:!0}),await sr(v),await zu.cp(s,y,{recursive:!0,force:!0});let b=gl.join(y,h.bin);await zu.access(b);let T={channelType:h.type,packageName:f,version:m,packageRoot:y,sourceTarball:i,installedAt:new Date().toISOString(),entry:{command:process.execPath,args:[b,...h.args]},envAllowlist:h.envAllowlist,health:h.healthCheck?{check:h.healthCheck}:void 0};return await Oze(r,T),await t$(r,T.channelType),T}finally{await zu.rm(o,{recursive:!0,force:!0})}},async listInstalled(){try{let n=await zu.readdir(r,{withFileTypes:!0}),i=[];for(let o of n){if(!o.isDirectory())continue;let s=await f6(r,o.name);if(!s)continue;let a=await sk(r,o.name);i.push({manifest:s,running:typeof a=="number"&&Ny(a),pid:a})}return i.sort((o,s)=>o.manifest.channelType.localeCompare(s.manifest.channelType)),i}catch{return[]}},async start(n,i,o){let s=await f6(r,n);if(!s)throw new Error(`Channel plugin not installed: ${n}`);let a=await sk(r,n);if(typeof a=="number"&&Ny(a))return{started:!1,pid:a};await sr(m6(r,n));let u=await zu.open(nre(r,n),"a"),f=kze(s.entry.command,[...s.entry.args,...i],{cwd:s.packageRoot,detached:!0,env:Ize(s.envAllowlist,o,t),stdio:["ignore",u.fd,u.fd]});if(f.unref(),await u.close(),!f.pid)throw new Error(`Failed to start channel plugin "${n}": spawn returned no pid for command "${s.entry.command}"`);return await $ze(r,n,f.pid),{started:!0,pid:f.pid}},async stop(n){let i=await sk(r,n);return typeof i!="number"||!Ny(i)?(await t$(r,n),{stopped:!1}):(await d6(r,n),{stopped:!0})},async status(n){let i=await f6(r,n);if(!i)return null;let o=await sk(r,n);return{manifest:i,running:typeof o=="number"&&Ny(o),pid:o}},async readLogs(n,i=64*1024){let o=nre(r,n),s=Date.now()+300;for(;;){try{let a=await zu.readFile(o,"utf8");if(a.length>0||Date.now()>=s)return a.length<=i?a:a.slice(-i)}catch{if(Date.now()>=s)return""}await new Promise(a=>setTimeout(a,25))}}}}V0();import{promises as Pze}from"node:fs";import Nze from"node:os";import sre from"node:path";function Z0(e){if(!e)return;let t=e.trim();if(t)try{let r=new URL(t);(r.protocol==="ws:"||r.protocol==="wss:")&&(r.protocol=r.protocol==="wss:"?"https:":"http:"),r.pathname==="/ws"||r.pathname==="/ws/"?r.pathname="/":r.pathname.endsWith("/ws")&&(r.pathname=r.pathname.slice(0,-3)||"/"),r.search="",r.hash="";let n=r.toString();return n.endsWith("/")?n.slice(0,-1):n}catch{return t.startsWith("ws://")||t.startsWith("wss://")?t.replace(/^wss?:\/\//,n=>n==="wss://"?"https://":"http://").replace(/\/ws\/?$/,""):t}}function are(e){if(!(e!=="debug"&&e!=="info"&&e!=="warn"&&e!=="error"))return e}function Aze(e){if(!e||typeof e!="object")return{};let t=e,r={};for(let[n,i]of Object.entries(t)){if(!i||typeof i!="object")continue;let o=i,s=typeof o.daemonUrl=="string"?Z0(o.daemonUrl):void 0;r[n]={daemonUrl:s}}return r}function jze(e){let t=JSON.parse(e);return{daemonUrl:typeof t.daemonUrl=="string"?Z0(t.daemonUrl):void 0,pluginRoot:typeof t.pluginRoot=="string"?t.pluginRoot:void 0,logLevel:are(t.logLevel),channels:Aze(t.channels)}}function Fze(e=Nze.homedir()){return sre.join(e,".config","aladuo","config.json")}async function r$(e=Fze()){try{let t=await Pze.readFile(e,"utf8");return jze(t)}catch{return{}}}function ak(e={}){let t=e.env??process.env,r=e.userConfig??{},n=zd({},t),i=Z0(e.daemonUrlOverride)??Z0(t.ALADUO_DAEMON_URL)??Z0(t.ALADUO_WS_URL)??Z0(r.daemonUrl)??"http://127.0.0.1:20233",o=e.pluginRootOverride??t.ALADUO_PLUGIN_ROOT??r.pluginRoot??sre.join(n.runtimeDir,"plugins","channels"),s=are(t.ALADUO_LOG_LEVEL)??r.logLevel??"info";return{daemonUrl:i,pluginRoot:o,logLevel:s,channels:r.channels??{}}}import{spawn as Lze}from"node:child_process";import{mkdir as n$}from"node:fs/promises";import Mze from"node:os";import W0 from"node:path";var ure="ghcr.io/antmanler/duoduo:latest",zze=["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ALADUO_LOG_LEVEL","ALADUO_PERMISSION_MODE","ALADUO_CADENCE_INTERVAL_MS","ALADUO_SESSION_IDLE_MS","ALADUO_SESSION_MAX_CONCURRENT","ALADUO_SESSION_HEARTBEAT_MS"];function Bp(e,t,r,n){if(r!==void 0)return{value:r,nextIndex:t};let i=e[t+1];if(!i)throw new Error(`Missing value for ${n}`);return{value:i,nextIndex:t+1}}function uk(e,t){return W0.resolve(e,t)}function Uze(e){let t=Number(e);if(!Number.isInteger(t)||t<1||t>65535)throw new Error(`Invalid port: ${e}`);return t}function qze(e){if(e==="always"||e==="missing"||e==="never")return e;throw new Error(`Invalid pull policy: ${e}`)}function g6(e){let t={};for(let r of zze){let n=e[r];n&&(t[r]=n)}return t}function y6(e,t){let r=W0.join(e,".aladuo","containers",t);return{workspaceDir:W0.join(r,"workspace"),kernelDir:W0.join(r,"kernel"),runtimeDir:W0.join(r,"runtime"),claudeDir:W0.join(r,"claude")}}function o$(e,t={}){let r=t.env??process.env,n=t.homeDir??Mze.homedir(),i=t.currentCwd??process.cwd(),o="default",s=r.ALADUO_CONTAINER_IMAGE??ure,a=20233,u,f=!1,m="missing",h,v,y,b;if(e.length===0||e[0]==="help"||e[0]==="--help"||e[0]==="-h"){let E=y6(n,o);return{help:!0,command:"plan",image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:E.workspaceDir,kernelDir:E.kernelDir,runtimeDir:E.runtimeDir,claudeDir:E.claudeDir,follow:f,pull:m,forwardedEnv:g6(r)}}let T=e[0];if(T!=="up"&&T!=="down"&&T!=="logs"&&T!=="ps"&&T!=="plan")throw new Error(`Unknown container command: ${T}`);for(let E=1;E<e.length;E++){let C=e[E],k=C.indexOf("="),x=k>=0?C.slice(k+1):void 0,N=k>=0?C.slice(0,k):C;if(N==="--help"||N==="-h"){let I=y6(n,o);return{help:!0,command:T,image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:h??I.workspaceDir,kernelDir:v??I.kernelDir,runtimeDir:y??I.runtimeDir,claudeDir:b??I.claudeDir,envFile:u,follow:f,pull:m,forwardedEnv:g6(r)}}if(N==="--follow"||N==="-f"){f=!0;continue}if(N==="--name"){let{value:I,nextIndex:P}=Bp(e,E,x,"--name");o=I,E=P;continue}if(N==="--image"){let{value:I,nextIndex:P}=Bp(e,E,x,"--image");s=I,E=P;continue}if(N==="--port"){let{value:I,nextIndex:P}=Bp(e,E,x,"--port");a=Uze(I),E=P;continue}if(N==="--workspace-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--workspace-dir");h=uk(i,I),E=P;continue}if(N==="--kernel-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--kernel-dir");v=uk(i,I),E=P;continue}if(N==="--runtime-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--runtime-dir");y=uk(i,I),E=P;continue}if(N==="--claude-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--claude-dir");b=uk(i,I),E=P;continue}if(N==="--env-file"){let{value:I,nextIndex:P}=Bp(e,E,x,"--env-file");u=uk(i,I),E=P;continue}if(N==="--pull"){let{value:I,nextIndex:P}=Bp(e,E,x,"--pull");m=qze(I),E=P;continue}throw new Error(`Unknown option: ${C}`)}let D=y6(n,o);return{help:!1,command:T,image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:h??D.workspaceDir,kernelDir:v??D.kernelDir,runtimeDir:y??D.runtimeDir,claudeDir:b??D.claudeDir,envFile:u,follow:f,pull:m,forwardedEnv:g6(r)}}function lk(e){let t=["run","-d","--name",e.containerName,"--restart","unless-stopped","--pull",e.pull,"-p",`${e.port}:20233`,"-e","HOME=/home/duoduo","-e","ALADUO_CONTAINER=1","-e","ALADUO_HOME=/home/duoduo","-e","ALADUO_BOOTSTRAP_DIR=/app/bootstrap","-e","ALADUO_KERNEL_DIR=/home/duoduo/aladuo","-e","ALADUO_WORK_DIR=/workspace","-e","ALADUO_RUNTIME_DIR=/home/duoduo/.aladuo","-e","ALADUO_RUNTIME_MODE=container","-e","PORT=20233","-v",`${e.workspaceDir}:/workspace`,"-v",`${e.kernelDir}:/home/duoduo/aladuo`,"-v",`${e.runtimeDir}:/home/duoduo/.aladuo`,"-v",`${e.claudeDir}:/home/duoduo/.claude`];e.envFile&&t.push("--env-file",e.envFile);for(let[r,n]of Object.entries(e.forwardedEnv))t.push("-e",`${r}=${n}`);return t.push(e.image,"node","/app/dist/release/daemon.js"),t}function Bze(e){return["rm","-f",e.containerName]}function Hze(e){return["logs",...e.follow?["-f"]:[],e.containerName]}function Vze(e){return["ps","-a","--filter",`name=^/${e.containerName}$`]}function Zze(e){return e.map(t=>/[^\w./:@=-]/.test(t)?JSON.stringify(t):t).join(" ")}function v6(){console.log("Usage: duoduo container <up|down|logs|ps|plan> [options]"),console.log(""),console.log("Options:"),console.log(" --name <name> Instance name (default: default)"),console.log(` --image <ref> Container image (default: ${ure})`),console.log(" --port <port> Host port mapped to daemon 20233"),console.log(" --workspace-dir <path> Host directory mounted to /workspace"),console.log(" --kernel-dir <path> Host directory mounted to /home/duoduo/aladuo"),console.log(" --runtime-dir <path> Host directory mounted to /home/duoduo/.aladuo"),console.log(" --claude-dir <path> Host directory mounted to /home/duoduo/.claude"),console.log(" --env-file <path> Pass a docker --env-file"),console.log(" --pull <always|missing|never> Image pull policy (default: missing)"),console.log(" -f, --follow Follow logs"),console.log(" -h, --help Show help")}function i$(e){return new Promise((t,r)=>{let n=Lze("docker",e,{stdio:"inherit"});n.on("error",r),n.on("exit",i=>{if(i===0){t();return}r(new Error(`docker ${e[0]} exited with code ${i??"unknown"}`))})})}async function lre(e){let t=o$(e);if(t.help){v6();return}if(t.command==="plan"){let r=lk(t);console.log(`instance: ${t.instanceName}`),console.log(`image: ${t.image}`),console.log(`container: ${t.containerName}`),console.log(`workspace_dir: ${t.workspaceDir}`),console.log(`kernel_dir: ${t.kernelDir}`),console.log(`runtime_dir: ${t.runtimeDir}`),console.log(`claude_dir: ${t.claudeDir}`),console.log(`daemon_url: http://127.0.0.1:${t.port}`),console.log(""),console.log("docker command:"),console.log(Zze(["docker",...r]));return}if(t.command==="up"){await Promise.all([n$(t.workspaceDir,{recursive:!0}),n$(t.kernelDir,{recursive:!0}),n$(t.runtimeDir,{recursive:!0}),n$(t.claudeDir,{recursive:!0})]),await i$(lk(t)),console.log(`container started: ${t.containerName}`),console.log(`daemon: http://127.0.0.1:${t.port}`);return}if(t.command==="down"){await i$(Bze(t));return}if(t.command==="logs"){await i$(Hze(t));return}await i$(Vze(t))}ta();V0();import{existsSync as s$,promises as ck}from"node:fs";import Ud from"node:path";import{spawn as Wze}from"node:child_process";import{fileURLToPath as Gze}from"node:url";function b6(e){return Ud.join(zd({},e).runDir,"daemon-supervisor.pid.json")}function cre(e){return Ud.join(zd({},e).runDir,"daemon-supervisor.log")}function Jze(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function fre(e){if(!e||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}async function S6(e){try{let t=await ck.readFile(b6(e),"utf8"),r=JSON.parse(t);return Jze(r.pid)}catch{return}}async function Kze(e,t){let r=b6(e);await sr(Ud.dirname(r)),await ck.writeFile(r,JSON.stringify({pid:t,startedAt:new Date().toISOString()},null,2)+`
|
|
856
|
+
`,"utf8")}async function t$(e,t){await zu.rm(h6(e,t),{force:!0})}async function d6(e,t,r="SIGTERM",n=1500){let i=await sk(e,t);if(typeof i!="number"||!Ny(i)){await t$(e,t);return}try{process.kill(i,r)}catch{}let o=Date.now()+n;for(;Date.now()<o&&Ny(i);)await new Promise(s=>setTimeout(s,50));if(Ny(i)&&r!=="SIGKILL"){await d6(e,t,"SIGKILL",250);return}await t$(e,t)}function Ize(e,t,r){let n={ALADUO_DAEMON_URL:t},i=["PATH","HOME","USER","LOGNAME","SHELL","TMPDIR","TMP","TEMP","LANG","LC_ALL","TZ","TERM","NO_COLOR","NODE_OPTIONS"];for(let o of i)o in r&&(n[o]=r[o]);for(let o of e)!o||!(o in r)||(n[o]=r[o]);return n}function ore(e={}){let t=e.env??process.env,r=e.rootDir??Rze(t);return{async installFromTarball(n){let i=gl.resolve(n);await zu.access(i);let o=await zu.mkdtemp(gl.join(Eze.tmpdir(),"aladuo-channel-plugin-"));try{await Tze("tar",["-xzf",i,"-C",o]);let s=gl.join(o,"package"),a=await zu.readFile(gl.join(s,"package.json"),"utf8"),u=JSON.parse(a),f=typeof u.name=="string"?u.name:"unknown",m=typeof u.version=="string"?u.version:"0.0.0",h=Cze(u),v=p6(r,h.type),y=gl.join(v,"package");await d6(r,h.type),await zu.rm(v,{recursive:!0,force:!0}),await sr(v),await zu.cp(s,y,{recursive:!0,force:!0});let b=gl.join(y,h.bin);await zu.access(b);let T={channelType:h.type,packageName:f,version:m,packageRoot:y,sourceTarball:i,installedAt:new Date().toISOString(),entry:{command:process.execPath,args:[b,...h.args]},envAllowlist:h.envAllowlist,health:h.healthCheck?{check:h.healthCheck}:void 0};return await Oze(r,T),await t$(r,T.channelType),T}finally{await zu.rm(o,{recursive:!0,force:!0})}},async listInstalled(){try{let n=await zu.readdir(r,{withFileTypes:!0}),i=[];for(let o of n){if(!o.isDirectory())continue;let s=await f6(r,o.name);if(!s)continue;let a=await sk(r,o.name);i.push({manifest:s,running:typeof a=="number"&&Ny(a),pid:a})}return i.sort((o,s)=>o.manifest.channelType.localeCompare(s.manifest.channelType)),i}catch{return[]}},async start(n,i,o){let s=await f6(r,n);if(!s)throw new Error(`Channel plugin not installed: ${n}`);let a=await sk(r,n);if(typeof a=="number"&&Ny(a))return{started:!1,pid:a};await sr(m6(r,n));let u=await zu.open(nre(r,n),"a"),f=kze(s.entry.command,[...s.entry.args,...i],{cwd:s.packageRoot,detached:!0,env:Ize(s.envAllowlist,o,t),stdio:["ignore",u.fd,u.fd]});if(f.unref(),await u.close(),!f.pid)throw new Error(`Failed to start channel plugin "${n}": spawn returned no pid for command "${s.entry.command}"`);return await $ze(r,n,f.pid),{started:!0,pid:f.pid}},async stop(n){let i=await sk(r,n);return typeof i!="number"||!Ny(i)?(await t$(r,n),{stopped:!1}):(await d6(r,n),{stopped:!0})},async status(n){let i=await f6(r,n);if(!i)return null;let o=await sk(r,n);return{manifest:i,running:typeof o=="number"&&Ny(o),pid:o}},async readLogs(n,i=64*1024){let o=nre(r,n),s=Date.now()+300;for(;;){try{let a=await zu.readFile(o,"utf8");if(a.length>0||Date.now()>=s)return a.length<=i?a:a.slice(-i)}catch{if(Date.now()>=s)return""}await new Promise(a=>setTimeout(a,25))}}}}V0();import{promises as Pze}from"node:fs";import Nze from"node:os";import sre from"node:path";function Z0(e){if(!e)return;let t=e.trim();if(t)try{let r=new URL(t);(r.protocol==="ws:"||r.protocol==="wss:")&&(r.protocol=r.protocol==="wss:"?"https:":"http:"),r.pathname==="/ws"||r.pathname==="/ws/"?r.pathname="/":r.pathname.endsWith("/ws")&&(r.pathname=r.pathname.slice(0,-3)||"/"),r.search="",r.hash="";let n=r.toString();return n.endsWith("/")?n.slice(0,-1):n}catch{return t.startsWith("ws://")||t.startsWith("wss://")?t.replace(/^wss?:\/\//,n=>n==="wss://"?"https://":"http://").replace(/\/ws\/?$/,""):t}}function are(e){if(!(e!=="debug"&&e!=="info"&&e!=="warn"&&e!=="error"))return e}function Aze(e){if(!e||typeof e!="object")return{};let t=e,r={};for(let[n,i]of Object.entries(t)){if(!i||typeof i!="object")continue;let o=i,s=typeof o.daemonUrl=="string"?Z0(o.daemonUrl):void 0;r[n]={daemonUrl:s}}return r}function jze(e){let t=JSON.parse(e);return{daemonUrl:typeof t.daemonUrl=="string"?Z0(t.daemonUrl):void 0,pluginRoot:typeof t.pluginRoot=="string"?t.pluginRoot:void 0,logLevel:are(t.logLevel),channels:Aze(t.channels)}}function Fze(e=Nze.homedir()){return sre.join(e,".config","aladuo","config.json")}async function r$(e=Fze()){try{let t=await Pze.readFile(e,"utf8");return jze(t)}catch{return{}}}function ak(e={}){let t=e.env??process.env,r=e.userConfig??{},n=zd({},t),i=Z0(e.daemonUrlOverride)??Z0(t.ALADUO_DAEMON_URL)??Z0(t.ALADUO_WS_URL)??Z0(r.daemonUrl)??"http://127.0.0.1:20233",o=e.pluginRootOverride??t.ALADUO_PLUGIN_ROOT??r.pluginRoot??sre.join(n.runtimeDir,"plugins","channels"),s=are(t.ALADUO_LOG_LEVEL)??r.logLevel??"info";return{daemonUrl:i,pluginRoot:o,logLevel:s,channels:r.channels??{}}}import{spawn as Lze}from"node:child_process";import{mkdir as n$}from"node:fs/promises";import Mze from"node:os";import W0 from"node:path";var ure="ghcr.io/openduo/duoduo:latest",zze=["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ALADUO_LOG_LEVEL","ALADUO_PERMISSION_MODE","ALADUO_CADENCE_INTERVAL_MS","ALADUO_SESSION_IDLE_MS","ALADUO_SESSION_MAX_CONCURRENT","ALADUO_SESSION_HEARTBEAT_MS"];function Bp(e,t,r,n){if(r!==void 0)return{value:r,nextIndex:t};let i=e[t+1];if(!i)throw new Error(`Missing value for ${n}`);return{value:i,nextIndex:t+1}}function uk(e,t){return W0.resolve(e,t)}function Uze(e){let t=Number(e);if(!Number.isInteger(t)||t<1||t>65535)throw new Error(`Invalid port: ${e}`);return t}function qze(e){if(e==="always"||e==="missing"||e==="never")return e;throw new Error(`Invalid pull policy: ${e}`)}function g6(e){let t={};for(let r of zze){let n=e[r];n&&(t[r]=n)}return t}function y6(e,t){let r=W0.join(e,".aladuo","containers",t);return{workspaceDir:W0.join(r,"workspace"),kernelDir:W0.join(r,"kernel"),runtimeDir:W0.join(r,"runtime"),claudeDir:W0.join(r,"claude")}}function o$(e,t={}){let r=t.env??process.env,n=t.homeDir??Mze.homedir(),i=t.currentCwd??process.cwd(),o="default",s=r.ALADUO_CONTAINER_IMAGE??ure,a=20233,u,f=!1,m="missing",h,v,y,b;if(e.length===0||e[0]==="help"||e[0]==="--help"||e[0]==="-h"){let E=y6(n,o);return{help:!0,command:"plan",image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:E.workspaceDir,kernelDir:E.kernelDir,runtimeDir:E.runtimeDir,claudeDir:E.claudeDir,follow:f,pull:m,forwardedEnv:g6(r)}}let T=e[0];if(T!=="up"&&T!=="down"&&T!=="logs"&&T!=="ps"&&T!=="plan")throw new Error(`Unknown container command: ${T}`);for(let E=1;E<e.length;E++){let C=e[E],k=C.indexOf("="),x=k>=0?C.slice(k+1):void 0,N=k>=0?C.slice(0,k):C;if(N==="--help"||N==="-h"){let I=y6(n,o);return{help:!0,command:T,image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:h??I.workspaceDir,kernelDir:v??I.kernelDir,runtimeDir:y??I.runtimeDir,claudeDir:b??I.claudeDir,envFile:u,follow:f,pull:m,forwardedEnv:g6(r)}}if(N==="--follow"||N==="-f"){f=!0;continue}if(N==="--name"){let{value:I,nextIndex:P}=Bp(e,E,x,"--name");o=I,E=P;continue}if(N==="--image"){let{value:I,nextIndex:P}=Bp(e,E,x,"--image");s=I,E=P;continue}if(N==="--port"){let{value:I,nextIndex:P}=Bp(e,E,x,"--port");a=Uze(I),E=P;continue}if(N==="--workspace-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--workspace-dir");h=uk(i,I),E=P;continue}if(N==="--kernel-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--kernel-dir");v=uk(i,I),E=P;continue}if(N==="--runtime-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--runtime-dir");y=uk(i,I),E=P;continue}if(N==="--claude-dir"){let{value:I,nextIndex:P}=Bp(e,E,x,"--claude-dir");b=uk(i,I),E=P;continue}if(N==="--env-file"){let{value:I,nextIndex:P}=Bp(e,E,x,"--env-file");u=uk(i,I),E=P;continue}if(N==="--pull"){let{value:I,nextIndex:P}=Bp(e,E,x,"--pull");m=qze(I),E=P;continue}throw new Error(`Unknown option: ${C}`)}let D=y6(n,o);return{help:!1,command:T,image:s,containerName:`duoduo-${o}`,instanceName:o,port:a,workspaceDir:h??D.workspaceDir,kernelDir:v??D.kernelDir,runtimeDir:y??D.runtimeDir,claudeDir:b??D.claudeDir,envFile:u,follow:f,pull:m,forwardedEnv:g6(r)}}function lk(e){let t=["run","-d","--name",e.containerName,"--restart","unless-stopped","--pull",e.pull,"-p",`${e.port}:20233`,"-e","HOME=/home/duoduo","-e","ALADUO_CONTAINER=1","-e","ALADUO_HOME=/home/duoduo","-e","ALADUO_BOOTSTRAP_DIR=/app/bootstrap","-e","ALADUO_KERNEL_DIR=/home/duoduo/aladuo","-e","ALADUO_WORK_DIR=/workspace","-e","ALADUO_RUNTIME_DIR=/home/duoduo/.aladuo","-e","ALADUO_RUNTIME_MODE=container","-e","PORT=20233","-v",`${e.workspaceDir}:/workspace`,"-v",`${e.kernelDir}:/home/duoduo/aladuo`,"-v",`${e.runtimeDir}:/home/duoduo/.aladuo`,"-v",`${e.claudeDir}:/home/duoduo/.claude`];e.envFile&&t.push("--env-file",e.envFile);for(let[r,n]of Object.entries(e.forwardedEnv))t.push("-e",`${r}=${n}`);return t.push(e.image,"node","/app/dist/release/daemon.js"),t}function Bze(e){return["rm","-f",e.containerName]}function Hze(e){return["logs",...e.follow?["-f"]:[],e.containerName]}function Vze(e){return["ps","-a","--filter",`name=^/${e.containerName}$`]}function Zze(e){return e.map(t=>/[^\w./:@=-]/.test(t)?JSON.stringify(t):t).join(" ")}function v6(){console.log("Usage: duoduo container <up|down|logs|ps|plan> [options]"),console.log(""),console.log("Options:"),console.log(" --name <name> Instance name (default: default)"),console.log(` --image <ref> Container image (default: ${ure})`),console.log(" --port <port> Host port mapped to daemon 20233"),console.log(" --workspace-dir <path> Host directory mounted to /workspace"),console.log(" --kernel-dir <path> Host directory mounted to /home/duoduo/aladuo"),console.log(" --runtime-dir <path> Host directory mounted to /home/duoduo/.aladuo"),console.log(" --claude-dir <path> Host directory mounted to /home/duoduo/.claude"),console.log(" --env-file <path> Pass a docker --env-file"),console.log(" --pull <always|missing|never> Image pull policy (default: missing)"),console.log(" -f, --follow Follow logs"),console.log(" -h, --help Show help")}function i$(e){return new Promise((t,r)=>{let n=Lze("docker",e,{stdio:"inherit"});n.on("error",r),n.on("exit",i=>{if(i===0){t();return}r(new Error(`docker ${e[0]} exited with code ${i??"unknown"}`))})})}async function lre(e){let t=o$(e);if(t.help){v6();return}if(t.command==="plan"){let r=lk(t);console.log(`instance: ${t.instanceName}`),console.log(`image: ${t.image}`),console.log(`container: ${t.containerName}`),console.log(`workspace_dir: ${t.workspaceDir}`),console.log(`kernel_dir: ${t.kernelDir}`),console.log(`runtime_dir: ${t.runtimeDir}`),console.log(`claude_dir: ${t.claudeDir}`),console.log(`daemon_url: http://127.0.0.1:${t.port}`),console.log(""),console.log("docker command:"),console.log(Zze(["docker",...r]));return}if(t.command==="up"){await Promise.all([n$(t.workspaceDir,{recursive:!0}),n$(t.kernelDir,{recursive:!0}),n$(t.runtimeDir,{recursive:!0}),n$(t.claudeDir,{recursive:!0})]),await i$(lk(t)),console.log(`container started: ${t.containerName}`),console.log(`daemon: http://127.0.0.1:${t.port}`);return}if(t.command==="down"){await i$(Bze(t));return}if(t.command==="logs"){await i$(Hze(t));return}await i$(Vze(t))}ta();V0();import{existsSync as s$,promises as ck}from"node:fs";import Ud from"node:path";import{spawn as Wze}from"node:child_process";import{fileURLToPath as Gze}from"node:url";function b6(e){return Ud.join(zd({},e).runDir,"daemon-supervisor.pid.json")}function cre(e){return Ud.join(zd({},e).runDir,"daemon-supervisor.log")}function Jze(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function fre(e){if(!e||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}async function S6(e){try{let t=await ck.readFile(b6(e),"utf8"),r=JSON.parse(t);return Jze(r.pid)}catch{return}}async function Kze(e,t){let r=b6(e);await sr(Ud.dirname(r)),await ck.writeFile(r,JSON.stringify({pid:t,startedAt:new Date().toISOString()},null,2)+`
|
|
857
857
|
`)}async function _6(e){await ck.rm(b6(e),{force:!0})}async function Hp(e,t=800){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{if(!(await fetch(`${e.replace(/\/$/,"")}/healthz`,{signal:r.signal})).ok)return{healthy:!1};let o=await fetch(`${e.replace(/\/$/,"")}/rpc`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:"1",method:"system.runtime.info",params:{}}),signal:r.signal});return o.ok?{healthy:!0,runtimeInfo:(await o.json()).result}:{healthy:!0}}catch{return{healthy:!1}}finally{clearTimeout(n)}}function Yze(e){let t=Ud.join(e,"dist","release","daemon.cjs"),r=Ud.join(e,"dist","release","daemon.js"),n=Ud.join(e,"src","daemon","daemon.ts"),i=Ud.join(e,"node_modules",".bin","tsx");if(s$(t))return{command:process.execPath,args:[t]};if(s$(r))return{command:process.execPath,args:[r]};if(s$(i)&&s$(n))return{command:i,args:[n]};throw new Error("Cannot find daemon entrypoint (dist/release/daemon.js or tsx src/daemon/daemon.ts)")}async function dre(e,t=process.env,r={}){let n=r.probeTimeoutMs??500,i=r.pollIntervalMs??150,o=r.startupTimeoutMs??5e3;if((await Hp(e,n)).healthy)return{started:!1,pid:await S6(t)};let a=Gze(import.meta.url),u=Ud.resolve(Ud.dirname(a),"..",".."),f=Yze(u),m=cre(t);await sr(Ud.dirname(m));let h=await ck.open(m,"a"),v=Wze(f.command,f.args,{detached:!0,stdio:["ignore",h.fd,h.fd],env:t});if(v.unref(),await h.close(),!v.pid)throw new Error("daemon start failed: missing child pid");await Kze(t,v.pid);let y=Date.now()+o;for(;Date.now()<y;){if((await Hp(e,n)).healthy)return{started:!0,pid:v.pid};await new Promise(T=>setTimeout(T,i))}try{process.kill(v.pid,"SIGTERM")}catch{}throw await _6(t),new Error(`daemon start timed out waiting for health checks at ${e}`)}async function pre(e=process.env){let t=await S6(e);if(!t||!fre(t))return await _6(e),{stopped:!1};try{process.kill(t,"SIGTERM")}catch{}return await _6(e),{stopped:!0}}async function mre(e,t=process.env){let r=await S6(t),n=fre(r),i=await Hp(e,500);return{healthy:i.healthy,pid:r,pidAlive:n,runtimeInfo:i.runtimeInfo}}async function hre(e=process.env){try{return await ck.readFile(cre(e),"utf8")}catch{return""}}import{EventEmitter as Xze}from"node:events";function a$(){let e=new Xze;return e.setMaxListeners(100),{emit(t,...r){return e.emit(t,...r)},on(t,r){e.on(t,r)},off(t,r){e.off(t,r)},once(t,r){e.once(t,r)},removeAllListeners(t){t?e.removeAllListeners(t):e.removeAllListeners()},listenerCount(t){return e.listenerCount(t)}}}function fk(){let e=new Map,t=new Map,r=null,n={},i=["final","stream"],o=(h,v)=>(h.returnMask??i).includes(v),s=h=>{let{sessionKey:v,record:y}=h,b=t.get(v);if(!b||b.size===0)return;let T={jsonrpc:"2.0",method:"session.output",params:{session_key:v,record:y}};for(let D of b){let E=e.get(D);if(E&&o(E,"final"))try{E.send(T)}catch{m(D)}}},a=h=>{let{sessionKey:v,chunk:y}=h,b=t.get(v);if(!b||b.size===0)return;let T={jsonrpc:"2.0",method:"session.stream",params:{session_key:v,chunk:y}};for(let D of b){let E=e.get(D);if(E&&o(E,"stream"))try{E.send(T)}catch{m(D)}}},u=h=>{let{sessionKey:v,event:y}=h,b=t.get(v);if(!b||b.size===0)return;let T={jsonrpc:"2.0",method:"session.execution",params:{session_key:v,event:y}};for(let D of b){let E=e.get(D);if(E&&o(E,"tool"))try{E.send(T)}catch{m(D)}}};function f(h){let{id:v,sessionKey:y}=h;e.has(v)&&m(v),e.set(v,h);let b=t.get(y);b||(b=new Set,t.set(y,b)),b.add(v),n.onAttach&&n.onAttach(y,v)}function m(h){let v=e.get(h);if(!v)return;let{sessionKey:y}=v,b=t.get(y);b&&(b.delete(h),b.size===0&&t.delete(y)),e.delete(h),n.onDetach&&n.onDetach(y,h)}return{subscribe:f,unsubscribe:m,getSubscribers(h){let v=t.get(h);return v?Array.from(v).map(y=>e.get(y)).filter(y=>y!==void 0):[]},subscriberCount(){return e.size},start(h){r||(r=h,r.on("session.output",s),r.on("session.stream",a),r.on("session.execution",u))},stop(){if(r){if(r.off("session.output",s),r.off("session.stream",a),r.off("session.execution",u),r=null,n.onDetach)for(let h of e.values())n.onDetach(h.sessionKey,h.id);for(let h of e.values())try{h.close()}catch{}e.clear(),t.clear()}},setAttachmentCallbacks(h){n=h}}}var eIe=tr(_ge(),1),tIe=tr(Qve(),1);import l$t from"node:crypto";import dc from"node:path";import{promises as qM}from"node:fs";dm();mT();ea();vo();aS();import{promises as aSe}from"node:fs";import bm from"node:path";ta();import clt from"node:crypto";import{promises as s_e}from"node:fs";import flt from"node:path";var zN=class{filePath;maxEntries;entries=new Map;constructor(t,r={}){this.filePath=t,this.maxEntries=r.maxEntries??1e4}async load(){let t;try{t=await s_e.readFile(this.filePath,"utf8")}catch{return}let r=t.trim().split(`
|
|
858
858
|
`);for(let n of r){if(!n)continue;let i=JSON.parse(n);this.entries.set(i.key,i)}}has(t){return this.entries.has(t)}get(t){return this.entries.get(t)}async record(t){this.entries.size>=this.maxEntries&&this.entries.clear(),this.entries.set(t.key,t),await sr(flt.dirname(this.filePath));let r=`${JSON.stringify(t)}
|
|
859
859
|
`;await s_e.appendFile(this.filePath,r)}async checkAndRecord(t){return(await this.checkAndRecordDetailed(t)).duplicate}async checkAndRecordDetailed(t){return this.entries.has(t.key)?{duplicate:!0,existing:this.entries.get(t.key)}:(await this.record(t),{duplicate:!1})}};function u_e(e,t=5){let r=e.source?.kind??"unknown",n=e.dedup;if(n?.source_id)return`${r}:${n.source_id}`;if(e.type==="channel.command")return null;if(n?.hash){let i=a_e(e.ts,t);return`${r}:hash:${n.hash}:${i}`}if(e.payload?.text){let i=dlt(e.payload.text),o=a_e(e.ts,t);return`${r}:text:${i}:${o}`}return null}function a_e(e,t){let n=new Date(e).getTime(),i=t*60*1e3;return String(Math.floor(n/i))}function dlt(e){return clt.createHash("sha256").update(e).digest("hex")}UN();Yl();FV();lp();TT();ea();ta();TT();import{promises as Zdt}from"node:fs";import qbe from"node:path";function Bbe(e,t){return vm(t),qbe.join(e.channelsDir,t,"nav.json")}async function Hbe(e,t,r){let n={root:r,stack:[r]};if(!t)return n;try{vm(t)}catch{return n}let i=Bbe(e,t),o;try{let s=await Zdt.readFile(i,"utf8");o=JSON.parse(s)}catch{return n}return!o||typeof o.root!="string"||!Array.isArray(o.stack)||o.stack.length===0?n:o}async function Vbe(e,t,r){vm(t);let n=qbe.join(e.channelsDir,t);await sr(n),await ji(Bbe(e,t),JSON.stringify(r,null,2)+`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openduo/duoduo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"ink-text-input": "^5.0.1",
|
|
54
54
|
"react": "^18.3.1",
|
|
55
55
|
"zod": "^4.3.6",
|
|
56
|
-
"@openduo/protocol": "0.2.
|
|
56
|
+
"@openduo/protocol": "0.2.1"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"test": "vitest run",
|