grix-connector 3.31.2 → 3.32.0
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/adapter/acp/acp-adapter.js +10 -10
- package/dist/adapter/claude/protocol-contract.js +1 -1
- package/dist/adapter/claude/skill-scanner.js +2 -2
- package/dist/adapter/codex/codex-bridge.js +8 -8
- package/dist/adapter/cursor/cursor-adapter.js +7 -7
- package/dist/adapter/cursor/resolve-command.js +1 -0
- package/dist/adapter/deepseek-harness/jsonrpc-adapter.js +2 -2
- package/dist/adapter/deepseek-harness/skill-manager.js +1 -1
- package/dist/adapter/shared/native-provider-config.js +5 -5
- package/dist/assets/dsh-bridge/{grix-dsh-bridge-3.31.2.tgz → grix-dsh-bridge-3.32.0.tgz} +0 -0
- package/dist/assets/dsh-bridge/manifest.json +5 -5
- package/dist/bridge/adapter-pool.js +1 -1
- package/dist/bridge/bridge.js +7 -7
- package/dist/bridge/session-controller.js +6 -6
- package/dist/core/aibot/binding-card-meta-cache.js +1 -1
- package/dist/core/aibot/connection-handle.js +1 -1
- package/dist/core/skill-sync/enable-roots.js +1 -1
- package/dist/core/skill-sync/hermes-trust.js +1 -0
- package/dist/core/skill-sync/skill-delete.js +1 -0
- package/dist/core/skill-sync/skill-enable.js +1 -1
- package/dist/core/skill-sync/sync-state.js +1 -1
- package/dist/core/util/display-path.js +1 -0
- package/dist/core/util/index.js +1 -1
- package/dist/default-skills/index.js +1 -1
- package/dist/grix.js +0 -0
- package/dist/manager.js +2 -2
- package/openclaw-plugin/index.js +727 -2606
- package/openclaw.plugin.json +14 -0
- package/package.json +4 -3
- package/dist/adapter/claude/claude-bridge-server.js +0 -1
- package/dist/adapter/claude/claude-tools.js +0 -1
- package/dist/adapter/claude/claude-worker-client.js +0 -1
- package/dist/adapter/claude/mcp-http-launcher.js +0 -2
- package/dist/adapter/claude/result-timeout.js +0 -1
- package/dist/adapter/deepseek/deepseek-adapter.js +0 -6
- package/dist/adapter/deepseek/index.js +0 -1
- package/dist/adapter/qwen/index.js +0 -1
- package/dist/adapter/qwen/qwen-adapter.js +0 -4
- package/dist/aibot/client.js +0 -1
- package/dist/aibot/index.js +0 -1
- package/dist/aibot/types.js +0 -0
- package/dist/core/access/allowlist-gate.js +0 -1
- package/dist/core/access/allowlist-store.js +0 -1
- package/dist/core/access/index.js +0 -1
- package/dist/core/file-ops/handler.js +0 -1
- package/dist/core/file-ops/list-files.js +0 -1
- package/dist/core/file-ops/types.js +0 -0
- package/dist/log.js +0 -3
- package/dist/main.js +0 -31
- package/dist/mcp/stream-http/config.js +0 -1
- package/dist/mcp/stream-http/connection-binding.js +0 -1
- package/dist/mcp/stream-http/event-tool-executor.js +0 -1
- package/dist/mcp/stream-http/gateway.js +0 -1
- package/dist/mcp/stream-http/index.js +0 -1
- package/dist/mcp/stream-http/security.js +0 -1
- package/dist/mcp/stream-http/session-manager.js +0 -1
- package/dist/mcp/stream-http/tool-executor.js +0 -1
- package/dist/mcp/stream-http/tool-registry.js +0 -1
- package/dist/mcp/stream-http/tool-schemas.js +0 -1
- package/dist/session/index.js +0 -1
- package/dist/session/manager.js +0 -1
- package/dist/transport/index.js +0 -1
- package/dist/transport/json-rpc.js +0 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{SESSION_CONTROL_VERBS as l,SESSION_CONTROL_ERROR_CODES as
|
|
2
|
-
Mode: ${
|
|
3
|
-
Model: ${
|
|
4
|
-
`),f=n.models.map(
|
|
1
|
+
import{SESSION_CONTROL_VERBS as l,SESSION_CONTROL_ERROR_CODES as u}from"../adapter/claude/protocol-contract.js";import{parseInteractionMessage as p,readCardSubmissionParam as _}from"../core/protocol/interaction-parser.js";import{log as S}from"../core/log/index.js";function h(r){const o=String(r.content??"").trim();if(!o.startsWith("/grix ")){const s=p(o);for(const i of s.cardSubmissions){if(i.cardId!=="agent_open_session")continue;const e=_(i,"cwd")??"";return{verb:l.open,args:e}}return null}const d=o.slice(6).trim().split(/\s+/),c=d[0]?.toLowerCase(),m=d.slice(1).join(" ");return Object.values(l).includes(c)?{verb:c,args:m}:null}function k(r,o,d,c){const{verb:m,args:a}=r,s=o.session_id,i=()=>c.sendEventAck(o.event_id,s),e=(n,t)=>c.sendEventResult(o.event_id,n,t);switch(m){case l.open:{const n=a.trim();if(!n){i(),e("failed",{msg:"Usage: /grix open <working-directory>",code:u.cwdRequired});return}d.getSessionBindings().set(s,n),d.onSessionBound?.(s,n),i(),e("responded",{msg:`Session bound to ${n}`});break}case l.where:{const n=d.getSessionBindings().get(s)||d.getCwd()||"not set";i(),e("responded",{msg:`Working directory: ${n}`});break}case l.status:{const n=d.getStatus(),t=d.getAcpSessionOptions(),f=t?`
|
|
2
|
+
Mode: ${t.currentModeId} (${t.modes.map(b=>b.id).join(", ")})`:"",g=t?`
|
|
3
|
+
Model: ${t.currentModelId} (${t.models.map(b=>b.modelId).join(", ")})`:"";i(),e("responded",{msg:`Status: alive=${n.alive} busy=${n.busy} adapter=${n.adapterType}${f}${g}`});break}case l.stop:{if(!d.getSessionBindings().get(s)){i(),e("failed",{msg:"No session binding found for this session",code:u.bindingMissing});return}d.cancelActiveRun?.().catch(()=>{}),i(),e("responded",{msg:`Session ${s} stopped`});break}case l.restart:{const n=d.getSessionBindings().get(s);if(!n){i(),e("failed",{msg:"No session binding found for this session",code:u.bindingMissing});return}d.cancelActiveRun?.().catch(()=>{}),i(),e("responded",{msg:`Session ${s} restarted for ${n}`});break}case"set_mode":{const n=a.trim();if(!n){i(),e("failed",{msg:"Usage: /grix set_mode <mode-id>"});return}d.setMode(n).then(t=>{t&&d.onModeSet?.(n),i(),e(t?"responded":"failed",{msg:t?`Mode set to ${n}`:`Failed to set mode ${n}`})});break}case"set_model":{const n=a.trim();if(!n){i(),e("failed",{msg:"Usage: /grix set_model <model-id>"});return}d.setModel(n).then(t=>{t&&d.onModelSet?.(n),i(),e(t?"responded":"failed",{msg:t?`Model set to ${n}`:`Failed to set model ${n}`})});break}case"list_options":{const n=d.getAcpSessionOptions();if(!n){i(),e("failed",{msg:"No ACP session active"});return}const t=n.modes.map(g=>`${g.id}: ${g.name}`).join(`
|
|
4
|
+
`),f=n.models.map(g=>`${g.modelId}: ${g.name}`).join(`
|
|
5
5
|
`);i(),e("responded",{msg:`Modes (current: ${n.currentModeId}):
|
|
6
|
-
${
|
|
6
|
+
${t}
|
|
7
7
|
|
|
8
8
|
Models (current: ${n.currentModelId}):
|
|
9
|
-
${f}`});break}case"approve":{const n=
|
|
9
|
+
${f}`});break}case"approve":{const n=a.trim();if(!n||!d.isAcpAlive){i(),e("failed",{msg:"Usage: /grix approve <tool-call-id>"});return}const t=d.getPendingApproval(n);t&&(d.deletePendingApproval(n),d.respondPermission(t.requestId,{behavior:"allow"}).catch(()=>{})),i(),e("responded",{msg:t?`Approved: ${n}`:`No pending approval: ${n}`});break}case"reject":{const n=a.trim();if(!n||!d.isAcpAlive){i(),e("failed",{msg:"Usage: /grix reject <tool-call-id>"});return}const t=d.getPendingApproval(n);t&&(d.deletePendingApproval(n),d.respondPermission(t.requestId,{behavior:"deny"}).catch(()=>{})),i(),e("responded",{msg:t?`Rejected: ${n}`:`No pending approval: ${n}`});break}case l.listSessions:{i(),e("responded",{msg:"list_sessions is handled at bridge level"});break}case l.unbind:{if(!d.getSessionBindings().get(s)){i(),e("failed",{msg:"No session binding found for this session",code:u.bindingMissing});return}Promise.resolve(d.onSessionUnbound?.(s)).then(()=>{i(),e("responded",{msg:`Session ${s} unbound`})}).catch(t=>{i(),e("failed",{msg:`Failed to unbind session: ${t instanceof Error?t.message:String(t)}`,code:u.runtimeError})});break}default:i(),e("failed",{msg:`Unknown command: /grix ${m}`,code:u.verbInvalid})}}function w(r,o,d){return v(r,o,d)}async function v(r,o,d){const c=r.params??{},m=String(c.verb??"").toLowerCase(),a=d.sendLocalActionResult;switch(m){case l.open:{const s=String(c.session_id??""),i=String(c.cwd??"");if(!i){a(r.action_id,"failed",void 0,u.cwdRequired,"session cwd is required");return}s&&o.getSessionBindings().set(s,i),s&&o.onSessionBound?.(s,i),a(r.action_id,"ok",{outcome:"opened",binding:{cwd:i}});break}case l.stop:{const s=String(c.session_id??"");if(!s){a(r.action_id,"failed",void 0,"session_id_required","session_id is required for stop");return}o.cancelActiveRun?.().catch(()=>{}),a(r.action_id,"ok",{outcome:"stopped",sessionId:s});break}case l.status:{const s=String(c.session_id??""),e=o.getSessionBindings().get(s)??"",n=o.getStatus();a(r.action_id,"ok",{outcome:"status",verb:"status",binding:{aibotSessionId:s,cwd:e,workerStatus:n.alive?n.busy?"busy":"ready":"stopped"}});break}case l.where:{const s=String(c.session_id??""),e=o.getSessionBindings().get(s)??"";a(r.action_id,"ok",{outcome:"where",verb:"where",binding:{aibotSessionId:s,cwd:e}});break}case"restart":{const s=String(c.session_id??"");if(!s){a(r.action_id,"failed",void 0,"session_id_required","session_id is required for restart");return}o.cancelActiveRun?.().catch(()=>{}),a(r.action_id,"ok",{outcome:"restarted",sessionId:s});break}case l.setMode:{const s=String(c.mode_id??""),i=String(c.session_id??"");if(o.acpSetMode){const e=await o.acpSetMode(i,s);e.status==="failed"?a(r.action_id,"failed",void 0,e.errorCode,e.errorMsg):(e.result?.outcome==="mode_set"&&s&&o.onModeSet?.(s),a(r.action_id,"ok",e.result));return}if(!s||!o.isAcpAlive){a(r.action_id,"failed",void 0,"set_mode_invalid","mode_id is required and ACP session must be active");return}o.setMode(s).then(e=>{e&&o.onModeSet?.(s),a(r.action_id,e?"ok":"failed",e?{outcome:"mode_set",modeId:s}:void 0,e?void 0:"set_mode_failed",e?void 0:`failed to set mode ${s}`)});break}case l.setModel:{const s=String(c.model_id??""),i=String(c.session_id??"");if(o.acpSetModel){const e=await o.acpSetModel(i,s);e.status==="failed"?a(r.action_id,"failed",void 0,e.errorCode,e.errorMsg):(e.result?.outcome==="model_set"&&s&&o.onModelSet?.(s),a(r.action_id,"ok",e.result));return}if(!s||!o.isAcpAlive){a(r.action_id,"failed",void 0,"set_model_invalid","model_id is required and ACP session must be active");return}o.setModel(s).then(e=>{e&&o.onModelSet?.(s),a(r.action_id,e?"ok":"failed",e?{outcome:"model_set",modelId:s}:void 0,e?void 0:"set_model_failed",e?void 0:`failed to set model ${s}`)});break}case l.listOptions:{const s=o.getAcpSessionOptions(),i=s?{modes:s.modes.map(e=>({id:e.id,name:e.name})),currentModeId:s.currentModeId,models:s.models.map(e=>({modelId:e.modelId,name:e.name})),currentModelId:s.currentModelId,available_models:s.models.map(e=>({id:e.modelId,displayName:e.name})),available_modes:s.modes.map(e=>({id:e.id,displayName:e.name}))}:{modes:[],currentModeId:"",models:[],currentModelId:"",available_models:[],available_modes:[]};S.info("session-controller",`[toolbar] listOptions currentModelId=${i.currentModelId} models=${JSON.stringify(i.models?.map(e=>e.modelId))}`),a(r.action_id,"ok",i);break}case l.listSessions:{a(r.action_id,"ok",{outcome:"sessions_listed",sessions:[]});break}case l.unbind:{const s=String(c.session_id??"");if(!o.getSessionBindings().get(s)){a(r.action_id,"failed",void 0,u.bindingMissing,"No session binding found for this session");return}await o.onSessionUnbound?.(s),a(r.action_id,"ok",{outcome:"unbound",sessionId:s});break}default:a(r.action_id,"failed",void 0,u.verbInvalid,`session control verb ${m} is not supported`)}}export{k as handleSessionControlCommand,w as handleSessionControlLocalAction,h as parseSessionControlCommand};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const b=["available_models","available_providers","available_modes","available_presets","available_profiles","model_id","provider_id","mode_id","agent_preset_id","agent_preset_locked","dsh_profile","dsh_profile_locked","dsh_profile_create","dsh_plugins","dsh_plugin_restart_required","available_efforts","effort","reasoning_effort","currentEffort","currentModelId","currentModeId","availableModels","availableModes","models","modes"],d=["available_presets","available_profiles","available_providers","agent_preset_id","agent_preset_locked","provider_id","dsh_profile","dsh_profile_locked","dsh_profile_create"],u=[["model_id","currentModelId"],["mode_id","currentModeId"],["effort","reasoning_effort"]];function _(a,o,e){for(const t of o)t in a&&(e[t]=a[t])}function p(a,o){return Object.prototype.hasOwnProperty.call(a,o)&&Array.isArray(a[o])}function y(a,...o){for(const e of o){const t=a[e];if(typeof t=="string"&&t.trim())return t}}function h(a){return a.replace(/_([a-z])/g,(o,e)=>e.toUpperCase())}class v{toolbarMetaBySession=new Map;merge(o,e){if(!o)return e;if(e&&p(e,"available_models")){const r=this.toolbarMetaBySession.get(o),i={};if(_(e,b,i),r)for(const n of d)!(n in i)&&n in r&&(i[n]=r[n]);return this.toolbarMetaBySession.set(o,i),e}if(e&&p(e,"available_profiles")){const r=this.toolbarMetaBySession.get(o)??{};_(e,d,r),this.toolbarMetaBySession.set(o,r)}const t=this.toolbarMetaBySession.get(o);if(!t)return e;if(e)for(const[r,i]of u){const n=e[r],l=e[i],s=typeof n=="string"&&n||typeof l=="string"&&l||null;s&&(t[r]=s,t[i]=s)}return{...t,...e??{}}}delete(o){this.toolbarMetaBySession.delete(o)}syncFromResult(o,e){if(!o||!e||typeof e!="object"||Array.isArray(e))return;const t=e;if(p(t,"available_models")){const l=this.toolbarMetaBySession.get(o),s={};if(_(t,b,s),l)for(const f of d)!(f in s)&&f in l&&(s[f]=l[f]);this.toolbarMetaBySession.set(o,s);return}const r=this.toolbarMetaBySession.get(o);if(!r)return;const i=t.session_context,n=i&&typeof i=="object"&&!Array.isArray(i)?i:void 0;for(const[l,s]of u){const f=[l,s,h(l),h(s)],c=y(t,...f)??(n?y(n,...f):void 0);c&&(r[l]=c,r[s]=c)}}}export{v as BindingCardMetaCache};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BindingCardMetaCache as i}from"./binding-card-meta-cache.js";class c{client;_status="ready";connectedAt;listeners=[];bindingCardMetaCache=new i;authAck=null;constructor(e){this.client=e,this.connectedAt=Date.now(),this.addInternalListener("close",()=>{this._status!=="closing"&&(this._status="reconnecting")}),this.addInternalListener("auth",t=>{this._status="ready",t&&(this.authAck=t)}),this.addInternalListener("disconnected",()=>{this._status!=="closing"&&this._status!=="closed"&&(this._status="reconnecting")})}get status(){return this._status}getStatusSnapshot(){return{status:this._status,connectedAt:this.connectedAt,reconnectAttempts:0}}sendEventAck(e){this.client.sendEventAck(e)}sendStreamChunk(e){this.client.sendStreamChunk(e)}sendMsg(e){this.client.sendMsg(e)}editMsg(e){this.client.editMsg(e)}sendEventResult(e){this.client.sendEventResult(e)}sendLocalActionResult(e){this.client.sendLocalActionResult(e)}sendEventStopAck(e){this.client.sendEventStopAck(e)}sendEventStopResult(e){this.client.sendEventStopResult(e)}sendSessionActivitySet(e){this.client.sendSessionActivitySet(e)}sendCodexEvent(e){this.client.sendCodexEvent(e)}sendUpdateBindingCard(e){const t=this.bindingCardMetaCache.merge(e.session_id,e.meta);this.client.sendUpdateBindingCard(t===e.meta?e:{...e,meta:t})}clearBindingCardMetaCache(e){this.bindingCardMetaCache.delete(e)}sendAuditState(e){this.client.sendAuditState(e)}sendSkillsUpdate(e){this.client.sendSkillsUpdate(e)}sendPing(){this.client.sendPing()}sendEventState(e){this.client.sendEventState(e)}sendEventCancelResult(e){this.client.sendEventCancelResult(e)}sendQueueClearResult(e){this.client.sendQueueClearResult(e)}sendQueueReorderResult(e){this.client.sendQueueReorderResult(e)}sendEventHoldResult(e){this.client.sendEventHoldResult(e)}sendQueueEditResult(e){this.client.sendQueueEditResult(e)}sendQueueSnapshot(e){this.client.sendQueueSnapshot(e)}agentInvoke(e,t,s){return this.client.agentInvoke(e,t,s)}sendStreamChunkRequest(e,t){return this.client.sendStreamChunkRequest(e,t)}sendText(e,t){return this.client.sendText(e,t)}sendMedia(e,t){return this.client.sendMedia(e,t)}editMessage(e,t){return this.client.editMessage(e,t)}deleteMessage(e,t,s){return this.client.deleteMessage(e,t,s)}sendEventResultRequest(e,t){return this.client.sendEventResultRequest(e,t)}relayCredentialRequest(e,t){return this.client.relayCredentialRequest(e,t)}relayStateSyncRequest(e,t){return this.client.relayStateSyncRequest(e,t)}sendRelayStateReport(e){this.client.sendRelayStateReport(e)}onEvent(e){return this.subscribe("event",e)}onLocalAction(e){return this.subscribe("localAction",e)}onStop(e){return this.subscribe("stop",e)}onRevoke(e){return this.subscribe("revoke",e)}onEdit(e){return this.subscribe("edit",e)}onEventCancel(e){return this.subscribe("eventCancel",e)}onQueueClear(e){return this.subscribe("queueClear",e)}onQueueReorder(e){return this.subscribe("queueReorder",e)}onQueueSnapshotQuery(e){return this.subscribe("queueSnapshotQuery",e)}onEventHold(e){return this.subscribe("eventHold",e)}onQueueEdit(e){return this.subscribe("queueEdit",e)}onKicked(e){return this.subscribe("kicked",e)}onAgentDeleted(e){return this.subscribe("agentDeleted",e)}onShareSet(e){return this.subscribe("shareSet",e)}onProfilePush(e){return this.subscribe("profilePush",e)}onSkillSync(e){return this.subscribe("skillSync",e)}onError(e){return this.subscribe("error",e)}onClose(e){return this.subscribe("close",e)}onDisconnected(e){return this.subscribe("disconnected",e)}onStreamRejected(e){return this.subscribe("streamRejected",e)}onReconnected(e){return this.subscribe("auth",e)}disconnect(){this._status="closing",this.removeAllListeners(),this.client.disconnect(),this._status="closed"}sendMcpFrame(e,t){this.client.sendMcpFrame(e,t)}onMcpFrame(e){return this.subscribe("mcpFrame",e)}subscribe(e,t){return this.client.on(e,t),this.listeners.push({event:e,handler:t}),()=>{this.client.removeListener(e,t);const s=this.listeners.findIndex(n=>n.event===e&&n.handler===t);s>=0&&this.listeners.splice(s,1)}}addInternalListener(e,t){this.client.on(e,t),this.listeners.push({event:e,handler:t})}removeAllListeners(){for(const{event:e,handler:t}of this.listeners)this.client.removeListener(e,t);this.listeners.length=0}}export{c as AibotConnectionHandleImpl};
|
|
1
|
+
import{BindingCardMetaCache as i}from"./binding-card-meta-cache.js";class c{client;_status="ready";connectedAt;listeners=[];bindingCardMetaCache=new i;authAck=null;constructor(e){this.client=e,this.connectedAt=Date.now(),this.addInternalListener("close",()=>{this._status!=="closing"&&(this._status="reconnecting")}),this.addInternalListener("auth",t=>{this._status="ready",t&&(this.authAck=t)}),this.addInternalListener("disconnected",()=>{this._status!=="closing"&&this._status!=="closed"&&(this._status="reconnecting")})}get status(){return this._status}getStatusSnapshot(){return{status:this._status,connectedAt:this.connectedAt,reconnectAttempts:0}}sendEventAck(e){this.client.sendEventAck(e)}sendStreamChunk(e){this.client.sendStreamChunk(e)}sendMsg(e){this.client.sendMsg(e)}editMsg(e){this.client.editMsg(e)}sendEventResult(e){this.client.sendEventResult(e)}sendLocalActionResult(e,t){t&&this.bindingCardMetaCache.syncFromResult(t,e.result),this.client.sendLocalActionResult(e)}sendEventStopAck(e){this.client.sendEventStopAck(e)}sendEventStopResult(e){this.client.sendEventStopResult(e)}sendSessionActivitySet(e){this.client.sendSessionActivitySet(e)}sendCodexEvent(e){this.client.sendCodexEvent(e)}sendUpdateBindingCard(e){const t=this.bindingCardMetaCache.merge(e.session_id,e.meta);this.client.sendUpdateBindingCard(t===e.meta?e:{...e,meta:t})}clearBindingCardMetaCache(e){this.bindingCardMetaCache.delete(e)}sendAuditState(e){this.client.sendAuditState(e)}sendSkillsUpdate(e){this.client.sendSkillsUpdate(e)}sendPing(){this.client.sendPing()}sendEventState(e){this.client.sendEventState(e)}sendEventCancelResult(e){this.client.sendEventCancelResult(e)}sendQueueClearResult(e){this.client.sendQueueClearResult(e)}sendQueueReorderResult(e){this.client.sendQueueReorderResult(e)}sendEventHoldResult(e){this.client.sendEventHoldResult(e)}sendQueueEditResult(e){this.client.sendQueueEditResult(e)}sendQueueSnapshot(e){this.client.sendQueueSnapshot(e)}agentInvoke(e,t,s){return this.client.agentInvoke(e,t,s)}sendStreamChunkRequest(e,t){return this.client.sendStreamChunkRequest(e,t)}sendText(e,t){return this.client.sendText(e,t)}sendMedia(e,t){return this.client.sendMedia(e,t)}editMessage(e,t){return this.client.editMessage(e,t)}deleteMessage(e,t,s){return this.client.deleteMessage(e,t,s)}sendEventResultRequest(e,t){return this.client.sendEventResultRequest(e,t)}relayCredentialRequest(e,t){return this.client.relayCredentialRequest(e,t)}relayStateSyncRequest(e,t){return this.client.relayStateSyncRequest(e,t)}sendRelayStateReport(e){this.client.sendRelayStateReport(e)}onEvent(e){return this.subscribe("event",e)}onLocalAction(e){return this.subscribe("localAction",e)}onStop(e){return this.subscribe("stop",e)}onRevoke(e){return this.subscribe("revoke",e)}onEdit(e){return this.subscribe("edit",e)}onEventCancel(e){return this.subscribe("eventCancel",e)}onQueueClear(e){return this.subscribe("queueClear",e)}onQueueReorder(e){return this.subscribe("queueReorder",e)}onQueueSnapshotQuery(e){return this.subscribe("queueSnapshotQuery",e)}onEventHold(e){return this.subscribe("eventHold",e)}onQueueEdit(e){return this.subscribe("queueEdit",e)}onKicked(e){return this.subscribe("kicked",e)}onAgentDeleted(e){return this.subscribe("agentDeleted",e)}onShareSet(e){return this.subscribe("shareSet",e)}onProfilePush(e){return this.subscribe("profilePush",e)}onSkillSync(e){return this.subscribe("skillSync",e)}onError(e){return this.subscribe("error",e)}onClose(e){return this.subscribe("close",e)}onDisconnected(e){return this.subscribe("disconnected",e)}onStreamRejected(e){return this.subscribe("streamRejected",e)}onReconnected(e){return this.subscribe("auth",e)}disconnect(){this._status="closing",this.removeAllListeners(),this.client.disconnect(),this._status="closed"}sendMcpFrame(e,t){this.client.sendMcpFrame(e,t)}onMcpFrame(e){return this.subscribe("mcpFrame",e)}subscribe(e,t){return this.client.on(e,t),this.listeners.push({event:e,handler:t}),()=>{this.client.removeListener(e,t);const s=this.listeners.findIndex(n=>n.event===e&&n.handler===t);s>=0&&this.listeners.splice(s,1)}}addInternalListener(e,t){this.client.on(e,t),this.listeners.push({event:e,handler:t})}removeAllListeners(){for(const{event:e,handler:t}of this.listeners)this.client.removeListener(e,t);this.listeners.length=0}}export{c as AibotConnectionHandleImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as o}from"node:path";import{findGitProjectRoot as c}from"../util/git-project-root.js";function u(
|
|
1
|
+
import{join as o}from"node:path";import{findGitProjectRoot as c}from"../util/git-project-root.js";function u(i,r){const{home:e}=r,l=r.cwd?.trim()||void 0,t=r.env??process.env;switch(i){case"claude":return{globalRoot:o(e,".claude","skills"),projectRoot:l?o(l,".claude","skills"):null};case"codex":{const s=t.CODEX_HOME?.trim()||o(e,".codex");return{globalRoot:o(s,"skills"),projectRoot:l?o(l,".codex","skills"):null}}case"gemini":return{globalRoot:o(e,".gemini","skills"),projectRoot:l?o(l,".gemini","skills"):null};case"qwen":return{globalRoot:o(e,".qwen","skills"),projectRoot:l?o(l,".qwen","skills"):null};case"pi":return{globalRoot:o(e,".pi","agent","skills"),projectRoot:l?o(l,".pi","skills"):null};case"kiro":return{globalRoot:o(e,".kiro","skills"),projectRoot:l?o(l,".kiro","skills"):null};case"cursor":return{globalRoot:o(e,".cursor","skills"),projectRoot:l?o(l,".cursor","skills"):null};case"codewhale":return{globalRoot:o(e,".codewhale","skills"),projectRoot:l?o(l,".codewhale","skills"):null};case"opencode":{const s=t.XDG_CONFIG_HOME?.trim()||o(e,".config");return{globalRoot:o(s,"opencode","skills"),projectRoot:null}}case"reasonix":return{globalRoot:o(e,".reasonix","skills"),projectRoot:null};case"kimi":{const s=t.KIMI_CODE_HOME?.trim()||o(e,".kimi-code");return{globalRoot:o(s,"skills"),projectRoot:null}}case"deepseek":{const s=t.DSH_HOME?.trim()||o(e,".dsh");return{globalRoot:o(s,"skills"),projectRoot:l?o(c(l),".dsh","skills"):null}}case"hermes":{const s=t.HERMES_HOME?.trim()||t.GRIX_HERMES_HOME?.trim()||o(e,".hermes");return{globalRoot:o(s,"skills"),projectRoot:l?o(c(l),".hermes","skills"):null}}case"copilot":return{globalRoot:o(e,".copilot","skills"),projectRoot:l?o(l,".github","skills"):null};default:return{globalRoot:null,projectRoot:null}}}export{u as resolveEnableRoots};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mkdir as a,readFile as d,writeFile as u}from"node:fs/promises";import{join as f}from"node:path";import{isMap as c,isSeq as m,parseDocument as w,Document as g,YAMLMap as p,YAMLSeq as _,Scalar as h}from"yaml";async function S(o,n){const l=f(o,"config.yaml");let s="";try{s=await d(l,"utf8")}catch(i){if(i.code!=="ENOENT")throw i}const r=s.trim()?w(s):new g({});if(r.errors.length>0)throw new Error(`config.yaml \u89E3\u6790\u5931\u8D25: ${r.errors[0].message}`);if(!c(r.contents))throw new Error("config.yaml: \u9876\u5C42\u4E0D\u662F\u6620\u5C04\uFF0C\u65E0\u6CD5\u5199\u5165 skills.trusted_project_dirs");let e=r.get("skills",!0);if(e==null&&(e=new p,r.set("skills",e)),!c(e))throw new Error("config.yaml: skills \u4E0D\u662F\u6620\u5C04\uFF0C\u65E0\u6CD5\u5199\u5165 trusted_project_dirs");let t=e.get("trusted_project_dirs",!0);if(t==null&&(t=new _,e.set("trusted_project_dirs",t)),!m(t))throw new Error("config.yaml: skills.trusted_project_dirs \u4E0D\u662F\u5217\u8868");return t.items.some(i=>String(i instanceof h?i.value:i)===n)?"exists":(t.items.push(r.createNode(n)),await a(o,{recursive:!0}),await u(l,r.toString(),{encoding:"utf8",mode:384}),"added")}export{S as ensureHermesProjectTrust};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{lstat as f,rm as a}from"node:fs/promises";import{dirname as c,extname as m}from"node:path";import{scanSkills as d}from"../../adapter/claude/skill-scanner.js";import{scanDefaultSkills as u}from"../../default-skills/index.js";class o extends Error{}function w(i,t){const e=i.trim();if(!e)throw new o("skill name is required");const l=d(t),r=u(),n=[...l,...r].find(s=>s.name===e);if(!n)throw new o(`skill "${e}" not found`);if(n.managed)throw new o(`skill "${e}" is system-managed and cannot be deleted`);if(!n.filePath)throw new o(`skill "${e}" has no local file`);return n}function k(i){const t=i.trim();if(!t)throw new o("skill file path is required");const e=t.split(/[/\\]/).pop()??"";if(e.toLowerCase()==="skill.md")return c(t);if(m(e).toLowerCase()===".md")return t;throw new o(`unsupported skill file layout: ${t}`)}async function y(i,t){const e=w(i,t),l=k(e.filePath);try{const r=await f(l);r.isSymbolicLink()?await a(l,{force:!0}):r.isDirectory()?await a(l,{recursive:!0,force:!0}):await a(l,{force:!0})}catch(r){throw new o(`failed to delete skill "${i}": ${r instanceof Error?r.message:String(r)}`)}return{name:e.name,path:l}}export{o as SkillDeleteError,y as deleteLocalSkill,w as findDeletableSkill,k as resolveSkillDeleteTarget};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as d,lstatSync as w,readFileSync as M,realpathSync as $}from"node:fs";import{mkdir as I,readFile as N,realpath as h,rm as O,rmdir as A,symlink as C,unlink as j}from"node:fs/promises";import{dirname as K,join as a}from"node:path";import{parseSkillFrontmatter as P,MANAGED_MARKER as k}from"../../adapter/claude/skill-scanner.js";import{computeContentDigest as p}from"./sync-state.js";import{readSkillManifest as F}from"./manifest.js";import{resolveEnableRoots as H}from"./enable-roots.js";import{findGitProjectRoot as T}from"../util/git-project-root.js";import{ensureHermesProjectTrust as G}from"./hermes-trust.js";import{log as B}from"../log/index.js";class o extends Error{code;constructor(r,t){super(r),this.code=t}}function y(e){return e.trim().toLowerCase().startsWith("grix-")}function x(e){return e?e.system===!0||e.owner_id==="0":!1}function S(e){return e instanceof Error?e.message:String(e)}function U(e){try{const r=M(a(e,"SKILL.md"),"utf8");return p(r)}catch{return null}}function V(e){if(!e.targetRoot)return"unavailable";if(y(e.name)||e.system===!0)return"blocked";const r=a(e.targetRoot,e.name);let t;try{t=w(r)}catch{return"none"}if(t.isSymbolicLink()){let n;try{n=$(r)}catch{return"broken"}return d(a(n,k))?"blocked":"link"}if(t.isDirectory()){if(d(a(r,k)))return"blocked";const n=U(r);return n===null?"conflict":n===e.sourceDigest?"unmanaged":"conflict"}return"conflict"}async function q(e,r){try{const[t,n]=await Promise.all([h(e),h(r)]);return t===n}catch{return!1}}async function W(e,r){await I(K(r),{recursive:!0}),await C(e,r,process.platform==="win32"?"junction":"dir")}async function g(e){process.platform==="win32"?await A(e):await j(e)}const b=new Map;function E(e,r){return`${e}:${r}`}function v(e,r){const n=(b.get(e)??Promise.resolve()).catch(()=>{}).then(r);return b.set(e,n.catch(()=>{})),n}function X(e,r){const t=e.skills[r];if(!t)throw new o(`skill "${r}" not found in library`,"SKILL_NOT_FOUND");return t}async function z(e,r,t){const n=a(e,t.dir);let s;try{s=await N(a(n,"SKILL.md"),"utf8")}catch(c){throw new o(`failed to read library skill "${r}": ${S(c)}`,"SKILL_FILE_MISSING")}const i=P(s);if(i.name!==r)throw new o(`frontmatter name "${i.name}" does not match library skill name "${r}"`,"NAME_MISMATCH");return{sourceDir:n,digest:p(s)}}function L(e,r){const t=H(e.mode,{home:e.home,cwd:e.cwd,env:e.env}),n=r==="global"?t.globalRoot:t.projectRoot;if(!n)throw new o(r==="project"?"project scope unavailable: no session working directory is bound":"skill enable is not supported for this agent mode","SCOPE_UNAVAILABLE");return n}async function _(e,r){if(!(e.mode!=="hermes"||r!=="project"||!e.cwd))try{const t=e.env??process.env,n=t.HERMES_HOME?.trim()||t.GRIX_HERMES_HOME?.trim()||a(e.home,".hermes");return await G(n,T(e.cwd))}catch(t){return B.warn("skill-enable",`hermes project trust failed: ${S(t)}`),"failed"}}function D(e,r){if(!e.trim())throw new o("name is required","MISSING_SKILL_NAME");if(r!=="global"&&r!=="project")throw new o(`invalid scope: ${r}`,"INVALID_SCOPE")}async function ae(e,r){const t=r.name.trim();D(t,r.scope);const n=r.scope;return v(E(n,t),async()=>{const s=await F(e.skillsDir),i=X(s,t),{sourceDir:c,digest:R}=await z(e.skillsDir,t,i);if(y(t))throw new o(`"${t}" uses the reserved "grix-" prefix and cannot be enabled`,"BLOCKED");const f=x(i);if(f)throw new o(`"${t}" is a platform system skill and cannot be enabled`,"BLOCKED");const m=L(e,n),u=a(m,t),l=V({name:t,targetRoot:m,system:f,sourceDigest:R});if(l==="blocked")throw new o(`"${t}" target slot is managed by the connector`,"BLOCKED");if(l==="conflict")throw new o(`"${t}" already exists locally with different content and cannot be overwritten`,"CONFLICT");if(l==="unmanaged"&&r.force!=="replace_with_link")throw new o(`"${t}" already exists locally as a real directory; pass force="replace_with_link" to overwrite`,"NEEDS_FORCE");if(l==="link"){if(await q(u,c))return{name:t,scope:n,status:"link",path:u,changed:!1,hermes_trust:await _(e,n)};if(r.force!=="replace_link")throw new o(`"${t}" is already linked elsewhere; pass force="replace_link" to overwrite`,"NEEDS_FORCE")}return l==="broken"||l==="link"?await g(u):l==="unmanaged"&&await O(u,{recursive:!0,force:!0}),await W(c,u),{name:t,scope:n,status:"link",path:u,changed:!0,hermes_trust:await _(e,n)}})}async function se(e,r){const t=r.name.trim();D(t,r.scope);const n=r.scope;return v(E(n,t),async()=>{const s=L(e,n),i=a(s,t);let c;try{c=w(i)}catch{return{name:t,scope:n,path:i,removed:!1}}if(!c.isSymbolicLink())throw new o(`"${t}" at ${i} is a real directory, not a connector-managed link, and cannot be disabled`,"NOT_MANAGED");return await g(i),{name:t,scope:n,path:i,removed:!0}})}export{o as SkillEnableError,V as computeEnableScope,se as disableSkill,ae as enableSkill,x as isSystemSkillEntry};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as s}from"node:fs";import{join as f}from"node:path";import{createHash as u}from"node:crypto";import{toDisplayPath as p}from"../util/display-path.js";const m=".grix-sync.json";function d(t){return u("sha256").update(t,"utf8").digest("hex")}function g(t){const e=new Map;try{const c=s(f(t,m),"utf8"),r=JSON.parse(c)?.skills;if(r&&typeof r=="object")for(const[i,o]of Object.entries(r))o&&typeof o.digest=="string"&&e.set(i,o.digest)}catch{}return e}function y(t,e){const c=g(e);return t.map(n=>{if(n.managed||!n.filePath)return n;let r;try{r=s(n.filePath,"utf8")}catch{return n}const i=d(r),o=c.get(n.name);let a;return o===void 0?a="unsynced":o===i?a="synced":a="modified",{...n,syncState:a}})}function h(t){const e=p(t.filePath);return{name:t.name,description:t.description,trigger:t.trigger,source:t.source,managed:t.managed,sync_state:t.syncState,...e?{path:e}:{}}}function P(t,e){return y(t,e).map(h)}export{y as annotateSyncStates,P as buildWireSkills,d as computeContentDigest,h as toWireSkill};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{homedir as e}from"node:os";import{sep as i}from"node:path";function o(s,r=e()){const t=String(s??"").trim();if(!t||!r)return t;if(t===r)return"~";const n=r.endsWith(i)?r:`${r}${i}`;return t.startsWith(n)?`~${i}${t.slice(n.length)}`:t}export{o as toDisplayPath};
|
package/dist/core/util/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readJSONFile as o,writeJSONFileAtomic as t}from"./json-file.js";import{EventBuffer as s}from"./event-buffer.js";import{QuotedMessageStream as
|
|
1
|
+
import{readJSONFile as o,writeJSONFileAtomic as t}from"./json-file.js";import{EventBuffer as s}from"./event-buffer.js";import{QuotedMessageStream as a}from"./quoted-message-stream.js";import{resolveClientVersion as p}from"./client-version.js";import{isUserVisibleAgentMessagePhase as l}from"./codex-output-policy.js";import{getMachineName as g}from"./host-info.js";import{toDisplayPath as M}from"./display-path.js";export{s as EventBuffer,a as QuotedMessageStream,g as getMachineName,l as isUserVisibleAgentMessagePhase,o as readJSONFile,p as resolveClientVersion,M as toDisplayPath,t as writeJSONFileAtomic};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as k,readdirSync as l,existsSync as m,mkdirSync as h,cpSync as y,writeFileSync as g,rmSync as v}from"node:fs";import{join as t,dirname as S}from"node:path";import{homedir as u}from"node:os";import{fileURLToPath as D}from"node:url";import{parseSkillFrontmatter as x,scanSkills as H,dedupeSkills as F,MANAGED_MARKER as f}from"../adapter/claude/skill-scanner.js";import{resolveRuntimePaths as d}from"../core/config/index.js";import{log as a}from"../core/log/index.js";const c=S(D(import.meta.url));function p(){const e=[];let i;try{i=l(c,{withFileTypes:!0,encoding:"utf8"})}catch{return e}for(const r of i){if(!r.isDirectory())continue;const n=t(c,r.name,"SKILL.md");try{const s=k(n,"utf-8"),o=x(s);o?.name&&e.push({name:o.name,description:o.description,trigger:o.trigger,source:"connector",filePath:n,managed:!0})}catch{}}return e}function O(e){let i=[];try{i=H(e)}catch{i=[]}return F([...i,...p()])}function P(e){const i=[];let r;try{r=l(c,{withFileTypes:!0,encoding:"utf8"})}catch{return i}for(const n of r){if(!n.isDirectory())continue;const s=t(c,n.name);if(m(t(s,"SKILL.md")))try{h(e,{recursive:!0});const o=t(e,n.name);y(s,o,{recursive:!0}),g(t(o,f),"","utf8"),i.push(n.name)}catch{}}return i}function w(e=process.env){return(e.KIMI_CODE_HOME||"").trim()||t(u(),".kimi-code")}function _(e=process.env){return(e.DSH_HOME||"").trim()||t(u(),".dsh")}function C(){const e=u(),i=process.env.XDG_CONFIG_HOME||t(e,".config"),r=[t(d().dataDir,"claude-plugin","skills"),t(e,".codex","skills"),t(e,".gemini","skills"),t(e,".qwen","skills"),t(e,".pi","agent","skills"),t(e,".codewhale","skills"),t(i,"opencode","skills"),t(e,".cursor","skills"),t(e,".openhuman","skills"),t(e,".kiro","skills"),t(e,".reasonix","skills"),t(w(),"skills"),t(_(),"skills"),t(e,".copilot","skills"),t(e,".hermes","skills")],n=t(d().rootDir,"runtime","native-provider");try{for(const s of l(n,{withFileTypes:!0}))s.isDirectory()&&r.push(t(n,s.name,"hermes","skills"))}catch{}return r}function j(){const e=[];for(const i of C()){let r;try{r=l(i,{withFileTypes:!0,encoding:"utf8"})}catch{continue}for(const n of r){if(!n.isDirectory())continue;const s=t(i,n.name);if(m(t(s,f)))try{v(s,{recursive:!0,force:!0}),e.push(s)}catch{}}}return e.length>0&&a.info("default-skills",`Cleaned ${e.length} projected skill dir(s)`),e}function b(){const e=p();if(e.length===0){a.warn("default-skills","No connector system skills found \u2014 dist/default-skills/ may be missing SKILL.md files");return}a.info("default-skills",`Connector system skills available: [${e.map(i=>i.name).join(", ")}]`)}export{O as buildReportedSkills,j as cleanupProjectedSkills,b as logDefaultSkillsCheck,_ as resolveDshSkillHome,w as resolveKimiCodeHome,p as scanDefaultSkills,P as syncDefaultSkillsToDir};
|
package/dist/grix.js
CHANGED
|
File without changes
|
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 ue}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 me}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{supportsKiroCwRelay as F,supportsNonMitmRelayConfig as ve}from"./core/config/provider-env.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 Ae,resolveCliPath as Ce}from"./core/util/cli-probe.js";import{AgentInstaller as xe}from"./core/installer/installer.js";import{reportInstallFailure as $e}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Ie}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as Te}from"./adapter/codex/config-overrides.js";import{resolveCodexDirectHome as Ee}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 Pe=8e3;function je(){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 Me(){return Promise.all(je().map(async n=>{const e=await Ce(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await Ae(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Re(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 v(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 De(n){return b(w.data,`session-bindings-${v(n,"unknown")}.json`)}function Oe(n,e){return b(w.data,`session-bindings-${v(n,e)}.json`)}function He(n,e){return b(w.data,`active-events-${v(n,e)}.json`)}function Le(n,e){const t=v(n,"agent"),r=v(e,"unknown");return b(w.data,`terminal-outbox-${t}-${r}.json`)}function Ne(...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 qe(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 Be(n,e={}){const t=me(),r=String(n.client_type??"").trim().toLowerCase(),a=Re(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",h="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,u=d==="acp",y=r==="qwen",m={...a.options??{}};if(d==="deepseek-harness"&&(m.integrationMode=c,m.dshProfile=n.dsh?.profile?.trim()||"web",m.autoInstallBridge=n.dsh?.auto_install_bridge??!s,m.autoStartProfile=n.dsh?.auto_start_profile??!s),d==="deepseek-harness"&&n.provider?.model?.trim()&&(m.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`);Te(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),m.codexConfigOverrides=n.codex_config_overrides}if(d==="codex"&&n.provider?.wire_api!==void 0){const _=n.provider;if(_.wire_api!=="responses"||!_.base_url?.trim()||!_.api_key?.trim()||!_.model?.trim()||!_.catalog_version?.trim()||!_.catalog_sha256?.trim()||!_.catalog_json?.trim())throw Object.assign(new Error(`agent ${n.name}: incomplete Codex direct relay config`),{code:"INVALID_CODEX_DIRECT_CONFIG"});const N=Ee(w.data,n.name);m.codexHome=N,m.codexDirect={codexHome:N,config:{baseUrl:_.base_url.trim(),model:_.model.trim(),..._.reasoning_effort?.trim()?{reasoningEffort:_.reasoning_effort.trim()}:{},token:_.api_key.trim()},catalog:{version:_.catalog_version.trim(),sha256:_.catalog_sha256.trim(),json:_.catalog_json}}}const f=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,C=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,x=d==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,$=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,j=d==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,I=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,T=d==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,E=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,M=new Set(["hermes","reasonix","kimi","copilot"]),J=u&&!M.has(r),X=u&&!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"||u&&M.has(r)?[i]:[o,i];u&&m.raw_transport===void 0&&(m.raw_transport=r==="gemini");const te=`${r}/base`,P=_e(d,r),ne=P==="kiro"?void 0:process.cwd(),R={...process.env,...n.env},D=ke({mode:P,projectDir:ne,env:R}),O=D.filter(_=>_.source==="connector").map(_=>_.name);O.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${O.join(", ")}]`);const H=ye(D,w.skills);let re=H.length>0?H:void 0;const ae=we({skillsDir:w.skills,mode:P,home:ce(),env:R}),L=z(n.provider);return{name:n.name,adapterType:d,aibot:{url:p,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:E?.adapterHint??a.adapterHint??S?.adapterHint??C?.adapterHint??x?.adapterHint??$?.adapterHint??I?.adapterHint??T?.adapterHint??te,capabilities:E?.capabilities??f?.capabilities??j?.capabilities??C?.capabilities??x?.capabilities??$?.capabilities??I?.capabilities??T?.capabilities??S?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Ne(E?.localActions??f?.localActions??j?.localActions??k?.localActions??C?.localActions??x?.localActions??$?.localActions??I?.localActions??T?.localActions??S?.localActions??Y?.localActions??X?.localActions??["exec_approve","exec_reject"],Z,ee,["connector_rollback","connector_upgrade_push",h,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...g]),skills:re,librarySkills:ae,terminalOutboxPath:Le(n.name,n.agent_id)},agent:{command:s?"dsh-jsonrpc-agent":a.command,args:[...a.args??[],...n.args??[]],env:n.env,clientType:r,...L?{provider:L}:{}},adapterOptions:m,acpAuthMethod:m.auth_method,acpInitialMode:m.initial_mode,acpMcpTools:m.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:De(n.agent_id),legacyBindingsPath:Oe(n.name,n.agent_id),activeEventStorePath:He(n.name,n.agent_id),...a.enableSessionBinding||u?{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:qe(d,n.event_queue),logDir:w.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Ue(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):Pe}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 A(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(A).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${A(e[r])}`).join(",")}}`}function Fe(n,e){return A(n)===A(e)}class yt{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 ue(w.data);installer=new xe;relaySecretResolver;auditProducer=Ie();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:h}of r)try{const g=this.toRuntimeInstanceConfig(i);s.push({config:g,entry:i,file:h}),l.info("manager",`Loaded ${g.name} (${g.adapterType??"acp"}) from ${h}`)}catch(g){const d=typeof i?.name=="string"?i.name:"<unknown>";l.error("manager",`Invalid agent config in ${h} (name=${d}): ${g}`),p++}let o=0;if(s.length>0){const i=Ue();l.info("manager",`Starting ${s.length} agent(s), startup wait=${i}ms`);const h=u=>{this.instances=this.instances.filter(y=>y!==u)},g=s.map(({config:u,entry:y,file:m})=>{const f=this.createConfiguredInstance(u);return this.instances.push(f),this.configMap.set(u.name,u),this.rawConfigMap.set(u.name,{entry:y,file:m}),{config:u,instance:f,startPromise:this.prepareProviderRuntime(u,y).then(()=>f.start())}}),d=await Promise.all(g.map(async u=>{const y=await new Promise(m=>{let f=!1;const k=setTimeout(()=>{f||(f=!0,m({kind:"timeout"}))},i);u.startPromise.then(()=>{f||(f=!0,clearTimeout(k),m({kind:"started"}))}).catch(S=>{f||(f=!0,clearTimeout(k),m({kind:"failed",error:S}))})});return{task:u,outcome:y}}));for(const{task:u,outcome:y}of d){if(y.kind==="started"){this.restoreCachedSharedInstances(u.config);continue}if(y.kind==="failed"){if(B(y.error)){this.onAgentDeletedByPlatform(u.config.name);continue}h(u.instance),l.error("manager",`Failed to start ${u.config.name}: ${y.error}`);continue}o++,l.warn("manager",`Startup pending for ${u.config.name}, continue retrying in background`),u.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${u.config.name}`),this.restoreCachedSharedInstances(u.config)}).catch(m=>{if(B(m)){this.onAgentDeletedByPlatform(u.config.name);return}h(u.instance),l.error("manager",`Delayed start failed: ${u.config.name}: ${m}`)})}if(this.instances.length>0){const u=Math.max(0,this.instances.length-o);l.info("manager",`${u}/${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)+`
|
|
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
|
|
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)+`
|
|
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};
|