grix-connector 3.19.2 → 3.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/persistence/fsync.js +1 -0
- package/dist/core/persistence/stop-result-outbox.js +2 -2
- package/dist/core/persistence/terminal-commit-token-store.js +2 -2
- package/dist/core/persistence/terminal-outbox.js +2 -2
- package/dist/core/upgrade/npm-upgrader.js +2 -2
- package/dist/manager.js +2 -2
- package/dist/mcp/stream-http/security.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{closeSync as t,fsyncSync as e,openSync as y}from"node:fs";function i(n){const c=y(n,"r");try{e(c)}catch(o){const r=o.code;if(process.platform!=="win32"||r!=="EPERM"&&r!=="EINVAL")throw o}finally{t(c)}}export{i as fsyncDirectory};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"});const
|
|
1
|
+
import{chmodSync as f,closeSync as y,existsSync as g,fsyncSync as _,mkdirSync as k,openSync as w,readFileSync as A,renameSync as b,unlinkSync as c,writeFileSync as v}from"node:fs";import{randomUUID as E}from"node:crypto";import{dirname as d}from"node:path";import{fsyncDirectory as p}from"./fsync.js";const l=1;function u(o){return`${o.event_id?.trim()??""}\0${o.stop_id.trim()}`}function a(o){return{...o,payload:{...o.payload}}}function m(o){if(!o||typeof o!="object"||Array.isArray(o))return!1;const t=o;return!!(t.event_id?.trim()&&t.stop_id?.trim()&&t.terminal_commit_token?.trim()&&(t.status==="stopped"||t.status==="already_finished"))}class ${filePath;pending=new Map;constructor(t){this.filePath=t,this.load()}enqueue(t){if(!m(t))throw new Error("stop result outbox requires event_id, stop_id, terminal token, and valid status");const r={...t,event_id:t.event_id.trim(),stop_id:t.stop_id.trim(),terminal_commit_token:t.terminal_commit_token.trim()},n=u(r),i=this.pending.get(n);if(i){if(i.payload.status!==r.status||i.payload.terminal_commit_token!==r.terminal_commit_token)throw new Error(`stop result changed for event=${r.event_id} stop=${r.stop_id}`);return a(i)}const e=Date.now(),s={key:n,payload:r,generation:1,createdAt:e,updatedAt:e,attempts:0,nextAttemptAt:0};this.pending.set(n,s);try{this.persist()}catch(h){throw this.pending.delete(n),h}return a(s)}listPending(){return[...this.pending.values()].map(a)}isCurrent(t){const r=this.pending.get(t.key);return r?.generation===t.generation&&r.payload.status===t.payload.status&&r.payload.terminal_commit_token===t.payload.terminal_commit_token}acknowledge(t,r,n,i){if(r?.trim()!==t.payload.event_id||n?.trim()!==t.payload.terminal_commit_token||i!==!0||!this.isCurrent(t))return!1;const e=this.pending.get(t.key);this.pending.delete(t.key);try{this.persist()}catch(s){throw this.pending.set(t.key,e),s}return!0}recordRetry(t,r,n){const i=this.pending.get(t.key);if(!i||i.generation!==t.generation)return!1;const e=a(i);i.attempts+=1,i.updatedAt=Date.now(),i.nextAttemptAt=r,i.lastError=n;try{this.persist()}catch(s){throw this.pending.set(t.key,e),s}return!0}discard(t){const r=this.pending.get(t.key);if(!r||r.generation!==t.generation)return!1;this.pending.delete(t.key);try{this.persist()}catch(n){throw this.pending.set(t.key,r),n}return!0}load(){if(!this.filePath||!g(this.filePath))return;let t;try{t=JSON.parse(A(this.filePath,"utf8"))}catch(n){throw new Error(`stop result outbox load failed: ${n instanceof Error?n.message:n}`)}if(!t||typeof t!="object"||Array.isArray(t))throw new Error("stop result outbox load failed: invalid root");const r=t;if(r.version!==l||!r.pending||typeof r.pending!="object"||Array.isArray(r.pending))throw new Error("stop result outbox load failed: unsupported or invalid file");for(const[n,i]of Object.entries(r.pending)){if(!i||typeof i!="object")continue;const e=i;!m(e.payload)||n!==e.key||n!==u(e.payload)||this.pending.set(n,{key:n,payload:{...e.payload},generation:Number.isInteger(e.generation)&&e.generation>0?e.generation:1,createdAt:Number.isFinite(e.createdAt)?e.createdAt:Date.now(),updatedAt:Number.isFinite(e.updatedAt)?e.updatedAt:Date.now(),attempts:Number.isInteger(e.attempts)&&e.attempts>=0?e.attempts:0,nextAttemptAt:Number.isFinite(e.nextAttemptAt)?e.nextAttemptAt:0,...typeof e.lastError=="string"?{lastError:e.lastError}:{}})}}persist(){if(!this.filePath)return;if(this.pending.size===0){try{c(this.filePath),p(d(this.filePath))}catch(i){if(i.code!=="ENOENT")throw i}return}const t=Object.create(null);for(const[i,e]of this.pending)t[i]=a(e);const r={version:l,pending:t};k(d(this.filePath),{recursive:!0,mode:448});const n=`${this.filePath}.${E()}.tmp`;try{v(n,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});const i=w(n,"r+");try{_(i)}finally{y(i)}b(n,this.filePath),p(d(this.filePath));try{f(this.filePath,384)}catch{}}finally{try{c(n)}catch{}}}}export{$ as StopResultOutbox};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"});const
|
|
1
|
+
import{chmodSync as f,closeSync as l,existsSync as m,fsyncSync as y,mkdirSync as d,openSync as k,readFileSync as p,renameSync as u,unlinkSync as s,writeFileSync as w}from"node:fs";import{randomUUID as P}from"node:crypto";import{dirname as n}from"node:path";import{fsyncDirectory as a}from"./fsync.js";const c=1;class N{filePath;tokens=new Map;constructor(e){this.filePath=e,this.load()}get(e){return this.tokens.get(e)}register(e,o){const t=e.trim(),r=o.trim();if(!t||!r)throw new Error("terminal commit token requires non-empty event_id and token");const i=this.tokens.get(t);if(i!==r){if(i)throw new Error(`terminal commit token changed for event=${t}`);this.tokens.set(t,r);try{this.persist()}catch(h){throw this.tokens.delete(t),h}}}remove(e,o){const t=this.tokens.get(e);if(!t||t!==o)return!1;this.tokens.delete(e);try{this.persist()}catch(r){throw this.tokens.set(e,t),r}return!0}load(){if(!this.filePath||!m(this.filePath))return;let e;try{e=JSON.parse(p(this.filePath,"utf8"))}catch(t){throw new Error(`terminal commit token store load failed: ${t instanceof Error?t.message:t}`)}if(!e||typeof e!="object"||Array.isArray(e))throw new Error("terminal commit token store load failed: invalid root");const o=e;if(o.version!==c||!o.tokens||typeof o.tokens!="object"||Array.isArray(o.tokens))throw new Error("terminal commit token store load failed: unsupported or invalid file");for(const[t,r]of Object.entries(o.tokens))t.trim()&&typeof r=="string"&&r.trim()&&this.tokens.set(t,r)}persist(){if(!this.filePath)return;if(this.tokens.size===0){try{s(this.filePath),a(n(this.filePath))}catch(r){if(r.code!=="ENOENT")throw r}return}const e=Object.create(null);for(const[r,i]of this.tokens)e[r]=i;const o={version:c,tokens:e};d(n(this.filePath),{recursive:!0,mode:448});const t=`${this.filePath}.${P()}.tmp`;try{w(t,`${JSON.stringify(o,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});const r=k(t,"r+");try{y(r)}finally{l(r)}u(t,this.filePath),a(n(this.filePath));try{f(this.filePath,384)}catch{}}finally{try{s(t)}catch{}}}}export{N as TerminalCommitTokenStore};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chmodSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"});const i=
|
|
1
|
+
import{chmodSync as m,closeSync as y,existsSync as g,fsyncSync as v,mkdirSync as A,openSync as _,readFileSync as w,renameSync as S,unlinkSync as b,writeFileSync as D}from"node:fs";import{randomUUID as L}from"node:crypto";import{dirname as c}from"node:path";import{fsyncDirectory as E}from"./fsync.js";const u=1,h=1e3;function p(s){return{...s}}function o(s){return{...s,payload:p(s.payload)}}function l(s){if(!s||typeof s!="object")return!1;const e=s;return typeof e.event_id=="string"&&e.event_id.length>0&&(e.status==="responded"||e.status==="failed"||e.status==="canceled")}class k{filePath;pending=new Map;deadLetters=[];constructor(e){this.filePath=e,this.load()}enqueue(e){if(!l(e))throw new Error("terminal outbox requires a non-empty event_id and terminal status");const t=this.pending.get(e.event_id),r=Date.now(),i={payload:p(e),generation:(t?.generation??0)+1,createdAt:t?.createdAt??r,updatedAt:r,attempts:0,nextAttemptAt:0};this.pending.set(e.event_id,i);try{this.persist()}catch(n){throw t?this.pending.set(e.event_id,t):this.pending.delete(e.event_id),n}return o(i)}get(e){const t=this.pending.get(e);return t?o(t):void 0}listPending(){return[...this.pending.values()].map(o)}listDeadLetters(){return this.deadLetters.map(e=>({...e,payload:p(e.payload)}))}isCurrent(e){const t=this.pending.get(e.payload.event_id);return t?.generation===e.generation&&t.payload.status===e.payload.status}markDeliveryStarted(e){const t=this.pending.get(e.payload.event_id);if(!t||t.generation!==e.generation)return;if(t.deliveryStartedAt)return o(t);const r=o(t);t.deliveryStartedAt=Date.now(),t.updatedAt=t.deliveryStartedAt;try{this.persist()}catch(i){throw this.pending.set(e.payload.event_id,r),i}return o(t)}acknowledge(e,t,r,i,n){if(t!==e.payload.event_id||r!==e.payload.status)return!1;const a=e.payload.terminal_commit_token?.trim();if(a&&(i?.trim()!==a||n!==!0))return!1;const d=this.pending.get(e.payload.event_id);if(!d||d.generation!==e.generation||d.payload.status!==e.payload.status||d.payload.terminal_commit_token?.trim()!==a)return!1;this.pending.delete(e.payload.event_id);try{this.persist()}catch(f){throw this.pending.set(e.payload.event_id,d),f}return!0}recordRetry(e,t,r){const i=this.pending.get(e.payload.event_id);if(!i||i.generation!==e.generation)return!1;const n=o(i);i.attempts+=1,i.updatedAt=Date.now(),i.nextAttemptAt=t,i.lastError=r;try{this.persist()}catch(a){throw this.pending.set(e.payload.event_id,n),a}return!0}moveToDeadLetter(e,t){const r=this.pending.get(e.payload.event_id);if(!r||r.generation!==e.generation)return!1;const i={payload:p(r.payload),rejectedAt:Date.now(),responseCmd:t.responseCmd,code:t.code,message:t.message},n=this.deadLetters;this.pending.delete(e.payload.event_id),this.deadLetters=[...this.deadLetters,i].slice(-h);try{this.persist()}catch(a){throw this.pending.set(e.payload.event_id,r),this.deadLetters=n,a}return!0}load(){if(!this.filePath||!g(this.filePath))return;let e;try{e=JSON.parse(w(this.filePath,"utf8"))}catch(r){throw new Error(`terminal outbox load failed: ${r instanceof Error?r.message:r}`)}if(!e||typeof e!="object"||Array.isArray(e))throw new Error("terminal outbox load failed: invalid root");const t=e;if(t.version!==u||!t.pending||typeof t.pending!="object"||Array.isArray(t.pending))throw new Error("terminal outbox load failed: unsupported or invalid file");for(const[r,i]of Object.entries(t.pending)){if(!i||typeof i!="object")continue;const n=i;if(r!==n.payload?.event_id||!l(n.payload))continue;const a=Number.isFinite(n.deliveryStartedAt)&&n.deliveryStartedAt>0?n.deliveryStartedAt:void 0,d=n.payload.code==="agent_output_unconfirmed"?a??(Number.isFinite(n.updatedAt)?n.updatedAt:Date.now()):a;this.pending.set(r,{payload:p(n.payload),generation:Number.isInteger(n.generation)&&n.generation>0?n.generation:1,createdAt:Number.isFinite(n.createdAt)?n.createdAt:Date.now(),updatedAt:Number.isFinite(n.updatedAt)?n.updatedAt:Date.now(),attempts:Number.isInteger(n.attempts)&&n.attempts>=0?n.attempts:0,nextAttemptAt:Number.isFinite(n.nextAttemptAt)?n.nextAttemptAt:0,...d?{deliveryStartedAt:d}:{},...typeof n.lastError=="string"?{lastError:n.lastError}:{}})}Array.isArray(t.deadLetters)&&(this.deadLetters=t.deadLetters.filter(r=>!!r&&l(r.payload)&&(r.responseCmd==="send_nack"||r.responseCmd==="error")).slice(-h).map(r=>({...r,payload:p(r.payload)})))}persist(){if(!this.filePath)return;const e=Object.create(null);for(const[i,n]of this.pending)e[i]=o(n);const t={version:u,pending:e,deadLetters:this.listDeadLetters()};A(c(this.filePath),{recursive:!0,mode:448});const r=`${this.filePath}.${L()}.tmp`;try{D(r,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});const i=_(r,"r+");try{v(i)}finally{y(i)}S(r,this.filePath),E(c(this.filePath));try{m(this.filePath,384)}catch{}}finally{try{b(r)}catch{}}}}export{k as TerminalOutbox};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execFile as
|
|
2
|
-
`;try{
|
|
1
|
+
import{execFile as E,execFileSync as m}from"node:child_process";import{promisify as w}from"node:util";import{existsSync as a,readFileSync as p,renameSync as y,statfsSync as I,unlinkSync as N,writeFileSync as v}from"node:fs";import{join as f}from"node:path";import{GRIX_PATHS as d}from"../log/index.js";import{appendRotatingFileSync as x}from"../log/rotation.js";import{getMachineName as F}from"../util/host-info.js";import{resolveInstallId as M}from"../util/install-id.js";import{npmInstallWithMirror as k,NPM_REGISTRIES as L}from"../installer/npm-registry.js";const b=w(E);class s extends Error{code;constructor(t,r){super(r),this.name="UpgradeError",this.code=t}}function g(){return f(d.log,"upgrade.log")}function l(){return f(d.data,"upgrade-pending.json")}function C(){return a(l())}function j(){const e=l();if(!a(e))return null;try{return JSON.parse(p(e,"utf-8"))}catch{return null}}function G(e,t){const r={from_version:e,target_version:t,upgraded_at:new Date().toISOString(),crash_count:0},i=l(),n=i+".tmp";v(n,JSON.stringify(r),"utf-8"),y(n,i)}function J(){const e=l();if(a(e))try{N(e)}catch{}}function u(e){const t=`[${new Date().toISOString()}] ${e}
|
|
2
|
+
`;try{x(g(),t)}catch{}}function K(e=4096){const t=g();if(!a(t))return"";try{const r=p(t,"utf-8");return r.length<=e?r:r.slice(-e)}catch{return""}}function h(){try{const e=process.platform==="win32";return m(e?"cmd.exe":"npm",e?["/c","npm","--version"]:["--version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new s("NPM_NOT_FOUND","npm is not available or timed out")}}const c=1e6;function _(){if(process.platform==="win32")return c;let e;try{e=m("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return c}try{const t=I(e),r=Math.floor(Number(t.bavail)*Number(t.bsize)/(1024*1024));return!Number.isFinite(r)||r<0?c:Math.min(r,c)}catch{return c}}function W(){let e;try{e=h()}catch(r){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:r instanceof Error?r.message:"npm not available"}}const t=_();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 B(){let e="";try{e=h()}catch{}let t=c;try{t=_()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:t,platform:process.platform,arch:process.arch,host_name:F(),install_id:M()}}async function H(e,t,r=12e4){const i=`${e}@${t}`;u(`npm install -g ${i} starting (with mirror fallback)`);try{const{registry:n}=await k(i,r,10485760);u(`npm install succeeded via ${n}`)}catch(n){const o=n instanceof Error?n.message:String(n);throw u(`npm install failed: ${o}`),/timed out|ETIMEDOUT/i.test(o)?new s("NPM_TIMEOUT",`npm install timed out after ${r/1e3}s (tried all mirrors): ${o}`):o.includes("EACCES")||o.includes("permission denied")?new s("NPM_INSTALL_FAILED",`Permission denied: ${o}`):o.includes("ENOSPC")||o.includes("no space left")?new s("DISK_FULL",`Disk full: ${o}`):o.includes("404")||o.includes("not found")?new s("NPM_INSTALL_FAILED",`Package not found: ${o}`):new s("NPM_INSTALL_FAILED",o)}}function Y(e){let t;try{const i=process.platform==="win32";t=m(i?"cmd.exe":"npm",i?["/c","npm","root","-g"]:["root","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new s("VERSION_VERIFY_FAILED","Unable to resolve the global npm package directory")}let r;try{const i=f(t,"grix-connector","package.json"),n=JSON.parse(p(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 s("VERSION_VERIFY_FAILED","Unable to read the installed grix-connector version")}if(r!==e)throw new s("VERSION_MISMATCH",`Installed version ${r} does not match expected ${e}`);return r}async function z(e,t){let r=!1;for(const i of L)try{const{stdout:n}=await b("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{s as UpgradeError,_ as checkDiskSpace,h as checkNpmAvailable,B as collectEnvInfo,K as getUpgradeLogTail,z as isVersionAvailable,H as npmInstall,C as pendingExists,W as preflightCheck,j as readPending,J as removePending,u as upgradeLog,Y as verifyInstalledVersion,G as writePending};
|
package/dist/manager.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readFileSync as Z,readdirSync as ee,writeFileSync as te}from"node:fs";import{join as A}from"node:path";import{homedir as ne}from"node:os";import{AgentInstance as E}from"./bridge/bridge.js";import{buildSharedInstanceConfig as ae,diffSharedOwners as re,sharedInstanceKey as se,SharedOwnersCache as ie}from"./manager-share-config.js";import{isAgentDeletedError as R}from"./core/aibot/errors.js";import{GRIX_PATHS as S,log as l}from"./core/log/index.js";import{resolveClientVersion as oe}from"./core/util/client-version.js";import{UpgradeChecker as ce}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as le}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as de}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as pe}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as me}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as ue}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as ge}from"./core/aibot/types.js";import{buildReportedSkills as he,logDefaultSkillsCheck as fe,cleanupProjectedSkills as q}from"./default-skills/index.js";import{supportsKiroCwRelay as H,supportsNonMitmRelayConfig as _e}from"./core/config/provider-env.js";import{ensureKiroRelay as N,stopKiroRelay as U}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as L}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as B}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ye,resolveCliPath as we}from"./core/util/cli-probe.js";import{AgentInstaller as Se}from"./core/installer/installer.js";import{reportInstallFailure as Ae}from"./core/observability/sentry.js";import{createDefaultAuditProducer as ve}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as ke}from"./adapter/codex/config-overrides.js";const be=8e3;function Ce(){const n=L();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:B()},{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"}]}async function xe(){return Promise.all(Ce().map(async n=>{const e=await we(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ye(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function $e(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:B()};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=L();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function k(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 Te(n,e){return A(S.data,`session-bindings-${k(n,e)}.json`)}function Ie(n,e){return A(S.data,`active-events-${k(n,e)}.json`)}function Ee(n,e){const t=k(n,"agent"),a=k(e,"unknown");return A(S.data,`terminal-outbox-${t}-${a}.json`)}function Me(...n){const e=[],t=new Set;for(const a of n)for(const r of a??[]){const i=String(r??"").trim(),s=i.toLowerCase();!i||t.has(s)||(t.add(s),e.push(i))}return e.length>0?e:void 0}function je(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}},a=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??a.maxConcurrent??1,maxQueued:e?.max_queued??a.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??a.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function b(n,e={}){const t=oe(),a=String(n.client_type??"").trim().toLowerCase(),r=$e(a),i=String(n.ws_url??"").trim(),s="get_session_usage",p="get_rate_limits",c="get_agent_global_config",o=ge;if(!n.name?.trim())throw new Error("agent name is required");if(!i)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=r.adapterType,u=d==="acp",w=a==="qwen",y={...r.options??{}};if(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`);ke(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),y.codexConfigOverrides=n.codex_config_overrides}const m=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",s,p]}:null,f=d==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",s,p]}:null,h=w?{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",s],adapterHint:"qwen/base"}:null,g=d==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",s,p]}:null,_=d==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,v=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",p]}:null,M=d==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",s]}:null,x=d==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","file_list","create_folder"]}:null,$=d==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,j=new Set(["hermes","reasonix","kimi","copilot"]),Q=u&&!j.has(a),K=u&&!w?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...Q?[s]:[]]}:null,W=a==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",s,p]}:null,z=d==="codex"||d==="claude"||a==="gemini"?["session_control","set_model","set_mode"]:void 0,G=d==="cursor"||d==="opencode"||d==="openhuman"||d==="agy"||u&&j.has(a)?[p]:[s,p];u&&y.raw_transport===void 0&&(y.raw_transport=a==="gemini");const J=`${a}/base`,T=pe(d,a),V=T==="kiro"?void 0:process.cwd(),P=he({mode:T,projectDir:V}),D=P.filter(I=>I.source==="connector").map(I=>I.name);D.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${D.join(", ")}]`);const O=me(P,S.skills);let X=O.length>0?O:void 0;const Y=ue({skillsDir:S.skills,mode:T,home:ne()});return{name:n.name,adapterType:d,aibot:{url:i,agentId:n.agent_id,apiKey:n.api_key,clientType:a,clientVersion:t,adapterHint:r.adapterHint??h?.adapterHint??g?.adapterHint??_?.adapterHint??v?.adapterHint??x?.adapterHint??$?.adapterHint??J,capabilities:m?.capabilities??M?.capabilities??g?.capabilities??_?.capabilities??v?.capabilities??x?.capabilities??$?.capabilities??h?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Me(m?.localActions??M?.localActions??f?.localActions??g?.localActions??_?.localActions??v?.localActions??x?.localActions??$?.localActions??h?.localActions??W?.localActions??K?.localActions??["exec_approve","exec_reject"],z,G,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...o]),skills:X,librarySkills:Y,terminalOutboxPath:Ee(n.name,n.agent_id)},agent:{command:r.command,args:[...r.args??[],...n.args??[]],env:n.env,clientType:a,...n.provider?{provider:{...n.provider.provider_id?.trim()?{providerId:n.provider.provider_id.trim()}:{},...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.quota_base_url?.trim()?{quotaBaseUrl:n.provider.quota_base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{}}}:{}},adapterOptions:y,acpAuthMethod:y.auth_method,acpInitialMode:y.initial_mode,acpMcpTools:y.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:Te(n.name,n.agent_id),activeEventStorePath:Ie(n.name,n.agent_id),...r.enableSessionBinding||u?{enableSessionBinding:!0}:{},...r.autoInjectArgs||a==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...r.autoInjectArgs??{},...a==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:je(d,n.event_queue),logDir:S.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Pe(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):be}function F(n){const e=[],t=[],a=[],r=ee(n).filter(i=>i.endsWith(".json")).sort();for(const i of r)try{const s=JSON.parse(Z(A(n,i),"utf-8"));if(s===null||typeof s!="object"||Array.isArray(s)||!("agents"in s)){a.push(i);continue}if(!Array.isArray(s.agents)){t.push({file:i,error:"agents is not an array"});continue}if(s.agents.length===0){t.push({file:i,error:"agents array is empty"});continue}for(const p of s.agents)e.push({entry:p,file:i})}catch(s){t.push({file:i,error:s instanceof Error?s.message:String(s)})}return{entries:e,fileErrors:t,skipped:a}}function C(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(C).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(a=>`${JSON.stringify(a)}:${C(e[a])}`).join(",")}}`}function De(n,e){return C(n)===C(e)}class ct{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=S.config;sharedOwnersCache=new ie(S.data);installer=new Se;auditProducer=ve();async start(e){const t=e??S.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),fe(),q(),this.globalConfigStore=new de(A(S.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:a,fileErrors:r,skipped:i}=F(t);for(const o of r)l.error("manager",`Failed to load ${o.file}: ${o.error}`);for(const o of i)l.info("manager",`Skipped ${o}: not an agent config (no "agents" key)`);if(a.length===0&&r.length===0&&i.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=r.length;for(const{entry:o,file:d}of a)try{const u=b(o);s.push({config:u,entry:o,file:d}),l.info("manager",`Loaded ${u.name} (${u.adapterType??"acp"}) from ${d}`)}catch(u){const w=typeof o?.name=="string"?o.name:"<unknown>";l.error("manager",`Invalid agent config in ${d} (name=${w}): ${u}`),p++}let c=0;if(s.length>0){const o=Pe();l.info("manager",`Starting ${s.length} agent(s), startup wait=${o}ms`);const d=()=>this.upgradeChecker?.triggerCheck(),u=m=>{this.instances=this.instances.filter(f=>f!==m)},w=s.map(({config:m,entry:f,file:h})=>{const g=new E(m,this.globalConfigStore,this.auditProducer);return g.setUpgradeTrigger(d),g.setShareSetHandler(_=>this.onShareSet(m,_)),g.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(m.name)),g.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),this.instances.push(g),this.configMap.set(m.name,m),this.rawConfigMap.set(m.name,{entry:f,file:h}),{config:m,instance:g,startPromise:g.start()}}),y=await Promise.all(w.map(async m=>{const f=await new Promise(h=>{let g=!1;const _=setTimeout(()=>{g||(g=!0,h({kind:"timeout"}))},o);m.startPromise.then(()=>{g||(g=!0,clearTimeout(_),h({kind:"started"}))}).catch(v=>{g||(g=!0,clearTimeout(_),h({kind:"failed",error:v}))})});return{task:m,outcome:f}}));for(const{task:m,outcome:f}of y){if(f.kind==="started"){this.restoreCachedSharedInstances(m.config);continue}if(f.kind==="failed"){if(R(f.error)){this.onAgentDeletedByPlatform(m.config.name);continue}u(m.instance),l.error("manager",`Failed to start ${m.config.name}: ${f.error}`);continue}c++,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(h=>{if(R(h)){this.onAgentDeletedByPlatform(m.config.name);return}u(m.instance),l.error("manager",`Delayed start failed: ${m.config.name}: ${h}`)})}if(this.instances.length>0){const m=Math.max(0,this.instances.length-c);l.info("manager",`${m}/${s.length} agent(s) running now`)}c>0&&l.warn("manager",`${c} 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 ce(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new le(e,S.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshAllInstanceSkills()),await this.skillSyncer.start())}refreshAllInstanceSkills(){for(const e of this.instances)try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for ${e.name}: ${t}`)}for(const e of this.sharedInstances.values())try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for shared instance: ${t}`)}}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=[],q(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const r=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,r)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:a,toRemove:r}=re(e.name,this.sharedInstances.keys(),t);for(const i of a){if(this.stopping)break;const s=se(e.name,i);try{const p=ae(e,i),c=new E(p,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(s,c),await c.start(),l.info("manager",`shared instance started: ${s}`)}catch(p){this.sharedInstances.delete(s);const c=p instanceof Error?p.message:String(p);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,i),l.warn("manager",`shared instance auth rejected, removed from cache: ${s}`)):l.error("manager",`start shared instance failed ${s}: ${p}`)}}for(const{key:i}of r){const s=this.sharedInstances.get(i);s&&(this.sharedInstances.delete(i),s.stop().catch(p=>l.error("manager",`stop shared instance failed ${i}: ${p}`)),l.info("manager",`shared instance stopped: ${i}`))}}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 a=b(e);if(this.instances.some(r=>r.name===a.name))throw new Error(`Agent "${a.name}" already exists`);await this.startInstanceFromConfig(a,e,t)}async startInstanceFromConfig(e,t,a){H(t.client_type)&&t.provider?.base_url?.trim()&&t.provider?.api_key?.trim()&&t.provider?.model?.trim()&&await N(e.name,{baseUrl:t.provider.base_url.trim(),apiKey:t.provider.api_key.trim(),model:t.provider.model.trim()});const r=new E(e,this.globalConfigStore,this.auditProducer);r.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),r.setShareSetHandler(i=>this.onShareSet(e,i)),r.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),r.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),r.setProviderConfigHandler(i=>this.setAgentProvider(e.name,i)),r.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(i,s)=>{const p=this.relayStateApplier;return p?p.applyEnable(e.name,i,s):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const i=this.relayStateApplier;return i?i.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),r.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),await r.start(),this.instances.push(r),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:a}),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 a=this.instances.findIndex(p=>p.name===e),r=a===-1?void 0:this.instances[a];a!==-1&&this.instances.splice(a,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const i=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),i&&await i.catch(()=>{});const s=`${e}#shared:`;for(const[p,c]of[...this.sharedInstances.entries()])p.startsWith(s)&&(this.sharedInstances.delete(p),c.stop().catch(o=>l.error("manager",`stop shared instance failed ${p}: ${o}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),r&&await r.stop(),t?.keepShareCache||await U(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(a=>a.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=A(this.configDir,"agents.json");try{const t=[];for(const[,r]of this.configMap){const i=this.rawConfigMap.get(r.name)?.entry.provider;t.push({name:r.name,ws_url:r.aibot.url,agent_id:r.aibot.agentId,api_key:r.aibot.apiKey,client_type:r.aibot.clientType,...i?{provider:i}:{}})}te(e,JSON.stringify({agents:t},null,4)+`
|
|
2
|
-
`,"utf-8")}catch(t){
|
|
1
|
+
import{readFileSync as Z,readdirSync as ee,writeFileSync as te}from"node:fs";import{join as v}from"node:path";import{homedir as ne}from"node:os";import{AgentInstance as D}from"./bridge/bridge.js";import{buildSharedInstanceConfig as ae,diffSharedOwners as re,sharedInstanceKey as se,SharedOwnersCache as ie}from"./manager-share-config.js";import{isAgentDeletedError as R}from"./core/aibot/errors.js";import{GRIX_PATHS as y,log as d}from"./core/log/index.js";import{resolveClientVersion as oe}from"./core/util/client-version.js";import{UpgradeChecker as ce}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as le}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as de}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as pe}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as me}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as ue}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as ge}from"./core/aibot/types.js";import{buildReportedSkills as he,logDefaultSkillsCheck as fe,cleanupProjectedSkills as q}from"./default-skills/index.js";import{supportsKiroCwRelay as N,supportsNonMitmRelayConfig as _e}from"./core/config/provider-env.js";import{ensureKiroRelay as H,stopKiroRelay as U}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as L}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as B}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ye,resolveCliPath as we}from"./core/util/cli-probe.js";import{AgentInstaller as Se}from"./core/installer/installer.js";import{reportInstallFailure as ve}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Ae}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as be}from"./adapter/codex/config-overrides.js";const ke=8e3;function Ce(){const n=L();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:B()},{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"}]}async function xe(){return Promise.all(Ce().map(async n=>{const e=await we(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ye(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function $e(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:B()};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=L();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",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 Te(n,e){return v(y.data,`session-bindings-${A(n,e)}.json`)}function Ie(n,e){return v(y.data,`active-events-${A(n,e)}.json`)}function Ee(n,e){const t=A(n,"agent"),a=A(e,"unknown");return v(y.data,`terminal-outbox-${t}-${a}.json`)}function Me(...n){const e=[],t=new Set;for(const a of n)for(const r of a??[]){const o=String(r??"").trim(),s=o.toLowerCase();!o||t.has(s)||(t.add(s),e.push(o))}return e.length>0?e:void 0}function Pe(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}},a=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??a.maxConcurrent??1,maxQueued:e?.max_queued??a.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??a.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function b(n,e={}){const t=oe(),a=String(n.client_type??"").trim().toLowerCase(),r=$e(a),o=String(n.ws_url??"").trim(),s="get_session_usage",m="get_rate_limits",c="get_agent_global_config",i=ge;if(!n.name?.trim())throw new Error("agent name is required");if(!o)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 l=r.adapterType,u=l==="acp",_=a==="qwen",p={...r.options??{}};if(n.codex_config_overrides!==void 0){if(l!=="codex")throw new Error(`agent ${n.name}: codex_config_overrides is only supported for client_type=codex`);be(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),p.codexConfigOverrides=n.codex_config_overrides}const h=l==="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",s,m]}:null,f=l==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",s,m]}:null,g=_?{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",s],adapterHint:"qwen/base"}:null,S=l==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",s,m]}:null,w=l==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,C=l==="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",m]}:null,E=l==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",s]}:null,x=l==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","file_list","create_folder"]}:null,$=l==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,M=new Set(["hermes","reasonix","kimi","copilot"]),Q=u&&!M.has(a),K=u&&!_?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...Q?[s]:[]]}:null,W=a==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",s,m]}:null,z=l==="codex"||l==="claude"||a==="gemini"?["session_control","set_model","set_mode"]:void 0,G=l==="cursor"||l==="opencode"||l==="openhuman"||l==="agy"||u&&M.has(a)?[m]:[s,m];u&&p.raw_transport===void 0&&(p.raw_transport=a==="gemini");const J=`${a}/base`,T=pe(l,a),V=T==="kiro"?void 0:process.cwd(),P=he({mode:T,projectDir:V}),j=P.filter(I=>I.source==="connector").map(I=>I.name);j.length>0&&!e.quiet&&d.info("manager",`[${n.name}] injecting connector skills: [${j.join(", ")}]`);const O=me(P,y.skills);let X=O.length>0?O:void 0;const Y=ue({skillsDir:y.skills,mode:T,home:ne()});return{name:n.name,adapterType:l,aibot:{url:o,agentId:n.agent_id,apiKey:n.api_key,clientType:a,clientVersion:t,adapterHint:r.adapterHint??g?.adapterHint??S?.adapterHint??w?.adapterHint??C?.adapterHint??x?.adapterHint??$?.adapterHint??J,capabilities:h?.capabilities??E?.capabilities??S?.capabilities??w?.capabilities??C?.capabilities??x?.capabilities??$?.capabilities??g?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Me(h?.localActions??E?.localActions??f?.localActions??S?.localActions??w?.localActions??C?.localActions??x?.localActions??$?.localActions??g?.localActions??W?.localActions??K?.localActions??["exec_approve","exec_reject"],z,G,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...i]),skills:X,librarySkills:Y,terminalOutboxPath:Ee(n.name,n.agent_id)},agent:{command:r.command,args:[...r.args??[],...n.args??[]],env:n.env,clientType:a,...n.provider?{provider:{...n.provider.provider_id?.trim()?{providerId:n.provider.provider_id.trim()}:{},...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.quota_base_url?.trim()?{quotaBaseUrl:n.provider.quota_base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{}}}:{}},adapterOptions:p,acpAuthMethod:p.auth_method,acpInitialMode:p.initial_mode,acpMcpTools:p.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:Te(n.name,n.agent_id),activeEventStorePath:Ie(n.name,n.agent_id),...r.enableSessionBinding||u?{enableSessionBinding:!0}:{},...r.autoInjectArgs||a==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...r.autoInjectArgs??{},...a==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:Pe(l,n.event_queue),logDir:y.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function je(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):ke}function F(n){const e=[],t=[],a=[],r=ee(n).filter(o=>o.endsWith(".json")).sort();for(const o of r)try{const s=JSON.parse(Z(v(n,o),"utf-8"));if(s===null||typeof s!="object"||Array.isArray(s)||!("agents"in s)){a.push(o);continue}if(!Array.isArray(s.agents)){t.push({file:o,error:"agents is not an array"});continue}if(s.agents.length===0){t.push({file:o,error:"agents array is empty"});continue}for(const m of s.agents)e.push({entry:m,file:o})}catch(s){t.push({file:o,error:s instanceof Error?s.message:String(s)})}return{entries:e,fileErrors:t,skipped:a}}function k(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(k).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(a=>`${JSON.stringify(a)}:${k(e[a])}`).join(",")}}`}function Oe(n,e){return k(n)===k(e)}class ct{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=y.config;sharedOwnersCache=new ie(y.data);installer=new Se;auditProducer=Ae();async start(e){const t=e??y.config;this.configDir=t,d.info("manager",`Loading configs from ${t}`),fe(),q(),this.globalConfigStore=new de(v(y.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:a,fileErrors:r,skipped:o}=F(t);for(const i of r)d.error("manager",`Failed to load ${i.file}: ${i.error}`);for(const i of o)d.info("manager",`Skipped ${i}: not an agent config (no "agents" key)`);if(a.length===0&&r.length===0&&o.length===0){d.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 m=r.length;for(const{entry:i,file:l}of a)try{const u=b(i);s.push({config:u,entry:i,file:l}),d.info("manager",`Loaded ${u.name} (${u.adapterType??"acp"}) from ${l}`)}catch(u){const _=typeof i?.name=="string"?i.name:"<unknown>";d.error("manager",`Invalid agent config in ${l} (name=${_}): ${u}`),m++}let c=0;if(s.length>0){const i=je();d.info("manager",`Starting ${s.length} agent(s), startup wait=${i}ms`);const l=p=>{this.instances=this.instances.filter(h=>h!==p)},u=s.map(({config:p,entry:h,file:f})=>{const g=this.createConfiguredInstance(p);return this.instances.push(g),this.configMap.set(p.name,p),this.rawConfigMap.set(p.name,{entry:h,file:f}),{config:p,instance:g,startPromise:this.prepareProviderRuntime(p,h).then(()=>g.start())}}),_=await Promise.all(u.map(async p=>{const h=await new Promise(f=>{let g=!1;const S=setTimeout(()=>{g||(g=!0,f({kind:"timeout"}))},i);p.startPromise.then(()=>{g||(g=!0,clearTimeout(S),f({kind:"started"}))}).catch(w=>{g||(g=!0,clearTimeout(S),f({kind:"failed",error:w}))})});return{task:p,outcome:h}}));for(const{task:p,outcome:h}of _){if(h.kind==="started"){this.restoreCachedSharedInstances(p.config);continue}if(h.kind==="failed"){if(R(h.error)){this.onAgentDeletedByPlatform(p.config.name);continue}l(p.instance),d.error("manager",`Failed to start ${p.config.name}: ${h.error}`);continue}c++,d.warn("manager",`Startup pending for ${p.config.name}, continue retrying in background`),p.startPromise.then(()=>{d.info("manager",`Delayed start succeeded: ${p.config.name}`),this.restoreCachedSharedInstances(p.config)}).catch(f=>{if(R(f)){this.onAgentDeletedByPlatform(p.config.name);return}l(p.instance),d.error("manager",`Delayed start failed: ${p.config.name}: ${f}`)})}if(this.instances.length>0){const p=Math.max(0,this.instances.length-c);d.info("manager",`${p}/${s.length} agent(s) running now`)}c>0&&d.warn("manager",`${c} 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 ce(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new le(e,y.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshAllInstanceSkills()),await this.skillSyncer.start())}refreshAllInstanceSkills(){for(const e of this.instances)try{e.forceRefreshSkills()}catch(t){d.warn("manager",`forceRefreshSkills failed for ${e.name}: ${t}`)}for(const e of this.sharedInstances.values())try{e.forceRefreshSkills()}catch(t){d.warn("manager",`forceRefreshSkills failed for shared instance: ${t}`)}}async stop(){d.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=[],q(),d.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const r=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,r)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:a,toRemove:r}=re(e.name,this.sharedInstances.keys(),t);for(const o of a){if(this.stopping)break;const s=se(e.name,o);try{const m=ae(e,o),c=new D(m,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(s,c),await c.start(),d.info("manager",`shared instance started: ${s}`)}catch(m){this.sharedInstances.delete(s);const c=m instanceof Error?m.message:String(m);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,o),d.warn("manager",`shared instance auth rejected, removed from cache: ${s}`)):d.error("manager",`start shared instance failed ${s}: ${m}`)}}for(const{key:o}of r){const s=this.sharedInstances.get(o);s&&(this.sharedInstances.delete(o),s.stop().catch(m=>d.error("manager",`stop shared instance failed ${o}: ${m}`)),d.info("manager",`shared instance stopped: ${o}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(d.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(),d.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const a=b(e);if(this.instances.some(r=>r.name===a.name))throw new Error(`Agent "${a.name}" already exists`);await this.startInstanceFromConfig(a,e,t)}createConfiguredInstance(e){const t=new D(e,this.globalConfigStore,this.auditProducer);return t.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),t.setShareSetHandler(a=>this.onShareSet(e,a)),t.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),t.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),t.setProviderConfigHandler(a=>this.setAgentProvider(e.name,a)),t.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(a,r)=>{const o=this.relayStateApplier;return o?o.applyEnable(e.name,a,r):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const a=this.relayStateApplier;return a?a.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),t.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),t}async prepareProviderRuntime(e,t){N(t.client_type)&&t.provider?.base_url?.trim()&&t.provider?.api_key?.trim()&&t.provider?.model?.trim()&&await H(e.name,{baseUrl:t.provider.base_url.trim(),apiKey:t.provider.api_key.trim(),model:t.provider.model.trim()})}async startInstanceFromConfig(e,t,a){await this.prepareProviderRuntime(e,t);const r=this.createConfiguredInstance(e);await r.start(),this.instances.push(r),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:a}),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(),d.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const a=this.instances.findIndex(m=>m.name===e),r=a===-1?void 0:this.instances[a];a!==-1&&this.instances.splice(a,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const o=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),o&&await o.catch(()=>{});const s=`${e}#shared:`;for(const[m,c]of[...this.sharedInstances.entries()])m.startsWith(s)&&(this.sharedInstances.delete(m),c.stop().catch(i=>d.error("manager",`stop shared instance failed ${m}: ${i}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),r&&await r.stop(),t?.keepShareCache||await U(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(a=>a.name===e)))return;d.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(),d.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){d.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=v(this.configDir,"agents.json");try{const t=[];for(const[,r]of this.configMap){const o=this.rawConfigMap.get(r.name)?.entry.provider;t.push({name:r.name,ws_url:r.aibot.url,agent_id:r.aibot.agentId,api_key:r.aibot.apiKey,client_type:r.aibot.clientType,...o?{provider:o}:{}})}te(e,JSON.stringify({agents:t},null,4)+`
|
|
2
|
+
`,"utf-8")}catch(t){d.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(a=>a.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const t=this.instances.find(a=>a.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(a=>a.name===e)?.reportRelayStateLocalChange()}getAgentProvider(e){return 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),d.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,t){const a=this.rawConfigMap.get(e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const r=String(a.entry.client_type??"").trim().toLowerCase();N(r)&&(t?.base_url?.trim()&&t?.api_key?.trim()&&t?.model?.trim()?await H(e,{baseUrl:t.base_url.trim(),apiKey:t.api_key.trim(),model:t.model.trim()}):await U(e));const o={...a.entry,provider:t};await this.replaceInstance(e,o,a.file),this.persistAgentsConfig(),d.info("manager",`Updated provider config for agent: ${e}`)}async fetchRelayCredential(e,t){const a=this.instances.find(r=>r.name===e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return a.fetchRelayCredential(t)}async clearDirectProviderConfigs(){const e=[...this.rawConfigMap.entries()].filter(([,a])=>!!a.entry.provider&&_e(a.entry.client_type)).map(([a])=>a),t=[];for(const a of e)try{await this.setAgentProvider(a,void 0),t.push(a)}catch(r){d.warn("manager",`Failed to clear provider config for "${a}": ${r instanceof Error?r.message:String(r)}`)}return t}async replaceInstance(e,t,a){const r=b(t);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(r,t,a),this.restoreCachedSharedInstances(r)}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:a}=F(this.configDir);for(const c of a)d.info("manager",`reload: skipped ${c}: not an agent config (no "agents" key)`);if(t.length>0){const c=t.map(i=>`${i.file}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${t.length} config file(s) failed to parse [${c}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const r=[];for(const{entry:c}of e)try{b(c,{quiet:!0})}catch(i){const l=c?.name,u=typeof l=="string"&&l.trim()?l:"<unknown>";r.push({name:u,error:i instanceof Error?i.message:String(i)})}if(r.length>0){const c=r.map(i=>`${i.name}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${r.length} agent config(s) invalid [${c}]`),{code:"RELOAD_UNSAFE"})}const o=new Map;for(const c of e){const i=String(c.entry?.name??"").trim();i&&(o.has(i)&&d.warn("manager",`reload: duplicate agent name "${i}", last one wins`),o.set(i,c))}const s={added:[],removed:[],restarted:[],unchanged:[],failed:[]},m=new Set(this.rawConfigMap.keys());for(const c of m)if(!o.has(c))try{await this.removeAgentInternal(c),s.removed.push(c)}catch(i){s.failed.push({name:c,error:i instanceof Error?i.message:String(i)})}for(const[c,i]of o){const l=this.rawConfigMap.get(c);if(l)if(Oe(l.entry,i.entry))this.rawConfigMap.set(c,i),s.unchanged.push(c);else try{await this.replaceInstance(c,i.entry,i.file),s.restarted.push(c)}catch(u){s.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}else try{await this.addAgentInternal(i.entry,i.file),s.added.push(c)}catch(u){s.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}}return d.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 De(this.instances,e)}async probeOne(e,t={}){return Re(this.instances,e,t)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const t=await this.installer.install(e);return ve(t),t}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function De(n,e){const t=e.concurrency??4,a=Date.now(),r=new Array(n.length);await new Promise(i=>{let l=0,u=0;const _=n.length;if(_===0){i();return}function p(g){const S=n[g];S.probe(e).then(w=>{r[g]=w,h()},w=>{r[g]={agent_name:S.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:w?.message??String(w)}},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}},h()})}function h(){u++,l<_?p(l++):u===_&&i()}const f=Math.min(t,_);for(let g=0;g<f;g++)p(l++)});const o=r.filter(i=>i.status==="healthy").length,s=r.filter(i=>i.status==="degraded").length,m=r.filter(i=>i.status==="unavailable").length,c=await xe();return{ok:o===r.length&&r.length>0,total:r.length,healthy:o,degraded:s,unavailable:m,installed_clients:c,agents:r,probed_at:a,duration_ms:Date.now()-a}}async function Re(n,e,t){const a=n.find(r=>r.name===e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return a.probe(t)}export{ct as Manager,xe as probeInstalledClientCommands,De as probeInstances,Re as probeOneInstance};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "3.19.
|
|
3
|
+
"version": "3.19.4",
|
|
4
4
|
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|