grix-connector 3.33.2 → 3.33.3

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.
Files changed (39) hide show
  1. package/dist/adapter/acp/acp-adapter.js +2 -2
  2. package/dist/adapter/agy/agy-adapter.js +5 -5
  3. package/dist/adapter/agy/model-list.js +2 -2
  4. package/dist/adapter/claude/claude-adapter.js +5 -5
  5. package/dist/adapter/claude/model-list.js +1 -1
  6. package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
  7. package/dist/adapter/codewhale/model-list.js +2 -2
  8. package/dist/adapter/codex/codex-bridge.js +1 -1
  9. package/dist/adapter/cursor/cursor-adapter.js +7 -7
  10. package/dist/adapter/cursor/fetch-models.js +2 -2
  11. package/dist/adapter/cursor/resolve-command.js +1 -1
  12. package/dist/adapter/openhuman/openhuman-adapter.js +3 -3
  13. package/dist/assets/dsh-bridge/{grix-dsh-bridge-3.33.2.tgz → grix-dsh-bridge-3.33.3.tgz} +0 -0
  14. package/dist/assets/dsh-bridge/manifest.json +5 -5
  15. package/dist/audit/adapters/openclaw/openclaw-audit-adapter.js +1 -1
  16. package/dist/audit/adapters/pi/pi-transcript-source.js +1 -1
  17. package/dist/audit/core/transcript-fingerprint.js +1 -0
  18. package/dist/audit/producer/ipc-audit-producer.js +1 -1
  19. package/dist/bridge/adapter-pool.js +1 -1
  20. package/dist/bridge/bridge.js +9 -9
  21. package/dist/bridge/cli-install-offer.js +1 -0
  22. package/dist/bridge/respawn-manager.js +1 -1
  23. package/dist/core/files/file-serve.js +1 -1
  24. package/dist/core/installer/installer.js +6 -6
  25. package/dist/core/installer/npm-registry.js +3 -3
  26. package/dist/core/installer/prereq-installer.js +1 -1
  27. package/dist/core/proxy/hermes-profile-relay.js +1 -1
  28. package/dist/core/runtime/spawn.js +3 -3
  29. package/dist/core/upgrade/npm-upgrader.js +2 -2
  30. package/dist/core/util/cli-probe.js +2 -2
  31. package/dist/core/util/git-project-root.js +1 -1
  32. package/dist/default-skills/grix-egg/SKILL.md +2 -2
  33. package/dist/default-skills/message-send/SKILL.md +1 -1
  34. package/dist/default-skills/message-unsend/SKILL.md +1 -1
  35. package/dist/manager.js +1 -1
  36. package/dist/service/process-control.js +1 -1
  37. package/openclaw-plugin/audit-recorder-worker.js +170 -44
  38. package/openclaw-plugin/index.js +88 -14
  39. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ import{SESSION_CONTROL_ERROR_CODES as l}from"../adapter/claude/protocol-contract.js";import{detectPlatformOS as u,getCliBinary as a,getInstallCommand as c,isKnownAgent as f}from"../core/installer/registry.js";const r="\u5B89\u88C5",m="\u6682\u4E0D\u5B89\u88C5",p="cli-install-";function g(t){const n=t,s=String(n.code??""),e=String(n.syscall??"");if(s==="cli_not_found"||e==="spawn"&&s==="ENOENT")return!0;const o=t instanceof Error?t.message:String(t);return/spawn \S+ ENOENT/i.test(o)||/ENOENT:.*\bspawn\b/i.test(o)||/spawn failed:.*ENOENT/i.test(o)||/command not found/i.test(o)}function S(t){const n=t,s=n.sessionControlErrorCode||n.cwdErrorCode||l.runtimeError,e=t instanceof Error?t.message:String(t);return{code:s,msg:e}}function C(t,n){const s=u();let e="";return t==="deepseek-harness"?e="deepseek":t==="acp"?e=String(n??"").trim().toLowerCase():t==="openhuman"?e="":e=String(t??"").trim().toLowerCase(),e||(e=String(n??"").trim().toLowerCase()),!e||!f(e)||!c(e,s)?null:e}function I(t,n){return a(t)||n||t}function N(t){return t.startsWith(p)}function O(t){return t.action==="accept"?!0:t.action==="cancel"?!1:t.response?.type==="single"?i(t.response.value):t.response?.type==="map"?t.response.entries.some(n=>i(n.value)):!1}function i(t){const n=String(t??"").trim();return n===r||/^yes$/i.test(n)||/^install$/i.test(n)}function _(t,n){return{request_id:t,mode:"form",questions:[{header:`\u672A\u627E\u5230 ${n}`,prompt:`\u672C\u673A\u6CA1\u6709\u627E\u5230 ${n} \u7A0B\u5E8F\uFF0C\u662F\u5426\u9700\u8981\u5B89\u88C5\uFF1F`,options:[r,m]}]}}export{m as CLI_INSTALL_OPTION_NO,r as CLI_INSTALL_OPTION_YES,p as CLI_INSTALL_REQUEST_PREFIX,_ as buildCliInstallQuestion,I as cliDisplayName,N as isCliInstallRequestId,g as isCliMissingError,O as isInstallConfirmReply,C as resolveInstallAgentType,S as sessionControlOpenFailure};
@@ -1 +1 @@
1
- import{log as t}from"../core/log/index.js";const l=3e3,n=6e4,i=10,r=300*1e3,o=6e4,p=1e4,h=3;class w{attempts=0;slowRetryTimer=null;respawnTimer=null;healthCheckTimer=null;healthFailures=0;get exhausted(){return this.attempts>=i}resetAttempts(){this.attempts=0}resetHealthFailures(){this.healthFailures=0}stopSlowRetry(){this.slowRetryTimer&&(clearTimeout(this.slowRetryTimer),this.slowRetryTimer=null)}stopHealthCheck(){this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=null)}stop(){this.stopSlowRetry(),this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null)}stopAll(){this.stopHealthCheck(),this.stop()}startHealthCheck(e){this.stopHealthCheck(),e.pingAgent&&(this.healthFailures=0,this.healthCheckTimer=setInterval(()=>{if(e.stopped){this.stopHealthCheck();return}if(!e.pingAgent){this.stopHealthCheck();return}e.agentAlive!==!1&&e.pingAgent(p).then(s=>{s?this.healthFailures=0:(this.healthFailures++,t.info(e.name,`Health check failed (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted, triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e)))}).catch(()=>{this.healthFailures++,t.info(e.name,`Health check error (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted (error), triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e))})},o))}scheduleRespawn(e){try{e.onCleanupAgent()}catch{}if(this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null),this.attempts++,this.attempts>i){t.error(e.name,`Max respawn attempts reached, will retry in ${r/1e3}s`),this.scheduleSlowRetry(e);return}const s=Math.min(l*2**(this.attempts-1),n);t.info(e.name,`Respawn attempt ${this.attempts}/${i} in ${s}ms`),this.respawnTimer=setTimeout(()=>{this.respawnTimer=null,!e.stopped&&e.onRespawnNeeded().catch(a=>{t.error(e.name,`Respawn failed: ${a}`),this.scheduleRespawn(e)})},s)}scheduleSlowRetry(e){this.stopSlowRetry(),this.slowRetryTimer=setTimeout(()=>{e.stopped||(t.info(e.name,"Slow retry: attempting respawn"),this.attempts=0,e.onRespawnNeeded().catch(s=>{t.error(e.name,`Slow retry failed: ${s}`),this.scheduleRespawn(e)}))},r)}}export{w as RespawnManager};
1
+ import{log as t}from"../core/log/index.js";const n=3e3,o=6e4,r=10,a=300*1e3,p=6e4,u=1e4,m=3;class c{attempts=0;slowRetryTimer=null;respawnTimer=null;healthCheckTimer=null;healthFailures=0;get exhausted(){return this.attempts>=r}resetAttempts(){this.attempts=0}resetHealthFailures(){this.healthFailures=0}stopSlowRetry(){this.slowRetryTimer&&(clearTimeout(this.slowRetryTimer),this.slowRetryTimer=null)}stopHealthCheck(){this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=null)}stop(){this.stopSlowRetry(),this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null)}stopAll(){this.stopHealthCheck(),this.stop()}startHealthCheck(e){if(this.stopHealthCheck(),!e.pingAgent)return;this.healthFailures=0;const s=e.healthCheckIntervalMs??p,i=e.healthCheckTimeoutMs??u,h=e.healthCheckMaxFailures??m;this.healthCheckTimer=setInterval(()=>{if(e.stopped){this.stopHealthCheck();return}if(!e.pingAgent){this.stopHealthCheck();return}e.agentAlive!==!1&&e.pingAgent(i).then(l=>{l?this.healthFailures=0:(this.healthFailures++,t.info(e.name,`Health check failed (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted, triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e)))}).catch(()=>{this.healthFailures++,t.info(e.name,`Health check error (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted (error), triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e))})},s)}scheduleRespawn(e){try{e.onCleanupAgent()}catch{}if(this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null),this.attempts++,this.attempts>r){t.error(e.name,`Max respawn attempts reached, will retry in ${a/1e3}s`),this.scheduleSlowRetry(e);return}const s=Math.min(n*2**(this.attempts-1),o);t.info(e.name,`Respawn attempt ${this.attempts}/${r} in ${s}ms`),this.respawnTimer=setTimeout(()=>{this.respawnTimer=null,!e.stopped&&e.onRespawnNeeded().catch(i=>{t.error(e.name,`Respawn failed: ${i}`),this.scheduleRespawn(e)})},s)}scheduleSlowRetry(e){this.stopSlowRetry(),this.slowRetryTimer=setTimeout(()=>{e.stopped||(t.info(e.name,"Slow retry: attempting respawn"),this.attempts=0,e.onRespawnNeeded().catch(s=>{t.error(e.name,`Slow retry failed: ${s}`),this.scheduleRespawn(e)}))},a)}}export{c as RespawnManager};
@@ -1,2 +1,2 @@
1
- import{randomUUID as A}from"node:crypto";import{execFile as F}from"node:child_process";import U from"node:http";import N from"node:https";import{createReadStream as z,createWriteStream as O}from"node:fs";import{stat as f,rename as B,unlink as E,access as V,readdir as W}from"node:fs/promises";import{basename as p,extname as S,isAbsolute as C,join as P,normalize as M,relative as G,resolve as _,sep as J}from"node:path";import*as X from"node:os";import{getCaCertPem as Y,getCaMobileConfig as Z,getLeafCredentials as K}from"./cert-store.js";const Q=365*24*60*60*1e3,T={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".tiff":"image/tiff",".tif":"image/tiff",".ico":"image/x-icon",".avif":"image/avif"};function q(e){return T[S(e).toLowerCase()]}const tt={".mp4":"video/mp4",".m4v":"video/mp4",".mov":"video/quicktime",".webm":"video/webm",".ogv":"video/ogg",".mkv":"video/x-matroska",".avi":"video/x-msvideo",".3gp":"video/3gpp",".ts":"video/mp2t"},et={".mp3":"audio/mpeg",".m4a":"audio/mp4",".aac":"audio/aac",".wav":"audio/wav",".ogg":"audio/ogg",".oga":"audio/ogg",".opus":"audio/opus",".flac":"audio/flac",".weba":"audio/webm"},nt={".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".xhtml":"application/xhtml+xml",".txt":"text/plain; charset=utf-8",".text":"text/plain; charset=utf-8",".log":"text/plain; charset=utf-8",".md":"text/markdown; charset=utf-8",".markdown":"text/markdown; charset=utf-8",".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".cjs":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".jsonl":"application/x-ndjson; charset=utf-8",".xml":"application/xml; charset=utf-8",".csv":"text/csv; charset=utf-8",".pdf":"application/pdf"};function it(e){const t=S(e).toLowerCase();return T[t]??tt[t]??et[t]??nt[t]}function $(e){const t=e.split(".");if(t.length!==4)return!1;const i=Number(t[0]),a=Number(t[1]);return!Number.isInteger(i)||!Number.isInteger(a)?!1:i===100&&a>=64&&a<=127}function at(){return new Promise(e=>{F("tailscale",["ip","-4"],{timeout:3e3},(t,i)=>{if(t){e(void 0);return}const a=i.trim().split(`
1
+ import{randomUUID as A}from"node:crypto";import{execFile as F}from"node:child_process";import U from"node:http";import N from"node:https";import{createReadStream as z,createWriteStream as O}from"node:fs";import{stat as f,rename as B,unlink as E,access as V,readdir as W}from"node:fs/promises";import{basename as p,extname as S,isAbsolute as C,join as P,normalize as M,relative as G,resolve as _,sep as J}from"node:path";import*as X from"node:os";import{getCaCertPem as Y,getCaMobileConfig as Z,getLeafCredentials as K}from"./cert-store.js";const Q=365*24*60*60*1e3,T={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".tiff":"image/tiff",".tif":"image/tiff",".ico":"image/x-icon",".avif":"image/avif"};function q(e){return T[S(e).toLowerCase()]}const tt={".mp4":"video/mp4",".m4v":"video/mp4",".mov":"video/quicktime",".webm":"video/webm",".ogv":"video/ogg",".mkv":"video/x-matroska",".avi":"video/x-msvideo",".3gp":"video/3gpp",".ts":"video/mp2t"},et={".mp3":"audio/mpeg",".m4a":"audio/mp4",".aac":"audio/aac",".wav":"audio/wav",".ogg":"audio/ogg",".oga":"audio/ogg",".opus":"audio/opus",".flac":"audio/flac",".weba":"audio/webm"},nt={".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".xhtml":"application/xhtml+xml",".txt":"text/plain; charset=utf-8",".text":"text/plain; charset=utf-8",".log":"text/plain; charset=utf-8",".md":"text/markdown; charset=utf-8",".markdown":"text/markdown; charset=utf-8",".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".cjs":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".jsonl":"application/x-ndjson; charset=utf-8",".xml":"application/xml; charset=utf-8",".csv":"text/csv; charset=utf-8",".pdf":"application/pdf"};function it(e){const t=S(e).toLowerCase();return T[t]??tt[t]??et[t]??nt[t]}function $(e){const t=e.split(".");if(t.length!==4)return!1;const i=Number(t[0]),a=Number(t[1]);return!Number.isInteger(i)||!Number.isInteger(a)?!1:i===100&&a>=64&&a<=127}function at(){return new Promise(e=>{F("tailscale",["ip","-4"],{timeout:3e3,windowsHide:!0},(t,i)=>{if(t){e(void 0);return}const a=i.trim().split(`
2
2
  `)[0].trim();e(a&&$(a)?a:void 0)})})}function ot(){const e=X.networkInterfaces();for(const t of Object.values(e))if(t){for(const i of t)if(!(i.family!=="IPv4"||i.internal)&&$(i.address))return i.address}}async function rt(){const e=await at();return e!==void 0?e:ot()}const m=new Map;let h=null,u="",v=0,g=null,y=null,b=0,w=null;function st(e){for(const[t,i]of m)i.expiresAt<=e&&m.delete(t)}const ct=2*1024*1024*1024;function I(e){const t=e.socket.remoteAddress??"",i=t.startsWith("::ffff:")?t.slice(7):t;return $(i)}async function dt(e,t){const i=S(t),a=p(t,i);let n=P(e,t),o=0;for(;;)try{await V(n),o++,n=P(e,`${a}(${o})${i}`)}catch{return n}}function lt(e,t,i){return new Promise((a,n)=>{const o=O(t);let r=0,s=!1;const d=()=>{s||(s=!0,o.destroy(),E(t).catch(()=>{}))};e.on("data",c=>{r+=c.length,r>ct&&(d(),n(Object.assign(new Error("file too large"),{code:413})))}),o.on("error",c=>{d(),n(c)}),e.on("error",c=>{d(),n(c)}),o.on("finish",async()=>{if(!s){s=!0;try{await B(t,i),a()}catch(c){E(t).catch(()=>{}),n(c)}}}),e.pipe(o)})}async function ut(e,t){if(!I(e)){t.statusCode=403,t.end("forbidden");return}const a=new URL(e.url??"/",`http://${e.headers.host}`).searchParams.get("dir")??"";if(!C(a)||M(a)!==_(a)){t.statusCode=400,t.end("invalid dir");return}const n=e.headers["x-filename"]??"",o=Array.isArray(n)?n[0]:n;let r;try{r=decodeURIComponent(o)}catch{r=o}if(!r||r.includes("/")||r.includes("\\")||r==="."||r===".."){t.statusCode=400,t.end("invalid filename");return}try{if(!(await f(a)).isDirectory()){t.statusCode=400,t.end("dir not found");return}}catch{t.statusCode=400,t.end("dir not found");return}const s=await dt(a,r),d=`${s}.${A()}.tmp`;try{await lt(e,d,s),t.statusCode=200,t.setHeader("Content-Type","application/json"),t.end(JSON.stringify({ok:!0,path:s,name:p(s)}))}catch(c){c.code===413?(t.statusCode=413,t.end("file too large")):(t.statusCode=500,t.end("upload failed"))}}function L(e,t,i,a,n,o){const r=it(a);if(t.setHeader("Content-Type",r??"application/octet-stream"),t.setHeader("Content-Disposition",`${o&&r?"inline":"attachment"}; filename*=UTF-8''${encodeURIComponent(a)}`),t.setHeader("Accept-Ranges","bytes"),n===0){if(e.headers.range){t.statusCode=416,t.setHeader("Content-Range","bytes */0"),t.end();return}t.statusCode=200,t.setHeader("Content-Length","0"),t.end();return}let s=0,d=n-1;const c=e.headers.range;if(c){const l=/^bytes=(\d*)-(\d*)$/.exec(c.trim());if(!l||l[1]===""&&l[2]===""){t.statusCode=416,t.setHeader("Content-Range",`bytes */${n}`),t.end();return}if(l[1]===""){const H=Number(l[2]);s=H>=n?0:n-H}else s=Number(l[1]),d=l[2]===""?n-1:Math.min(Number(l[2]),n-1);if(s>d||s>=n){t.statusCode=416,t.setHeader("Content-Range",`bytes */${n}`),t.end();return}t.statusCode=206,t.setHeader("Content-Range",`bytes ${s}-${d}/${n}`)}else t.statusCode=200;if(t.setHeader("Content-Length",String(d-s+1)),e.method==="HEAD"){t.end();return}const x=z(i,{start:s,end:d});x.on("error",()=>{t.headersSent||(t.statusCode=500),t.end()}),x.pipe(t)}function ft(e,t){const i=String(e.url??"").split("?")[0],n=/^\/d\/([A-Za-z0-9-]+)$/.exec(i)?.[1],o=n?m.get(n):void 0;if(!o||o.expiresAt<=Date.now()){t.statusCode=404,t.end("not found");return}L(e,t,o.filePath,o.fileName,o.size,!0)}async function pt(e,t){if(!I(e)){t.statusCode=403,t.end("forbidden");return}const a=new URL(e.url??"/",`http://${e.headers.host}`).searchParams.get("path")??"";if(!C(a)||M(a)!==_(a)){t.statusCode=400,t.end("invalid path");return}let n;try{n=await f(a)}catch{t.statusCode=404,t.end("not found");return}if(!n.isFile()){t.statusCode=400,t.end("not a file");return}L(e,t,a,p(a),n.size,!1)}const k=5e4;async function mt(e){const t=[],i=[e];let a=0;for(;i.length>0&&!(t.length>=k);){const n=i.pop();let o;try{o=await W(n,{withFileTypes:!0})}catch{a++;continue}for(const r of o){if(t.length>=k)break;const s=P(n,r.name),d=G(e,s).split(J).join("/");if(!r.isSymbolicLink()){if(r.isDirectory())t.push({rel:d,is_dir:!0}),i.push(s);else if(r.isFile()){let c=0;try{c=(await f(s)).size}catch{a++;continue}t.push({rel:d,is_dir:!1,size:c,abs:s})}}}}return{entries:t,unreadable:a}}async function ht(e,t){if(!I(e)){t.statusCode=403,t.end("forbidden");return}const a=new URL(e.url??"/",`http://${e.headers.host}`).searchParams.get("path")??"";if(!C(a)||M(a)!==_(a)){t.statusCode=400,t.end("invalid path");return}let n;try{n=await f(a)}catch{t.statusCode=404,t.end("not found");return}if(!n.isDirectory()){t.statusCode=400,t.end("not a directory");return}const{entries:o,unreadable:r}=await mt(a),s=o.length>=k;t.statusCode=200,t.setHeader("Content-Type","application/json"),t.end(JSON.stringify({ok:!0,root_name:p(a),truncated:s,unreadable:r,entries:o}))}function gt(e){return/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&/Mobile/i.test(e)}async function wt(e,t){const i=String(e.headers["user-agent"]??""),n=new URL(e.url??"/",`http://${e.headers.host}`).searchParams.get("fmt");if(n==="mobileconfig"||n!=="crt"&&gt(i)){const s=await Z();t.statusCode=200,t.setHeader("Content-Type","application/x-apple-aspen-config"),t.setHeader("Content-Disposition",'attachment; filename="grix-tailnet-ca.mobileconfig"'),t.end(s);return}const r=await Y();t.statusCode=200,t.setHeader("Content-Type","application/x-x509-ca-cert"),t.setHeader("Content-Disposition",'attachment; filename="grix-tailnet-ca.crt"'),t.end(r)}function j(e,t){t.setHeader("Access-Control-Allow-Origin","*");const i=String(e.url??"").split("?")[0];if(i==="/ping"){t.statusCode=200,t.end("ok");return}if(i==="/ca"){wt(e,t).catch(()=>{t.headersSent||(t.statusCode=500,t.end("ca unavailable"))});return}if(i==="/upload"&&e.method==="POST"){ut(e,t).catch(()=>{t.headersSent||(t.statusCode=500,t.end("internal error"))});return}if(i==="/download"){pt(e,t).catch(()=>{t.headersSent||(t.statusCode=500,t.end("internal error"))});return}if(i==="/manifest"){ht(e,t).catch(()=>{t.headersSent||(t.statusCode=500,t.end("internal error"))});return}ft(e,t)}async function Ct(e){const t=U.createServer(j);await new Promise((a,n)=>{t.once("error",n),t.listen(0,e,()=>{t.removeListener("error",n),a()})});const i=t.address();h=t,u=e,v=typeof i=="object"&&i?i.port:0}async function vt(e){const{key:t,cert:i}=await K(e),a=N.createServer({key:t,cert:i},j);await new Promise((o,r)=>{a.once("error",r),a.listen(0,e,()=>{a.removeListener("error",r),o()})});const n=a.address();y=a,b=typeof n=="object"&&n?n.port:0}async function R(){const e=h,t=y;h=null,y=null,u="",v=0,b=0,await Promise.all([e&&new Promise(i=>e.close(()=>i())),t&&new Promise(i=>t.close(()=>i()))].filter(Boolean))}async function yt(e){y&&u===e||(w||(w=vt(e).catch(t=>{throw w=null,t})),await w,w=null)}async function D(e){h&&u===e||(h&&u!==e&&await R(),g||(g=Ct(e).catch(t=>{throw g=null,t})),await g,g=null),await yt(e)}async function bt(e){const t=await f(e.filePath);if(!t.isFile())throw new Error(`path is not a file: ${e.filePath}`);const i=Date.now();st(i),await D(e.host);const a=A(),n=p(e.filePath),o=e.ttlMs&&e.ttlMs>0?e.ttlMs:Q,r=i+o;return m.set(a,{filePath:e.filePath,fileName:n,size:t.size,expiresAt:r}),{url:`https://${u}:${b}/d/${a}`,ca_install_url:`http://${u}:${v}/ca`,file_name:n,size:t.size,expires_at:r}}async function Ht(){m.clear(),await R()}async function At(e){return await D(e),v}function Et(){return b}async function Tt(e){const t=String(e.file_path??"").trim();if(!t)throw new Error("missing file_path");if(!C(t))throw new Error("file_path must be an absolute path");const i=await rt();if(!i)throw new Error("tailnet_unavailable: no tailnet IPv4 detected; ensure Tailscale is up on this host");const a=typeof e.ttl_ms=="number"?e.ttl_ms:void 0,n=await bt({filePath:t,host:i,ttlMs:a}),o=q(n.file_name)!==void 0;return{ok:!0,markdown:o?`![${n.file_name}](${n.url})`:`[${n.file_name}](${n.url})`,is_image:o,...n}}export{rt as detectTailnetIPv4,At as ensureServerAndGetPort,Et as getFileServerHttpsPort,bt as registerFileForServe,Tt as serveLocalFile,Ht as stopFileServer,mt as walkManifest};
@@ -1,12 +1,12 @@
1
- import{execFile as R,spawn as _}from"node:child_process";import{log as m}from"../log/logger.js";import{resolveCliPath as P,getCliVersion as k,invalidateCliPathCache as x}from"../util/cli-probe.js";import{getInstallCommand as S,getCliBinary as O,isKnownAgent as D,detectPlatformOS as A,formatInstallCommand as U}from"./registry.js";import{checkPrerequisites as y,getMissingPrerequisites as v}from"./preflight.js";import{installMissingPrerequisites as C}from"./prereq-installer.js";import{detectEnvironment as V,formatEnvironmentInfo as F,isEnvironmentSupported as q}from"./env-detect.js";import{generateManualGuide as b}from"./manual-guide.js";import{npmInstallWithMirror as j,isTransientInstallError as G}from"./npm-registry.js";import{getAllAgentInstallInfo as B}from"./registry.js";class u extends Error{code;output;constructor(n,t,e){super(t),this.name="InstallerError",this.code=n,this.output=e}}const T=64*1024,H=20,N=2,W=3e3;class le{os;activeInstalls=new Map;constructor(){this.os=A()}listInstallable(){return{platform:this.os,agents:B(this.os)}}getProgress(n){return this.activeInstalls.get(n)}isInProgress(n){return this.activeInstalls.has(n)}async install(n){const{agentType:t}=n,e=Date.now();if(this.activeInstalls.has(t))return this.fail(t,"preflight",e,new u("INSTALL_IN_PROGRESS",`${t} is already being installed`));try{return await this._doInstall(n,e)}catch(i){this.activeInstalls.delete(t);const o=i instanceof Error?i.message:String(i);return m.error("installer",`${t} install unexpected error: ${o}`),{agentType:t,ok:!1,phase:"failed",error:{code:"INTERNAL",message:`Unexpected error: ${o}`},durationMs:Date.now()-e,output:""}}}async _doInstall(n,t){const{agentType:e}=n;let i;try{i=await V()}catch(s){const a=s instanceof Error?s.message:String(s);return this.fail(e,"preflight",t,new u("INTERNAL",`Environment detection failed: ${a}`))}m.info("installer",`Install request: ${e}
2
- ${F(i)}`);const o=q(i);if(!o.supported)return this.fail(e,"preflight",t,new u("ENVIRONMENT_UNSUPPORTED",`Current environment is not supported for automatic installation: ${o.reason}. Please install ${e} manually.`),i);if(this.setProgress(e,"preflight",t),!D(e))return this.fail(e,"preflight",t,new u("UNKNOWN_AGENT",`Unknown agent type: ${e}`),i);const l=S(e,this.os);if(!l){const s=this.getManualHint(e,this.os),a=s?`Installation of ${e} is not supported on ${this.os}. ${s}`:`Installation of ${e} is not supported on ${this.os}`;return this.fail(e,"preflight",t,new u("UNSUPPORTED_OS",a),i)}const c=O(e),p=await P(c),d=p?(await k(p)).version:null;if(p&&!n.force&&!n.dryRun){this.activeInstalls.delete(e);const s=Date.now()-t;return m.info("installer",`${e} already installed at ${p}${d?` (v${d})`:""}`),{agentType:e,ok:!0,phase:"completed",installedPath:p,installedVersion:d,durationMs:s,output:"",environment:i}}const h=l.prerequisites??[];let r=[];if(h.length>0){m.info("installer",`Checking prerequisites for ${e}: ${h.join(", ")}`),r=await y(h,this.os),m.info("installer",`Prerequisites: ${r.map(a=>`${a.label}=${a.met?a.version:"missing"}`).join(", ")}`);const s=v(r);if(s.length>0){const a=s.map(g=>`${g.label}${g.minVersion?` >= ${g.minVersion}`:""}`).join(", ");if(!n.dryRun){if(n.skipPrereqInstall)return this.fail(e,"preflight",t,new u("PREREQ_MISSING",`Missing prerequisites: ${a}. Install them first or retry without skipPrereqInstall.`),i,r);const g=s.map($=>`${$.label}${$.minVersion?` >= ${$.minVersion}`:""}`);m.info("installer",`Will auto-install prerequisites: ${g.join(", ")}`),this.setProgress(e,"installing_prereq",t,s[0].label,g);const I=await C(s,this.os);if(!I.allOk){const $=I.results.find(M=>!M.ok),L=$?`Failed to install prerequisite ${$.prereq.label}: ${$.output}`:"Prerequisite installation failed";return this.fail(e,"installing_prereq",t,new u("PREREQ_INSTALL_FAILED",L),i,r)}m.info("installer",`All prerequisites installed for ${e}`),r=await y(h,this.os)}}}if(n.dryRun){this.activeInstalls.delete(e);const s=v(r),a=this.getManualHint(e,this.os),g={agentType:e,environment:i,canInstall:!0,alreadyInstalled:!!p,installedPath:p,installedVersion:d,installCommand:U(l),installMode:l.mode,prerequisites:r,missingPrerequisites:s,fallbackCommand:l.fallback?.command??null,manualHint:a},I=b({agentType:e,os:this.os,env:i,missingPrereqs:s});return{agentType:e,ok:!0,phase:"completed",durationMs:Date.now()-t,output:"dry-run: no commands executed",environment:i,dryRun:g,manualGuide:I}}this.setProgress(e,"installing",t),m.info("installer",`Installing ${e}: ${l.command}`);let f;try{f=await this.executeWithRetry(l,e,t,n.timeoutMs)}catch(s){if(l.fallback&&s instanceof u&&(s.code==="INSTALL_FAILED"||s.code==="INSTALL_TIMEOUT")){m.info("installer",`Primary install (${l.command}) failed: ${s.message}`),m.info("installer",`Trying fallback: ${l.fallback.command}`),this.setProgress(e,"installing",t);try{f=await this.executeWithRetry(l.fallback,e,t,n.timeoutMs),f=`[primary failed, fallback succeeded]
3
- ${f}`}catch(a){const g=s.message,I=a instanceof u?a.message:String(a),$=a instanceof u?a.output:void 0,L=X(s.output,$);return this.fail(e,"installing",t,new u("FALLBACK_EXHAUSTED",`Both primary and fallback install methods failed.
1
+ import{execFile as R,spawn as _}from"node:child_process";import{log as m}from"../log/logger.js";import{resolveCliPath as P,getCliVersion as k,invalidateCliPathCache as x}from"../util/cli-probe.js";import{getInstallCommand as S,getCliBinary as O,isKnownAgent as D,detectPlatformOS as A,formatInstallCommand as U}from"./registry.js";import{checkPrerequisites as y,getMissingPrerequisites as v}from"./preflight.js";import{installMissingPrerequisites as C}from"./prereq-installer.js";import{detectEnvironment as V,formatEnvironmentInfo as F,isEnvironmentSupported as q}from"./env-detect.js";import{generateManualGuide as b}from"./manual-guide.js";import{npmInstallWithMirror as j,isTransientInstallError as H}from"./npm-registry.js";import{getAllAgentInstallInfo as G}from"./registry.js";class u extends Error{code;output;constructor(n,t,e){super(t),this.name="InstallerError",this.code=n,this.output=e}}const T=64*1024,B=20,N=2,W=3e3;class le{os;activeInstalls=new Map;constructor(){this.os=A()}listInstallable(){return{platform:this.os,agents:G(this.os)}}getProgress(n){return this.activeInstalls.get(n)}isInProgress(n){return this.activeInstalls.has(n)}async install(n){const{agentType:t}=n,e=Date.now();if(this.activeInstalls.has(t))return this.fail(t,"preflight",e,new u("INSTALL_IN_PROGRESS",`${t} is already being installed`));try{return await this._doInstall(n,e)}catch(i){this.activeInstalls.delete(t);const o=i instanceof Error?i.message:String(i);return m.error("installer",`${t} install unexpected error: ${o}`),{agentType:t,ok:!1,phase:"failed",error:{code:"INTERNAL",message:`Unexpected error: ${o}`},durationMs:Date.now()-e,output:""}}}async _doInstall(n,t){const{agentType:e}=n;let i;try{i=await V()}catch(s){const a=s instanceof Error?s.message:String(s);return this.fail(e,"preflight",t,new u("INTERNAL",`Environment detection failed: ${a}`))}m.info("installer",`Install request: ${e}
2
+ ${F(i)}`);const o=q(i);if(!o.supported)return this.fail(e,"preflight",t,new u("ENVIRONMENT_UNSUPPORTED",`Current environment is not supported for automatic installation: ${o.reason}. Please install ${e} manually.`),i);if(this.setProgress(e,"preflight",t),!D(e))return this.fail(e,"preflight",t,new u("UNKNOWN_AGENT",`Unknown agent type: ${e}`),i);const l=S(e,this.os);if(!l){const s=this.getManualHint(e,this.os),a=s?`Installation of ${e} is not supported on ${this.os}. ${s}`:`Installation of ${e} is not supported on ${this.os}`;return this.fail(e,"preflight",t,new u("UNSUPPORTED_OS",a),i)}const c=O(e),p=await P(c),d=p?(await k(p)).version:null;if(p&&!n.force&&!n.dryRun){this.activeInstalls.delete(e);const s=Date.now()-t;return m.info("installer",`${e} already installed at ${p}${d?` (v${d})`:""}`),{agentType:e,ok:!0,phase:"completed",installedPath:p,installedVersion:d,durationMs:s,output:"",environment:i}}const h=l.prerequisites??[];let r=[];if(h.length>0){m.info("installer",`Checking prerequisites for ${e}: ${h.join(", ")}`),r=await y(h,this.os),m.info("installer",`Prerequisites: ${r.map(a=>`${a.label}=${a.met?a.version:"missing"}`).join(", ")}`);const s=v(r);if(s.length>0){const a=s.map(g=>`${g.label}${g.minVersion?` >= ${g.minVersion}`:""}`).join(", ");if(!n.dryRun){if(n.skipPrereqInstall)return this.fail(e,"preflight",t,new u("PREREQ_MISSING",`Missing prerequisites: ${a}. Install them first or retry without skipPrereqInstall.`),i,r);const g=s.map(w=>`${w.label}${w.minVersion?` >= ${w.minVersion}`:""}`);m.info("installer",`Will auto-install prerequisites: ${g.join(", ")}`),this.setProgress(e,"installing_prereq",t,s[0].label,g);const I=await C(s,this.os);if(!I.allOk){const w=I.results.find(M=>!M.ok),L=w?`Failed to install prerequisite ${w.prereq.label}: ${w.output}`:"Prerequisite installation failed";return this.fail(e,"installing_prereq",t,new u("PREREQ_INSTALL_FAILED",L),i,r)}m.info("installer",`All prerequisites installed for ${e}`),r=await y(h,this.os)}}}if(n.dryRun){this.activeInstalls.delete(e);const s=v(r),a=this.getManualHint(e,this.os),g={agentType:e,environment:i,canInstall:!0,alreadyInstalled:!!p,installedPath:p,installedVersion:d,installCommand:U(l),installMode:l.mode,prerequisites:r,missingPrerequisites:s,fallbackCommand:l.fallback?.command??null,manualHint:a},I=b({agentType:e,os:this.os,env:i,missingPrereqs:s});return{agentType:e,ok:!0,phase:"completed",durationMs:Date.now()-t,output:"dry-run: no commands executed",environment:i,dryRun:g,manualGuide:I}}this.setProgress(e,"installing",t),m.info("installer",`Installing ${e}: ${l.command}`);let f;try{f=await this.executeWithRetry(l,e,t,n.timeoutMs)}catch(s){if(l.fallback&&s instanceof u&&(s.code==="INSTALL_FAILED"||s.code==="INSTALL_TIMEOUT")){m.info("installer",`Primary install (${l.command}) failed: ${s.message}`),m.info("installer",`Trying fallback: ${l.fallback.command}`),this.setProgress(e,"installing",t);try{f=await this.executeWithRetry(l.fallback,e,t,n.timeoutMs),f=`[primary failed, fallback succeeded]
3
+ ${f}`}catch(a){const g=s.message,I=a instanceof u?a.message:String(a),w=a instanceof u?a.output:void 0,L=X(s.output,w);return this.fail(e,"installing",t,new u("FALLBACK_EXHAUSTED",`Both primary and fallback install methods failed.
4
4
  Primary: ${g}
5
5
  Fallback: ${I}`,L),i,r)}}else return s instanceof u?this.fail(e,"installing",t,new u(s.code,s.message,s.output),i,r):this.fail(e,"installing",t,new u("INTERNAL",s instanceof Error?s.message:String(s)),i,r)}{const s=(f??"").trim().split(`
6
6
  `).slice(-12).join(`
7
7
  `);m.info("installer",`${e} \u5B89\u88C5\u547D\u4EE4\u8F93\u51FA(\u5C3E\u90E8):
8
- ${s||"<\u7A7A>"}`)}if(x(),!n.skipVerify&&!l.skipVerification){this.setProgress(e,"verifying",t),m.info("installer",`Verifying ${e} installation...`);const s=await P(c);if(!s)return this.fail(e,"verifying",t,new u("VERIFICATION_FAILED",`${c} not found on PATH after installation. You may need to open a new terminal or run: source ~/.zshrc (or ~/.bashrc)`),i,r);let{version:a,error:g}=await k(s);a===null&&g&&(await this.sleep(1e3),{version:a,error:g}=await k(s));const I=Date.now()-t;return this.activeInstalls.delete(e),m.info("installer",`${e} installed successfully at ${s} (v${a??"unknown"}, ${I}ms)`),{agentType:e,ok:!0,phase:"completed",installedPath:s,installedVersion:a,durationMs:I,output:f,prerequisites:r.length>0?r:void 0,environment:i}}const E=Date.now()-t;return this.activeInstalls.delete(e),m.info("installer",`${e} install command completed (${E}ms, verification skipped)`),{agentType:e,ok:!0,phase:"completed",installedPath:null,installedVersion:null,durationMs:E,output:f,prerequisites:r.length>0?r:void 0,environment:i}}getManualHint(n,t){const i=S(n,t)?.fallback,l={claude:"https://docs.anthropic.com/en/docs/claude-code/overview",codex:"https://github.com/openai/codex",qwen:"https://github.com/QwenLM/qwen-code",cursor:"https://cursor.com/docs/cli/installation",copilot:"https://github.com/github/copilot-cli",kiro:"https://kiro.dev/docs/cli/",openclaw:"https://github.com/openclaw/openclaw",reasonix:"https://github.com/esengine/DeepSeek-Reasonix",deepseek:"https://www.npmjs.com/package/@deepseek-ai/dsh"}[n],c=[];return l&&c.push(`Docs: ${l}`),i&&c.push(`Alternative: ${i.command}`),c.length>0?c.join(" | "):null}setProgress(n,t,e,i,o){this.activeInstalls.set(n,{agentType:n,phase:t,startedAt:e,elapsedMs:Date.now()-e,...i?{currentPrereq:i}:{},...o?{pendingPrereqs:o}:{}})}fail(n,t,e,i,o,l,c){const p=c??i.output??this.activeInstalls.get(n)?.outputTail??"";this.activeInstalls.delete(n),m.error("installer",`${n} install failed at ${t}: ${i.message}`);const d=l?v(l):[],h=b({agentType:n,os:this.os,env:o??{platform:this.os,osVersion:"unknown",arch:process.arch,shell:process.env.SHELL??null,nodeVersion:null,npmVersion:null,isDocker:!1,isCI:!1},missingPrereqs:d,primaryFailed:t==="installing",fallbackFailed:i.code==="FALLBACK_EXHAUSTED",error:i.message});return{agentType:n,ok:!1,phase:"failed",error:{code:i.code,message:i.message},durationMs:Date.now()-e,output:p,environment:o,prerequisites:l,manualGuide:h}}async executeWithRetry(n,t,e,i){let o=null;for(let l=0;l<=N;l++)try{return l>0&&(m.info("installer",`Retry ${l}/${N} for ${t}...`),await this.sleep(W)),await this.executeCommand(n,t,e,i)}catch(c){if(o=c instanceof u?c:new u("INTERNAL",String(c)),!(o.code==="INSTALL_TIMEOUT"||o.code==="INSTALL_FAILED"&&G(o.message))||l>=N)throw o;m.info("installer",`Attempt ${l+1} failed (retryable): ${o.message}`)}throw o??new u("INTERNAL","Unexpected retry loop exit")}sleep(n){return new Promise(t=>setTimeout(t,n))}executeCommand(n,t,e,i){const o=i??n.timeoutMs;switch(n.mode){case"npm":return this.executeNpm(n.npmPackage,o,t,e);case"shell":return this.executeShell(n.command,o,t,e);case"exec":return this.executeExec(n.command,n.execArgs??[],o,t,e);default:return Promise.reject(new u("INTERNAL",`Unknown install mode: ${n.mode}`))}}async executeNpm(n,t,e,i){try{const{output:o,registry:l}=await j(n,t,T);return m.info("installer",`npm install ${n} succeeded via ${l}`),o}catch(o){const l=o instanceof Error?o.message:String(o),c=K(o);throw c&&this.updateOutputTail(e,i,c),l.includes("timed out")||l.includes("ETIMEDOUT")?new u("INSTALL_TIMEOUT",`npm install timed out (tried all mirrors): ${l}`,c):new u("INSTALL_FAILED",`npm install failed (tried all mirrors): ${l}`,c)}}executeShell(n,t,e,i){return new Promise((o,l)=>{const c=process.platform==="win32",p=c?"cmd.exe":"bash",d=c?["/d","/c",n]:["-c",`set -o pipefail; ${n}`];m.info("installer",`exec: ${p} ${d.join(" ")}`);const h=_(p,d,{timeout:t,stdio:["ignore","pipe","pipe"],...c?{windowsVerbatimArguments:!0}:{},env:{...process.env,NONINTERACTIVE:"1",DEBIAN_FRONTEND:"noninteractive"}});let r="",f=!1;const E=setTimeout(()=>{f=!0;try{h.kill("SIGTERM")}catch{}setTimeout(()=>{try{h.kill("SIGKILL")}catch{}},5e3).unref()},t);h.stdout?.on("data",s=>{const a=s.toString("utf-8");r+=a,r.length>T&&(r=r.slice(-T)),this.updateOutputTail(e,i,r)}),h.stderr?.on("data",s=>{const a=s.toString("utf-8");r+=a,r.length>T&&(r=r.slice(-T)),this.updateOutputTail(e,i,r)}),h.on("error",s=>{clearTimeout(E),l(new u("INSTALL_FAILED",`Spawn error: ${s.message}`))}),h.on("close",s=>{if(clearTimeout(E),f){l(new u("INSTALL_TIMEOUT",`Install timed out after ${t/1e3}s`,r.trim()));return}if(s!==0){const a=r.slice(-1024);l(new u("INSTALL_FAILED",`Process exited with code ${s}: ${a}`,r.trim()));return}o(r.trim())})})}executeExec(n,t,e,i,o){return new Promise((l,c)=>{m.info("installer",`exec: ${n} ${t.join(" ")}`);const p=R(n,t,{timeout:e,maxBuffer:T},(d,h,r)=>{const f=`${h??""}
8
+ ${s||"<\u7A7A>"}`)}if(x(),!n.skipVerify&&!l.skipVerification){this.setProgress(e,"verifying",t),m.info("installer",`Verifying ${e} installation...`);const s=await P(c);if(!s)return this.fail(e,"verifying",t,new u("VERIFICATION_FAILED",`${c} not found on PATH after installation. You may need to open a new terminal or run: source ~/.zshrc (or ~/.bashrc)`),i,r);let{version:a,error:g}=await k(s);a===null&&g&&(await this.sleep(1e3),{version:a,error:g}=await k(s));const I=Date.now()-t;return this.activeInstalls.delete(e),m.info("installer",`${e} installed successfully at ${s} (v${a??"unknown"}, ${I}ms)`),{agentType:e,ok:!0,phase:"completed",installedPath:s,installedVersion:a,durationMs:I,output:f,prerequisites:r.length>0?r:void 0,environment:i}}const E=Date.now()-t;return this.activeInstalls.delete(e),m.info("installer",`${e} install command completed (${E}ms, verification skipped)`),{agentType:e,ok:!0,phase:"completed",installedPath:null,installedVersion:null,durationMs:E,output:f,prerequisites:r.length>0?r:void 0,environment:i}}getManualHint(n,t){const i=S(n,t)?.fallback,l={claude:"https://docs.anthropic.com/en/docs/claude-code/overview",codex:"https://github.com/openai/codex",qwen:"https://github.com/QwenLM/qwen-code",cursor:"https://cursor.com/docs/cli/installation",copilot:"https://github.com/github/copilot-cli",kiro:"https://kiro.dev/docs/cli/",openclaw:"https://github.com/openclaw/openclaw",reasonix:"https://github.com/esengine/DeepSeek-Reasonix",deepseek:"https://www.npmjs.com/package/@deepseek-ai/dsh"}[n],c=[];return l&&c.push(`Docs: ${l}`),i&&c.push(`Alternative: ${i.command}`),c.length>0?c.join(" | "):null}setProgress(n,t,e,i,o){this.activeInstalls.set(n,{agentType:n,phase:t,startedAt:e,elapsedMs:Date.now()-e,...i?{currentPrereq:i}:{},...o?{pendingPrereqs:o}:{}})}fail(n,t,e,i,o,l,c){const p=c??i.output??this.activeInstalls.get(n)?.outputTail??"";this.activeInstalls.delete(n),m.error("installer",`${n} install failed at ${t}: ${i.message}`);const d=l?v(l):[],h=b({agentType:n,os:this.os,env:o??{platform:this.os,osVersion:"unknown",arch:process.arch,shell:process.env.SHELL??null,nodeVersion:null,npmVersion:null,isDocker:!1,isCI:!1},missingPrereqs:d,primaryFailed:t==="installing",fallbackFailed:i.code==="FALLBACK_EXHAUSTED",error:i.message});return{agentType:n,ok:!1,phase:"failed",error:{code:i.code,message:i.message},durationMs:Date.now()-e,output:p,environment:o,prerequisites:l,manualGuide:h}}async executeWithRetry(n,t,e,i){let o=null;for(let l=0;l<=N;l++)try{return l>0&&(m.info("installer",`Retry ${l}/${N} for ${t}...`),await this.sleep(W)),await this.executeCommand(n,t,e,i)}catch(c){if(o=c instanceof u?c:new u("INTERNAL",String(c)),!(o.code==="INSTALL_TIMEOUT"||o.code==="INSTALL_FAILED"&&H(o.message))||l>=N)throw o;m.info("installer",`Attempt ${l+1} failed (retryable): ${o.message}`)}throw o??new u("INTERNAL","Unexpected retry loop exit")}sleep(n){return new Promise(t=>setTimeout(t,n))}executeCommand(n,t,e,i){const o=i??n.timeoutMs;switch(n.mode){case"npm":return this.executeNpm(n.npmPackage,o,t,e);case"shell":return this.executeShell(n.command,o,t,e);case"exec":return this.executeExec(n.command,n.execArgs??[],o,t,e);default:return Promise.reject(new u("INTERNAL",`Unknown install mode: ${n.mode}`))}}async executeNpm(n,t,e,i){try{const{output:o,registry:l}=await j(n,t,T);return m.info("installer",`npm install ${n} succeeded via ${l}`),o}catch(o){const l=o instanceof Error?o.message:String(o),c=K(o);throw c&&this.updateOutputTail(e,i,c),l.includes("timed out")||l.includes("ETIMEDOUT")?new u("INSTALL_TIMEOUT",`npm install timed out (tried all mirrors): ${l}`,c):new u("INSTALL_FAILED",`npm install failed (tried all mirrors): ${l}`,c)}}executeShell(n,t,e,i){return new Promise((o,l)=>{const c=process.platform==="win32",p=c?"cmd.exe":"bash",d=c?["/d","/c",n]:["-c",`set -o pipefail; ${n}`];m.info("installer",`exec: ${p} ${d.join(" ")}`);const h=_(p,d,{timeout:t,stdio:["ignore","pipe","pipe"],windowsHide:!0,...c?{windowsVerbatimArguments:!0}:{},env:{...process.env,NONINTERACTIVE:"1",DEBIAN_FRONTEND:"noninteractive"}});let r="",f=!1;const E=setTimeout(()=>{f=!0;try{h.kill("SIGTERM")}catch{}setTimeout(()=>{try{h.kill("SIGKILL")}catch{}},5e3).unref()},t);h.stdout?.on("data",s=>{const a=s.toString("utf-8");r+=a,r.length>T&&(r=r.slice(-T)),this.updateOutputTail(e,i,r)}),h.stderr?.on("data",s=>{const a=s.toString("utf-8");r+=a,r.length>T&&(r=r.slice(-T)),this.updateOutputTail(e,i,r)}),h.on("error",s=>{clearTimeout(E),l(new u("INSTALL_FAILED",`Spawn error: ${s.message}`))}),h.on("close",s=>{if(clearTimeout(E),f){l(new u("INSTALL_TIMEOUT",`Install timed out after ${t/1e3}s`,r.trim()));return}if(s!==0){const a=r.slice(-1024);l(new u("INSTALL_FAILED",`Process exited with code ${s}: ${a}`,r.trim()));return}o(r.trim())})})}executeExec(n,t,e,i,o){return new Promise((l,c)=>{m.info("installer",`exec: ${n} ${t.join(" ")}`);const p=R(n,t,{timeout:e,maxBuffer:T,windowsHide:!0},(d,h,r)=>{const f=`${h??""}
9
9
  ${r??""}`.trim();if(f&&this.updateOutputTail(i,o,f),d){if(d.killed)c(new u("INSTALL_TIMEOUT",`${n} timed out after ${e/1e3}s`,f));else{const E=f||d.message;c(new u("INSTALL_FAILED",`${n} failed: ${E}`,f))}return}l(f)});this.trackOutput(p,i,o)})}trackOutput(n,t,e){n.on("close",()=>{const i=this.activeInstalls.get(t);i&&(i.elapsedMs=Date.now()-e)})}updateOutputTail(n,t,e){const o=e.split(`
10
- `).slice(-H).join(`
11
- `),l=this.activeInstalls.get(n);l&&(l.outputTail=o,l.elapsedMs=Date.now()-t)}}function K(w){if(w&&typeof w=="object"&&"output"in w){const n=w.output;return typeof n=="string"?n:""}return""}function X(...w){return w.map(t=>t?.trim()).filter(t=>!!t).join(`
10
+ `).slice(-B).join(`
11
+ `),l=this.activeInstalls.get(n);l&&(l.outputTail=o,l.elapsedMs=Date.now()-t)}}function K($){if($&&typeof $=="object"&&"output"in $){const n=$.output;return typeof n=="string"?n:""}return""}function X(...$){return $.map(t=>t?.trim()).filter(t=>!!t).join(`
12
12
  `)||void 0}export{le as AgentInstaller,u as InstallerError};
@@ -1,4 +1,4 @@
1
- import{execFile as d}from"node:child_process";import{promisify as x}from"node:util";import{log as b}from"../log/logger.js";import{probeUrls as $}from"./speed-test.js";const T=x(d),I=1e4;class E extends Error{output;constructor(r,e){super(r),this.name="NpmInstallError",this.output=e}}const u=[{id:"official",label:"npm \u5B98\u65B9",url:"https://registry.npmjs.org"},{id:"npmmirror",label:"npmmirror (\u6DD8\u5B9D\u955C\u50CF)",url:"https://registry.npmmirror.com"}];async function O(){const t=await $(u.map(e=>({url:e.url,label:e.label})),5e3),r=[];for(const e of t)if(e.reachable){const n=u.find(i=>i.url===e.url);n&&r.push(n)}for(const e of t)if(!e.reachable){const n=u.find(i=>i.url===e.url);n&&!r.includes(n)&&r.push(n)}for(const e of u)r.includes(e)||r.push(e);return r}async function D(){try{const t=process.platform==="win32",r=t?"cmd.exe":"npm",e=t?["/c","npm","config","get","registry"]:["config","get","registry"],{stdout:n}=await T(r,e,{timeout:I,encoding:"utf-8"});return n.trim()}catch{return"https://registry.npmjs.org"}}async function F(t,r,e,n){const i=await O();if(i.length===0)throw new Error("All npm registries are unreachable. Check your network connection.");let a="",c="";for(const o of i)try{return b.info("installer",`npm install ${t} using ${o.label} (${o.url})`),{output:await R(t,o.url,r,e,n),registry:o.label}}catch(s){const l=s instanceof Error?s.message:String(s),p=k(s);if(a=l,c=C(`${c}
1
+ import{execFile as E}from"node:child_process";import{promisify as x}from"node:util";import{log as b}from"../log/logger.js";import{probeUrls as $}from"./speed-test.js";const T=x(E),I=1e4;class d extends Error{output;constructor(r,e){super(r),this.name="NpmInstallError",this.output=e}}const u=[{id:"official",label:"npm \u5B98\u65B9",url:"https://registry.npmjs.org"},{id:"npmmirror",label:"npmmirror (\u6DD8\u5B9D\u955C\u50CF)",url:"https://registry.npmmirror.com"}];async function O(){const t=await $(u.map(e=>({url:e.url,label:e.label})),5e3),r=[];for(const e of t)if(e.reachable){const n=u.find(i=>i.url===e.url);n&&r.push(n)}for(const e of t)if(!e.reachable){const n=u.find(i=>i.url===e.url);n&&!r.includes(n)&&r.push(n)}for(const e of u)r.includes(e)||r.push(e);return r}async function D(){try{const t=process.platform==="win32",r=t?"cmd.exe":"npm",e=t?["/c","npm","config","get","registry"]:["config","get","registry"],{stdout:n}=await T(r,e,{timeout:I,encoding:"utf-8"});return n.trim()}catch{return"https://registry.npmjs.org"}}async function F(t,r,e,n){const i=await O();if(i.length===0)throw new Error("All npm registries are unreachable. Check your network connection.");let a="",c="";for(const o of i)try{return b.info("installer",`npm install ${t} using ${o.label} (${o.url})`),{output:await R(t,o.url,r,e,n),registry:o.label}}catch(s){const l=s instanceof Error?s.message:String(s),p=k(s);if(a=l,c=C(`${c}
2
2
  [${o.label}] ${l}
3
- ${p}`.trim(),e),b.info("installer",`${o.label} failed: ${l.slice(0,200)}`),!N(l))throw new E(l,c)}throw new E(`npm install failed on all registries. Last error: ${a}`,c)}function N(t){return/ECONNRESET|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ERR_SOCKET_TIMEOUT|getaddrinfo|socket hang up|network|fetch failed|timed out|tunneling socket|self.signed|404|ETARGET|No matching version|notarget/i.test(t)}function j(t){return/\bEBUSY\b|resource busy or locked|EPERM[^\n]*\brename\b|\bELOCKED\b/i.test(t)}function R(t,r,e,n,i){return new Promise((a,c)=>{const o=["install","-g",t,"--registry",r,"--prefer-online","--no-audit","--no-fund"];i?.prefix&&o.push("--prefix",i.prefix);const s=process.platform==="win32",l=s?"cmd.exe":"npm",p=s?["/c","npm",...o]:o;d(l,p,{timeout:e,maxBuffer:n},(m,h,y)=>{const f=`${h??""}
4
- ${y??""}`.trim();if(m){const g=f||m.message,w=m.killed===!0?`ETIMEDOUT: npm install exceeded ${e}ms (registry likely unreachable): ${g}`:g;c(new E(w,f||g));return}a(f)})})}function k(t){if(t&&typeof t=="object"&&"output"in t){const r=t.output;return typeof r=="string"?r:""}return""}function C(t,r){return t.length<=r?t:t.slice(-r)}function G(t){return u.map(r=>({label:r.label,command:`npm install -g ${t} --registry ${r.url}`}))}export{u as NPM_REGISTRIES,E as NpmInstallError,D as getCurrentRegistry,G as getMirrorInstallCommands,N as isRetriableRegistryError,j as isTransientInstallError,F as npmInstallWithMirror,O as probeRegistries};
3
+ ${p}`.trim(),e),b.info("installer",`${o.label} failed: ${l.slice(0,200)}`),!N(l))throw new d(l,c)}throw new d(`npm install failed on all registries. Last error: ${a}`,c)}function N(t){return/ECONNRESET|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ERR_SOCKET_TIMEOUT|getaddrinfo|socket hang up|network|fetch failed|timed out|tunneling socket|self.signed|404|ETARGET|No matching version|notarget/i.test(t)}function j(t){return/\bEBUSY\b|resource busy or locked|EPERM[^\n]*\brename\b|\bELOCKED\b/i.test(t)}function R(t,r,e,n,i){return new Promise((a,c)=>{const o=["install","-g",t,"--registry",r,"--prefer-online","--no-audit","--no-fund"];i?.prefix&&o.push("--prefix",i.prefix);const s=process.platform==="win32",l=s?"cmd.exe":"npm",p=s?["/c","npm",...o]:o;E(l,p,{timeout:e,maxBuffer:n,windowsHide:!0},(m,h,y)=>{const f=`${h??""}
4
+ ${y??""}`.trim();if(m){const g=f||m.message,w=m.killed===!0?`ETIMEDOUT: npm install exceeded ${e}ms (registry likely unreachable): ${g}`:g;c(new d(w,f||g));return}a(f)})})}function k(t){if(t&&typeof t=="object"&&"output"in t){const r=t.output;return typeof r=="string"?r:""}return""}function C(t,r){return t.length<=r?t:t.slice(-r)}function G(t){return u.map(r=>({label:r.label,command:`npm install -g ${t} --registry ${r.url}`}))}export{u as NPM_REGISTRIES,d as NpmInstallError,D as getCurrentRegistry,G as getMirrorInstallCommands,N as isRetriableRegistryError,j as isTransientInstallError,F as npmInstallWithMirror,O as probeRegistries};
@@ -1,3 +1,3 @@
1
1
  import{spawn as f}from"node:child_process";import{log as d}from"../log/logger.js";import{checkPrerequisite as b}from"./preflight.js";const u=64*1024,h={node:{id:"node",label:"Node.js",macos:"NONINTERACTIVE=1 CI=1 brew install node 2>&1 && brew link node --overwrite 2>/dev/null; command -v node >/dev/null 2>&1 || (npm install -g n 2>&1 && n lts 2>&1)",linux:'curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-latest-lts --skip-shell 2>&1 && eval "$(fnm env)" && fnm install --lts 2>&1 && fnm use --lts 2>&1',windows:"winget install Schniz.fnm --accept-source-agreements --accept-package-agreements",mode:"shell",timeoutMs:18e4},npm:{id:"npm",label:"npm",macos:null,linux:null,windows:null,mode:"exec",timeoutMs:6e4},curl:{id:"curl",label:"curl",macos:null,linux:'sudo apt-get install -y -qq curl 2>/dev/null || sudo dnf install -y curl 2>/dev/null || sudo pacman -S --noconfirm curl 2>/dev/null || echo "curl install skipped: no supported package manager"',windows:null,mode:"shell",timeoutMs:6e4},gh:{id:"gh",label:"GitHub CLI",macos:"NONINTERACTIVE=1 brew install gh 2>/dev/null",linux:`(command -v apt-get >/dev/null 2>&1 && (sudo mkdir -p /etc/apt/keyrings 2>/dev/null; wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg 2>/dev/null | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null 2>&1; echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null 2>&1; sudo apt-get update -qq 2>/dev/null; sudo apt-get install -y -qq gh 2>/dev/null)) || (command -v dnf >/dev/null 2>&1 && sudo dnf install -y 'dnf-command(config-manager)' 2>/dev/null && sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo 2>/dev/null && sudo dnf install -y gh 2>/dev/null) || echo "gh install skipped: no supported package manager"`,windows:"winget install GitHub.cli --accept-source-agreements --accept-package-agreements",mode:"shell",timeoutMs:18e4},brew:{id:"brew",label:"Homebrew",macos:'NONINTERACTIVE=1 CI=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',linux:'NONINTERACTIVE=1 CI=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',windows:null,mode:"shell",timeoutMs:3e5}};async function w(e,t){const i=h[e.id];if(!i)return{ok:!1,output:`No install spec for ${e.id}`};const n=i[t];if(!n){const l=g(e.id,t);return{ok:!1,output:`${e.label} cannot be auto-installed on ${t}.${l?` Please install manually: ${l}`:""}`}}d.info("installer",`Installing prerequisite ${e.label}: ${n}`);try{const l=await k(n,i.timeoutMs);return d.info("installer",`Prerequisite ${e.label} installed successfully`),{ok:!0,output:l}}catch(l){const a=l instanceof Error?l.message:String(l);d.error("installer",`Failed to install prerequisite ${e.label}: ${a}`);const c=g(e.id,t),o=e.id==="brew"&&(a.includes("code 1")||a.includes("sudo"))?`
2
2
  Note: Homebrew installation may require administrator (sudo) password. Try running: NONINTERACTIVE=1 CI=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" in your terminal.`:"";return{ok:!1,output:`${a}${o}${c?`
3
- Manual install: ${c}`:""}`}}}async function T(e,t){const i=[];for(const n of e){const l=await w(n,t);if(i.push({prereq:n,ok:l.ok,output:l.output}),!l.ok)return{allOk:!1,results:i};if(!(await b(n.id,t)).met)return i.push({prereq:{...n,met:!1},ok:!1,output:`${n.label} install command succeeded but verification failed. This usually means you need to open a new terminal or run: source ~/.bashrc (or ~/.zshrc)`}),{allOk:!1,results:i}}return{allOk:!0,results:i}}function E(e,t){return h[e]?.[t]??null}function g(e,t){switch(e){case"node":return t==="windows"?"Install Node.js LTS from https://nodejs.org or run: winget install OpenJS.NodeJS.LTS":"Install Node.js LTS from https://nodejs.org or run: brew install node (macOS) / follow instructions at https://fnm.vercel.app (Linux)";case"npm":return"npm comes bundled with Node.js. Install Node.js first.";case"curl":return t==="windows"?"curl is built into Windows 10+. For older versions, install from https://curl.se/windows/":t==="macos"?"curl is pre-installed on macOS. If missing, install Xcode Command Line Tools: xcode-select --install":"Install curl: sudo apt install curl (Debian/Ubuntu) or sudo dnf install curl (Fedora/RHEL)";case"gh":return"Install GitHub CLI from https://cli.github.com or follow instructions at https://github.com/cli/cli#installation";case"brew":return'Install Homebrew from https://brew.sh or run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"';default:return null}}function k(e,t){return new Promise((i,n)=>{const l=process.platform==="win32",o=f(l?"cmd.exe":"sh",l?["/d","/s","/c",e]:["-c",e],{timeout:t,stdio:["ignore","pipe","pipe"],env:{...process.env,NONINTERACTIVE:"1",DEBIAN_FRONTEND:"noninteractive"}});let s="",m=!1;const p=setTimeout(()=>{m=!0,o.kill("SIGTERM"),setTimeout(()=>{try{o.kill("SIGKILL")}catch{}},5e3).unref()},t);o.stdout?.on("data",r=>{s+=r.toString("utf-8"),s.length>u&&(s=s.slice(-u))}),o.stderr?.on("data",r=>{s+=r.toString("utf-8"),s.length>u&&(s=s.slice(-u))}),o.on("error",r=>{clearTimeout(p),n(r)}),o.on("close",r=>{if(clearTimeout(p),s.length>u&&(s=s.slice(-u)),m){n(new Error(`Timed out after ${t/1e3}s`));return}if(r!==0){n(new Error(`Process exited with code ${r}: ${s.slice(-1024)}`));return}i(s.trim())})})}export{E as getPrereqInstallCommand,g as getPrereqManualInstructions,T as installMissingPrerequisites,w as installPrerequisite};
3
+ Manual install: ${c}`:""}`}}}async function T(e,t){const i=[];for(const n of e){const l=await w(n,t);if(i.push({prereq:n,ok:l.ok,output:l.output}),!l.ok)return{allOk:!1,results:i};if(!(await b(n.id,t)).met)return i.push({prereq:{...n,met:!1},ok:!1,output:`${n.label} install command succeeded but verification failed. This usually means you need to open a new terminal or run: source ~/.bashrc (or ~/.zshrc)`}),{allOk:!1,results:i}}return{allOk:!0,results:i}}function E(e,t){return h[e]?.[t]??null}function g(e,t){switch(e){case"node":return t==="windows"?"Install Node.js LTS from https://nodejs.org or run: winget install OpenJS.NodeJS.LTS":"Install Node.js LTS from https://nodejs.org or run: brew install node (macOS) / follow instructions at https://fnm.vercel.app (Linux)";case"npm":return"npm comes bundled with Node.js. Install Node.js first.";case"curl":return t==="windows"?"curl is built into Windows 10+. For older versions, install from https://curl.se/windows/":t==="macos"?"curl is pre-installed on macOS. If missing, install Xcode Command Line Tools: xcode-select --install":"Install curl: sudo apt install curl (Debian/Ubuntu) or sudo dnf install curl (Fedora/RHEL)";case"gh":return"Install GitHub CLI from https://cli.github.com or follow instructions at https://github.com/cli/cli#installation";case"brew":return'Install Homebrew from https://brew.sh or run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"';default:return null}}function k(e,t){return new Promise((i,n)=>{const l=process.platform==="win32",o=f(l?"cmd.exe":"sh",l?["/d","/s","/c",e]:["-c",e],{timeout:t,stdio:["ignore","pipe","pipe"],windowsHide:!0,env:{...process.env,NONINTERACTIVE:"1",DEBIAN_FRONTEND:"noninteractive"}});let s="",m=!1;const p=setTimeout(()=>{m=!0,o.kill("SIGTERM"),setTimeout(()=>{try{o.kill("SIGKILL")}catch{}},5e3).unref()},t);o.stdout?.on("data",r=>{s+=r.toString("utf-8"),s.length>u&&(s=s.slice(-u))}),o.stderr?.on("data",r=>{s+=r.toString("utf-8"),s.length>u&&(s=s.slice(-u))}),o.on("error",r=>{clearTimeout(p),n(r)}),o.on("close",r=>{if(clearTimeout(p),s.length>u&&(s=s.slice(-u)),m){n(new Error(`Timed out after ${t/1e3}s`));return}if(r!==0){n(new Error(`Process exited with code ${r}: ${s.slice(-1024)}`));return}i(s.trim())})})}export{E as getPrereqInstallCommand,g as getPrereqManualInstructions,T as installMissingPrerequisites,w as installPrerequisite};
@@ -1 +1 @@
1
- import{execFile as h}from"node:child_process";import{existsSync as a}from"node:fs";import{readFile as g}from"node:fs/promises";import{homedir as f}from"node:os";import{delimiter as w,dirname as S,join as l}from"node:path";import{fileURLToPath as I}from"node:url";const R=3e4,v="hermes-profile-relay.py";class i extends Error{code;constructor(o,n){super(o),this.code=n,this.name="HermesProfileRelayError"}}function E(){return l(S(I(import.meta.url)),v)}function P(){const e=(process.env.PATH??"").split(w).filter(Boolean),o=process.platform==="win32"?["hermes.exe","hermes.cmd","hermes"]:["hermes"];for(const n of e)for(const r of o){const t=l(n,r);if(a(t))return t}}async function A(){const e=process.env.GRIX_HERMES_PYTHON?.trim();if(e){if(!a(e))throw new i(`GRIX_HERMES_PYTHON points to a missing interpreter: ${e}`,"HERMES_NOT_FOUND");return e}const o=P();if(o)try{const r=(await g(o,"utf8")).slice(0,512),t=/^#!\s*(\S+)/.exec(r)?.[1];if(t&&a(t))return t}catch{}const n=l(f(),".hermes","hermes-agent",".venv","bin","python3");if(a(n))return n;throw new i("cannot locate hermes' python interpreter (set GRIX_HERMES_PYTHON to override)","HERMES_NOT_FOUND")}async function d(e){const o=await A(),n=E();if(!a(n))throw new i(`relay script is missing: ${n}`,"SCRIPT_MISSING");const r=await new Promise((m,_)=>{h(o,[n],{timeout:R,cwd:f(),maxBuffer:8388608},(u,s,y)=>{if(s&&s.trim())return m(s);if(u)return _(new i(`hermes relay script failed: ${String(y||u.message).slice(0,400)}`,"SCRIPT_FAILED"));m(s)}).stdin?.end(JSON.stringify(e))});let t;try{t=JSON.parse(r.trim())}catch{throw new i(`hermes relay script returned non-JSON output: ${r.slice(0,200)}`,"SCRIPT_FAILED")}if(!t.ok)throw new i(String(t.error_msg??"hermes relay script reported failure"),String(t.error_code??"SCRIPT_FAILED"));return t}function c(e){return typeof e=="boolean"?e:void 0}function p(e){return{profile:String(e.profile??""),home:String(e.home??""),gatewayRunning:e.gateway_running===!0,restartRequired:e.restart_required===!0,providerKept:c(e.provider_kept),restoredModel:c(e.restored_model),userSwitchedAway:c(e.user_switched_away),modelCleared:c(e.model_cleared),warning:typeof e.warning=="string"?e.warning:void 0,snapshot:typeof e.snapshot=="string"?e.snapshot:void 0}}async function G(){const e=await d({command:"discover"}),o=Array.isArray(e.profiles)?e.profiles:[],n=Array.isArray(e.unreadable)?e.unreadable:[];return{profiles:o.map(r=>N(r)),unreadable:n.map(r=>{const t=r;return{name:String(t.name??""),home:String(t.home??""),error:String(t.error??"")}})}}function N(e){return{name:String(e.name??""),home:String(e.home??""),agentId:String(e.agent_id??""),gatewayRunning:e.gateway_running===!0,relayActive:e.relay_active===!0,modelProvider:typeof e.model_provider=="string"?e.model_provider:void 0,modelDefault:typeof e.model_default=="string"?e.model_default:void 0}}async function L(){const e=await d({command:"discover"});return(Array.isArray(e.profiles)?e.profiles:[]).map(n=>{const r=n;return{name:String(r.name??""),home:String(r.home??""),agentId:String(r.agent_id??""),gatewayRunning:r.gateway_running===!0,relayActive:r.relay_active===!0,modelProvider:typeof r.model_provider=="string"?r.model_provider:void 0,modelDefault:typeof r.model_default=="string"?r.model_default:void 0}})}async function U(e){const o=e.agentId?.trim(),n=e.baseUrl?.trim(),r=e.virtualKey?.trim(),t=e.model?.trim();if(!o)throw new i("agent_id is required","MISSING_AGENT_ID");if(!r)throw new i("virtual_key is required","MISSING_VIRTUAL_KEY");if(!n)throw new i("openai_base_url is required","MISSING_BASE_URL");try{new URL(n)}catch{throw new i("openai_base_url must be a valid URL","INVALID_BASE_URL")}if(!t)throw new i("model is required for hermes","MISSING_MODEL");return p(await d({command:"apply",agent_id:o,base_url:n,api_key:r,model:t}))}async function q(e){const o=e?.trim();if(!o)throw new i("agent_id is required","MISSING_AGENT_ID");return p(await d({command:"clear",agent_id:o}))}export{i as HermesProfileRelayError,U as applyHermesProfileRelay,q as clearHermesProfileRelay,L as discoverHermesProfiles,G as discoverHermesProfilesRaw,A as resolveHermesPython};
1
+ import{execFile as h}from"node:child_process";import{existsSync as a}from"node:fs";import{readFile as w}from"node:fs/promises";import{homedir as f}from"node:os";import{delimiter as g,dirname as S,join as l}from"node:path";import{fileURLToPath as I}from"node:url";const R=3e4,v="hermes-profile-relay.py";class i extends Error{code;constructor(o,n){super(o),this.code=n,this.name="HermesProfileRelayError"}}function E(){return l(S(I(import.meta.url)),v)}function P(){const e=(process.env.PATH??"").split(g).filter(Boolean),o=process.platform==="win32"?["hermes.exe","hermes.cmd","hermes"]:["hermes"];for(const n of e)for(const r of o){const t=l(n,r);if(a(t))return t}}async function A(){const e=process.env.GRIX_HERMES_PYTHON?.trim();if(e){if(!a(e))throw new i(`GRIX_HERMES_PYTHON points to a missing interpreter: ${e}`,"HERMES_NOT_FOUND");return e}const o=P();if(o)try{const r=(await w(o,"utf8")).slice(0,512),t=/^#!\s*(\S+)/.exec(r)?.[1];if(t&&a(t))return t}catch{}const n=l(f(),".hermes","hermes-agent",".venv","bin","python3");if(a(n))return n;throw new i("cannot locate hermes' python interpreter (set GRIX_HERMES_PYTHON to override)","HERMES_NOT_FOUND")}async function d(e){const o=await A(),n=E();if(!a(n))throw new i(`relay script is missing: ${n}`,"SCRIPT_MISSING");const r=await new Promise((m,_)=>{h(o,[n],{timeout:R,cwd:f(),maxBuffer:8388608,windowsHide:!0},(u,s,y)=>{if(s&&s.trim())return m(s);if(u)return _(new i(`hermes relay script failed: ${String(y||u.message).slice(0,400)}`,"SCRIPT_FAILED"));m(s)}).stdin?.end(JSON.stringify(e))});let t;try{t=JSON.parse(r.trim())}catch{throw new i(`hermes relay script returned non-JSON output: ${r.slice(0,200)}`,"SCRIPT_FAILED")}if(!t.ok)throw new i(String(t.error_msg??"hermes relay script reported failure"),String(t.error_code??"SCRIPT_FAILED"));return t}function c(e){return typeof e=="boolean"?e:void 0}function p(e){return{profile:String(e.profile??""),home:String(e.home??""),gatewayRunning:e.gateway_running===!0,restartRequired:e.restart_required===!0,providerKept:c(e.provider_kept),restoredModel:c(e.restored_model),userSwitchedAway:c(e.user_switched_away),modelCleared:c(e.model_cleared),warning:typeof e.warning=="string"?e.warning:void 0,snapshot:typeof e.snapshot=="string"?e.snapshot:void 0}}async function G(){const e=await d({command:"discover"}),o=Array.isArray(e.profiles)?e.profiles:[],n=Array.isArray(e.unreadable)?e.unreadable:[];return{profiles:o.map(r=>N(r)),unreadable:n.map(r=>{const t=r;return{name:String(t.name??""),home:String(t.home??""),error:String(t.error??"")}})}}function N(e){return{name:String(e.name??""),home:String(e.home??""),agentId:String(e.agent_id??""),gatewayRunning:e.gateway_running===!0,relayActive:e.relay_active===!0,modelProvider:typeof e.model_provider=="string"?e.model_provider:void 0,modelDefault:typeof e.model_default=="string"?e.model_default:void 0}}async function L(){const e=await d({command:"discover"});return(Array.isArray(e.profiles)?e.profiles:[]).map(n=>{const r=n;return{name:String(r.name??""),home:String(r.home??""),agentId:String(r.agent_id??""),gatewayRunning:r.gateway_running===!0,relayActive:r.relay_active===!0,modelProvider:typeof r.model_provider=="string"?r.model_provider:void 0,modelDefault:typeof r.model_default=="string"?r.model_default:void 0}})}async function U(e){const o=e.agentId?.trim(),n=e.baseUrl?.trim(),r=e.virtualKey?.trim(),t=e.model?.trim();if(!o)throw new i("agent_id is required","MISSING_AGENT_ID");if(!r)throw new i("virtual_key is required","MISSING_VIRTUAL_KEY");if(!n)throw new i("openai_base_url is required","MISSING_BASE_URL");try{new URL(n)}catch{throw new i("openai_base_url must be a valid URL","INVALID_BASE_URL")}if(!t)throw new i("model is required for hermes","MISSING_MODEL");return p(await d({command:"apply",agent_id:o,base_url:n,api_key:r,model:t}))}async function q(e){const o=e?.trim();if(!o)throw new i("agent_id is required","MISSING_AGENT_ID");return p(await d({command:"clear",agent_id:o}))}export{i as HermesProfileRelayError,U as applyHermesProfileRelay,q as clearHermesProfileRelay,L as discoverHermesProfiles,G as discoverHermesProfilesRaw,A as resolveHermesPython};
@@ -1,3 +1,3 @@
1
- import{accessSync as m,constants as l}from"node:fs";import{spawn as d,execSync as w}from"node:child_process";import{isAbsolute as h,join as f}from"node:path";const P=process.platform==="win32"?";":":";function S(t){try{return m(t,l.X_OK),!0}catch{return!1}}function b(t,n){const e=String(t??"").trim();if(!e||h(e))return e;const r=process.platform==="win32",i=String(n??process.env.PATH??""),o=[],s=new Set;for(const c of i.split(P)){const p=c.trim();if(!p)continue;if(r){const u=f(p,e+".cmd");s.has(u)||(s.add(u),o.push(u))}const a=f(p,e);s.has(a)||(s.add(a),o.push(a))}for(const c of o)if(S(c))return c;return console.warn(`[spawn:resolve] command="${e}" not found in PATH. candidates tried: [${o.join(", ")}] PATH=${i.substring(0,500)}${i.length>500?"...(truncated)":""}`),e}function k(t,n,e={}){const{cwd:r,env:i,...o}=e,s={stdio:o.stdio??["pipe","pipe","pipe"],env:i??{...process.env},cwd:r,windowsHide:!0,...o};if(process.platform==="win32"&&/\.(cmd|bat)$/i.test(t)){const p=process.env.ComSpec||"cmd.exe",a=`""${t}" ${n.join(" ")}"`;return{process:d(p,["/d","/s","/c",a],{...s,windowsVerbatimArguments:!0}),isCmdSpawn:!0}}return{process:d(t,n,{...s,detached:s.detached??!0}),isCmdSpawn:!1}}async function C(t){return!t||t<=0?[]:new Promise(n=>{if(process.platform==="win32"){const i=d("wmic",["process","where",`(ParentProcessId=${t})`,"get","ProcessId"],{stdio:"pipe",timeout:3e3});let o="";i.stdout?.on("data",s=>{o+=s.toString()}),i.on("close",()=>{n(o.split(`
2
- `).map(s=>parseInt(s.trim(),10)).filter(s=>!isNaN(s)&&s>0))}),i.on("error",()=>n([]));return}const e=d("pgrep",["-g",String(t)],{stdio:"pipe",timeout:3e3}),r=[];e.stdout?.on("data",i=>{i.toString().split(`
3
- `).forEach(o=>{const s=parseInt(o.trim(),10);!isNaN(s)&&s>0&&r.push(s)})}),e.on("close",()=>n(r)),e.on("error",()=>n([]))})}async function g(t,n=[]){return(await C(t)).some(r=>!n.includes(r))}function v(t,n="SIGTERM"){if(t.pid){if(process.platform==="win32"){try{w(`taskkill /pid ${t.pid} /T /F`,{stdio:"pipe",timeout:5e3})}catch{t.kill(n)}return}try{process.kill(-t.pid,n)}catch{t.kill(n)}}}export{g as hasChildProcesses,v as killProcessGroup,C as listGroupPids,b as resolveCommandPath,k as spawnCommand};
1
+ import{accessSync as m,constants as l}from"node:fs";import{spawn as d,execSync as w}from"node:child_process";import{isAbsolute as h,join as f}from"node:path";const P=process.platform==="win32"?";":":";function S(t){try{return m(t,l.X_OK),!0}catch{return!1}}function b(t,e){const n=String(t??"").trim();if(!n||h(n))return n;const r=process.platform==="win32",i=String(e??process.env.PATH??""),o=[],s=new Set;for(const c of i.split(P)){const p=c.trim();if(!p)continue;if(r){const u=f(p,n+".cmd");s.has(u)||(s.add(u),o.push(u))}const a=f(p,n);s.has(a)||(s.add(a),o.push(a))}for(const c of o)if(S(c))return c;return console.warn(`[spawn:resolve] command="${n}" not found in PATH. candidates tried: [${o.join(", ")}] PATH=${i.substring(0,500)}${i.length>500?"...(truncated)":""}`),n}function k(t,e,n={}){const{cwd:r,env:i,...o}=n,s={stdio:o.stdio??["pipe","pipe","pipe"],env:i??{...process.env},cwd:r,windowsHide:!0,...o};if(process.platform==="win32"&&/\.(cmd|bat)$/i.test(t)){const p=process.env.ComSpec||"cmd.exe",a=`""${t}" ${e.join(" ")}"`;return{process:d(p,["/d","/s","/c",a],{...s,windowsVerbatimArguments:!0}),isCmdSpawn:!0}}return{process:d(t,e,{...s,detached:s.detached??process.platform!=="win32"}),isCmdSpawn:!1}}async function C(t){return!t||t<=0?[]:new Promise(e=>{if(process.platform==="win32"){const i=d("wmic",["process","where",`(ParentProcessId=${t})`,"get","ProcessId"],{stdio:"pipe",timeout:3e3,windowsHide:!0});let o="";i.stdout?.on("data",s=>{o+=s.toString()}),i.on("close",()=>{e(o.split(`
2
+ `).map(s=>parseInt(s.trim(),10)).filter(s=>!isNaN(s)&&s>0))}),i.on("error",()=>e([]));return}const n=d("pgrep",["-g",String(t)],{stdio:"pipe",timeout:3e3}),r=[];n.stdout?.on("data",i=>{i.toString().split(`
3
+ `).forEach(o=>{const s=parseInt(o.trim(),10);!isNaN(s)&&s>0&&r.push(s)})}),n.on("close",()=>e(r)),n.on("error",()=>e([]))})}async function H(t,e=[]){return(await C(t)).some(r=>!e.includes(r))}function g(t,e="SIGTERM"){if(t.pid){if(process.platform==="win32"){try{w(`taskkill /pid ${t.pid} /T /F`,{stdio:"pipe",timeout:5e3,windowsHide:!0})}catch{t.kill(e)}return}try{process.kill(-t.pid,e)}catch{t.kill(e)}}}export{H as hasChildProcesses,g as killProcessGroup,C as listGroupPids,b as resolveCommandPath,k as spawnCommand};
@@ -1,2 +1,2 @@
1
- import{execFile as C,execFileSync as h}from"node:child_process";import{promisify as j}from"node:util";import{existsSync as c,mkdirSync as P,mkdtempSync as G,readFileSync as k,renameSync as f,rmSync as g,statfsSync as Y,symlinkSync as J,unlinkSync as $,writeFileSync as K}from"node:fs";import{basename as x,join as l,relative as H,resolve as d,sep as D}from"node:path";import{GRIX_PATHS as F}from"../log/index.js";import{appendRotatingFileSync as W}from"../log/rotation.js";import{getMachineName as X}from"../util/host-info.js";import{resolveInstallId as z}from"../util/install-id.js";import{npmInstallWithMirror as N,probeRegistries as q}from"../installer/npm-registry.js";const Q=j(C);class a extends Error{code;constructor(t,r){super(r),this.name="UpgradeError",this.code=t}}const M=".grix-upgrade-backup",Z=".grix-upgrade-failed";function A(){return l(F.log,"upgrade.log")}function _(){return l(F.data,"upgrade-pending.json")}function de(){return c(_())}function S(){const e=_();if(!c(e))return null;try{return JSON.parse(k(e,"utf-8"))}catch{return null}}function me(e,t){const r={from_version:e,target_version:t,upgraded_at:new Date().toISOString(),crash_count:0},i=_();L(i,r)}function L(e,t){const r=e+".tmp";K(r,JSON.stringify(t),"utf-8"),f(r,e)}function w(e,t){const r=d(e);return d(t)===`${r}${M}`&&r.includes(`${D}node_modules${D}`)&&x(r).length>0}function ee(e,t){const r=S();!r||!w(e,t)||(r.package_dir=d(e),r.backup_dir=d(t),L(_(),r))}function he(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!(!t||!r||!w(t,r)))try{g(r,{recursive:!0,force:!0})}catch{}}function _e(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!t||!r||!w(t,r)||!c(r))return!1;const i=`${t}${Z}`;try{return g(i,{recursive:!0,force:!0}),c(t)&&f(t,i),f(r,t),g(i,{recursive:!0,force:!0}),p(`atomic rollback restored ${t}`),!0}catch(n){try{!c(t)&&c(i)&&f(i,t)}catch{}return p(`atomic rollback failed: ${n instanceof Error?n.message:String(n)}`),!1}}function ye(){const e=_();if(c(e))try{$(e)}catch{}}function p(e){const t=`[${new Date().toISOString()}] ${e}
2
- `;try{W(A(),t)}catch{}}function ke(e=4096){const t=A();if(!c(t))return"";try{const r=k(t,"utf-8");return r.length<=e?r:r.slice(-e)}catch{return""}}function O(){try{const e=process.platform==="win32";return h(e?"cmd.exe":"npm",e?["/c","npm","--version"]:["--version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND","npm is not available or timed out")}}const m=1e6;function R(){if(process.platform==="win32")return m;let e;try{e=h("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return m}try{const t=Y(e),r=Math.floor(Number(t.bavail)*Number(t.bsize)/(1024*1024));return!Number.isFinite(r)||r<0?m:Math.min(r,m)}catch{return m}}function ve(){let e;try{e=O()}catch(r){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:r instanceof Error?r.message:"npm not available"}}const t=R();return t<100?{ok:!1,errorCode:"DISK_FULL",errorMsg:`Only ${t}MB free disk space (need >= 100MB)`,npmVersion:e,diskFreeMb:t}:{ok:!0,npmVersion:e,diskFreeMb:t}}function Se(){let e="";try{e=O()}catch{}let t=m;try{t=R()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:t,platform:process.platform,arch:process.arch,host_name:X(),install_id:z()}}function b(e,t,r){const i=l(e,"package.json");let n;try{n=JSON.parse(k(i,"utf-8"))}catch{throw new a("VERSION_VERIFY_FAILED",`Unable to read staged package metadata: ${i}`)}if(n.name!==t||n.version?.replace(/^v(?=\d)/,"")!==r)throw new a("VERSION_MISMATCH",`Staged package ${String(n.name)}@${String(n.version)} does not match ${t}@${r}`);return n}function te(e){return typeof e.bin=="string"?[[x(e.name),e.bin]]:!e.bin||typeof e.bin!="object"?[]:Object.entries(e.bin).filter(t=>typeof t[1]=="string")}function E(e,t){const r=te(t);if(r.length===0)throw new a("VERSION_VERIFY_FAILED",`Staged package ${t.name} has no executable bin`);for(const[,i]of r){const n=l(e,i);if(!c(n))throw new a("VERSION_VERIFY_FAILED",`Staged package entrypoint is missing: ${n}`)}return r}function re(e,t,r){if(process.platform==="win32")return;const i=l(e,"bin");P(i,{recursive:!0});for(const[n,o]of r){const s=l(i,n);if(c(s))continue;const u=`${s}.grix-upgrade-${process.pid}`;try{$(u)}catch{}J(H(i,l(t,o)),u),f(u,s)}}function ne(e){const t=d(e.activePackageDir),r=d(e.stagedPackageDir),i=`${t}${M}`,n=b(r,e.packageName,e.version),o=E(r,n);c(i)&&(c(t)?g(i,{recursive:!0,force:!0}):f(i,t)),ee(t,i);let s=!1;try{c(t)&&(f(t,i),s=!0),f(r,t);const u=b(t,e.packageName,e.version),v=E(t,u);return re(e.npmPrefix,t,v),{packageDir:t,backupDir:i}}catch(u){try{c(t)&&g(t,{recursive:!0,force:!0}),s&&c(i)&&f(i,t)}catch{}throw u}}function I(e){try{return h("npm",e,{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND",`Unable to resolve npm ${e.join(" ")}`)}}async function ie(e,t,r){const i=`${e}@${t}`,n=I(["prefix","-g"]),o=I(["root","-g"]);P(n,{recursive:!0});const s=G(l(n,".grix-upgrade-stage-"));try{p(`staging npm install ${i} under ${s}`);const{registry:u}=await N(i,r,10*1024*1024,{prefix:s}),v=I(["root","-g","--prefix",s]),y=l(v,e),U=b(y,e,t),T=E(y,U),V=l(y,T[0][1]);h(process.execPath,[V,"--version"],{encoding:"utf-8",timeout:15e3,maxBuffer:2*1024*1024});const B=ne({packageName:e,version:t,npmPrefix:n,activePackageDir:l(o,e),stagedPackageDir:y});p(`atomic package switch succeeded via ${u}; backup=${B.backupDir}`)}finally{try{g(s,{recursive:!0,force:!0})}catch{}}}async function we(e,t,r=12e4){const i=`${e}@${t}`;p(`npm install -g ${i} starting (atomic staging with mirror fallback)`);try{if(process.platform==="win32"){const{registry:n}=await N(i,r,10485760);p(`npm install succeeded via ${n}`)}else await ie(e,t,r)}catch(n){if(n instanceof a)throw n;const o=n instanceof Error?n.message:String(n);throw p(`npm install failed: ${o}`),/timed out|ETIMEDOUT/i.test(o)?new a("NPM_TIMEOUT",`npm install timed out after ${r/1e3}s (tried all mirrors): ${o}`):o.includes("EACCES")||o.includes("permission denied")?new a("NPM_INSTALL_FAILED",`Permission denied: ${o}`):o.includes("ENOSPC")||o.includes("no space left")?new a("DISK_FULL",`Disk full: ${o}`):o.includes("404")||o.includes("not found")?new a("NPM_INSTALL_FAILED",`Package not found: ${o}`):new a("NPM_INSTALL_FAILED",o)}}function be(e){let t;try{const i=process.platform==="win32";t=h(i?"cmd.exe":"npm",i?["/c","npm","root","-g"]:["root","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("VERSION_VERIFY_FAILED","Unable to resolve the global npm package directory")}let r;try{const i=l(t,"grix-connector","package.json"),n=JSON.parse(k(i,"utf-8"));if(n.name!=="grix-connector"||typeof n.version!="string"||!n.version.trim())throw new Error("invalid package metadata");r=n.version.trim().replace(/^v(?=\d)/,"")}catch{throw new a("VERSION_VERIFY_FAILED","Unable to read the installed grix-connector version")}if(r!==e)throw new a("VERSION_MISMATCH",`Installed version ${r} does not match expected ${e}`);return r}async function Ee(e,t){let r=!1;for(const i of await q())try{const{stdout:n}=await Q("npm",["view",`${e}@${t}`,"version","--registry",i.url,"--no-audit","--no-fund"],{timeout:8e3});if(n.trim())return!0}catch(n){const o=n,s=o.stderr||o.message||String(n);/ETARGET|No matching version|notarget|E404/i.test(s)&&(r=!0)}return!r}export{a as UpgradeError,R as checkDiskSpace,O as checkNpmAvailable,he as cleanupPendingBackup,Se as collectEnvInfo,ne as commitStagedGlobalPackage,ke as getUpgradeLogTail,Ee as isVersionAvailable,we as npmInstall,de as pendingExists,ve as preflightCheck,S as readPending,ye as removePending,_e as rollbackPendingInstall,p as upgradeLog,be as verifyInstalledVersion,me as writePending};
1
+ import{execFile as C,execFileSync as h}from"node:child_process";import{promisify as H}from"node:util";import{existsSync as c,mkdirSync as P,mkdtempSync as j,readFileSync as y,renameSync as f,rmSync as d,statfsSync as G,symlinkSync as Y,unlinkSync as $,writeFileSync as J}from"node:fs";import{basename as x,join as u,relative as K,resolve as g,sep as D}from"node:path";import{GRIX_PATHS as F}from"../log/index.js";import{appendRotatingFileSync as W}from"../log/rotation.js";import{getMachineName as X}from"../util/host-info.js";import{resolveInstallId as z}from"../util/install-id.js";import{npmInstallWithMirror as N,probeRegistries as q}from"../installer/npm-registry.js";const Q=H(C);class a extends Error{code;constructor(t,r){super(r),this.name="UpgradeError",this.code=t}}const M=".grix-upgrade-backup",Z=".grix-upgrade-failed";function A(){return u(F.log,"upgrade.log")}function w(){return u(F.data,"upgrade-pending.json")}function ge(){return c(w())}function v(){const e=w();if(!c(e))return null;try{return JSON.parse(y(e,"utf-8"))}catch{return null}}function me(e,t){const r={from_version:e,target_version:t,upgraded_at:new Date().toISOString(),crash_count:0},i=w();L(i,r)}function L(e,t){const r=e+".tmp";J(r,JSON.stringify(t),"utf-8"),f(r,e)}function S(e,t){const r=g(e);return g(t)===`${r}${M}`&&r.includes(`${D}node_modules${D}`)&&x(r).length>0}function ee(e,t){const r=v();!r||!S(e,t)||(r.package_dir=g(e),r.backup_dir=g(t),L(w(),r))}function he(e=v()){const t=e?.package_dir,r=e?.backup_dir;if(!(!t||!r||!S(t,r)))try{d(r,{recursive:!0,force:!0})}catch{}}function we(e=v()){const t=e?.package_dir,r=e?.backup_dir;if(!t||!r||!S(t,r)||!c(r))return!1;const i=`${t}${Z}`;try{return d(i,{recursive:!0,force:!0}),c(t)&&f(t,i),f(r,t),d(i,{recursive:!0,force:!0}),p(`atomic rollback restored ${t}`),!0}catch(n){try{!c(t)&&c(i)&&f(i,t)}catch{}return p(`atomic rollback failed: ${n instanceof Error?n.message:String(n)}`),!1}}function _e(){const e=w();if(c(e))try{$(e)}catch{}}function p(e){const t=`[${new Date().toISOString()}] ${e}
2
+ `;try{W(A(),t)}catch{}}function ye(e=4096){const t=A();if(!c(t))return"";try{const r=y(t,"utf-8");return r.length<=e?r:r.slice(-e)}catch{return""}}function O(){try{const e=process.platform==="win32";return h(e?"cmd.exe":"npm",e?["/c","npm","--version"]:["--version"],{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim()}catch{throw new a("NPM_NOT_FOUND","npm is not available or timed out")}}const m=1e6;function R(){if(process.platform==="win32")return m;let e;try{e=h("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim()}catch{return m}try{const t=G(e),r=Math.floor(Number(t.bavail)*Number(t.bsize)/(1024*1024));return!Number.isFinite(r)||r<0?m:Math.min(r,m)}catch{return m}}function ke(){let e;try{e=O()}catch(r){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:r instanceof Error?r.message:"npm not available"}}const t=R();return t<100?{ok:!1,errorCode:"DISK_FULL",errorMsg:`Only ${t}MB free disk space (need >= 100MB)`,npmVersion:e,diskFreeMb:t}:{ok:!0,npmVersion:e,diskFreeMb:t}}function ve(){let e="";try{e=O()}catch{}let t=m;try{t=R()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:t,platform:process.platform,arch:process.arch,host_name:X(),install_id:z()}}function b(e,t,r){const i=u(e,"package.json");let n;try{n=JSON.parse(y(i,"utf-8"))}catch{throw new a("VERSION_VERIFY_FAILED",`Unable to read staged package metadata: ${i}`)}if(n.name!==t||n.version?.replace(/^v(?=\d)/,"")!==r)throw new a("VERSION_MISMATCH",`Staged package ${String(n.name)}@${String(n.version)} does not match ${t}@${r}`);return n}function te(e){return typeof e.bin=="string"?[[x(e.name),e.bin]]:!e.bin||typeof e.bin!="object"?[]:Object.entries(e.bin).filter(t=>typeof t[1]=="string")}function E(e,t){const r=te(t);if(r.length===0)throw new a("VERSION_VERIFY_FAILED",`Staged package ${t.name} has no executable bin`);for(const[,i]of r){const n=u(e,i);if(!c(n))throw new a("VERSION_VERIFY_FAILED",`Staged package entrypoint is missing: ${n}`)}return r}function re(e,t,r){if(process.platform==="win32")return;const i=u(e,"bin");P(i,{recursive:!0});for(const[n,o]of r){const s=u(i,n);if(c(s))continue;const l=`${s}.grix-upgrade-${process.pid}`;try{$(l)}catch{}Y(K(i,u(t,o)),l),f(l,s)}}function ne(e){const t=g(e.activePackageDir),r=g(e.stagedPackageDir),i=`${t}${M}`,n=b(r,e.packageName,e.version),o=E(r,n);c(i)&&(c(t)?d(i,{recursive:!0,force:!0}):f(i,t)),ee(t,i);let s=!1;try{c(t)&&(f(t,i),s=!0),f(r,t);const l=b(t,e.packageName,e.version),k=E(t,l);return re(e.npmPrefix,t,k),{packageDir:t,backupDir:i}}catch(l){try{c(t)&&d(t,{recursive:!0,force:!0}),s&&c(i)&&f(i,t)}catch{}throw l}}function I(e){try{return h("npm",e,{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim()}catch{throw new a("NPM_NOT_FOUND",`Unable to resolve npm ${e.join(" ")}`)}}async function ie(e,t,r){const i=`${e}@${t}`,n=I(["prefix","-g"]),o=I(["root","-g"]);P(n,{recursive:!0});const s=j(u(n,".grix-upgrade-stage-"));try{p(`staging npm install ${i} under ${s}`);const{registry:l}=await N(i,r,10*1024*1024,{prefix:s}),k=I(["root","-g","--prefix",s]),_=u(k,e),U=b(_,e,t),T=E(_,U),V=u(_,T[0][1]);h(process.execPath,[V,"--version"],{encoding:"utf-8",timeout:15e3,maxBuffer:2*1024*1024,windowsHide:!0});const B=ne({packageName:e,version:t,npmPrefix:n,activePackageDir:u(o,e),stagedPackageDir:_});p(`atomic package switch succeeded via ${l}; backup=${B.backupDir}`)}finally{try{d(s,{recursive:!0,force:!0})}catch{}}}async function Se(e,t,r=12e4){const i=`${e}@${t}`;p(`npm install -g ${i} starting (atomic staging with mirror fallback)`);try{if(process.platform==="win32"){const{registry:n}=await N(i,r,10485760);p(`npm install succeeded via ${n}`)}else await ie(e,t,r)}catch(n){if(n instanceof a)throw n;const o=n instanceof Error?n.message:String(n);throw p(`npm install failed: ${o}`),/timed out|ETIMEDOUT/i.test(o)?new a("NPM_TIMEOUT",`npm install timed out after ${r/1e3}s (tried all mirrors): ${o}`):o.includes("EACCES")||o.includes("permission denied")?new a("NPM_INSTALL_FAILED",`Permission denied: ${o}`):o.includes("ENOSPC")||o.includes("no space left")?new a("DISK_FULL",`Disk full: ${o}`):o.includes("404")||o.includes("not found")?new a("NPM_INSTALL_FAILED",`Package not found: ${o}`):new a("NPM_INSTALL_FAILED",o)}}function be(e){let t;try{const i=process.platform==="win32";t=h(i?"cmd.exe":"npm",i?["/c","npm","root","-g"]:["root","-g"],{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim()}catch{throw new a("VERSION_VERIFY_FAILED","Unable to resolve the global npm package directory")}let r;try{const i=u(t,"grix-connector","package.json"),n=JSON.parse(y(i,"utf-8"));if(n.name!=="grix-connector"||typeof n.version!="string"||!n.version.trim())throw new Error("invalid package metadata");r=n.version.trim().replace(/^v(?=\d)/,"")}catch{throw new a("VERSION_VERIFY_FAILED","Unable to read the installed grix-connector version")}if(r!==e)throw new a("VERSION_MISMATCH",`Installed version ${r} does not match expected ${e}`);return r}async function Ee(e,t){let r=!1;for(const i of await q())try{const{stdout:n}=await Q("npm",["view",`${e}@${t}`,"version","--registry",i.url,"--no-audit","--no-fund"],{timeout:8e3});if(n.trim())return!0}catch(n){const o=n,s=o.stderr||o.message||String(n);/ETARGET|No matching version|notarget|E404/i.test(s)&&(r=!0)}return!r}export{a as UpgradeError,R as checkDiskSpace,O as checkNpmAvailable,he as cleanupPendingBackup,ve as collectEnvInfo,ne as commitStagedGlobalPackage,ye as getUpgradeLogTail,Ee as isVersionAvailable,Se as npmInstall,ge as pendingExists,ke as preflightCheck,v as readPending,_e as removePending,we as rollbackPendingInstall,p as upgradeLog,be as verifyInstalledVersion,me as writePending};
@@ -1,2 +1,2 @@
1
- import{execFile as c}from"node:child_process";import{accessSync as b,constants as A,existsSync as H,statSync as T}from"node:fs";import{join as h,dirname as m,basename as $,delimiter as p}from"node:path";import{promisify as l}from"node:util";import{log as a}from"../log/logger.js";const I=3e3,C=5e3,d="__GRIX_SHELL_PATH__";function x(t,e){const n=[".cmd",".bat",".exe",""];for(const r of t)if(r)for(const i of n){const s=h(r,`${e}${i}`);if(H(s))return s}return null}const M=1e4,P={cache:null,inflight:null},_={cache:null,inflight:null},S={cache:null,inflight:null};let w=0;function z(){w++;for(const t of[P,_,S])t.cache=null,t.inflight=null}function g(t,e){if(t.cache&&Date.now()-t.cache.at<M)return Promise.resolve(t.cache.value);if(t.inflight)return t.inflight;const n=w,r=e().then(i=>(w===n&&(t.cache={value:i,at:Date.now()}),t.inflight===r&&(t.inflight=null),i),i=>{throw t.inflight===r&&(t.inflight=null),i});return t.inflight=r,r}function D(){return g(P,async()=>{const t=l(c),e=async n=>{try{const{stdout:r}=await t("powershell",["-NoProfile","-NonInteractive","-Command",`[Environment]::GetEnvironmentVariable('Path','${n}')`],{timeout:5e3,encoding:"utf-8",windowsHide:!0});return r.split(";").map(i=>i.trim()).filter(Boolean)}catch(r){return a.warn("cli-probe",`\u8BFB\u53D6\u6CE8\u518C\u8868 ${n} PATH \u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),[]}};return[...await e("User"),...await e("Machine")]})}async function F(t){if(process.platform!=="win32")return null;const e=await D(),n=x(e,t)??await E(t);return n&&L(m(n)),n}function O(t){try{return T(t).isFile()?(b(t,A.X_OK),!0):!1}catch{return!1}}function y(t,e){for(const n of t){if(!n)continue;const r=h(n,e);if(O(r))return r}return null}const W=new Set(["sh","bash","zsh","ksh","dash","ash"]);function G(){return g(_,async()=>{const t=process.env.SHELL||"/bin/sh";if(!W.has($(t)))return a.info("cli-probe",`\u767B\u5F55 shell ${t} \u4E0D\u652F\u6301 -lic\uFF0C\u8DF3\u8FC7 shell PATH \u8BFB\u53D6`),[];const e=l(c);try{const n=e(t,["-lic",`printf '\\n${d}%s\\n' "$PATH"`],{timeout:C,killSignal:"SIGKILL",encoding:"utf-8"});n.child?.stdin?.end();const{stdout:r}=await n,i=r.split(/\r?\n/).reverse().find(s=>s.startsWith(d));return i?i.slice(d.length).split(p).map(s=>s.trim()).filter(Boolean):[]}catch(n){return a.warn("cli-probe",`\u8BFB\u53D6\u767B\u5F55 shell PATH \u5931\u8D25: ${n instanceof Error?n.message:String(n)}`),[]}})}function k(){return g(S,async()=>{const t=l(c),e=process.platform==="win32";try{const{stdout:n}=await t(e?"cmd.exe":"npm",e?["/c","npm","prefix","-g"]:["prefix","-g"],{timeout:5e3,killSignal:"SIGKILL",encoding:"utf-8",...e?{windowsHide:!0}:{}});return n.trim()||null}catch{return null}})}async function E(t){const e=await k();return e?process.platform==="win32"?x([e],t):y([h(e,"bin"),e],t):null}async function N(t){if(process.platform==="win32")return null;const e=await G(),n=y(e,t)??await E(t);return a.info("cli-probe",`\u767B\u5F55 shell PATH / npm \u5168\u5C40 bin \u515C\u5E95\u67E5\u627E ${t}: \u7ED3\u679C=${n??"\u672A\u627E\u5230"}`),n&&L(m(n)),n}function L(t){const e=process.env.PATH??"",n=process.platform==="win32"?(r,i)=>r.toLowerCase()===i.toLowerCase():(r,i)=>r===i;e.split(p).some(r=>n(r,t))||(process.env.PATH=e?`${e}${p}${t}`:t,a.info("cli-probe",`\u5DF2\u5C06 ${t} \u8FFD\u52A0\u5230\u5F53\u524D\u8FDB\u7A0B PATH\uFF08\u5B89\u88C5\u540E\u81EA\u6108\uFF09`))}async function q(t){const e=l(c),n=process.platform==="win32",r=n?"where":"which";try{const{stdout:i}=await e(r,[t],{timeout:3e3,encoding:"utf-8"}),s=i.trim().split(/\r?\n/).map(o=>o.trim()).filter(Boolean);if(s.length>0){if(n){const o=s.find(f=>/\.(cmd|bat)$/i.test(f));if(o)return o;const u=s.find(f=>/\.exe$/i.test(f));return u||s[0]}return s[0]}return await v(t)}catch{return await v(t)}}function v(t){return process.platform==="win32"?F(t):N(t)}async function B(t,e=["--version"],n=I){const r=l(c),i=process.platform==="win32";try{const s=i&&/\s/.test(t)&&!t.startsWith('"')?`"${t}"`:t,{stdout:o,stderr:u}=await r(s,e,{timeout:n,encoding:"utf-8",...i?{shell:!0}:{}});return{version:(o||u||"").trim().split(`
2
- `)[0]?.trim()||null||null}}catch(s){const o=s;return o.killed||o.code==="ETIMEDOUT"?{version:null,error:{code:"version_timeout",message:"version check timed out"}}:{version:null,error:{code:"cli_error",message:o.message??String(s)}}}}export{y as findPosixExecutableInDirs,x as findWindowsExecutableInDirs,B as getCliVersion,z as invalidateCliPathCache,q as resolveCliPath,N as resolvePosixInstalledCli,E as resolveViaNpmGlobalBin,F as resolveWindowsInstalledCli};
1
+ import{execFile as c}from"node:child_process";import{accessSync as b,constants as H,existsSync as A,statSync as T}from"node:fs";import{join as h,dirname as g,basename as $,delimiter as p}from"node:path";import{promisify as l}from"node:util";import{log as a}from"../log/logger.js";const I=3e3,C=5e3,d="__GRIX_SHELL_PATH__";function x(t,e){const n=[".cmd",".bat",".exe",""];for(const r of t)if(r)for(const i of n){const s=h(r,`${e}${i}`);if(A(s))return s}return null}const M=1e4,P={cache:null,inflight:null},S={cache:null,inflight:null},_={cache:null,inflight:null};let w=0;function q(){w++;for(const t of[P,S,_])t.cache=null,t.inflight=null}function m(t,e){if(t.cache&&Date.now()-t.cache.at<M)return Promise.resolve(t.cache.value);if(t.inflight)return t.inflight;const n=w,r=e().then(i=>(w===n&&(t.cache={value:i,at:Date.now()}),t.inflight===r&&(t.inflight=null),i),i=>{throw t.inflight===r&&(t.inflight=null),i});return t.inflight=r,r}function D(){return h(process.env.SystemRoot||"C:\\Windows","System32","WindowsPowerShell","v1.0","powershell.exe")}function W(){return m(P,async()=>{const t=l(c),e=async n=>{try{const{stdout:r}=await t(D(),["-NoProfile","-NonInteractive","-WindowStyle","Hidden","-Command",`[Environment]::GetEnvironmentVariable('Path','${n}')`],{timeout:5e3,encoding:"utf-8",windowsHide:!0});return r.split(";").map(i=>i.trim()).filter(Boolean)}catch(r){return a.warn("cli-probe",`\u8BFB\u53D6\u6CE8\u518C\u8868 ${n} PATH \u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),[]}};return[...await e("User"),...await e("Machine")]})}async function F(t){if(process.platform!=="win32")return null;const e=await W(),n=x(e,t)??await v(t);return n&&E(g(n)),n}function O(t){try{return T(t).isFile()?(b(t,H.X_OK),!0):!1}catch{return!1}}function y(t,e){for(const n of t){if(!n)continue;const r=h(n,e);if(O(r))return r}return null}const G=new Set(["sh","bash","zsh","ksh","dash","ash"]);function R(){return m(S,async()=>{const t=process.env.SHELL||"/bin/sh";if(!G.has($(t)))return a.info("cli-probe",`\u767B\u5F55 shell ${t} \u4E0D\u652F\u6301 -lic\uFF0C\u8DF3\u8FC7 shell PATH \u8BFB\u53D6`),[];const e=l(c);try{const n=e(t,["-lic",`printf '\\n${d}%s\\n' "$PATH"`],{timeout:C,killSignal:"SIGKILL",encoding:"utf-8"});n.child?.stdin?.end();const{stdout:r}=await n,i=r.split(/\r?\n/).reverse().find(s=>s.startsWith(d));return i?i.slice(d.length).split(p).map(s=>s.trim()).filter(Boolean):[]}catch(n){return a.warn("cli-probe",`\u8BFB\u53D6\u767B\u5F55 shell PATH \u5931\u8D25: ${n instanceof Error?n.message:String(n)}`),[]}})}function k(){return m(_,async()=>{const t=l(c),e=process.platform==="win32";try{const{stdout:n}=await t(e?"cmd.exe":"npm",e?["/c","npm","prefix","-g"]:["prefix","-g"],{timeout:5e3,killSignal:"SIGKILL",encoding:"utf-8",...e?{windowsHide:!0}:{}});return n.trim()||null}catch{return null}})}async function v(t){const e=await k();return e?process.platform==="win32"?x([e],t):y([h(e,"bin"),e],t):null}async function N(t){if(process.platform==="win32")return null;const e=await R(),n=y(e,t)??await v(t);return a.info("cli-probe",`\u767B\u5F55 shell PATH / npm \u5168\u5C40 bin \u515C\u5E95\u67E5\u627E ${t}: \u7ED3\u679C=${n??"\u672A\u627E\u5230"}`),n&&E(g(n)),n}function E(t){const e=process.env.PATH??"",n=process.platform==="win32"?(r,i)=>r.toLowerCase()===i.toLowerCase():(r,i)=>r===i;e.split(p).some(r=>n(r,t))||(process.env.PATH=e?`${e}${p}${t}`:t,a.info("cli-probe",`\u5DF2\u5C06 ${t} \u8FFD\u52A0\u5230\u5F53\u524D\u8FDB\u7A0B PATH\uFF08\u5B89\u88C5\u540E\u81EA\u6108\uFF09`))}async function B(t){const e=l(c),n=process.platform==="win32",r=n?"where":"which";try{const{stdout:i}=await e(r,[t],{timeout:3e3,encoding:"utf-8"}),s=i.trim().split(/\r?\n/).map(o=>o.trim()).filter(Boolean);if(s.length>0){if(n){const o=s.find(f=>/\.(cmd|bat)$/i.test(f));if(o)return o;const u=s.find(f=>/\.exe$/i.test(f));return u||s[0]}return s[0]}return await L(t)}catch{return await L(t)}}function L(t){return process.platform==="win32"?F(t):N(t)}async function J(t,e=["--version"],n=I){const r=l(c),i=process.platform==="win32";try{const s=i&&/\s/.test(t)&&!t.startsWith('"')?`"${t}"`:t,{stdout:o,stderr:u}=await r(s,e,{timeout:n,encoding:"utf-8",...i?{shell:!0}:{}});return{version:(o||u||"").trim().split(`
2
+ `)[0]?.trim()||null||null}}catch(s){const o=s;return o.killed||o.code==="ETIMEDOUT"?{version:null,error:{code:"version_timeout",message:"version check timed out"}}:{version:null,error:{code:"cli_error",message:o.message??String(s)}}}}export{y as findPosixExecutableInDirs,x as findWindowsExecutableInDirs,J as getCliVersion,q as invalidateCliPathCache,B as resolveCliPath,N as resolvePosixInstalledCli,v as resolveViaNpmGlobalBin,F as resolveWindowsInstalledCli};
@@ -1 +1 @@
1
- import{execFileSync as n}from"node:child_process";import{existsSync as c}from"node:fs";import{dirname as s,join as f,resolve as m}from"node:path";function g(i){const o=m(i);try{const e=n("git",["-C",o,"rev-parse","--show-toplevel"],{timeout:5e3,stdio:["ignore","pipe","ignore"]}).toString("utf8").trim();if(e)return e}catch{}let t=o;for(;;){if(c(f(t,".git")))return t;const r=s(t);if(r===t)return o;t=r}}export{g as findGitProjectRoot};
1
+ import{execFileSync as n}from"node:child_process";import{existsSync as c}from"node:fs";import{dirname as s,join as f,resolve as u}from"node:path";function d(i){const o=u(i);try{const e=n("git",["-C",o,"rev-parse","--show-toplevel"],{timeout:5e3,stdio:["ignore","pipe","ignore"],windowsHide:!0}).toString("utf8").trim();if(e)return e}catch{}let t=o;for(;;){if(c(f(t,".git")))return t;const r=s(t);if(r===t)return o;t=r}}export{d as findGitProjectRoot};
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: grix-egg
3
- description: Install a Grix egg skill package into your own skill directory. Use when you receive an instruction containing a line like "技能包: <URL>" and are asked to install / incubate it as a skill for yourself.
4
- trigger: 当收到含「技能包: <URL>」的安装指令、要求把虾蛋技能包装进自己的技能目录时
3
+ description: 'Install a Grix egg skill package into your own skill directory. Use when you receive an instruction containing a line like "技能包: <URL>" and are asked to install / incubate it as a skill for yourself.'
4
+ trigger: "当收到含「技能包: <URL>」的安装指令、要求把虾蛋技能包装进自己的技能目录时"
5
5
  ---
6
6
 
7
7
  # Grix Egg — Skill Package Self-Install
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: message-send
3
- description: Send a message into a specific Grix session by session ID, including cross-session and proactive sends. For replying to the current event use the reply/complete tools instead. Trigger words: send DM, DM, send message, notify, message another session.
3
+ description: "Send a message into a specific Grix session by session ID, including cross-session and proactive sends. For replying to the current event use the reply/complete tools instead. Trigger words: send DM, DM, send message, notify, message another session."
4
4
  trigger: 当用户要主动给某个指定会话发消息、跨会话发送、或通知另一个会话时
5
5
  ---
6
6
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: message-unsend
3
- description: Silently recall/unsend an already-sent message in a Grix session. After execution, end immediately without replying any confirmation text. Trigger words: recall, unsend, delete message, withdraw message.
3
+ description: "Silently recall/unsend an already-sent message in a Grix session. After execution, end immediately without replying any confirmation text. Trigger words: recall, unsend, delete message, withdraw message."
4
4
  trigger: 当用户要撤回、收回、删除一条已经发出的消息时
5
5
  ---
6
6
 
package/dist/manager.js CHANGED
@@ -1,2 +1,2 @@
1
- import{readFileSync as se,readdirSync as ie,writeFileSync as oe}from"node:fs";import{join as b}from"node:path";import{homedir as ce}from"node:os";import{AgentInstance as q}from"./bridge/bridge.js";import{buildSharedInstanceConfig as le,diffSharedOwners as de,sharedInstanceKey as pe,SharedOwnersCache as me}from"./manager-share-config.js";import{isAgentDeletedError as B}from"./core/aibot/errors.js";import{GRIX_PATHS as w,log as l}from"./core/log/index.js";import{resolveClientVersion as ue}from"./core/util/client-version.js";import{UpgradeChecker as ge}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as fe}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as he}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as _e}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as ye}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as we}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as Se}from"./core/aibot/types.js";import{buildReportedSkills as ke,logDefaultSkillsCheck as be,cleanupProjectedSkills as U}from"./default-skills/index.js";import{buildProviderEnv as ve,supportsKiroCwRelay as F,supportsNonMitmRelayConfig as Ae}from"./core/config/provider-env.js";import{resolveHermesHomeDir as Ce}from"./adapter/shared/native-provider-config.js";import{ensureKiroRelay as K,stopKiroRelay as Q}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as W}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as G}from"./core/runtime/cursor-resolve.js";import{getCliVersion as xe,resolveCliPath as $e}from"./core/util/cli-probe.js";import{AgentInstaller as Ee}from"./core/installer/installer.js";import{reportInstallFailure as Ie}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Te}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as Me}from"./adapter/codex/config-overrides.js";import{resolveCodexDirectHome as Pe}from"./adapter/codex/direct-home.js";function z(n){if(n)return{...n.provider_id?.trim()?{providerId:n.provider_id.trim()}:{},...n.base_url?.trim()?{baseUrl:n.base_url.trim()}:{},...n.quota_base_url?.trim()?{quotaBaseUrl:n.quota_base_url.trim()}:{},...n.api_key?.trim()?{apiKey:n.api_key.trim()}:{},...n.model?.trim()?{model:n.model.trim()}:{},...n.fast_model?.trim()?{fastModel:n.fast_model.trim()}:{},...n.effort?.trim()?{effort:n.effort.trim()}:{}}}const je=8e3;function Re(){const n=W();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:G()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"},{clientType:"deepseek",command:"dsh"}]}async function De(){return Promise.all(Re().map(async n=>{const e=await $e(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await xe(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Oe(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:G()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=W();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"deepseek":return{adapterType:"deepseek-harness",command:"dsh",adapterHint:"deepseek/grix-bridge-v1",options:{integrationMode:"profile_bridge",dshProfile:"web",autoInstallBridge:!0,autoStartProfile:!0},enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function A(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function He(n){return b(w.data,`session-bindings-${A(n,"unknown")}.json`)}function Le(n,e){return b(w.data,`session-bindings-${A(n,e)}.json`)}function Ne(n,e){return b(w.data,`active-events-${A(n,e)}.json`)}function qe(n,e){const t=A(n,"agent"),r=A(e,"unknown");return b(w.data,`terminal-outbox-${t}-${r}.json`)}function Be(...n){const e=[],t=new Set;for(const r of n)for(const a of r??[]){const c=String(a??"").trim(),s=c.toLowerCase();!c||t.has(s)||(t.add(s),e.push(c))}return e.length>0?e:void 0}function Ue(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},"deepseek-harness":{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function Fe(n,e={}){const t=ue(),r=String(n.client_type??"").trim().toLowerCase(),a=Oe(r),c=r==="deepseek"?n.dsh?.integration_mode??"profile_bridge":void 0,s=c==="embedded_jsonrpc",p=String(n.ws_url??"").trim(),o="get_session_usage",i="get_rate_limits",_="get_agent_global_config",g=Se;if(!n.name?.trim())throw new Error("agent name is required");if(!p)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const d=a.adapterType,m=d==="acp",y=r==="qwen",u={...a.options??{}};if(d==="deepseek-harness"&&(u.integrationMode=c,u.dshProfile=n.dsh?.profile?.trim()||"web",u.autoInstallBridge=n.dsh?.auto_install_bridge??!s,u.autoStartProfile=n.dsh?.auto_start_profile??!s),d==="deepseek-harness"&&n.provider?.model?.trim()&&(u.defaultModel=n.provider.model.trim()),n.codex_config_overrides!==void 0){if(d!=="codex")throw new Error(`agent ${n.name}: codex_config_overrides is only supported for client_type=codex`);Me(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),u.codexConfigOverrides=n.codex_config_overrides}if(d==="codex"&&n.provider?.wire_api!==void 0){const f=n.provider;if(f.wire_api!=="responses"||!f.base_url?.trim()||!f.api_key?.trim()||!f.model?.trim()||!f.catalog_version?.trim()||!f.catalog_sha256?.trim()||!f.catalog_json?.trim())throw Object.assign(new Error(`agent ${n.name}: incomplete Codex direct relay config`),{code:"INVALID_CODEX_DIRECT_CONFIG"});const N=Pe(w.data,n.name);u.codexHome=N,u.codexDirect={codexHome:N,config:{baseUrl:f.base_url.trim(),model:f.model.trim(),...f.reasoning_effort?.trim()?{reasoningEffort:f.reasoning_effort.trim()}:{},token:f.api_key.trim()},catalog:{version:f.catalog_version.trim(),sha256:f.catalog_sha256.trim(),json:f.catalog_json}}}const h=d==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",o,i]}:null,k=d==="claude"?{localActions:["session_control","set_mode","set_model","set_reasoning_effort","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",o,i]}:null,S=y?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o],adapterHint:"qwen/base"}:null,$=d==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",o,i]}:null,E=d==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,I=d==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",i]}:null,R=d==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,T=d==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder"]}:null,M=d==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,P=d==="deepseek-harness"?{adapterHint:s?"deepseek/jsonrpc-v1":"deepseek/grix-bridge-v1",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_provider","set_model","set_mode","set_thinking","set_reasoning_effort","set_preset","set_profile","create_profile",o,i,"exec_approve","exec_reject","permission_approve","permission_reject","file_list","create_folder","dsh_bridge_status","dsh_install_bridge","dsh_list_plugins","dsh_enable_plugin","dsh_disable_plugin","dsh_refresh_plugins","dsh_list_skills","dsh_enable_skill","dsh_disable_skill","dsh_list_mcp","dsh_list_tools","dsh_list_jobs","dsh_list_goals"]}:null,D=new Set(["hermes","reasonix","kimi","copilot"]),J=m&&!D.has(r),X=m&&!y?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder",...J?[o]:[]]}:null,Y=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",o,i]}:null,Z=d==="codex"||d==="claude"||d==="opencode"||d==="deepseek-harness"||r==="gemini"?["session_control","set_model","set_mode",...d==="deepseek-harness"?["set_provider","set_thinking","set_reasoning_effort","set_preset","set_profile","create_profile","dsh_list_plugins","dsh_enable_plugin","dsh_disable_plugin","dsh_refresh_plugins","dsh_list_skills","dsh_enable_skill","dsh_disable_skill"]:[],...d==="claude"?["set_reasoning_effort"]:[]]:void 0,ee=d==="cursor"||d==="opencode"||d==="openhuman"||d==="agy"||m&&D.has(r)?[i]:[o,i];m&&u.raw_transport===void 0&&(u.raw_transport=r==="gemini");const te=`${r}/base`,C=_e(d,r),ne=C==="kiro"?void 0:process.cwd(),j=z(n.provider),v={...process.env,...n.env};if(C==="hermes"&&!v.HERMES_HOME?.trim()){const f=ve(r,j);v.HERMES_HOME=Ce({...f,...v},n.name)}const O=ke({mode:C,projectDir:ne,env:v}),H=O.filter(f=>f.source==="connector").map(f=>f.name);H.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${H.join(", ")}]`);const L=ye(O,w.skills);let re=L.length>0?L:void 0;const ae=we({skillsDir:w.skills,mode:C,home:ce(),env:v});return{name:n.name,adapterType:d,aibot:{url:p,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:P?.adapterHint??a.adapterHint??S?.adapterHint??$?.adapterHint??E?.adapterHint??I?.adapterHint??T?.adapterHint??M?.adapterHint??te,capabilities:P?.capabilities??h?.capabilities??R?.capabilities??$?.capabilities??E?.capabilities??I?.capabilities??T?.capabilities??M?.capabilities??S?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Be(P?.localActions??h?.localActions??R?.localActions??k?.localActions??$?.localActions??E?.localActions??I?.localActions??T?.localActions??M?.localActions??S?.localActions??Y?.localActions??X?.localActions??["exec_approve","exec_reject"],Z,ee,["connector_rollback","connector_upgrade_push",_,"configure_gateway_provider","skill_upload","skill_delete","skill_enable","skill_disable","skill_refresh",...g]),skills:re,librarySkills:ae,terminalOutboxPath:qe(n.name,n.agent_id)},agent:{command:s?"dsh-jsonrpc-agent":a.command,args:[...a.args??[],...n.args??[]],env:n.env,clientType:r,...j?{provider:j}:{}},adapterOptions:u,acpAuthMethod:u.auth_method,acpInitialMode:u.initial_mode,acpMcpTools:u.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:He(n.agent_id),legacyBindingsPath:Le(n.name,n.agent_id),activeEventStorePath:Ne(n.name,n.agent_id),...a.enableSessionBinding||m?{enableSessionBinding:!0}:{},...a.autoInjectArgs||r==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...a.autoInjectArgs??{},...r==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize??(d==="deepseek-harness"?4:void 0),poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:Ue(d,n.event_queue),logDir:w.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Ke(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):je}function V(n){const e=[],t=[],r=[],a=ie(n).filter(c=>c.endsWith(".json")).sort();for(const c of a)try{const s=JSON.parse(se(b(n,c),"utf-8"));if(s===null||typeof s!="object"||Array.isArray(s)||!("agents"in s)){r.push(c);continue}if(!Array.isArray(s.agents)){t.push({file:c,error:"agents is not an array"});continue}if(s.agents.length===0){t.push({file:c,error:"agents array is empty"});continue}for(const p of s.agents)e.push({entry:p,file:c})}catch(s){t.push({file:c,error:s instanceof Error?s.message:String(s)})}return{entries:e,fileErrors:t,skipped:r}}function x(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(x).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${x(e[r])}`).join(",")}}`}function Qe(n,e){return x(n)===x(e)}class kt{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=w.config;sharedOwnersCache=new me(w.data);installer=new Ee;relaySecretResolver;auditProducer=Te();async start(e){const t=e??w.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),be(),U(),this.globalConfigStore=new he(b(w.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:a,skipped:c}=V(t);for(const i of a)l.error("manager",`Failed to load ${i.file}: ${i.error}`);for(const i of c)l.info("manager",`Skipped ${i}: not an agent config (no "agents" key)`);if(r.length===0&&a.length===0&&c.length===0){l.warn("manager",`No config files found in ${t}; daemon idle (waiting for config). Add agents under this directory then run: grix-connector reload`);return}const s=[];let p=a.length;for(const{entry:i,file:_}of r)try{const g=this.toRuntimeInstanceConfig(i);s.push({config:g,entry:i,file:_}),l.info("manager",`Loaded ${g.name} (${g.adapterType??"acp"}) from ${_}`)}catch(g){const d=typeof i?.name=="string"?i.name:"<unknown>";l.error("manager",`Invalid agent config in ${_} (name=${d}): ${g}`),p++}let o=0;if(s.length>0){const i=Ke();l.info("manager",`Starting ${s.length} agent(s), startup wait=${i}ms`);const _=m=>{this.instances=this.instances.filter(y=>y!==m)},g=s.map(({config:m,entry:y,file:u})=>{const h=this.createConfiguredInstance(m);return this.instances.push(h),this.configMap.set(m.name,m),this.rawConfigMap.set(m.name,{entry:y,file:u}),{config:m,instance:h,startPromise:this.prepareProviderRuntime(m,y).then(()=>h.start())}}),d=await Promise.all(g.map(async m=>{const y=await new Promise(u=>{let h=!1;const k=setTimeout(()=>{h||(h=!0,u({kind:"timeout"}))},i);m.startPromise.then(()=>{h||(h=!0,clearTimeout(k),u({kind:"started"}))}).catch(S=>{h||(h=!0,clearTimeout(k),u({kind:"failed",error:S}))})});return{task:m,outcome:y}}));for(const{task:m,outcome:y}of d){if(y.kind==="started"){this.restoreCachedSharedInstances(m.config);continue}if(y.kind==="failed"){if(B(y.error)){this.onAgentDeletedByPlatform(m.config.name);continue}_(m.instance),l.error("manager",`Failed to start ${m.config.name}: ${y.error}`);continue}o++,l.warn("manager",`Startup pending for ${m.config.name}, continue retrying in background`),m.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${m.config.name}`),this.restoreCachedSharedInstances(m.config)}).catch(u=>{if(B(u)){this.onAgentDeletedByPlatform(m.config.name);return}_(m.instance),l.error("manager",`Delayed start failed: ${m.config.name}: ${u}`)})}if(this.instances.length>0){const m=Math.max(0,this.instances.length-o);l.info("manager",`${m}/${s.length} agent(s) running now`)}o>0&&l.warn("manager",`${o} agent(s) still connecting in background`)}if(this.instances.length===0&&s.length>0)throw new Error("All agent configurations failed to start");await this.ensureAuxServices()}async ensureAuxServices(){if(this.configMap.size===0)return;const e=[...this.configMap.values()].map(t=>({apiKey:t.aibot.apiKey,wsUrl:t.aibot.url}));this.upgradeChecker||(this.upgradeChecker=new ge(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new fe(e,w.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshOwnerLibrarySkills()),await this.skillSyncer.start())}refreshOwnerLibrarySkills(){const e=new Map,t=r=>{let a;try{a=r.skillsSyncGroupKey()}catch(s){l.warn("manager",`skillsSyncGroupKey failed for ${r.name}: ${s}`);return}const c=e.get(a)??[];c.push(r),e.set(a,c)};for(const r of this.instances)t(r);for(const r of this.sharedInstances.values())t(r);for(const[r,a]of e){let c=!1;const s=[];for(const p of a){if(c){s.push(p);continue}let o=!1;try{o=p.forceRefreshSkills(void 0,{force:!0,ownerLibrarySync:!0})===!0}catch(i){l.warn("manager",`owner library skills reporter threw group=${r} agent=${p.name}: ${i}`)}if(o){c=!0;continue}l.warn("manager",`owner library skills reporter failed group=${r} agent=${p.name}; trying next`)}if(!c){l.warn("manager",`owner library skills: no reporter succeeded group=${r}`);continue}for(const p of s)try{p.adoptSkillsWireHashFromDisk()}catch(o){l.warn("manager",`adoptSkillsWireHashFromDisk failed for ${p.name}: ${o}`)}}}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),await this.auditProducer.stop({timeoutMs:5e3}).catch(()=>!1),this.instances=[],U(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const a=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,a)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:r,toRemove:a}=de(e.name,this.sharedInstances.keys(),t);for(const c of r){if(this.stopping)break;const s=pe(e.name,c);try{const p=le(e,c),o=new q(p,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(s,o),await o.start(),o.forceRefreshSkills(void 0,{force:!0}),l.info("manager",`shared instance started: ${s}`)}catch(p){this.sharedInstances.delete(s);const o=p instanceof Error?p.message:String(p);/Auth failed/i.test(o)?(this.sharedOwnersCache.remove(e.name,c),l.warn("manager",`shared instance auth rejected, removed from cache: ${s}`)):l.error("manager",`start shared instance failed ${s}: ${p}`)}}for(const{key:c}of a){const s=this.sharedInstances.get(c);s&&(this.sharedInstances.delete(c),s.stop().catch(p=>l.error("manager",`stop shared instance failed ${c}: ${p}`)),l.info("manager",`shared instance stopped: ${c}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(l.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),await this.ensureAuxServices(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const r=this.toRuntimeInstanceConfig(e);if(this.instances.some(a=>a.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,t)}createConfiguredInstance(e){const t=new q(e,this.globalConfigStore,this.auditProducer);return t.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),t.setShareSetHandler(r=>this.onShareSet(e,r)),t.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),t.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),t.setProviderConfigHandler(r=>this.setAgentProvider(e.name,r)),t.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(r,a)=>{const c=this.relayStateApplier;return c?c.applyEnable(e.name,r,a):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const r=this.relayStateApplier;return r?r.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),t.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),t.setProviderResolver(()=>z(this.getAgentProvider(e.name))),t}async prepareProviderRuntime(e,t){const r=this.resolveAgentProvider(t.provider);F(t.client_type)&&r?.base_url?.trim()&&r?.api_key?.trim()&&r?.model?.trim()&&await K(e.name,{baseUrl:r.base_url.trim(),apiKey:r.api_key.trim(),model:r.model.trim()})}async startInstanceFromConfig(e,t,r){await this.prepareProviderRuntime(e,t);const a=this.createConfiguredInstance(e);await a.start(),this.instances.push(a),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const r=this.instances.findIndex(p=>p.name===e),a=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const c=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),c&&await c.catch(()=>{});const s=`${e}#shared:`;for(const[p,o]of[...this.sharedInstances.entries()])p.startsWith(s)&&(this.sharedInstances.delete(p),o.stop().catch(i=>l.error("manager",`stop shared instance failed ${p}: ${i}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),a&&await a.stop(),t?.keepShareCache||await Q(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){l.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=b(this.configDir,"agents.json");try{const t=[];for(const[,a]of this.configMap){const c=this.rawConfigMap.get(a.name)?.entry.provider;t.push({name:a.name,ws_url:a.aibot.url,agent_id:a.aibot.agentId,api_key:a.aibot.apiKey,client_type:a.aibot.clientType,...c?{provider:c}:{}})}oe(e,JSON.stringify({agents:t},null,4)+`
1
+ import{readFileSync as se,readdirSync as ie,writeFileSync as oe}from"node:fs";import{join as b}from"node:path";import{homedir as ce}from"node:os";import{AgentInstance as q}from"./bridge/bridge.js";import{buildSharedInstanceConfig as le,diffSharedOwners as de,sharedInstanceKey as pe,SharedOwnersCache as me}from"./manager-share-config.js";import{isAgentDeletedError as B}from"./core/aibot/errors.js";import{GRIX_PATHS as w,log as l}from"./core/log/index.js";import{resolveClientVersion as ue}from"./core/util/client-version.js";import{UpgradeChecker as ge}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as fe}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as he}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as _e}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as ye}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as we}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as Se}from"./core/aibot/types.js";import{buildReportedSkills as ke,logDefaultSkillsCheck as be,cleanupProjectedSkills as U}from"./default-skills/index.js";import{buildProviderEnv as ve,supportsKiroCwRelay as F,supportsNonMitmRelayConfig as Ae}from"./core/config/provider-env.js";import{resolveHermesHomeDir as Ce}from"./adapter/shared/native-provider-config.js";import{ensureKiroRelay as K,stopKiroRelay as Q}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as W}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as G}from"./core/runtime/cursor-resolve.js";import{getCliVersion as xe,resolveCliPath as $e}from"./core/util/cli-probe.js";import{AgentInstaller as Ee}from"./core/installer/installer.js";import{reportInstallFailure as Ie}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Te}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as Me}from"./adapter/codex/config-overrides.js";import{resolveCodexDirectHome as Pe}from"./adapter/codex/direct-home.js";function z(n){if(n)return{...n.provider_id?.trim()?{providerId:n.provider_id.trim()}:{},...n.base_url?.trim()?{baseUrl:n.base_url.trim()}:{},...n.quota_base_url?.trim()?{quotaBaseUrl:n.quota_base_url.trim()}:{},...n.api_key?.trim()?{apiKey:n.api_key.trim()}:{},...n.model?.trim()?{model:n.model.trim()}:{},...n.fast_model?.trim()?{fastModel:n.fast_model.trim()}:{},...n.effort?.trim()?{effort:n.effort.trim()}:{}}}const je=8e3;function Re(){const n=W();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:G()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"},{clientType:"deepseek",command:"dsh"}]}async function De(){return Promise.all(Re().map(async n=>{const e=await $e(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await xe(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Oe(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:G()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=W();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"deepseek":return{adapterType:"deepseek-harness",command:"dsh",adapterHint:"deepseek/grix-bridge-v1",options:{integrationMode:"profile_bridge",dshProfile:"web",autoInstallBridge:!0,autoStartProfile:!0},enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function A(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function He(n){return b(w.data,`session-bindings-${A(n,"unknown")}.json`)}function Le(n,e){return b(w.data,`session-bindings-${A(n,e)}.json`)}function Ne(n,e){return b(w.data,`active-events-${A(n,e)}.json`)}function qe(n,e){const t=A(n,"agent"),r=A(e,"unknown");return b(w.data,`terminal-outbox-${t}-${r}.json`)}function Be(...n){const e=[],t=new Set;for(const r of n)for(const a of r??[]){const c=String(a??"").trim(),s=c.toLowerCase();!c||t.has(s)||(t.add(s),e.push(c))}return e.length>0?e:void 0}function Ue(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},"deepseek-harness":{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function Fe(n,e={}){const t=ue(),r=String(n.client_type??"").trim().toLowerCase(),a=Oe(r),c=r==="deepseek"?n.dsh?.integration_mode??"profile_bridge":void 0,s=c==="embedded_jsonrpc",p=String(n.ws_url??"").trim(),o="get_session_usage",i="get_rate_limits",_="get_agent_global_config",g=Se;if(!n.name?.trim())throw new Error("agent name is required");if(!p)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const d=a.adapterType,m=d==="acp",y=r==="qwen",u={...a.options??{}};if(d==="deepseek-harness"&&(u.integrationMode=c,u.dshProfile=n.dsh?.profile?.trim()||"web",u.autoInstallBridge=n.dsh?.auto_install_bridge??!s,u.autoStartProfile=n.dsh?.auto_start_profile??!s),d==="deepseek-harness"&&n.provider?.model?.trim()&&(u.defaultModel=n.provider.model.trim()),n.codex_config_overrides!==void 0){if(d!=="codex")throw new Error(`agent ${n.name}: codex_config_overrides is only supported for client_type=codex`);Me(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),u.codexConfigOverrides=n.codex_config_overrides}if(d==="codex"&&n.provider?.wire_api!==void 0){const f=n.provider;if(f.wire_api!=="responses"||!f.base_url?.trim()||!f.api_key?.trim()||!f.model?.trim()||!f.catalog_version?.trim()||!f.catalog_sha256?.trim()||!f.catalog_json?.trim())throw Object.assign(new Error(`agent ${n.name}: incomplete Codex direct relay config`),{code:"INVALID_CODEX_DIRECT_CONFIG"});const N=Pe(w.data,n.name);u.codexHome=N,u.codexDirect={codexHome:N,config:{baseUrl:f.base_url.trim(),model:f.model.trim(),...f.reasoning_effort?.trim()?{reasoningEffort:f.reasoning_effort.trim()}:{},token:f.api_key.trim()},catalog:{version:f.catalog_version.trim(),sha256:f.catalog_sha256.trim(),json:f.catalog_json}}}const h=d==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",o,i]}:null,k=d==="claude"?{localActions:["session_control","set_mode","set_model","set_reasoning_effort","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",o,i]}:null,S=y?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o],adapterHint:"qwen/base"}:null,$=d==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",o,i]}:null,E=d==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,I=d==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",i]}:null,R=d==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,T=d==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder"]}:null,M=d==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,P=d==="deepseek-harness"?{adapterHint:s?"deepseek/jsonrpc-v1":"deepseek/grix-bridge-v1",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_provider","set_model","set_mode","set_thinking","set_reasoning_effort","set_preset","set_profile","create_profile",o,i,"exec_approve","exec_reject","permission_approve","permission_reject","file_list","create_folder","dsh_bridge_status","dsh_install_bridge","dsh_list_plugins","dsh_enable_plugin","dsh_disable_plugin","dsh_refresh_plugins","dsh_list_skills","dsh_enable_skill","dsh_disable_skill","dsh_list_mcp","dsh_list_tools","dsh_list_jobs","dsh_list_goals"]}:null,D=new Set(["hermes","reasonix","kimi","copilot"]),J=m&&!D.has(r),X=m&&!y?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder",...J?[o]:[]]}:null,Y=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",o,i]}:null,Z=d==="codex"||d==="claude"||d==="opencode"||d==="deepseek-harness"||r==="gemini"?["session_control","set_model","set_mode",...d==="deepseek-harness"?["set_provider","set_thinking","set_reasoning_effort","set_preset","set_profile","create_profile","dsh_list_plugins","dsh_enable_plugin","dsh_disable_plugin","dsh_refresh_plugins","dsh_list_skills","dsh_enable_skill","dsh_disable_skill"]:[],...d==="claude"?["set_reasoning_effort"]:[]]:void 0,ee=d==="cursor"||d==="opencode"||d==="openhuman"||d==="agy"||m&&D.has(r)?[i]:[o,i];m&&u.raw_transport===void 0&&(u.raw_transport=r==="gemini");const te=`${r}/base`,C=_e(d,r),ne=C==="kiro"?void 0:process.cwd(),j=z(n.provider),v={...process.env,...n.env};if(C==="hermes"&&!v.HERMES_HOME?.trim()){const f=ve(r,j);v.HERMES_HOME=Ce({...f,...v},n.name)}const O=ke({mode:C,projectDir:ne,env:v}),H=O.filter(f=>f.source==="connector").map(f=>f.name);H.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${H.join(", ")}]`);const L=ye(O,w.skills);let re=L.length>0?L:void 0;const ae=we({skillsDir:w.skills,mode:C,home:ce(),env:v});return{name:n.name,adapterType:d,aibot:{url:p,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:P?.adapterHint??a.adapterHint??S?.adapterHint??$?.adapterHint??E?.adapterHint??I?.adapterHint??T?.adapterHint??M?.adapterHint??te,capabilities:P?.capabilities??h?.capabilities??R?.capabilities??$?.capabilities??E?.capabilities??I?.capabilities??T?.capabilities??M?.capabilities??S?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Be(P?.localActions??h?.localActions??R?.localActions??k?.localActions??$?.localActions??E?.localActions??I?.localActions??T?.localActions??M?.localActions??S?.localActions??Y?.localActions??X?.localActions??["exec_approve","exec_reject"],Z,ee,["connector_rollback","connector_upgrade_push",_,"configure_gateway_provider","skill_upload","skill_delete","skill_enable","skill_disable","skill_refresh",...g]),skills:re,librarySkills:ae,terminalOutboxPath:qe(n.name,n.agent_id)},agent:{command:s?"dsh-jsonrpc-agent":a.command,args:[...a.args??[],...n.args??[]],env:n.env,clientType:r,...j?{provider:j}:{}},adapterOptions:u,acpAuthMethod:u.auth_method,acpInitialMode:u.initial_mode,acpMcpTools:u.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:He(n.agent_id),legacyBindingsPath:Le(n.name,n.agent_id),activeEventStorePath:Ne(n.name,n.agent_id),...a.enableSessionBinding||m?{enableSessionBinding:!0}:{},...a.autoInjectArgs||r==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...a.autoInjectArgs??{},...r==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize??(d==="deepseek-harness"?4:void 0),poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:Ue(d,n.event_queue),logDir:w.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Ke(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):je}function V(n){const e=[],t=[],r=[],a=ie(n).filter(c=>c.endsWith(".json")).sort();for(const c of a)try{const s=JSON.parse(se(b(n,c),"utf-8"));if(s===null||typeof s!="object"||Array.isArray(s)||!("agents"in s)){r.push(c);continue}if(!Array.isArray(s.agents)){t.push({file:c,error:"agents is not an array"});continue}if(s.agents.length===0){t.push({file:c,error:"agents array is empty"});continue}for(const p of s.agents)e.push({entry:p,file:c})}catch(s){t.push({file:c,error:s instanceof Error?s.message:String(s)})}return{entries:e,fileErrors:t,skipped:r}}function x(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(x).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${x(e[r])}`).join(",")}}`}function Qe(n,e){return x(n)===x(e)}class kt{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=w.config;sharedOwnersCache=new me(w.data);installer=new Ee;relaySecretResolver;auditProducer=Te();async start(e){const t=e??w.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),be(),U(),this.globalConfigStore=new he(b(w.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:a,skipped:c}=V(t);for(const i of a)l.error("manager",`Failed to load ${i.file}: ${i.error}`);for(const i of c)l.info("manager",`Skipped ${i}: not an agent config (no "agents" key)`);if(r.length===0&&a.length===0&&c.length===0){l.warn("manager",`No config files found in ${t}; daemon idle (waiting for config). Add agents under this directory then run: grix-connector reload`);return}const s=[];let p=a.length;for(const{entry:i,file:_}of r)try{const g=this.toRuntimeInstanceConfig(i);s.push({config:g,entry:i,file:_}),l.info("manager",`Loaded ${g.name} (${g.adapterType??"acp"}) from ${_}`)}catch(g){const d=typeof i?.name=="string"?i.name:"<unknown>";l.error("manager",`Invalid agent config in ${_} (name=${d}): ${g}`),p++}let o=0;if(s.length>0){const i=Ke();l.info("manager",`Starting ${s.length} agent(s), startup wait=${i}ms`);const _=m=>{this.instances=this.instances.filter(y=>y!==m)},g=s.map(({config:m,entry:y,file:u})=>{const h=this.createConfiguredInstance(m);return this.instances.push(h),this.configMap.set(m.name,m),this.rawConfigMap.set(m.name,{entry:y,file:u}),{config:m,instance:h,startPromise:this.prepareProviderRuntime(m,y).then(()=>h.start())}}),d=await Promise.all(g.map(async m=>{const y=await new Promise(u=>{let h=!1;const k=setTimeout(()=>{h||(h=!0,u({kind:"timeout"}))},i);m.startPromise.then(()=>{h||(h=!0,clearTimeout(k),u({kind:"started"}))}).catch(S=>{h||(h=!0,clearTimeout(k),u({kind:"failed",error:S}))})});return{task:m,outcome:y}}));for(const{task:m,outcome:y}of d){if(y.kind==="started"){this.restoreCachedSharedInstances(m.config);continue}if(y.kind==="failed"){if(B(y.error)){this.onAgentDeletedByPlatform(m.config.name);continue}_(m.instance),l.error("manager",`Failed to start ${m.config.name}: ${y.error}`);continue}o++,l.warn("manager",`Startup pending for ${m.config.name}, continue retrying in background`),m.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${m.config.name}`),this.restoreCachedSharedInstances(m.config)}).catch(u=>{if(B(u)){this.onAgentDeletedByPlatform(m.config.name);return}_(m.instance),l.error("manager",`Delayed start failed: ${m.config.name}: ${u}`)})}if(this.instances.length>0){const m=Math.max(0,this.instances.length-o);l.info("manager",`${m}/${s.length} agent(s) running now`)}o>0&&l.warn("manager",`${o} agent(s) still connecting in background`)}if(this.instances.length===0&&s.length>0)throw new Error("All agent configurations failed to start");await this.ensureAuxServices()}async ensureAuxServices(){if(this.configMap.size===0)return;const e=[...this.configMap.values()].map(t=>({apiKey:t.aibot.apiKey,wsUrl:t.aibot.url}));this.upgradeChecker||(this.upgradeChecker=new ge(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new fe(e,w.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshOwnerLibrarySkills()),await this.skillSyncer.start())}refreshOwnerLibrarySkills(){const e=new Map,t=r=>{let a;try{a=r.skillsSyncGroupKey()}catch(s){l.warn("manager",`skillsSyncGroupKey failed for ${r.name}: ${s}`);return}const c=e.get(a)??[];c.push(r),e.set(a,c)};for(const r of this.instances)t(r);for(const r of this.sharedInstances.values())t(r);for(const[r,a]of e){let c=!1;const s=[];for(const p of a){if(c){s.push(p);continue}let o=!1;try{o=p.forceRefreshSkills(void 0,{force:!0,ownerLibrarySync:!0})===!0}catch(i){l.warn("manager",`owner library skills reporter threw group=${r} agent=${p.name}: ${i}`)}if(o){c=!0;continue}l.warn("manager",`owner library skills reporter failed group=${r} agent=${p.name}; trying next`)}if(!c){l.warn("manager",`owner library skills: no reporter succeeded group=${r}`);continue}for(const p of s)try{p.adoptSkillsWireHashFromDisk()}catch(o){l.warn("manager",`adoptSkillsWireHashFromDisk failed for ${p.name}: ${o}`)}}}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),await this.auditProducer.stop({timeoutMs:5e3}).catch(()=>!1),this.instances=[],U(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const a=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,a)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:r,toRemove:a}=de(e.name,this.sharedInstances.keys(),t);for(const c of r){if(this.stopping)break;const s=pe(e.name,c);try{const p=le(e,c),o=new q(p,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(s,o),await o.start(),o.forceRefreshSkills(void 0,{force:!0}),l.info("manager",`shared instance started: ${s}`)}catch(p){this.sharedInstances.delete(s);const o=p instanceof Error?p.message:String(p);/Auth failed/i.test(o)?(this.sharedOwnersCache.remove(e.name,c),l.warn("manager",`shared instance auth rejected, removed from cache: ${s}`)):l.error("manager",`start shared instance failed ${s}: ${p}`)}}for(const{key:c}of a){const s=this.sharedInstances.get(c);s&&(this.sharedInstances.delete(c),s.stop().catch(p=>l.error("manager",`stop shared instance failed ${c}: ${p}`)),l.info("manager",`shared instance stopped: ${c}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(l.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),await this.ensureAuxServices(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const r=this.toRuntimeInstanceConfig(e);if(this.instances.some(a=>a.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,t)}createConfiguredInstance(e){const t=new q(e,this.globalConfigStore,this.auditProducer);return t.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),t.setInstallAgentHandler(r=>this.installAgent(r)),t.setShareSetHandler(r=>this.onShareSet(e,r)),t.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),t.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),t.setProviderConfigHandler(r=>this.setAgentProvider(e.name,r)),t.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(r,a)=>{const c=this.relayStateApplier;return c?c.applyEnable(e.name,r,a):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const r=this.relayStateApplier;return r?r.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),t.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),t.setProviderResolver(()=>z(this.getAgentProvider(e.name))),t}async prepareProviderRuntime(e,t){const r=this.resolveAgentProvider(t.provider);F(t.client_type)&&r?.base_url?.trim()&&r?.api_key?.trim()&&r?.model?.trim()&&await K(e.name,{baseUrl:r.base_url.trim(),apiKey:r.api_key.trim(),model:r.model.trim()})}async startInstanceFromConfig(e,t,r){await this.prepareProviderRuntime(e,t);const a=this.createConfiguredInstance(e);await a.start(),this.instances.push(a),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const r=this.instances.findIndex(p=>p.name===e),a=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const c=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),c&&await c.catch(()=>{});const s=`${e}#shared:`;for(const[p,o]of[...this.sharedInstances.entries()])p.startsWith(s)&&(this.sharedInstances.delete(p),o.stop().catch(i=>l.error("manager",`stop shared instance failed ${p}: ${i}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),a&&await a.stop(),t?.keepShareCache||await Q(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){l.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=b(this.configDir,"agents.json");try{const t=[];for(const[,a]of this.configMap){const c=this.rawConfigMap.get(a.name)?.entry.provider;t.push({name:a.name,ws_url:a.aibot.url,agent_id:a.aibot.agentId,api_key:a.aibot.apiKey,client_type:a.aibot.clientType,...c?{provider:c}:{}})}oe(e,JSON.stringify({agents:t},null,4)+`
2
2
  `,"utf-8")}catch(t){l.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(r=>r.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const t=this.instances.find(r=>r.name===e);return t?(t.markRelayEnvStale(),!0):!1}relayEnvSettledHandler;setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}relayStateApplier;setRelayStateApplier(e){this.relayStateApplier=e}reportRelayStateLocalChange(e){this.instances.find(r=>r.name===e)?.reportRelayStateLocalChange()}setRelaySecretResolver(e){this.relaySecretResolver=e}resolveAgentProvider(e){if(!e?.api_key_ref?.trim())return e;const t=e.api_key_ref.trim(),r=this.relaySecretResolver?.(t);if(!r)throw Object.assign(new Error(`relay credential "${t}" is unavailable`),{code:"RELAY_SECRET_UNAVAILABLE"});return{...e,api_key:r}}toRuntimeInstanceConfig(e,t={}){const r=this.resolveAgentProvider(e.provider);return Fe(r===e.provider?e:{...e,provider:r},t)}getAgentProvider(e){return this.resolveAgentProvider(this.rawConfigMap.get(e)?.entry.provider)}async restartAgent(e){const t=this.rawConfigMap.get(e);if(!t)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.replaceInstance(e,t.entry,t.file),l.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,t,r){const a=this.rawConfigMap.get(e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const c=String(a.entry.client_type??"").trim().toLowerCase();F(c)&&(t?.base_url?.trim()&&t?.api_key?.trim()&&t?.model?.trim()?await K(e,{baseUrl:t.base_url.trim(),apiKey:t.api_key.trim(),model:t.model.trim()}):await Q(e));const s=t?.api_key_ref?.trim()?Object.fromEntries(Object.entries(t).filter(([o])=>o!=="api_key")):t,p={...a.entry,provider:s};if(r?.deferRestart){this.rawConfigMap.set(e,{...a,entry:p}),this.instances.find(o=>o.name===e)?.markRelayEnvStale(),this.persistAgentsConfig(),l.info("manager",`Updated provider config for agent (deferred restart): ${e}`);return}await this.replaceInstance(e,p,a.file),this.persistAgentsConfig(),l.info("manager",`Updated provider config for agent: ${e}`)}hasDirectRelayConfig(e){const t=this.rawConfigMap.get(e)?.entry.provider;return!!(t?.api_key_ref?.trim()||t?.api_key?.trim())}getDirectRelayConfigAgentNames(){return[...this.rawConfigMap.entries()].filter(([,e])=>!!e.entry.provider&&(Ae(e.entry.client_type)||["claude","codex"].includes(String(e.entry.client_type??"").trim().toLowerCase()))).map(([e])=>e)}async fetchRelayCredential(e,t){const r=this.instances.find(a=>a.name===e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return r.fetchRelayCredential(t)}async clearDirectProviderConfigs(){const e=this.getDirectRelayConfigAgentNames(),t=[];for(const r of e)try{await this.setAgentProvider(r,void 0,{deferRestart:this.isAgentBusy(r)}),t.push(r)}catch(a){l.warn("manager",`Failed to clear provider config for "${r}": ${a instanceof Error?a.message:String(a)}`)}return t}async replaceInstance(e,t,r){const a=this.toRuntimeInstanceConfig(t);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(a,t,r),this.restoreCachedSharedInstances(a)}async reload(){const e=this.reloadChain.catch(()=>{}).then(()=>this.doReload());return this.reloadChain=e.catch(()=>{}),e}async doReload(){if(this.stopping)throw Object.assign(new Error("manager is stopping"),{code:"RELOAD_UNSAFE"});const{entries:e,fileErrors:t,skipped:r}=V(this.configDir);for(const o of r)l.info("manager",`reload: skipped ${o}: not an agent config (no "agents" key)`);if(t.length>0){const o=t.map(i=>`${i.file}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${t.length} config file(s) failed to parse [${o}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const a=[];for(const{entry:o}of e)try{this.toRuntimeInstanceConfig(o,{quiet:!0})}catch(i){const _=o?.name,g=typeof _=="string"&&_.trim()?_:"<unknown>";a.push({name:g,error:i instanceof Error?i.message:String(i)})}if(a.length>0){const o=a.map(i=>`${i.name}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${a.length} agent config(s) invalid [${o}]`),{code:"RELOAD_UNSAFE"})}const c=new Map;for(const o of e){const i=String(o.entry?.name??"").trim();i&&(c.has(i)&&l.warn("manager",`reload: duplicate agent name "${i}", last one wins`),c.set(i,o))}const s={added:[],removed:[],restarted:[],unchanged:[],failed:[]},p=new Set(this.rawConfigMap.keys());for(const o of p)if(!c.has(o))try{await this.removeAgentInternal(o),s.removed.push(o)}catch(i){s.failed.push({name:o,error:i instanceof Error?i.message:String(i)})}for(const[o,i]of c){const _=this.rawConfigMap.get(o);if(_)if(Qe(_.entry,i.entry))this.rawConfigMap.set(o,i),s.unchanged.push(o);else try{await this.replaceInstance(o,i.entry,i.file),s.restarted.push(o)}catch(g){s.failed.push({name:o,error:g instanceof Error?g.message:String(g)})}else try{await this.addAgentInternal(i.entry,i.file),s.added.push(o)}catch(g){s.failed.push({name:o,error:g instanceof Error?g.message:String(g)})}}return l.info("manager",`reload done: +${s.added.length} -${s.removed.length} ~${s.restarted.length} =${s.unchanged.length} !${s.failed.length}`),await this.ensureAuxServices(),s}async checkUpgrade(){return this.upgradeChecker?this.upgradeChecker.checkForUpdate():{available:!1}}triggerUpgrade(){this.upgradeChecker?.triggerCheck()}async probeAll(e={}){return We(this.instances,e)}async probeOne(e,t={}){return Ge(this.instances,e,t)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const t=await this.installer.install(e);return Ie(t),t}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function We(n,e){const t=e.concurrency??4,r=Date.now(),a=new Array(n.length);await new Promise(i=>{let _=0,g=0;const d=n.length;if(d===0){i();return}function m(h){const k=n[h];k.probe(e).then(S=>{a[h]=S,y()},S=>{a[h]={agent_name:k.name,client_type:"unknown",adapter_type:"acp",ok:!1,status:"error",probed_at:Date.now(),duration_ms:0,cached:!1,cli:{command:"",installed:!1,path:null,version:null,error:{code:"internal",message:S?.message??String(S)}},conversation:{attempted:!1,ok:!1,latency_ms:null},config:{model:null,base_url:null,source:{model:"unknown",base_url:"unknown"}},process:{started:!1,alive:!1,busy:!1}},y()})}function y(){g++,_<d?m(_++):g===d&&i()}const u=Math.min(t,d);for(let h=0;h<u;h++)m(_++)});const c=a.filter(i=>i.status==="healthy").length,s=a.filter(i=>i.status==="degraded").length,p=a.filter(i=>i.status==="unavailable").length,o=await De();return{ok:c===a.length&&a.length>0,total:a.length,healthy:c,degraded:s,unavailable:p,installed_clients:o,agents:a,probed_at:r,duration_ms:Date.now()-r}}async function Ge(n,e,t){const r=n.find(a=>a.name===e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return r.probe(t)}export{kt as Manager,z as normalizeAgentProviderForRuntime,De as probeInstalledClientCommands,We as probeInstances,Ge as probeOneInstance};
@@ -1 +1 @@
1
- import{execSync as f,spawn as y}from"node:child_process";import o from"node:process";import{setTimeout as P}from"node:timers/promises";let l;function T(){if(o.platform!=="win32")return!1;if(l!==void 0)return l;try{f("net session",{stdio:"ignore"}),l=!0}catch{l=!1}return l}function F(t,e,r={}){y(t,e,{detached:!0,stdio:"ignore",windowsHide:!0,env:r.env??o.env}).unref()}function p(t,e,r={}){const{cwd:n,env:s=o.env,allowFailure:d=!1}=r;return new Promise((c,i)=>{const u=y(t,e,{cwd:n||void 0,env:s,stdio:["ignore","pipe","pipe"],windowsHide:!0}),g=[],C=[];u.stdout&&u.stdout.on("data",a=>g.push(a)),u.stderr&&u.stderr.on("data",a=>C.push(a)),u.on("error",i),u.on("close",a=>{const m=a??0,I=Buffer.concat(g).toString("utf8"),x=Buffer.concat(C).toString("utf8");if(m!==0&&!d){const E=x.trim()||I.trim()||`${t} exited with code ${m}`;i(new Error(E));return}c({exitCode:m,stdout:I,stderr:x})})})}function w(t){if(t<=0)return!1;try{return o.kill(t,0),!0}catch(e){if(e instanceof Error&&"code"in e){if(e.code==="ESRCH")return!1;if(e.code==="EPERM")return!0}return!1}}const h=3e3;function L(t){try{const n=f(`wmic process where ProcessId=${t} get CommandLine /format:list`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h}).match(/CommandLine=(.*)/)?.[1]?.trim();if(n)return n}catch{}try{const r=f(`powershell -NoProfile -Command "(Get-CimInstance Win32_Process -Filter 'ProcessId=${t}').CommandLine"`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h}).trim();return r||null}catch{return null}}function R(t){if(t<=0||!Number.isInteger(t))return null;if(o.platform==="win32")return L(t);try{const r=f(`ps -ww -o command= -p ${t}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h}).trim();return r||null}catch{return null}}async function k(t,e={}){const{platform:r=o.platform,runCommandImpl:n=p}=e;if(t<=0)return!1;if(r==="win32")return await n("taskkill",["/PID",String(t),"/T","/F"],{allowFailure:!0}),!0;try{return o.kill(-t,"SIGTERM"),!0}catch{}try{return o.kill(t,"SIGTERM"),!0}catch{return!1}}async function $(t,e={}){const{timeoutMs:r=5e3,intervalMs:n=100}=e;if(t<=0)return!0;const s=Date.now()+r;for(;Date.now()<=s;){if(!w(t))return!0;await P(n)}return!w(t)}async function v(t){const e=p;if(o.platform==="win32"){const n=await e("wmic",["process","where",`CommandLine Like '%${t}%'`,"get","ProcessId"],{allowFailure:!0});return n.exitCode!==0?[]:n.stdout.split(/\r?\n/).map(s=>parseInt(s.trim(),10)).filter(s=>s>0&&!isNaN(s))}const r=await e("pgrep",["-f",t],{allowFailure:!0});return r.exitCode!==0?[]:r.stdout.split(/\n/).map(n=>parseInt(n.trim(),10)).filter(n=>n>0&&!isNaN(n))}async function B(t,e={}){const{exceptPid:r=0,platform:n=o.platform}=e,s=await v(t),d=new Set([o.pid,o.ppid,r]),c=s.filter(i=>!d.has(i));if(c.length===0)return 0;if(n==="win32")for(const i of c)await k(i,{platform:"win32",runCommandImpl:p});else{for(const i of c)try{o.kill(i,"SIGTERM")}catch{}await P(500);for(const i of c)if(w(i))try{o.kill(i,"SIGKILL")}catch{}}return c.length}export{R as getProcessCommandLine,w as isProcessRunning,T as isWindowsElevated,B as killProcessesByCommandLine,p as runCommand,F as spawnDetached,k as terminateProcessTree,$ as waitForProcessExit};
1
+ import{execFileSync as v,execSync as m,spawn as I}from"node:child_process";import o from"node:process";import{setTimeout as P}from"node:timers/promises";let l;function R(){if(o.platform!=="win32")return!1;if(l!==void 0)return l;try{m("net session",{stdio:"ignore",windowsHide:!0}),l=!0}catch{l=!1}return l}function T(t,r,n={}){I(t,r,{detached:!0,stdio:"ignore",windowsHide:!0,env:n.env??o.env}).unref()}function w(t,r,n={}){const{cwd:e,env:s=o.env,allowFailure:d=!1}=n;return new Promise((c,i)=>{const u=I(t,r,{cwd:e||void 0,env:s,stdio:["ignore","pipe","pipe"],windowsHide:!0}),g=[],C=[];u.stdout&&u.stdout.on("data",a=>g.push(a)),u.stderr&&u.stderr.on("data",a=>C.push(a)),u.on("error",i),u.on("close",a=>{const f=a??0,y=Buffer.concat(g).toString("utf8"),x=Buffer.concat(C).toString("utf8");if(f!==0&&!d){const S=x.trim()||y.trim()||`${t} exited with code ${f}`;i(new Error(S));return}c({exitCode:f,stdout:y,stderr:x})})})}function p(t){if(t<=0)return!1;try{return o.kill(t,0),!0}catch(r){if(r instanceof Error&&"code"in r){if(r.code==="ESRCH")return!1;if(r.code==="EPERM")return!0}return!1}}const h=3e3;function E(t){try{const e=m(`wmic process where ProcessId=${t} get CommandLine /format:list`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h,windowsHide:!0}).match(/CommandLine=(.*)/)?.[1]?.trim();if(e)return e}catch{}try{const r=`${o.env.SystemRoot||"C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,e=v(r,["-NoProfile","-NonInteractive","-WindowStyle","Hidden","-Command",`(Get-CimInstance Win32_Process -Filter 'ProcessId=${t}').CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h,windowsHide:!0}).trim();return e||null}catch{return null}}function H(t){if(t<=0||!Number.isInteger(t))return null;if(o.platform==="win32")return E(t);try{const n=m(`ps -ww -o command= -p ${t}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:h}).trim();return n||null}catch{return null}}async function L(t,r={}){const{platform:n=o.platform,runCommandImpl:e=w}=r;if(t<=0)return!1;if(n==="win32")return await e("taskkill",["/PID",String(t),"/T","/F"],{allowFailure:!0}),!0;try{return o.kill(-t,"SIGTERM"),!0}catch{}try{return o.kill(t,"SIGTERM"),!0}catch{return!1}}async function $(t,r={}){const{timeoutMs:n=5e3,intervalMs:e=100}=r;if(t<=0)return!0;const s=Date.now()+n;for(;Date.now()<=s;){if(!p(t))return!0;await P(e)}return!p(t)}async function k(t){const r=w;if(o.platform==="win32"){const e=await r("wmic",["process","where",`CommandLine Like '%${t}%'`,"get","ProcessId"],{allowFailure:!0});return e.exitCode!==0?[]:e.stdout.split(/\r?\n/).map(s=>parseInt(s.trim(),10)).filter(s=>s>0&&!isNaN(s))}const n=await r("pgrep",["-f",t],{allowFailure:!0});return n.exitCode!==0?[]:n.stdout.split(/\n/).map(e=>parseInt(e.trim(),10)).filter(e=>e>0&&!isNaN(e))}async function W(t,r={}){const{exceptPid:n=0,platform:e=o.platform}=r,s=await k(t),d=new Set([o.pid,o.ppid,n]),c=s.filter(i=>!d.has(i));if(c.length===0)return 0;if(e==="win32")for(const i of c)await L(i,{platform:"win32",runCommandImpl:w});else{for(const i of c)try{o.kill(i,"SIGTERM")}catch{}await P(500);for(const i of c)if(p(i))try{o.kill(i,"SIGKILL")}catch{}}return c.length}export{H as getProcessCommandLine,p as isProcessRunning,R as isWindowsElevated,W as killProcessesByCommandLine,w as runCommand,T as spawnDetached,L as terminateProcessTree,$ as waitForProcessExit};