grix-connector 4.2.7 → 4.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/adapter/claude/claude-bridge-server.js +1 -1
  2. package/dist/adapter/claude/claude-tools.js +1 -1
  3. package/dist/adapter/claude/claude-worker-client.js +1 -1
  4. package/dist/adapter/claude/mcp-http-launcher.js +2 -2
  5. package/dist/adapter/claude/result-timeout.js +1 -1
  6. package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
  7. package/dist/adapter/codewhale/codewhale-provider-config.js +2 -2
  8. package/dist/adapter/deepseek-harness/dsh-provider-config.js +7 -7
  9. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.2.8.tgz +0 -0
  10. package/dist/assets/dsh-bridge/manifest.json +5 -5
  11. package/dist/bridge/bridge.js +5 -9
  12. package/dist/bridge/cli-install-flow.js +1 -0
  13. package/dist/bridge/connector-ops.js +1 -0
  14. package/dist/bridge/event-stop.js +1 -0
  15. package/dist/bridge/host-contract.js +0 -0
  16. package/dist/bridge/provider-quota.js +1 -0
  17. package/dist/bridge/rate-limits.js +1 -0
  18. package/dist/bridge/session-control-open.js +1 -0
  19. package/dist/bridge/session-control-router.js +3 -0
  20. package/dist/bridge/session-list.js +3 -0
  21. package/dist/bridge/session-usage.js +1 -0
  22. package/dist/bridge/skill-actions.js +1 -0
  23. package/dist/bridge/toolbar-meta.js +1 -0
  24. package/dist/core/access/allowlist-store.js +1 -1
  25. package/dist/core/file-ops/list-files.js +1 -1
  26. package/dist/core/skill-sync/sync-state.js +1 -1
  27. package/dist/log.js +2 -2
  28. package/dist/mcp/stream-http/config.js +1 -1
  29. package/dist/mcp/stream-http/connection-binding.js +1 -1
  30. package/dist/mcp/stream-http/tool-executor.js +1 -1
  31. package/dist/mcp/stream-http/tool-registry.js +1 -1
  32. package/dist/mcp/stream-http/tool-schemas.js +1 -1
  33. package/package.json +2 -1
  34. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.2.7.tgz +0 -0
@@ -0,0 +1 @@
1
+ import{randomUUID as u}from"node:crypto";import{parseAgentQuestionReplyMessage as g}from"../core/protocol/interaction-parser.js";import{resolveCliPath as m}from"../core/util/cli-probe.js";import{CLI_INSTALL_OPTION_YES as I,CLI_INSTALL_REQUEST_PREFIX as f,buildCliInstallQuestion as v,cliDisplayName as C,isCliMissingError as S,isInstallConfirmReply as w,resolveInstallAgentType as b}from"./cli-install-offer.js";import{log as $}from"../core/log/index.js";const q=["bindSessionForPool","ensureSlotStarted","sendGrixAgentQuestionCard","runConfirmedCliInstall"],y=["name","config","aibotHandle","bindingStore","sessionBindings","pendingCliInstalls","installAgentHandler"];function E(n,e){if(!n.installAgentHandler||!S(e.err))return;const s=b(n.config.adapterType,n.config.agent.clientType||n.config.aibot.clientType);if(!s)return;const i=C(s,n.config.agent.command),t=`${f}${u()}`,r=String(e.cwd??"").trim()||n.bindingStore.get(e.sessionId)?.cwd;n.pendingCliInstalls.set(t,{sessionId:e.sessionId,agentType:s,cliName:i,cwd:r});const d=e.eventId||`cli-install:${e.sessionId}`,a=`\u6CA1\u627E\u5230\u672C\u673A\u7A0B\u5E8F \`${i}\`\uFF0C\u65E0\u6CD5\u542F\u52A8\u3002\u662F\u5426\u9700\u8981\u5B89\u88C5\uFF1F`;n.aibotHandle.sendMsg({event_id:d,session_id:e.sessionId,msg_type:1,content:a,...e.quotedMessageId?{quoted_message_id:e.quotedMessageId}:{}}),n.sendGrixAgentQuestionCard(d,e.sessionId,v(t,i)),$.warn(n.name,`cli missing: offered install card session=${e.sessionId} agentType=${s} cli=${i}`)}async function M(n,e){const s=g(String(e.content??""));if(!s)return!1;const i=n.pendingCliInstalls.get(s.request_id);if(!i)return!1;if(n.pendingCliInstalls.delete(s.request_id),n.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),!w(s))return n.aibotHandle.sendMsg({event_id:e.event_id,session_id:e.session_id,msg_type:1,content:`\u5DF2\u53D6\u6D88\u5B89\u88C5 ${i.cliName}\u3002`,quoted_message_id:e.msg_id}),n.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()}),!0;try{await n.runConfirmedCliInstall(i,{eventId:e.event_id,sessionId:e.session_id,quotedMessageId:e.msg_id})}catch(t){n.aibotHandle.sendMsg({event_id:e.event_id,session_id:e.session_id,msg_type:1,content:`${i.cliName} \u5B89\u88C5\u5931\u8D25\uFF1A${t instanceof Error?t.message:String(t)}`,quoted_message_id:e.msg_id})}return n.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()}),!0}async function R(n,e){const s=e.params??{},i=String(s.request_id??"").trim();if(!i)return!1;const t=n.pendingCliInstalls.get(i);if(!t)return!1;n.pendingCliInstalls.delete(i);const r=s.resolution??s.response??{},d=String(s.action??s.kind??"").trim(),a=String(r.value??s.value??"").trim(),_=d==="accept"||a===I||/^yes$/i.test(a)||/^install$/i.test(a),o=String(s.session_id??t.sessionId).trim()||t.sessionId,c=`cli-install:${i}`;if(!_)return n.aibotHandle.sendMsg({event_id:c,session_id:o,msg_type:1,content:`\u5DF2\u53D6\u6D88\u5B89\u88C5 ${t.cliName}\u3002`}),n.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"install_declined"}}),!0;try{await n.runConfirmedCliInstall(t,{eventId:c,sessionId:o}),n.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"install_started"}})}catch(l){n.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"cli_install_failed",error_msg:l instanceof Error?l.message:String(l)})}return!0}async function x(n,e,s){const i=r=>{n.aibotHandle.sendMsg({event_id:s.eventId,session_id:s.sessionId,msg_type:1,content:r,...s.quotedMessageId?{quoted_message_id:s.quotedMessageId}:{}})};if(!n.installAgentHandler){i(`\u65E0\u6CD5\u5B89\u88C5 ${e.cliName}\uFF1A\u5B89\u88C5\u5668\u672A\u5C31\u7EEA\u3002`);return}i(`\u5F00\u59CB\u5B89\u88C5 ${e.cliName}\u2026`);const t=await n.installAgentHandler({agentType:e.agentType});if(!t.ok){i(`${e.cliName} \u5B89\u88C5\u5931\u8D25\uFF1A${t.error?.message??t.phase}`);return}try{await m(e.cliName)}catch{}i(`\u2705 ${e.cliName} \u5B89\u88C5\u6210\u529F\u3002`),e.cwd&&(n.bindingStore.set(e.sessionId,e.cwd),n.sessionBindings.set(e.sessionId,e.cwd));try{await n.ensureSlotStarted(e.sessionId),e.cwd&&(await n.bindSessionForPool(e.sessionId,e.cwd),n.aibotHandle.sendUpdateBindingCard({session_id:e.sessionId,worker_status:"ready",cwd:e.cwd}),i(`\u5DE5\u4F5C\u76EE\u5F55\u5DF2\u5C31\u7EEA\uFF1A\`${e.cwd}\``))}catch(r){i(`\u5B89\u88C5\u6210\u529F\uFF0C\u4F46\u542F\u52A8\u4ECD\u5931\u8D25\uFF1A${r instanceof Error?r.message:String(r)}`)}}export{y as CLI_INSTALL_HOST_FIELDS,q as CLI_INSTALL_HOST_METHODS,R as handleCliInstallInteractionReply,M as handleCliInstallQuestionReply,E as maybeOfferCliInstall,x as runConfirmedCliInstall};
@@ -0,0 +1 @@
1
+ import E from"node:path";import{existsSync as I}from"node:fs";import{AuditLocalActionHandler as P}from"../audit/query/audit-local-actions.js";import{AuditReplayQueryService as U}from"../audit/query/audit-replay-query-service.js";import{resolveDefaultAuditStorageRootDir as C}from"../audit/runtime/default-audit-recorder.js";import{FileAuditReplayStore as T}from"../audit/storage/file-audit-replay-store.js";import{getProxyManager as v,relayHostsForClientType as D,buildGatewayRoute as N}from"../core/proxy/index.js";import{fetchRelayCredentialWithRetry as O,deriveGatewayBaseUrls as w,RelayFetchError as k}from"../core/proxy/relay-credential-fetch.js";import{isDirectRelayExplicitlyUnsupported as x}from"../core/proxy/relay-credential.js";import{RelayStateSyncer as G}from"../core/proxy/relay-state-sync.js";import{supportsKiroCwRelay as q}from"../core/config/provider-env.js";import{log as m,GRIX_PATHS as H}from"../core/log/index.js";const J=["recycleAdaptersForRelayChange","waitUntilLifecycleIdle","getAuditLocalActionHandler","getRelayStateSyncer","isSharedInstance"],Z=["name","config","aibotConfig","aibotHandle","auditLocalActionHandler","providerConfigHandler","relayStateApplyPorts","relayStateSyncer","daemonShutdownRequester","lifecycleAdmissionRestorer"];async function ee(e,t){const r=t.params??{},o=String(r.api_key??"").trim(),i=String(r.anthropic_base_url??"").trim(),n=String(r.openai_base_url??"").trim(),l=typeof r.provider_id=="string"&&r.provider_id.trim().toLowerCase()||void 0,s=typeof r.quota_base_url=="string"&&r.quota_base_url.trim()||void 0,u=typeof r.model=="string"&&r.model.trim()||void 0;let g=!1,_;if(!o){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"MISSING_API_KEY",error_msg:"api_key is required"});return}const d=e.config.adapterType??"acp",f=d==="claude"||d==="codex",y=f&&x(r.direct_relay,d),R=f&&r.direct_relay!==void 0&&!y;try{if(R){if(!e.relayStateApplyPorts){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"unsupported",error_code:"UNSUPPORTED_CLIENT_TYPE",error_msg:"relay state applier is not configured"});return}const a=await e.relayStateApplyPorts.applyEnable({apiKey:o,...i?{anthropicBaseUrl:i}:{},...n?{openaiBaseUrl:n}:{},...u?{model:u}:{},directRelay:r.direct_relay},u);a&&(_=a,g=a.busy||a.pending!==void 0)}else if(f){const a=d==="claude"?i:n;if(!a){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"MISSING_TARGET_BASE_URL",error_msg:`${d==="claude"?"anthropic_base_url":"openai_base_url"} is required`});return}const c=v();if(!c){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"PROXY_UNAVAILABLE",error_msg:"MITM proxy manager not initialized"});return}const p=D(d),A=N(d,a,o,{model:u});c.setRoute(A);for(const S of p)c.setHostDefaultRoute(S,A.routeKey);await c.setAgentRelayEnabled(e.name,!0,{relayHosts:p}),g=!await e.recycleAdaptersForRelayChange()}else{if(!e.providerConfigHandler){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"unsupported",error_code:"UNSUPPORTED_CLIENT_TYPE",error_msg:`client type "${d}" does not support Grix relay provider config`});return}const a=e.config.aibot.clientType,c=q(a),p=c?i:n;if(!p){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"MISSING_TARGET_BASE_URL",error_msg:`${c?"anthropic_base_url":"openai_base_url"} is required`});return}if(c&&!u){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"MISSING_MODEL",error_msg:'model is required for client type "kiro"'});return}await e.providerConfigHandler({...l?{provider_id:l}:{},base_url:p||void 0,...s?{quota_base_url:s}:{},api_key:o,model:u})}e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{accepted:!0,restart_deferred:g,..._?{restarted:_.restarted,busy:_.busy,..._.pending?{pending:_.pending}:{}}:{}}})}catch(a){m.error(e.name,`handleConfigureGatewayProvider failed: ${a}`),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"CONFIGURE_FAILED",error_msg:a instanceof Error?a.message:String(a)})}}function re(e){if(!e.auditLocalActionHandler){const t=new T({rootDir:C()});e.auditLocalActionHandler=new P(new U(t))}return e.auditLocalActionHandler}async function te(e,t){const r=await e.getAuditLocalActionHandler().handle(t.action_type,t.params);if(r.status==="ok"){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:r.result});return}e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:r.errorCode,error_msg:r.errorMsg})}async function ne(e,t){let r=null,o=!1,i=!1,n=String((t.params??{}).target_version??"").trim();const l=String((t.params??{}).reason??"server_initiated");if(!n){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"MISSING_TARGET_VERSION",error_msg:"target_version is required for connector_rollback"});return}m.info(e.name,`connector_rollback: target=${n} reason=${l}`);try{const{UpgradeError:s,armWindowsUpgradeHandoff:u,normalizeUpgradeVersion:g,npmInstall:_,pendingExists:d,upgradeLog:f,verifyInstalledVersion:y,writePending:R}=await import("../core/upgrade/npm-upgrader.js"),{resolveClientVersion:a}=await import("../core/util/client-version.js");n=g(n);const c=a(),p=process.platform==="win32";if(d())throw new s("UPGRADE_IN_PROGRESS","Another connector upgrade transaction is already active");if(p){const L=["upgrade-guardian.mjs","upgrade-guardian.fallback.mjs"].map(b=>E.join(H.base,"bin",b)).find(b=>I(b));if(process.env.GRIX_WRAPPER_SUPERVISED!=="1"||!L||!e.daemonShutdownRequester)throw new s("WINDOWS_UPGRADE_UNSUPPORTED","Windows rollback requires a refreshed managed wrapper and external guardian")}f(`server rollback: ${c} -> ${n} reason=${l}`);const S=R(c,n,p?"preparing":void 0).transaction_id;if(!S)throw new s("INVALID_UPGRADE_STATE","Upgrade transaction has no owner ID");if(r=S,(await _("grix-connector",n))?.activationRequired||y(n),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{accepted:!0,target_version:n}}),i=!0,o=!0,!await e.waitUntilLifecycleIdle("connector_rollback"))throw f("server rollback: aborted before idle restart (instance stopped, idle wait timed out, or work arrived)"),new s("UPGRADE_ABORTED","Connector rollback was aborted before lifecycle handoff");if(p){if(!["upgrade-guardian.mjs","upgrade-guardian.fallback.mjs"].some(b=>I(E.join(H.base,"bin",b))))throw new s("WINDOWS_UPGRADE_UNSUPPORTED","Windows external guardian disappeared before lifecycle handoff");u(process.pid,S),await e.daemonShutdownRequester("upgrade")}else process.kill(process.pid,"SIGTERM")}catch(s){try{const{discardPendingStaging:g,finalizePendingTransaction:_,readPending:d,removePending:f,removeWindowsHandoffFiles:y,rollbackPendingInstall:R}=await import("../core/upgrade/npm-upgrader.js"),a=d(),c=!!(r&&a?.transaction_id===r);c&&process.platform==="win32"?(y(),g(a)):c&&R(a),c&&(process.platform==="win32"?_(a):f(r))}catch{}o&&e.lifecycleAdmissionRestorer?.();const u=s instanceof Error?s.message:String(s);m.error(e.name,`connector_rollback failed: ${u}`),i||e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:s instanceof Error&&"code"in s&&typeof s.code=="string"?s.code:"ROLLBACK_FAILED",error_msg:u})}}function ae(e){const t=e.relayStateApplyPorts;return!t||!e.aibotHandle||e.isSharedInstance()?null:(e.relayStateSyncer||(e.relayStateSyncer=new G({...t,sendSyncRequest:(r,o)=>{const{anthropicBaseUrl:i,openaiBaseUrl:n}=w(e.aibotConfig.url);return e.aibotHandle.relayStateSyncRequest({anthropic_base_url:i,openai_base_url:n,...r},o)},sendCredentialRequest:(r,o)=>{const{anthropicBaseUrl:i,openaiBaseUrl:n}=w(e.aibotConfig.url);return e.aibotHandle.relayCredentialRequest({anthropic_base_url:i,openai_base_url:n,...r},o)},sendReport:r=>e.aibotHandle.sendRelayStateReport(r),log:{info:r=>m.info(e.name,r),warn:r=>m.warn(e.name,r)}})),e.relayStateSyncer)}function ie(e){const t=e.getRelayStateSyncer();t&&t.syncOnConnect().catch(r=>{m.warn(e.name,`relay state sync failed: ${r instanceof Error?r.message:String(r)}`)})}function oe(e){try{e.getRelayStateSyncer()?.reportLocalChange()}catch{}}async function se(e,t){const r=t.params??{},o=r.enabled,i=Number(r.revision);if(typeof o!="boolean"||!Number.isFinite(i)){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"INVALID_PARAMS",error_msg:"enabled (boolean) and revision (number) are required"});return}const n=e.getRelayStateSyncer();if(!n){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"RELAY_UNAVAILABLE",error_msg:"relay state sync is not available on this agent",result:{revision:i}});return}const l=await n.applyFromLocalAction({enabled:o,model:typeof r.model=="string"?r.model:void 0,revision:i});e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:l.ok?"ok":"failed",result:{revision:l.revision},...l.error_code?{error_code:l.error_code}:{},...l.error_msg?{error_msg:l.error_msg}:{}})}async function ce(e,t){const r=e.aibotHandle;if(!r||r.status!=="ready")throw new k("agent websocket is not connected","OFFLINE");const{anthropicBaseUrl:o,openaiBaseUrl:i}=w(e.aibotConfig.url);return O((n,l)=>r.relayCredentialRequest(n,l),{anthropic_base_url:o,openai_base_url:i,...t.model?{model:t.model}:{}})}function le(e){return!!e.config.aibot.sharedOwnerId}export{Z as CONNECTOR_OPS_HOST_FIELDS,J as CONNECTOR_OPS_HOST_METHODS,ce as fetchRelayCredential,re as getAuditLocalActionHandler,ae as getRelayStateSyncer,se as handleApplyRelayState,te as handleAuditLocalAction,ee as handleConfigureGatewayProvider,ne as handleConnectorRollback,le as isSharedInstance,ie as relayStateSyncOnConnect,oe as reportRelayStateLocalChange};
@@ -0,0 +1 @@
1
+ import{log as l}from"../core/log/index.js";const R=10*1e3,C=["discardEventTrackingState","pushQueueSnapshotForSession","sendCanceledPendingEventResult","sendEventResultWithCleanup","killAndResumeStopSlot","waitForEventDone"],w=["name","config","stopped","aibotHandle","pool","pendingEvents","deferredMgr","revokeHandler","sendCtrl"];async function A(e,n){const{event_id:t,session_id:i}=n;if(l.info(e.name,`handleEventCancel start event_id=${t} session_id=${i}`),e.pendingEvents.markCanceled(t),e.pool.cancelEvent(t,i)){if(!(e.pool.getSlot(i)?.adapter?.getActiveEventIds().includes(t)??!1)){await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}await e.waitForEventDone(t,i,15e3),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"}),e.pushQueueSnapshotForSession(i);return}const a=e.deferredMgr.removeEvent(t);if(a){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(a,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}const c=await e.pendingEvents.cancel(t,i);if(c){e.sendCanceledPendingEventResult(c.event,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!1,reason:"event not found or not cancelable"})}function T(e,n,t,i){return new Promise(s=>{const a=e.pool.getSlot(t);if(!a?.adapter){s();return}const c=setTimeout(()=>{a.adapter.removeListener("eventDone",d),s()},i),d=u=>{u===n&&(clearTimeout(c),a.adapter.removeListener("eventDone",d),s())};a.adapter.on("eventDone",d)})}function D(e,n){const t=n.event_id?.trim()??"",i=n.scope?.trim()??"";l.info(e.name,`[stop-trace] handleAibotStop begin session=${n.session_id} event=${t||"-"} scope=${i||"event"} stop_id=${n.stop_id||"-"} adapterType=${e.config.adapterType??"acp"}`);const s=e.pool.getSlot(n.session_id),a=s?.adapter?.getStatus().busy??!1;let c=!1,d=[];if(s?.adapter)try{d=[...new Set(s.adapter.getActiveEventIds().map(r=>r.trim()).filter(Boolean))]}catch(r){c=!0,l.warn(e.name,`[stop-trace] handleAibotStop active event probe failed session=${n.session_id}: ${r}`)}const u=i==="session";let o=u?"":t;const p=r=>({stop_id:n.stop_id,...r?{event_id:r}:{},...n.terminal_commit_token?{terminal_commit_token:n.terminal_commit_token}:{},session_id:n.session_id,...i?{scope:i}:{}}),m=r=>{!r||!n.terminal_commit_token?.trim()||e.sendEventResultWithCleanup(r,"canceled","stopped by owner","event_stopped")};if(u)if(!c&&d.length===1)[o]=d;else if(!c&&d.length===0&&!a){e.aibotHandle.sendEventStopAck({...p(""),accepted:!0,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"already_finished",updated_at:Date.now()}),l.info(e.name,`[stop-trace] handleAibotStop session idle -> stopResult(already_finished) session=${n.session_id} stop_id=${n.stop_id||"-"}`);return}else{const r=c?"session_stop_target_unavailable":d.length>1?"session_stop_target_ambiguous":"session_stop_target_unresolved",f=c?"failed to inspect active events for session stop":d.length>1?"multiple active events prevent a safe session stop":"adapter is busy but no active event can be identified";e.aibotHandle.sendEventStopAck({...p(""),accepted:!1,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"failed",code:r,msg:f,updated_at:Date.now()}),l.warn(e.name,`[stop-trace] handleAibotStop session target unsafe -> stopResult(failed) session=${n.session_id} activeIds=[${d.join(",")}] busy=${a} code=${r}`);return}if(e.aibotHandle.sendEventStopAck({...p(o),accepted:!0,updated_at:Date.now()}),e.pool.removeQueuedEvent(n.session_id,o)){l.info(e.name,`[stop-trace] handleAibotStop removed queued(not-running) event -> stopResult(stopped) session=${n.session_id} event=${o} stop_id=${n.stop_id||"-"}`),n.terminal_commit_token?.trim()?m(o):e.discardEventTrackingState(o),e.pushQueueSnapshotForSession(n.session_id),e.aibotHandle.sendEventStopResult({...p(o),status:"stopped",updated_at:Date.now()});return}const $=(e.config.adapterType??"acp")==="acp",g=d.length>0?d.includes(o):a,v=($||(e.config.adapterType??"acp")==="codex"||(e.config.adapterType??"acp")==="claude")&&g;if(l.info(e.name,`[stop-trace] handleAibotStop decision session=${n.session_id} event=${o} scope=${i||"event"} slotExists=${!!s?.adapter} busy=${a} activeIds=[${d.join(",")}] stoppingActiveEvent=${g} killOnStop=${v}`),g&&e.sendCtrl.markEventStopped(o),s?.adapter&&a){const r=v?e.pool.drainQueuedForSession(n.session_id):[];let f=!1,_=null;const S=E=>{f||(f=!0,_&&(clearTimeout(_),_=null),s.adapter.removeListener("eventDone",b),l.info(e.name,`[stop-trace] handleAibotStop ${E} -> stopResult(stopped) session=${n.session_id} event=${o} stop_id=${n.stop_id||"-"} killOnStop=${v}`),m(o),e.aibotHandle.sendEventStopResult({...p(o),status:"stopped",updated_at:Date.now()}),v&&e.killAndResumeStopSlot(n.session_id,r))},b=E=>{E===o&&S("eventDone")};s.adapter.on("eventDone",b),_=setTimeout(()=>S("timeout"),R),e.pool.deliverStopEvent(o,n.session_id)}else l.info(e.name,`[stop-trace] handleAibotStop slot-not-busy -> immediate stopResult(stopped) session=${n.session_id} event=${o} slotExists=${!!s?.adapter}`),e.pool.deliverStopEvent(o,n.session_id),m(o),e.aibotHandle.sendEventStopResult({...p(o),status:"stopped",updated_at:Date.now()});(e.config.adapterType??"acp")==="pi"&&e.aibotHandle.sendText({event_id:o,session_id:n.session_id,content:"/stop",msg_type:0})}async function H(e,n,t){if(!e.stopped){l.info(e.name,`[stop-trace] killAndResumeStopSlot begin session=${n} siblings=${t.length} -> removeSlot (kill process group)`);try{await e.pool.removeSlot(n),l.info(e.name,`[stop-trace] killAndResumeStopSlot removeSlot done session=${n} (process killed) -> redeliver ${t.length} sibling(s)`)}catch(i){l.warn(e.name,`[acp-stop] removeSlot failed session=${n}: ${i instanceof Error?i.message:String(i)}`)}if(!e.stopped)for(const i of t){if(e.stopped)break;try{await e.pool.deliverInboundEvent(i)}catch(s){l.error(e.name,`[acp-stop] sibling redeliver failed event=${i.event_id} session=${n}: ${s instanceof Error?s.message:String(s)}`),e.sendEventResultWithCleanup(i.event_id,"failed",s instanceof Error?s.message:String(s))}}}}async function x(e,n){if(!n.event_id||!e.revokeHandler.checkAndTrack(n.event_id))return;const t=n.event_id,i=n.session_id;if(e.pendingEvents.markCanceled(t),i&&e.pool.cancelEvent(t,i)){(e.pool.getSlot(i)?.adapter?.getActiveEventIds().includes(t)??!1)||(await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","revoked"));return}const s=e.deferredMgr.removeEvent(t);if(s){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(s,"revoked");return}const a=e.pool.cancelStartupEvent(t,i||void 0);if(a){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(a,"revoked");return}const c=await e.pendingEvents.cancel(t,i||void 0);if(c){e.sendCanceledPendingEventResult(c.event,"revoked");return}e.pool.deliverStopEvent(t,i||void 0)}export{w as EVENT_STOP_HOST_FIELDS,C as EVENT_STOP_HOST_METHODS,x as handleAibotRevoke,D as handleAibotStop,A as handleEventCancel,H as killAndResumeStopSlot,T as waitForEventDone};
File without changes
@@ -0,0 +1 @@
1
+ import{sharedProviderQuotaService as Q,detectProviderFromModel as m,normalizeProviderId as y,readPiProviderSettings as b,readOpenCodeProviderSettings as $,isOpenaiCodexProviderName as q,queryOpenaiCodexQuota as S,openaiCodexQuotaCacheKey as K,resolveKimiProviderSettings as A,providerQuotaToRateLimits as T,providerQuotaToCodexRateLimits as H}from"../core/provider-quota/index.js";import{queryKiroQuota as E}from"../core/provider-quota/kiro.js";import{DshJsonRpcAdapter as x,resolveDshHome as R,readDshCredentials as M}from"../adapter/deepseek-harness/index.js";import{readSettingsEnv as D}from"../adapter/claude/model-list.js";import{readCodexProviderSettings as U}from"../adapter/codex/codex-trust.js";import{log as u}from"../core/log/index.js";const w=30*1e3,k=10*1e3,N=["isRateLimitsCacheFresh","providerQuotaToRateLimits","resolveProviderQuotaSource","maybeQueryProviderQuota","stopProviderQuotaTimer","refreshAndPushProviderQuota","pushProviderQuotaToBindings","enrichProviderQuotaMeta","refreshProviderQuotaForSession","doRefreshQuotaAfterModelSwitch"],V=["name","config","stopped","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","sessionProviderMeta","cachedAcpContextWindow","cachedProviderQuota","cachedProviderQuotaKey","cachedProviderQuotaSampledAtMs","providerQuotaTimer","lastModelSwitchQuotaRefresh"];async function W(e,o){if(o?.disabled||o?.providerId==="openai_codex")return null;let a=e.config.providerBaseUrl??e.config.agent.provider?.baseUrl,t=e.config.providerApiKey??e.config.agent.provider?.apiKey;if((e.config.adapterType??"acp")==="deepseek-harness"){if(t??=e.config.agent.env?.DEEPSEEK_API_KEY,a??=e.config.agent.env?.DEEPSEEK_BASE_URL,!t){const r=R(typeof e.config.adapterOptions?.dshHome=="string"?e.config.adapterOptions.dshHome:void 0,e.config.agent.env);try{const i=await M(r),d=typeof i.DEEPSEEK_API_KEY=="string"?i.DEEPSEEK_API_KEY.trim():"";d&&(t=d,a??=typeof i.DEEPSEEK_BASE_URL=="string"&&i.DEEPSEEK_BASE_URL.trim()?i.DEEPSEEK_BASE_URL.trim():"https://api.deepseek.com",u.debug(e.name,"[provider-quota] deepseek-harness: resolved official DeepSeek API key from DSH credential store ($DSH_HOME)"))}catch(i){u.warn(e.name,`[provider-quota] deepseek-harness: could not read DSH credential store: ${i instanceof Error?i.message:String(i)}`)}}a??=t?"https://api.deepseek.com":void 0}if((!a||!t)&&(e.config.adapterType??"acp")==="claude"){const r=D();a||(a=(r.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(r.ANTHROPIC_API_KEY??"").trim()||(r.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!a||!t)&&(e.config.adapterType??"acp")==="codex"){const r=U();!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="acp"&&e.config.aibot.clientType==="kimi"){const r=await A();!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="pi"){const r=b(o);!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="opencode"){const r=$(o);!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if(!a||!t)return null;const n=y(o?.providerId)??m(o?.model)?.id??y(e.config.agent.provider?.providerId)??m(e.config.agent.provider?.model)?.id;return{baseUrl:a,...e.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:e.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...n?{providerId:n}:{}}}async function z(e,o=!1,a){if(e.config.aibot.clientType==="kiro"){if(!o&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota)return e.cachedProviderQuota;try{const r=await E();return e.cachedProviderQuota=r,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro",u.info(e.name,`[provider-quota] kiro queried: success=${r.success}`+(r.balance?` balance=${r.balance.remaining} ${r.balance.unit}`:"")+(r.planName?` plan=${r.planName}`:"")+(r.error?` error=${r.error}`:"")),r}catch(r){return u.warn(e.name,`[provider-quota] kiro query failed: ${r instanceof Error?r.message:String(r)}`),null}}if(a?.providerId==="openai_codex")try{const r=await S();return r.quota.success?r.quota:null}catch(r){return u.warn(e.name,`[provider-quota] openai_codex query failed: ${r instanceof Error?r.message:String(r)}`),null}const t=await e.resolveProviderQuotaSource(a);if(!t)return null;const n=Q.cacheKey(t);if(!o&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota&&e.cachedProviderQuotaKey===n)return e.cachedProviderQuota;try{const r=await Q.query(t,{fresh:o}),i=r.quota;return e.cachedProviderQuota=i,e.cachedProviderQuotaSampledAtMs=r.sampledAt,e.cachedProviderQuotaKey=r.cacheKey,u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(d=>`${d.name}=${d.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")),i}catch(r){return u.warn(e.name,`[provider-quota] query failed: ${r instanceof Error?r.message:String(r)}`),null}}function Y(e){e.stopped||e.providerQuotaTimer||(e.providerQuotaTimer=setInterval(()=>{if(e.stopped){e.stopProviderQuotaTimer();return}e.refreshAndPushProviderQuota().catch(()=>{})},w),u.info(e.name,`[provider-quota-timer] started (interval=${w}ms)`))}function j(e){e.providerQuotaTimer&&(clearInterval(e.providerQuotaTimer),e.providerQuotaTimer=null,u.info(e.name,"[provider-quota-timer] stopped"))}async function G(e,o=!1){try{let a;if(e.config.aibot.clientType==="kiro")a=await E(),e.cachedProviderQuota=a,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro";else{const t=[...e.sessionBindings.entries()].filter(([n,r])=>!!r&&e.sessionProviderHints.has(n));if(t.length>0&&await Promise.all(t.map(([n,r])=>e.refreshProviderQuotaForSession(n,r,o))),t.length===e.sessionBindings.size&&t.length>0)return;a=await e.maybeQueryProviderQuota(o)}a?.success&&e.pushProviderQuotaToBindings(a,e.sessionProviderHints.size>0)}catch{}}function J(e,o,a=!1){const t=e.providerQuotaToRateLimits(o);for(const[n,r]of e.sessionBindings.entries()){if(!r||a&&e.sessionProviderHints.has(n))continue;if((e.config.adapterType??"acp")==="deepseek-harness"){const s=e.pool.getSlot(n)?.adapter;if(s instanceof x){s.updateProviderQuotaSnapshot(o);continue}}const i={provider_quota:o};t&&(i.rate_limits=t);const d=e.cachedAcpContextWindow;d&&("usedPercentage"in d?i.context_window={usedPercentage:d.usedPercentage,remainingPercentage:100-d.usedPercentage}:i.context_window=d),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:r,meta:i})}}function X(e,o,a="standard",t=e.cachedProviderQuota,n=e.cachedProviderQuotaSampledAtMs){const r={...o??{}};if(!t?.success||(r.provider_quota||(r.provider_quota=t),r.rate_limits))return r;if(a==="codex"){const d=H(t,n??Date.now());return d&&(r.rate_limits=d.rateLimits,r.rate_limit_primary_percent=d.primaryPercent,r.rate_limit_secondary_percent=d.secondaryPercent,r.rate_limit_primary_window_min=d.primaryWindowMin,r.rate_limit_secondary_window_min=d.secondaryWindowMin),r}const i=T(t,n??Date.now());return i&&(r.rate_limits=i),r}function Z(e,o,a,t){let n=e.cachedProviderQuota,r=e.cachedProviderQuotaSampledAtMs,i=!1;if(a){const s=typeof o?.model_provider=="string"?o.model_provider:void 0,p=typeof o?.model_id=="string"?o.model_id:void 0,v=y(s)??m(s)?.id??m(p)?.id??(q(s)?"openai_codex":null);if(v||p){const c=s?.trim().toLowerCase()??"",l=c==="grix"||c.startsWith("grix-"),P={...v?{providerId:v}:{},...p?{model:p}:{},...!!s&&!l&&!v?{disabled:!0}:{}},g=e.sessionProviderHints.get(a),_=g?.providerId!==P.providerId||g?.model!==P.model||g?.disabled!==P.disabled;e.sessionProviderHints.set(a,P),e.sessionProviderMeta.set(a,{...o??{}}),_&&e.sessionProviderQuotas.delete(a),(_||!e.sessionProviderQuotas.has(a))&&t&&e.refreshProviderQuotaForSession(a,t,!1)}const f=e.sessionProviderQuotas.get(a);i=e.sessionProviderHints.has(a),i&&(n=null,r=null),f&&(n=f.quota,r=f.sampledAt)}const d=e.enrichProviderQuotaMeta(o,"standard",n,r);return i&&(d.provider_quota||(d.provider_quota=null),d.rate_limits||(d.rate_limits=null)),Object.keys(d).length>0?{meta:d}:{}}async function ee(e,o,a,t){const n=e.sessionProviderHints.get(o);if(!n)return;if(n.disabled){u.debug(e.name,`[provider-quota] session skip: session=${o} reason=hint_disabled providerId=${n.providerId??""} model=${n.model??""}`);return}const r=`${n.providerId??""}|${n.model??""}|false`;try{let i,d,s;if(n.providerId==="openai_codex"){const c=e.sessionProviderQuotas.get(o);if(!t&&c&&c.quota.success&&c.cacheKey.startsWith("openai_codex|")&&e.isRateLimitsCacheFresh(c.sampledAt))i=c.quota,d=c.sampledAt,s=c.cacheKey;else{const l=await S();i=l.quota,d=Date.now(),s=K(l.accountKey)}}else{const c=await e.resolveProviderQuotaSource(n);if(!c){u.debug(e.name,`[provider-quota] session skip: session=${o} reason=no_source providerId=${n.providerId??""} model=${n.model??""}`);return}const l=await Q.query(c,{fresh:t});i=l.quota,d=l.sampledAt,s=l.cacheKey}const p=e.sessionProviderHints.get(o);if(`${p?.providerId??""}|${p?.model??""}|${p?.disabled===!0}`!==r)return;if(u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(c=>`${c.name}=${c.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")+` session=${o}`),!i.success){const c=e.sessionProviderQuotas.get(o);(!c?.quota.success||c.cacheKey!==s)&&e.sessionProviderQuotas.delete(o);return}e.sessionProviderQuotas.set(o,{quota:i,sampledAt:d,cacheKey:s});const f=e.enrichProviderQuotaMeta(e.sessionProviderMeta.get(o),"standard",i,d);e.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:a,meta:f})}catch(i){u.warn(e.name,`[provider-quota] session query failed: session=${o} ${i instanceof Error?i.message:String(i)}`)}}function re(e,o,a,t){const n=a.trim();if(!o||!n)return;const r=t?.trim()||void 0,i=`${o}|${r??""}|${n}`,d=Date.now();e.lastModelSwitchQuotaRefresh&&e.lastModelSwitchQuotaRefresh.key===i&&d-e.lastModelSwitchQuotaRefresh.at<k||(e.lastModelSwitchQuotaRefresh={key:i,at:d},e.doRefreshQuotaAfterModelSwitch(o,n,r).catch(s=>{u.warn(e.name,`[provider-quota] model-switch refresh failed: session=${o} model=${n} ${s instanceof Error?s.message:String(s)}`)}))}async function ie(e,o,a,t){const n=e.sessionProviderHints.get(o);if(n||t){const i=t??m(a)?.id??n?.providerId,d={...i?{providerId:i}:{},model:a,...n?.disabled?{disabled:!0}:{}},s=n?.providerId!==d.providerId||n?.model!==d.model||n?.disabled!==d.disabled;e.sessionProviderHints.set(o,d),s&&e.sessionProviderQuotas.delete(o);const p=e.sessionBindings.get(o)??e.bindingStore.get(o)?.cwd??"";(s||!e.sessionProviderQuotas.has(o))&&p&&await e.refreshProviderQuotaForSession(o,p,!0);return}const r=await e.maybeQueryProviderQuota(!0,{model:a});r?.success&&e.pushProviderQuotaToBindings(r,e.sessionProviderHints.size>0)}export{V as PROVIDER_QUOTA_HOST_FIELDS,N as PROVIDER_QUOTA_HOST_METHODS,ie as doRefreshQuotaAfterModelSwitch,X as enrichProviderQuotaMeta,z as maybeQueryProviderQuota,Z as providerQuotaMetaPayload,J as pushProviderQuotaToBindings,G as refreshAndPushProviderQuota,ee as refreshProviderQuotaForSession,re as refreshQuotaAfterModelSwitch,W as resolveProviderQuotaSource,Y as startProviderQuotaTimer,j as stopProviderQuotaTimer};
@@ -0,0 +1 @@
1
+ import{queryKiroQuota as g}from"../core/provider-quota/kiro.js";import{ClaudeAdapter as f}from"../adapter/claude/index.js";import{CursorAdapter as v,fetchCursorAccountUsage as L}from"../adapter/cursor/index.js";import{getCachedAgyQuotaInfo as A,refreshAgyQuotaInfo as b}from"../adapter/agy/quota.js";import{log as s}from"../core/log/index.js";const x=["isRateLimitsCacheFresh","getFreshClaudeRateLimitState","getFreshCodexGlobalRateLimitCache","maybeQueryProviderQuota","refreshProviderQuotaForSession","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard","resolveRateLimitWakeSessionId","wakeRateLimitSlot"],y=["name","config","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","cachedAcpContextWindow","cachedClaudeRateLimitState","cachedCodexUsageSampledAtMs","cachedProviderQuota","cachedProviderQuotaSampledAtMs","cachedRateLimitsSampledAtMs"];async function R(e,c,n){const r=e.config.adapterType??"acp";if(e.config.aibot.clientType==="kiro"){const i=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs),a=e.cachedAcpContextWindow;if(i&&e.cachedProviderQuota){e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!0,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:a,tokenUsage:null,providerQuota:e.cachedProviderQuota}});return}try{const t=await g();e.cachedProviderQuota=t,e.cachedProviderQuotaSampledAtMs=Date.now(),s.info(e.name,`[rate-limits] kiro quota queried: success=${t.success}`+(t.balance?` balance=${t.balance.remaining} ${t.balance.unit}`:"")+(t.error?` error=${t.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!1,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:a,tokenUsage:null,providerQuota:t}})}catch(t){s.warn(e.name,`[rate-limits] kiro quota query failed: ${t instanceof Error?t.message:String(t)}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:a,tokenUsage:null}})}return}switch(r){case"codex":{const i=e.maybeQueryProviderQuota(),a=e.getFreshCodexGlobalRateLimitCache();if(a.hasData&&!e.isRateLimitsCacheFresh(e.cachedRateLimitsSampledAtMs)&&!e.isRateLimitsCacheFresh(e.cachedCodexUsageSampledAtMs)){const l=e.pool.getAllSlots().find(p=>p.state==="ready"&&p.adapter);if(l&&(s.info(e.name,`[rate-limits] codex cache stale, refreshing from slot: session=${l.sessionId}`),(await l.adapter.handleLocalAction?.(c))?.handled))return}if(a.hasData){a.rateLimits?s.info(e.name,`[rate-limits] codex cached: primary=${a.rateLimits.primary.usedPercent.toFixed(1)}% resetsAt=${a.rateLimits.primary.resetsAt} secondary=${a.rateLimits.secondary.usedPercent.toFixed(1)}% resetsAt=${a.rateLimits.secondary.resetsAt}`):s.info(e.name,`[rate-limits] codex cached context/token only: hasContext=${!!a.contextWindow} hasToken=${!!a.tokenUsage}`);const l=await i;e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"codex",available:a.hasData||!!l,cached:!0,sampledAt:a.sampledAt,rateLimits:a.rateLimits,contextWindow:a.contextWindow,tokenUsage:a.tokenUsage,providerQuota:l}});return}const o=e.pool.getAllSlots().find(l=>l.state==="ready"&&l.adapter);if(o&&(s.info(e.name,`[rate-limits] codex reuse existing slot: session=${o.sessionId}`),(await o.adapter.handleLocalAction?.(c))?.handled))return;const u=e.resolveRateLimitWakeSessionId(n,r);if(u){const l=await e.wakeRateLimitSlot(u,r);if(l?.adapter&&(await l.adapter.handleLocalAction?.(c))?.handled)return}const d=await i,m=!!d;s.info(e.name,`[rate-limits] codex no native data, providerQuota=${d?d.provider:"none"} available=${m}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"codex",available:m,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:d}});return}case"claude":{const i=e.maybeQueryProviderQuota(),a=e.getFreshClaudeRateLimitState();if(a){const m=a.rateLimits,l=await i;s.info(e.name,`[rate-limits] claude global cached: sampledAt=${a.sampledAt} hasRateLimits=${!!m}`+(l?` providerQuota=${l.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!0,sampledAt:a.sampledAt,rateLimits:a.rateLimits??null,contextWindow:a.contextWindow,tokenUsage:null,providerQuota:l}});return}let t=e.pool.getAllSlots().find(m=>m.state==="ready"&&m.adapter instanceof f)??null;if(!t){const m=e.resolveRateLimitWakeSessionId(n,r);m&&(t=await e.wakeRateLimitSlot(m,r))}s.info(e.name,`[rate-limits] handleGetRateLimits: session_id=${n} adapterType=claude hasSlot=${!!t} hasAdapter=${!!t?.adapter}`);const o=t?.adapter,u=o instanceof f?o.getSessionState():null,d=await i;if(u){(u.rateLimits?.fiveHour||u.rateLimits?.sevenDay||u.contextWindow?.usedPercentage!=null)&&(e.cachedClaudeRateLimitState=u);const m=e.getFreshClaudeRateLimitState(),l=m?.rateLimits&&!u.rateLimits?{...u,rateLimits:m.rateLimits}:u,p=l.rateLimits;s.info(e.name,`[rate-limits] claude global state: sampledAt=${l.sampledAt} hasRateLimits=${!!p}`+(p?` fiveHour=${p.fiveHour?.usedPercentage??"n/a"}% resetsAt=${p.fiveHour?.resetsAt??"n/a"} sevenDay=${p.sevenDay?.usedPercentage??"n/a"}% resetsAt=${p.sevenDay?.resetsAt??"n/a"}`:"")+(m?.rateLimits&&!u.rateLimits?" source=live+cached-fallback":" source=live")+(d?` providerQuota=${d.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!1,sampledAt:l.sampledAt,rateLimits:l.rateLimits??null,contextWindow:l.contextWindow,tokenUsage:null,providerQuota:d}})}else s.info(e.name,`[rate-limits] claude no global state: hasAdapter=${!!o} adapterType=${o?.constructor?.name??"n/a"}`+(d?` providerQuota=${d.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!!d,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:d}});return}case"cursor":{const a=(n?e.pool.getSlot(n):null)?.adapter;if(a instanceof v){await a.refreshAccountRateLimits({force:!0});const o=a.getRateLimitsSnapshot(n);s.info(e.name,`[rate-limits] cursor: available=${o.available} monthly=${o.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${o.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:o});return}const t=await L();s.info(e.name,`[rate-limits] cursor(no-slot): available=${t.available} monthly=${t.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${t.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`+(t.error?` error=${t.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"cursor",available:t.available,cached:!1,sampledAt:Number.isFinite(Date.parse(t.sampledAt))?Date.parse(t.sampledAt):Date.now(),rateLimits:t.rateLimits,contextWindow:null,tokenUsage:null,...t.displayMessage?{displayMessage:t.displayMessage}:{},...t.error?{error:t.error}:{}}});return}case"agy":{const i=await b(e.config.agent.command,!0).catch(()=>A(e.config.agent.command)),a=n?e.buildAgyToolbarMeta(n,i):{...e.buildAgyQuotaMeta(i)},t=n?e.bindingStore.get(n):void 0;t?.cwd&&e.sendAgyBindingCard(n,t.cwd,a),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"agy",available:!!i.rateLimits,cached:!1,sampledAt:i.sampledAt??null,rateLimits:i.rateLimits?{primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()}:null,extraLimits:i.rateLimits?.extras??[],contextWindow:null,tokenUsage:null,...i.plan!==void 0?{plan:i.plan}:{},...i.quota_exhausted!==void 0?{quota_exhausted:i.quota_exhausted}:{},...i.quota_reset_at!==void 0?{quota_reset_at:i.quota_reset_at}:{},...i.available_credits!==void 0?{available_credits:i.available_credits}:{}}});return}default:{const i=e.sessionProviderHints.get(n),a=e.sessionBindings.get(n)||e.bindingStore.get(n)?.cwd;if(i&&a&&!i.disabled){await e.refreshProviderQuotaForSession(n,a,!0);const u=e.sessionProviderQuotas.get(n),d=u?.quota??null;if(!d){s.info(e.name,`[rate-limits] no session provider quota available for adapterType=${r} session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] session provider quota queried: provider=${d.provider} success=${d.success}`+(d.tiers.length>0?` tiers=${d.tiers.map(m=>`${m.name}=${m.usedPercent}%`).join(",")}`:"")+(d.error?` error=${d.error}`:"")+` session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!0,cached:!1,sampledAt:u?.sampledAt??null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:d}});return}const t=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&!!e.cachedProviderQuota,o=await e.maybeQueryProviderQuota();if(!o){s.info(e.name,`[rate-limits] no provider quota available for adapterType=${r}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] provider quota ${t?"cached":"queried"}: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!0,cached:t,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:o}});return}}}function Q(e,c,n){const r=String(c??"").trim(),i=e.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0});return i?r&&r===i?r:n==="codex"||n==="claude"?(r&&r!==i&&s.info(e.name,`[rate-limits] ${n} remap wake session: requested=${r} use_recent=${i}`),i):r&&r!==i?(s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=not_recent_session recent=${i}`),null):r||null:(s.info(e.name,`[rate-limits] skip wake slot: adapterType=${n} reason=no_recent_binding`),null)}async function P(e,c,n){const r=String(c??"").trim();if(!r)return null;if(!e.bindingStore.get(r)?.cwd)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=binding_cwd_missing`),null;try{const a=await e.pool.getOrCreateSlot(r);if(!a)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=slot_unavailable`),null;if(a.startPromise){const t=n==="claude"?6e4:2e4;await Promise.race([a.startPromise,new Promise((o,u)=>setTimeout(()=>u(new Error(`wake rate-limits slot timeout (${t}ms)`)),t))])}return s.info(e.name,`[rate-limits] wake slot success: session=${r} adapterType=${n}`),e.pool.getSlot(r)??a}catch(a){return s.warn(e.name,`[rate-limits] wake slot failed: session=${r} adapterType=${n} err=${a instanceof Error?a.message:String(a)}`),null}}export{y as RATE_LIMITS_HOST_FIELDS,x as RATE_LIMITS_HOST_METHODS,R as handleGetRateLimits,Q as resolveRateLimitWakeSessionId,P as wakeRateLimitSlot};
@@ -0,0 +1 @@
1
+ import{homedir as w}from"node:os";import{LOCAL_ACTION_TYPES as b,SESSION_CONTROL_ERROR_CODES as g,SESSION_CONTROL_VERBS as f}from"../adapter/claude/protocol-contract.js";import{AcpAdapter as S}from"../adapter/acp/index.js";import{OpenCodeAdapter as _}from"../adapter/opencode/index.js";import{handleSessionControlCommand as p}from"./session-controller.js";import{isCliMissingError as m}from"./cli-install-offer.js";import{log as u}from"../core/log/index.js";const C=new Set(["hermes"]),E=["buildCursorToolbarMeta","buildDshOpenedToolbarMeta","buildOpenedBindingResult","captureEventRuntimeConfig","ensureImportedAgentSession","ensureSlotStarted","failSessionOpen","forceRefreshSkills","resolveCwdForBinding","resolveSessionModeId","resolveSessionModelId","sendEventResultWithCleanup","sessionControlCtx","sessionControlSenders","setResolvedAgentSessionId","bindSessionForPool","deferredCallbacks","handleSessionControlForPool","isWorkspaceFreeClient","syncOpenCodeBinding"],A=["name","config","aibotHandle","pool","bindingStore","sessionBindings","sessionScanCache","pendingEvents","deferredMgr"];async function y(e,s,d){const n=d.session_id,o=s.args.trim(),c=()=>e.aibotHandle.sendEventAck({event_id:d.event_id,session_id:n,received_at:Date.now()}),a=(i,r)=>e.aibotHandle.sendEventResult({event_id:d.event_id,status:i,...r,updated_at:Date.now()});if(!o){c(),a("failed",{msg:"Usage: /grix open <working-directory>",code:g.cwdRequired});return}try{const i=await e.resolveCwdForBinding(o),r=e.bindingStore.get(n);if(r?.cwd){let t=!1;try{const l=await e.resolveCwdForBinding(r.cwd);if(l===i){c(),e.sessionBindings.set(n,l),e.deferredMgr.sendCodexDeferredReplayComposing(n,e.deferredCallbacks()),await e.bindSessionForPool(n,l),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),a("responded",{msg:`Session already bound to ${r.cwd}`});return}}catch{t=!0,u.info("bridge",`Stale codex binding for session ${n}: ${r.cwd} no longer exists, allowing rebind`)}if(!t){c(),a("failed",{msg:`Session already bound to ${r.cwd}. Rebinding is not allowed.`,code:g.rebindForbidden});return}}e.bindingStore.set(n,i),e.sessionBindings.set(n,i),e.deferredMgr.sendCodexDeferredReplayComposing(n,e.deferredCallbacks()),await e.bindSessionForPool(n,i),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i}),c(),a("responded",{msg:`Session bound to ${i}`})}catch(i){c(),e.failSessionOpen(i,{sessionId:n,eventId:d.event_id,quotedMessageId:d.msg_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",{code:r,msg:t})})}}async function I(e,s,d){s.verb===f.open&&await e.bindSessionForPool(d.session_id,s.args.trim())}async function $(e,s){if(String(s.action_type??"")!==b.sessionControl)return;const d=s.params??{};if(String(d.verb??"").trim().toLowerCase()!==f.open)return;const o=String(d.session_id??"").trim(),c=String(d.cwd??"").trim();!o||!c||await e.bindSessionForPool(o,c)}async function H(e,s){const d=s.params??{},n=String(d.session_id??"").trim(),o=String(d.cwd??"").trim(),c=String(d.agent_session_id??"").trim(),a=(i,r,t,l)=>{e.aibotHandle.sendLocalActionResult({action_id:s.action_id,status:i,...r!==void 0?{result:r}:{},...t?{error_code:t}:{},...l?{error_msg:l}:{}})};if(!n||!o){a("failed",void 0,g.cwdRequired,"session cwd is required");return}try{const i=await e.resolveCwdForBinding(o);e.ensureImportedAgentSession(c,i);const r=e.bindingStore.get(n);if(r?.cwd){let t=!1;try{const l=await e.resolveCwdForBinding(r.cwd);if(l===i){e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,l),e.deferredMgr.sendCodexDeferredReplayComposing(n,e.deferredCallbacks()),await e.bindSessionForPool(n,l),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,l)});return}}catch{t=!0,u.info("bridge",`Stale codex binding for session ${n}: ${r.cwd} no longer exists, allowing rebind`)}if(!t){a("failed",void 0,g.rebindForbidden,`Session already bound to ${r.cwd}`);return}}e.bindingStore.set(n,i),e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,i),e.deferredMgr.sendCodexDeferredReplayComposing(n,e.deferredCallbacks()),await e.bindSessionForPool(n,i),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,i)})}catch(i){e.failSessionOpen(i,{sessionId:n,eventId:s.action_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",void 0,r,t)})}}async function M(e,s){const d=s.params??{},n=String(d.session_id??"").trim(),o=String(d.cwd??"").trim(),c=String(d.agent_session_id??"").trim(),a=(i,r,t,l)=>{e.aibotHandle.sendLocalActionResult({action_id:s.action_id,status:i,...r!==void 0?{result:r}:{},...t?{error_code:t}:{},...l?{error_msg:l}:{}})};if(!n||!o){a("failed",void 0,g.cwdRequired,"session cwd is required");return}try{const i=await e.resolveCwdForBinding(o);e.ensureImportedAgentSession(c,i);const r=e.bindingStore.get(n);if(r?.cwd){let t=!1;try{const l=await e.resolveCwdForBinding(r.cwd);if(l===i){e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,l),await e.bindSessionForPool(n,l),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:l,meta:e.buildCursorToolbarMeta(n)}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,l)});return}}catch{t=!0,u.info("bridge",`Stale cursor binding for session ${n}: ${r.cwd} no longer exists, allowing rebind`)}if(!t){a("failed",void 0,g.rebindForbidden,`Session already bound to ${r.cwd}`);return}}e.bindingStore.set(n,i),e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,i),e.deferredMgr.sendCursorDeferredReplayComposing(n,e.deferredCallbacks()),await e.bindSessionForPool(n,i),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i,meta:e.buildCursorToolbarMeta(n)}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,i)})}catch(i){e.failSessionOpen(i,{sessionId:n,eventId:s.action_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",void 0,r,t)})}}async function P(e,s,d){const n=d.session_id,o=s.args.trim(),c=()=>e.aibotHandle.sendEventAck({event_id:d.event_id,session_id:n,received_at:Date.now()}),a=(i,r)=>e.aibotHandle.sendEventResult({event_id:d.event_id,status:i,...r,updated_at:Date.now()});if(!o){c(),a("failed",{msg:"Usage: /grix open <working-directory>",code:g.cwdRequired});return}try{const i=await e.resolveCwdForBinding(o),r=e.bindingStore.get(n);if(r?.cwd){let t=!1;try{const l=await e.resolveCwdForBinding(r.cwd);if(l===i){e.sessionBindings.set(n,l),await e.ensureSlotStarted(n),c(),a("responded",{msg:`Session already bound to ${r.cwd}`}),e.aibotHandle.sendMsg({event_id:d.event_id,session_id:n,msg_type:1,content:`\u2705 Session already bound to \`${r.cwd}\``,quoted_message_id:d.msg_id});return}}catch{t=!0,u.info("bridge",`Stale pi binding for session ${n}: ${r.cwd} no longer exists, allowing rebind`)}if(!t){c(),a("failed",{msg:`Session already bound to ${r.cwd}. Rebinding is not allowed.`,code:g.rebindForbidden});return}}e.bindingStore.set(n,i),e.sessionBindings.set(n,i),await e.ensureSlotStarted(n).catch(t=>{if(m(t))throw t;u.warn("bridge",`pi ensureSlotStarted on bind failed (non-fatal): ${t instanceof Error?t.message:String(t)}`)}),await e.deferredMgr.release(n,e.deferredCallbacks()),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i}),c(),a("responded",{msg:`Session bound to ${i}`}),e.aibotHandle.sendMsg({event_id:d.event_id,session_id:n,msg_type:1,content:`\u2705 Working directory bound: \`${i}\``,quoted_message_id:d.msg_id})}catch(i){c(),e.failSessionOpen(i,{sessionId:n,eventId:d.event_id,quotedMessageId:d.msg_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",{code:r,msg:t})})}}async function D(e,s){const d=s.session_id,n=()=>e.aibotHandle.sendEventAck({event_id:s.event_id,session_id:d,received_at:Date.now()}),o=(i,r)=>e.aibotHandle.sendEventResult({event_id:s.event_id,status:i,...r,updated_at:Date.now()}),a=e.bindingStore.get(d)?.cwd??"";if(!a){n(),o("failed",{msg:"session binding was not found",code:g.bindingMissing});return}n(),await e.pool.removeSlot(d).catch(()=>{}),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"ready",cwd:a}),o("responded",{msg:`Session worker restarted for ${a}`})}async function L(e,s){const d=s.params??{},n=String(d.session_id??"").trim(),c=(n?e.bindingStore.get(n):void 0)?.cwd??"",a=(i,r,t,l)=>{e.aibotHandle.sendLocalActionResult({action_id:s.action_id,status:i,...r!==void 0?{result:r}:{},...t?{error_code:t}:{},...l?{error_msg:l}:{}})};if(!n){a("failed",void 0,"session_id_required","session_id is required for restart");return}if(!c){a("failed",void 0,g.bindingMissing,"Session binding missing. Open a workspace first.");return}await e.pool.removeSlot(n).catch(()=>{}),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:c}),a("ok",{outcome:"restarted",binding:{aibotSessionId:n,cwd:c,workerStatus:"ready"}})}async function T(e,s,d){if(!s||!d)return;try{e.resolveSessionModelId(s),e.resolveSessionModeId(s)}catch(o){u.warn(e.name,`[opencode] resolve global toolbar default failed: ${o instanceof Error?o.message:String(o)}`)}let n=e.pool.getSlot(s);n?.stopping&&(await e.pool.waitForSlotRemoval(s),n=e.pool.getSlot(s)),!n&&(e.config.adapterType??"acp")==="opencode"&&(await e.ensureSlotStarted(s),n=e.pool.getSlot(s)),n?.startPromise&&await n.startPromise,n?.adapter instanceof _&&await n.adapter.bindSession(s,d)}function q(e){const s=String(e.config.agent.clientType??e.config.aibot.clientType??"").trim().toLowerCase();return C.has(s)}async function U(e,s,d){if(!s||!e.isWorkspaceFreeClient()||e.bindingStore.get(s)?.cwd)return;let n;try{n=await e.resolveCwdForBinding(w())}catch(o){u.warn(e.name,`[${d}] default cwd unavailable, falling back to binding prompt session=${s}: ${o instanceof Error?o.message:String(o)}`);return}e.bindingStore.set(s,n),e.sessionBindings.set(s,n),u.info(e.name,`[${d}] auto-bound workspace-free client session=${s} cwd=${n}`)}async function N(e,s,d){const n=String(d??"").trim();if(!s||!n)return;const o=await e.pool.getOrCreateSlot(s);if(!o||(o.startPromise&&await o.startPromise,!o.adapter))return;const c=o.adapter instanceof S?o.adapter:null;if(!c?.hasSessionBinding)return;const a=await e.resolveCwdForBinding(n);c.announceDeferredComposing(s),await c.bindSession(s,a),e.sessionBindings.set(s,a),e.sessionScanCache.invalidate(),c.replayDeferredEvents(s),e.forceRefreshSkills(s)}function W(e){return{captureEventRuntimeConfig:s=>e.captureEventRuntimeConfig(s),deliverInboundEvent:async s=>{await e.pool.deliverInboundEvent(s)},sendEventResult:(s,d,n)=>{e.sendEventResultWithCleanup(s,d,n),e.pendingEvents.remove(s).catch(o=>{u.warn(e.name,`Failed to remove terminal deferred event from pending store event=${s}: ${o instanceof Error?o.message:String(o)}`)})},sendSessionComposing:(s,d,n)=>{const o={};d&&(o.ttl_ms=n?.ttlMs??3e4,n?.activity&&(o.activity=n.activity)),e.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:d,...o})}}}async function Y(e,s,d){const n=()=>e.aibotHandle.sendEventAck({event_id:d.event_id,session_id:d.session_id,received_at:Date.now()});try{const o=await e.resolveCwdForBinding(s.args.trim());await e.handleSessionControlForPool(s,d),await e.syncOpenCodeBinding(d.session_id,o),p(s,d,e.sessionControlCtx(d.session_id),e.sessionControlSenders(d.session_id)),await e.deferredMgr.release(d.session_id,e.deferredCallbacks())}catch(o){n(),e.failSessionOpen(o,{sessionId:d.session_id,eventId:d.event_id,quotedMessageId:d.msg_id,cwd:e.bindingStore.get(d.session_id)?.cwd||s.args.trim(),send:(c,a)=>e.aibotHandle.sendEventResult({event_id:d.event_id,status:"failed",code:c,msg:a,updated_at:Date.now()})})}}async function K(e,s,d){const n=d.session_id,o=s.args.trim(),c=()=>e.aibotHandle.sendEventAck({event_id:d.event_id,session_id:n,received_at:Date.now()}),a=(i,r)=>e.aibotHandle.sendEventResult({event_id:d.event_id,status:i,...r,updated_at:Date.now()});if(!o){c(),a("failed",{msg:"Usage: /grix open <working-directory>",code:g.cwdRequired});return}try{const i=await e.resolveCwdForBinding(o),r=e.bindingStore.get(n);if(r?.cwd){if(await e.resolveCwdForBinding(r.cwd)!==i){c(),a("failed",{msg:`Session already bound to ${r.cwd}. Rebinding is not allowed.`,code:g.rebindForbidden});return}c(),a("responded",{msg:`Session already bound to ${r.cwd}`});return}e.bindingStore.set(n,i),e.sessionBindings.set(n,i),await e.bindSessionForPool(n,i),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i}),c(),a("responded",{msg:`Session bound to ${i}`})}catch(i){c(),e.failSessionOpen(i,{sessionId:n,eventId:d.event_id,quotedMessageId:d.msg_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",{code:r,msg:t})})}}async function V(e,s){const d=s.params??{},n=String(d.session_id??"").trim(),o=String(d.cwd??"").trim(),c=String(d.agent_session_id??"").trim(),a=(i,r,t,l)=>{e.aibotHandle.sendLocalActionResult({action_id:s.action_id,status:i,...r!==void 0?{result:r}:{},...t?{error_code:t}:{},...l?{error_msg:l}:{}})};if(!n||!o){a("failed",void 0,g.cwdRequired,"session cwd is required");return}try{const i=await e.resolveCwdForBinding(o);e.ensureImportedAgentSession(c,i);const r=e.bindingStore.get(n);if(r?.cwd){const t=await e.resolveCwdForBinding(r.cwd);if(t!==i){a("failed",void 0,g.rebindForbidden,`Session already bound to ${r.cwd}`);return}e.setResolvedAgentSessionId(n,c),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,t)});return}e.bindingStore.set(n,i),e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,i),await e.bindSessionForPool(n,i),await e.deferredMgr.release(n,e.deferredCallbacks(),{announceComposing:!1}),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,i)})}catch(i){e.failSessionOpen(i,{sessionId:n,eventId:s.action_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",void 0,r,t)})}}async function j(e,s){const d=s.params??{},n=String(d.session_id??"").trim(),o=String(d.cwd??"").trim(),c=String(d.agent_session_id??"").trim(),a=(i,r,t,l)=>{e.aibotHandle.sendLocalActionResult({action_id:s.action_id,status:i,...r!==void 0?{result:r}:{},...t?{error_code:t}:{},...l?{error_msg:l}:{}})};if(!n||!o){a("failed",void 0,g.cwdRequired,"session cwd is required");return}try{const i=await e.resolveCwdForBinding(o);e.ensureImportedAgentSession(c,i);const r=e.bindingStore.get(n);if(r?.cwd){const t=await e.resolveCwdForBinding(r.cwd);if(t!==i){a("failed",void 0,g.rebindForbidden,`Session already bound to ${r.cwd}`);return}e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,t),await e.deferredMgr.release(n,e.deferredCallbacks()),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:t,meta:e.buildDshOpenedToolbarMeta(n)}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,t)});return}e.bindingStore.set(n,i),e.setResolvedAgentSessionId(n,c),e.sessionBindings.set(n,i),await e.deferredMgr.release(n,e.deferredCallbacks()),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:i,meta:e.buildDshOpenedToolbarMeta(n)}),a("ok",{outcome:"opened",binding:e.buildOpenedBindingResult(n,i)})}catch(i){e.failSessionOpen(i,{sessionId:n,eventId:s.action_id,cwd:e.bindingStore.get(n)?.cwd||o,send:(r,t)=>a("failed",void 0,r,t)})}}export{A as SESSION_CONTROL_OPEN_HOST_FIELDS,E as SESSION_CONTROL_OPEN_HOST_METHODS,N as bindSessionForPool,W as deferredCallbacks,U as ensureDefaultBindingForWorkspaceFreeClient,V as handleCodeWhaleSessionControlLocalActionOpen,K as handleCodeWhaleSessionControlOpen,H as handleCodexSessionControlLocalActionOpen,y as handleCodexSessionControlOpen,M as handleCursorSessionControlLocalActionOpen,j as handleDeepSeekSessionControlLocalActionOpen,Y as handleOpenHumanSessionControlOpen,P as handlePiSessionControlOpen,D as handlePiSessionControlRestart,L as handlePiSessionControlRestartLocalAction,I as handleSessionControlForPool,$ as handleSessionControlLocalActionForPool,q as isWorkspaceFreeClient,T as syncOpenCodeBinding};
@@ -0,0 +1,3 @@
1
+ import{LOCAL_ACTION_ERROR_CODES as C,LOCAL_ACTION_TYPES as w,SESSION_CONTROL_ERROR_CODES as u,SESSION_CONTROL_VERBS as l,SESSION_MODE_IDS as b}from"../adapter/claude/protocol-contract.js";import{fetchAvailableModels as I,getCachedModels as v}from"../adapter/claude/model-list.js";import{normalizeClaudeEffort as M,CLAUDE_EFFORT_LEVELS as _}from"../core/config/claude-direct-env.js";import{log as p}from"../core/log/index.js";const R=["buildClaudeToolbarMeta","buildOpenedBindingResult","currentClaudeModeId","deferredCallbacks","ensureImportedAgentSession","ensureSlotStarted","failSessionOpen","getClaudeWorkerStatus","normalizeClaudeModeId","refreshClaudeWorkerStatusCard","refreshQuotaAfterModelSwitch","resolveClaudeSessionEffort","resolveCwdForBinding","setResolvedAgentSessionId"],A=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","sessionBindings","claudeWorkerStatus","deferredMgr"];async function x(e,c,g){const d=g.session_id,r=(i,s,t)=>{e.aibotHandle.sendEventResult({event_id:g.event_id,status:i,...s?{msg:s}:{},...t?{code:t}:{},updated_at:Date.now()})};e.aibotHandle.sendEventAck({event_id:g.event_id,session_id:d,received_at:Date.now()});try{switch(c.verb){case l.open:{await I().catch(()=>{});const i=c.args.trim();if(!i){r("failed","Usage: /grix open <working-directory>",u.cwdRequired);return}let s="";try{s=await e.resolveCwdForBinding(i)}catch(n){r("failed",n instanceof Error?n.message:String(n),u.invalidCwd);return}const t=e.bindingStore.get(d);if(t?.cwd){const n=await e.resolveCwdForBinding(t.cwd);if(n!==s){r("failed","session binding cannot be changed to another working directory",u.rebindForbidden);return}e.bindingStore.ensureModeId(d,b.fullAuto),e.sessionBindings.set(d,n),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,n),r("responded",`Working directory already bound: ${n}`);return}e.bindingStore.set(d,s,{modeId:b.fullAuto}),e.sessionBindings.set(d,s),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,s),r("responded",`Session bound to ${s}`);return}case l.where:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}r("responded",`Working directory: ${i.cwd}`);return}case l.status:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}const s=e.currentClaudeModeId(d),t=e.getClaudeWorkerStatus(d);r("responded",`Status: worker=${t} mode=${s} cwd=${i.cwd}`);return}case l.stop:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),e.claudeWorkerStatus.set(d,"stopped"),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd}),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd,meta:e.buildClaudeToolbarMeta(d)}),r("responded",`Session worker stopped for ${i.cwd}`);return}case l.restart:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,i.cwd),r("responded",`Session worker restarted for ${i.cwd}`);return}case l.setMode:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_mode <mode-id>",C.modeInvalid);return}const s=e.normalizeClaudeModeId(i);if(s!==i.toLowerCase()){r("failed","set mode_id is invalid",C.modeInvalid);return}const t=e.bindingStore.get(d);if(!t?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if(e.currentClaudeModeId(d)===s){r("responded",`Mode unchanged: ${s}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F",u.workerBusy);return}e.bindingStore.setModeId(d,s),e.globalConfigStore?.set(e.name,{modeId:s}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,t.cwd),r("responded",`Mode set to ${s}`);return}case l.setModel:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_model <model-id>");return}const s=e.bindingStore.get(d);if(!s?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if((s.modelId??"")===i){r("responded",`Model unchanged: ${i}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B",u.workerBusy);return}e.bindingStore.setModelId(d,i),e.globalConfigStore?.set(e.name,{modelId:i}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,s.cwd),e.refreshQuotaAfterModelSwitch(d,i),r("responded",`Model set to ${i}`);return}case l.listOptions:{const i=v(),s=e.bindingStore.get(d),t=i.map(a=>a.id).join(", "),n=`${b.fullAuto}, ${b.approval}`,o=e.resolveClaudeSessionEffort(d)??"auto";r("responded",`Modes (current: ${e.currentClaudeModeId(d)}): ${n}
2
+ Models (current: ${s?.modelId??"default"}): ${t}
3
+ Effort (current: ${o}): ${_.join(", ")}`);return}case l.exec:{const[i,...s]=c.args.trim().split(/\s+/);if(!i){r("failed","Usage: /grix exec <command> [args]",u.verbInvalid);return}const n=e.pool.getSlot(d)?.adapter;if(!n?.execCommand){r("failed","Agent does not support command execution",u.verbInvalid);return}const o=n.getSupportedCommands?.()??[];if(!o.some(a=>a.name===i)){r("failed",`Unknown command: ${i}. Supported: ${o.map(a=>a.name).join(", ")}`,u.verbInvalid);return}try{const a=await n.execCommand(i,s.join(" "),d);r(a.status==="ok"?"responded":"failed",a.message??`${i} ${a.status}`,a.status==="ok"?void 0:u.runtimeError)}catch(a){r("failed",`exec error: ${a instanceof Error?a.message:a}`,u.runtimeError)}return}default:r("failed",`Unsupported command for Claude: /grix ${c.verb}`,u.verbInvalid)}}catch(i){if(c.verb===l.open){const{code:s,msg:t}=e.failSessionOpen(i,{sessionId:d,eventId:g.event_id,quotedMessageId:g.msg_id,cwd:e.bindingStore.get(d)?.cwd||c.args.trim()});r("failed",t,s)}else r("failed",i instanceof Error?i.message:String(i),u.runtimeError)}}async function W(e,c){const g=String(c.action_type??"").trim();if(g!==w.sessionControl&&g!==w.setMode&&g!=="set_mode"&&g!==w.setModel&&g!=="set_model"&&g!==w.setReasoningEffort&&g!=="set_effort")return!1;const d=c.params??{},r=String(d.session_id??"").trim(),i=g===w.setMode?l.setMode:g===w.setModel?l.setModel:g===w.setReasoningEffort||g==="set_effort"?w.setReasoningEffort:String(d.verb??"").trim().toLowerCase();if(p.info(e.name,`handleSessionControlLocalAction verb=${i} action_id=${c.action_id} session_id=${r}`),!r)return e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:C.localActionRouteMissing,error_msg:"local action session_id is required"}),!0;const s=n=>{e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:n},r)},t=(n,o)=>{p.warn(e.name,`session_control local_action failed action_id=${c.action_id} session_id=${r} verb=${i} code=${n} msg=${o}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:n,error_msg:o})};try{switch(i){case l.open:{await I().catch(()=>{});const n=String(d.cwd??"").trim(),o=String(d.agent_session_id??"").trim();if(!n)return t(u.cwdRequired,"session control cwd is required"),!0;p.info(e.name,`handleSessionControlLocalAction open cwd=${n} session_id=${r}`);const a=await e.resolveCwdForBinding(n);e.ensureImportedAgentSession(o,a);const f=e.bindingStore.get(r);if(f?.cwd){const S=await e.resolveCwdForBinding(f.cwd);return S!==a?(t(u.rebindForbidden,"session binding cannot be changed to another working directory"),!0):(e.bindingStore.ensureModeId(r,b.fullAuto),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,S),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,S),s({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,S),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0)}return e.bindingStore.set(r,a,{modeId:b.fullAuto}),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,a),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,a),s({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,a),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0}case l.status:case l.where:{const n=e.bindingStore.get(r);return n?.cwd?(s({outcome:i,binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:e.getClaudeWorkerStatus(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.stop:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),s({outcome:"stopped",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:"stopped"}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.restart:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,n.cwd),s({outcome:"restarted",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case w.setReasoningEffort:{const n=[d.effort,d.reasoning_effort,d.reasoning_eff,d.value].map(S=>String(S??"").trim()).find(Boolean)??"",o=M(n);if(!n||!o)return t(C.effortInvalid,`effort is invalid; expected one of ${_.join(", ")}`),!0;const a=e.bindingStore.get(r);if(!a?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.bindingStore.getEffort(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362 effort"),!0;e.bindingStore.setEffort(r,o),await e.pool.removeSlot(r),await e.ensureSlotStarted(r)}return e.globalConfigStore?.set(e.name,{effort:o}),e.refreshClaudeWorkerStatusCard(r,a.cwd),s({outcome:"effort_set",effort:o,reasoning_effort:o,available_efforts:[..._],binding:{cwd:a.cwd,effort:o}}),!0}case l.setMode:{const n=String(d.mode_id??d.modeId??"").trim();if(!n)return t(C.modeInvalid,"set mode_id is invalid"),!0;const o=e.normalizeClaudeModeId(n);if(o!==n.toLowerCase())return t(C.modeInvalid,"set mode_id is invalid"),!0;const a=e.bindingStore.get(r);if(!a?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.currentClaudeModeId(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F"),!0;e.bindingStore.setModeId(r,o),e.globalConfigStore?.set(e.name,{modeId:o}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,a.cwd)}return s({outcome:"mode_set",mode_id:o,binding:{cwd:a.cwd,mode_id:o}}),!0}case l.setModel:{const n=String(d.model_id??d.modelId??"").trim();if(!n)return t("set_model_invalid","model_id is required"),!0;const o=e.bindingStore.get(r);if(!o?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if((o.modelId??"")!==n){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B"),!0;e.bindingStore.setModelId(r,n),e.globalConfigStore?.set(e.name,{modelId:n}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,o.cwd),e.refreshQuotaAfterModelSwitch(r,n)}return s({outcome:"model_set",model_id:n,binding:{cwd:o.cwd,model_id:n}}),!0}case l.listOptions:{const n=v(),o=e.pool.getSlot(r),a=e.resolveClaudeSessionEffort(r)??"auto";return s({modes:[b.fullAuto,b.approval],currentModeId:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId),models:n.map(f=>({modelId:f.id,name:f.displayName})),currentModelId:e.bindingStore.get(r)?.modelId??"",available_models:n.map(f=>({id:f.id,displayName:f.displayName})),available_efforts:[..._],effort:a,reasoning_effort:a,agent_commands:o?.adapter?.getSupportedCommands?.()??[]}),!0}case l.exec:{const[n,...o]=String(d.args??"").trim().split(/\s+/);if(!n)return t(u.verbInvalid,"Usage: exec <command> [args]"),!0;await e.ensureSlotStarted(r);const f=e.pool.getSlot(r)?.adapter;if(!f?.execCommand)return t(u.verbInvalid,"Agent does not support command execution"),!0;const S=f.getSupportedCommands?.()??[];if(!S.some(m=>m.name===n))return t(u.verbInvalid,`Unknown command: ${n}. Supported: ${S.map(m=>m.name).join(", ")}`),!0;try{const m=await f.execCommand(n,o.join(" "),r);m.status==="ok"?s({outcome:"exec",command:n,message:m.message,data:m.data}):t(u.runtimeError,m.message??`${n} failed`)}catch(m){t(u.runtimeError,`exec error: ${m instanceof Error?m.message:m}`)}return!0}default:return t(u.verbInvalid,`session control verb ${i} is not supported`),!0}}catch(n){if(i===l.open){const{code:o,msg:a}=e.failSessionOpen(n,{sessionId:r,eventId:c.action_id,cwd:e.bindingStore.get(r)?.cwd||String(d.cwd??"").trim()});p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${a}`),t(o,a)}else{const o=n instanceof Error?n.message:String(n);p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${o}`),t(u.runtimeError,o)}return!0}}export{A as SESSION_CONTROL_ROUTER_HOST_FIELDS,R as SESSION_CONTROL_ROUTER_HOST_METHODS,x as routeSessionControlCommand,W as routeSessionControlLocalAction};
@@ -0,0 +1,3 @@
1
+ import{SESSION_CONTROL_ERROR_CODES as _}from"../adapter/claude/protocol-contract.js";import{getSessionHistoryReader as b,SessionHistoryError as A,SESSION_HISTORY_ERROR_CODES as g}from"../adapter/shared/session-history.js";import{DshJsonRpcAdapter as I}from"../adapter/deepseek-harness/index.js";import{log as f}from"../core/log/index.js";const m=["discardEventTrackingState","resolveAgentSessionId","resolveOrphanTitle","unbindSession"],y=["name","config","aibotHandle","pool","bindingStore","sessionBindings","sessionScanCache","deferredMgr","claudeWorkerStatus","sessionProviderHints","sessionProviderQuotas","sessionProviderMeta"];async function k(n,o){const d=n.pool.getSlot(o)?.adapter;n.bindingStore.delete(o),n.sessionBindings.delete(o),n.sessionProviderHints.delete(o),n.sessionProviderQuotas.delete(o),n.sessionProviderMeta.delete(o),n.claudeWorkerStatus.delete(o),n.deferredMgr.clearSession(o);for(const u of n.pool.drainQueuedForSession(o))n.discardEventTrackingState(u.event_id);const S=n.pool.removeSlot(o).catch(u=>{f.warn(n.name,`failed to remove adapter slot on unbind: ${u instanceof Error?u.message:String(u)}`)});d instanceof I&&await d.destroySession(o).catch(u=>{f.warn(n.name,`failed to delete DeepSeek Harness session state: ${u instanceof Error?u.message:String(u)}`)}),await S,n.aibotHandle.clearBindingCardMetaCache?.(o),n.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"stopped"})}async function T(n,o){if(n.aibotHandle.sendEventAck({event_id:o.event_id,session_id:o.session_id,received_at:Date.now()}),!n.bindingStore.get(o.session_id)?.cwd){n.aibotHandle.sendEventResult({event_id:o.event_id,status:"failed",code:_.bindingMissing,msg:"No session binding found for this session",updated_at:Date.now()});return}await n.unbindSession(o.session_id),n.aibotHandle.sendEventResult({event_id:o.event_id,status:"responded",msg:"Session unbound",updated_at:Date.now()})}async function C(n,o){const d=String((o.params??{}).session_id??"");if(!n.bindingStore.get(d)?.cwd){n.aibotHandle.sendLocalActionResult({action_id:o.action_id,status:"failed",error_code:_.bindingMissing,error_msg:"No session binding found for this session"});return}await n.unbindSession(d),n.aibotHandle.sendLocalActionResult({action_id:o.action_id,status:"ok",result:{outcome:"unbound",sessionId:d}})}async function D(n,o){n.aibotHandle.sendEventAck({event_id:o.event_id,session_id:o.session_id,received_at:Date.now()});const d=n.config.adapterType??"acp",S=new Map;for(const i of n.pool.getAllSlots())S.set(i.sessionId,i);const u=Array.from(n.bindingStore.entries()),p=new Map;for(const[i,e]of u){const s=n.resolveAgentSessionId(e);if(s){const a=S.get(i),r=a?a.adapter.getStatus().busy?"busy":"ready":"inactive";p.set(s,{aibotSessionId:i,workerStatus:r})}}const t=[],c=new Set;if(d==="codex"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.threadId);const s=p.get(e.threadId);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.threadId}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??(e.archived?"archived":"inactive")}`),t.push(` Created: ${new Date(e.createdAt).toISOString()}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}else if(d==="claude"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.sessionId}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??"inactive"}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}else if(d==="acp"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.sessionId}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??"inactive"}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}else if(d==="deepseek-harness"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.sessionId}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??"inactive"}`),e.createdAt&&t.push(` Created: ${new Date(e.createdAt).toISOString()}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}else if(d==="pi"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionPath);const s=p.get(e.sessionPath);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.sessionPath}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??"inactive"}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}else if(d==="codewhale"||d==="opencode"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId);e.title&&t.push(` Title: ${e.title}`),t.push(` Agent: ${e.sessionId}`),s&&t.push(` AIBot: ${s.aibotSessionId}`),t.push(` CWD: ${e.cwd||"-"}`),t.push(` State: ${s?.workerStatus??"inactive"}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}}for(const[i,e]of u){const s=n.resolveAgentSessionId(e);if(s&&c.has(s))continue;const a=S.get(i),r=a?a.adapter.getStatus().busy?"busy":"ready":"closed",l=n.resolveOrphanTitle(s)??(s?s.slice(0,8)+"\u2026":i.slice(0,8)+"\u2026");t.push(` Title: ${l}`),t.push(` AIBot: ${i}`),s&&t.push(` Agent: ${s}`),t.push(` CWD: ${e.cwd??"-"}`),t.push(` State: ${r}`),t.push(` Updated: ${new Date(e.updatedAt).toISOString()}`),t.push("---")}if(t.length===0){n.aibotHandle.sendEventResult({event_id:o.event_id,status:"responded",msg:"No sessions found.",updated_at:Date.now()});return}n.aibotHandle.sendEventResult({event_id:o.event_id,status:"responded",msg:`Sessions (${t.filter(i=>i==="---").length}):
2
+ ${t.join(`
3
+ `)}`,updated_at:Date.now()})}async function O(n,o){const d=n.config.adapterType??"acp",S=new Map;for(const i of n.pool.getAllSlots())S.set(i.sessionId,i);const u=Array.from(n.bindingStore.entries()),p=new Map;for(const[i,e]of u){const s=n.resolveAgentSessionId(e);if(s){const a=S.get(i),r=a?a.adapter.getStatus().busy?"busy":"ready":"inactive";p.set(s,{aibotSessionId:i,workerStatus:r,bindingUpdatedAt:e.updatedAt??0})}}const t=[],c=new Set;if(d==="codex"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.threadId);const s=p.get(e.threadId),a={agentSessionId:e.threadId,cwd:e.cwd||null,workerStatus:s?.workerStatus??(e.archived?"archived":"inactive"),createdAt:e.createdAt,updatedAt:e.updatedAt,archived:e.archived};s&&(a.aibotSessionId=s.aibotSessionId),e.title&&(a.title=e.title),t.push(a)}}else if(d==="claude"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId),a={agentSessionId:e.sessionId,cwd:e.cwd||null,workerStatus:s?.workerStatus??"inactive",updatedAt:e.updatedAt};s&&(a.aibotSessionId=s.aibotSessionId),e.title&&(a.title=e.title),t.push(a)}}else if(d==="acp"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId),a=s&&s.bindingUpdatedAt>0?s.bindingUpdatedAt:e.updatedAt,r={agentSessionId:e.sessionId,cwd:e.cwd||null,agentType:e.agentType,workerStatus:s?.workerStatus??"inactive",updatedAt:a};s&&(r.aibotSessionId=s.aibotSessionId),e.title&&(r.title=e.title),e.createdAt&&(r.createdAt=e.createdAt),t.push(r)}}else if(d==="deepseek-harness"){const i=n.sessionScanCache.get();for(const e of i){c.add(e.sessionId);const s=p.get(e.sessionId),a=s&&s.bindingUpdatedAt>0?s.bindingUpdatedAt:e.updatedAt,r={agentSessionId:e.sessionId,cwd:e.cwd||null,workerStatus:s?.workerStatus??"inactive",updatedAt:a};s&&(r.aibotSessionId=s.aibotSessionId),e.title&&(r.title=e.title),e.createdAt&&(r.createdAt=e.createdAt),t.push(r)}}else if(d==="pi"||d==="codewhale"||d==="opencode"){const i=n.sessionScanCache.get();for(const e of i){const s="sessionPath"in e?e.sessionPath:e.sessionId;c.add(s);const a=p.get(s),r={agentSessionId:s,cwd:e.cwd||null,workerStatus:a?.workerStatus??("archived"in e&&e.archived?"archived":"inactive"),updatedAt:a&&a.bindingUpdatedAt>0?a.bindingUpdatedAt:e.updatedAt};a&&(r.aibotSessionId=a.aibotSessionId),e.title&&(r.title=e.title),e.createdAt&&(r.createdAt=e.createdAt),"archived"in e&&(r.archived=e.archived),t.push(r)}}for(const[i,e]of u){const s=n.resolveAgentSessionId(e);if(s&&c.has(s))continue;const a=S.get(i),r=a?a.adapter.getStatus().busy?"busy":"ready":"closed",l={aibotSessionId:i,cwd:e.cwd??null,workerStatus:r,updatedAt:e.updatedAt,title:n.resolveOrphanTitle(s)??(s?`${s.slice(0,8)}\u2026`:`${i.slice(0,8)}\u2026`)};s&&(l.agentSessionId=s),t.push(l)}t.sort((i,e)=>e.updatedAt-i.updatedAt),n.aibotHandle.sendLocalActionResult({action_id:o.action_id,status:"ok",result:{outcome:"sessions_listed",sessions:t,total:t.length}})}async function H(n,o){const d=o.params??{},S=String(d.provider_key??n.config.adapterType??"acp").trim().toLowerCase(),u=String(d.agent_session_id??"").trim(),p=String(d.cwd??"").trim(),t=typeof d.sync_run_id=="string"&&d.sync_run_id?d.sync_run_id:void 0,c=(e,s)=>{f.warn(n.name,`sync_history failed action_id=${o.action_id} provider=${S} code=${e} msg=${s}`),n.aibotHandle.sendLocalActionResult({action_id:o.action_id,status:"failed",error_code:e,error_msg:s})};if(!u){c(g.agentSessionRequired,"agent_session_id is required for sync_history");return}if(!p){c(g.cwdRequired,"cwd is required for sync_history");return}const i=b(S);if(!i){c(g.providerUnsupported,`provider ${S} does not support sync_history`);return}try{const e=await i({session_id:String(d.session_id??""),provider_key:S,agent_session_id:u,cwd:p,cursor:typeof d.cursor=="string"&&d.cursor?d.cursor:void 0,limit:typeof d.limit=="number"?d.limit:void 0,sync_run_id:t});f.debug(n.name,`sync_history ok action_id=${o.action_id} provider=${S} agent_session_id=${u} messages=${e.messages.length} has_more=${e.has_more}`),n.aibotHandle.sendLocalActionResult({action_id:o.action_id,status:"ok",result:{outcome:"history_synced",messages:e.messages,has_more:e.has_more,next_cursor:e.next_cursor,...t?{sync_run_id:t}:{}}})}catch(e){e instanceof A?c(e.code,e.message):c(g.runtimeError,String(e))}}export{y as SESSION_LIST_HOST_FIELDS,m as SESSION_LIST_HOST_METHODS,O as handleListSessionsLocalAction,D as handleListSessionsTextCommand,H as handleSyncHistoryLocalAction,C as handleUnbindLocalAction,T as handleUnbindTextCommand,k as unbindSession};
@@ -0,0 +1 @@
1
+ import{SESSION_CONTROL_ERROR_CODES as m}from"../adapter/claude/protocol-contract.js";import{parseClaudeSessionUsage as f}from"../adapter/claude/usage-parser.js";import{parseCodexSessionUsage as p}from"../adapter/codex/usage-parser.js";import{parseAcpSessionUsage as b}from"../adapter/acp/usage-parser.js";import{parsePiSessionUsage as S}from"../adapter/pi/usage-parser.js";import{CursorAdapter as A}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as R}from"../adapter/codewhale/index.js";import{log as d}from"../core/log/index.js";const x=["ensureSlotStarted"],N=["name","config","aibotHandle","pool","bindingStore"];async function O(e,t,n){if(!n){d.warn(e.name,`[usage] get_session_usage rejected: no session_id in params, action_id=${t.action_id}`),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for get_session_usage"});return}const l=e.config.adapterType??"acp",r=e.bindingStore.get(n),c=r?.cwd??e.config.agent.cwd??process.cwd();d.info(e.name,`[usage] get_session_usage action_id=${t.action_id} session_id=${n} adapterType=${l} hasBinding=${!!r} cwd=${c}`);let i=null,a,s;switch(l){case"claude":{if(a=r?.claudeSessionId,!a){d.warn(e.name,`[usage] no claude binding for session_id=${n}, action_id=${t.action_id}`),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No Claude session binding found"});return}d.info(e.name,`[usage] parsing claude usage: claudeSessionId=${a} cwd=${c}`),i=await f(a,c),s="claude";break}case"agy":{e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:"agy print-mode adapter does not track token usage"});return}case"opencode":{e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:"opencode session usage parsing is not implemented"});return}case"openhuman":{e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:"openhuman is deprecated; session usage is not tracked"});return}case"acp":default:{if(a=r?.acpSessionId,!a){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No ACP session binding found"});return}i=await b(a,c,e.config.aibot.clientType),s=l,(!s||s==="acp")&&(s="acp");break}case"codex":{if(a=r?.codexThreadId,!a){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No Codex thread binding found"});return}i=await p(a),s="codex";break}case"pi":{if(a=r?.piSessionPath,!a){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No Pi session path binding found"});return}i=await S(a),s="pi";break}case"cursor":{const u=e.pool.getSlot(n)?.adapter;if(!(u instanceof A)){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No Cursor session found"});return}const o=u.getUsageSnapshot(n);if(!o){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:"No usage data found for this session"});return}const _={inputTokens:o.total.input,outputTokens:o.total.output,cacheReadInputTokens:o.total.cacheRead,cacheCreationInputTokens:o.total.cacheWrite};e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{sessionId:n,adapterType:"cursor",models:[{model:e.bindingStore.get(n)?.modelId??"auto",turns:o.turns,total:_}],total:_,turns:o.turns,sampledAt:o.sampledAt}});return}case"codewhale":{const u=e.pool.getSlot(n)?.adapter;if(!(u instanceof R)){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"no_binding",error_msg:"No CodeWhale session found"});return}const o=u.getUsageSnapshot();if(!o){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:"No usage data found for this session"});return}const _={inputTokens:o.total.input,outputTokens:o.total.output,cacheReadInputTokens:0,cacheCreationInputTokens:0};e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{sessionId:n,adapterType:"codewhale",models:[{model:e.bindingStore.get(n)?.modelId??"codewhale",turns:o.turns,total:_}],total:_,turns:o.turns,sampledAt:o.sampledAt}});return}}if(!i){d.info(e.name,`[usage] no usage data found: session_id=${n} adapterSessionId=${a} adapterType=${s}`);const g=String(e.config.aibot.clientType??"").trim().toLowerCase(),o=l==="acp"&&new Set(["hermes","reasonix","kimi","copilot"]).has(g)?`${g} session usage parsing is not available`:"No usage data found for this session";e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"usage_not_found",error_msg:o});return}d.info(e.name,`[usage] result ok: session_id=${n} adapterSessionId=${a} turns=${i.turns} models=${i.models.length}`),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{sessionId:a,adapterType:s,models:i.models,total:i.total,turns:i.turns,sampledAt:new Date().toISOString()}})}async function U(e,t,n){if(!n){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for thread_compact"});return}if(!e.bindingStore.get(n)?.cwd){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:m.bindingMissing,error_msg:"session binding was not found"});return}try{await e.ensureSlotStarted(n);const c=e.pool.getSlot(n)?.adapter;if(!c?.execCommand){e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:m.runtimeError,error_msg:"Agent does not support command execution"});return}d.info(e.name,`thread_compact session_id=${n} action_id=${t.action_id}`);const i=await c.execCommand("compact","",n);i.status==="ok"?e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"ok",result:{outcome:"compacted",message:i.message,data:i.data}}):e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:m.runtimeError,error_msg:i.message??"compact failed"})}catch(r){d.warn(e.name,`thread_compact error session_id=${n}: ${r instanceof Error?r.message:r}`),e.aibotHandle.sendLocalActionResult({action_id:t.action_id,status:"failed",error_code:m.runtimeError,error_msg:r instanceof Error?r.message:String(r)})}}export{N as SESSION_USAGE_HOST_FIELDS,x as SESSION_USAGE_HOST_METHODS,O as handleGetSessionUsage,U as handleThreadCompact};
@@ -0,0 +1 @@
1
+ import{homedir as S}from"node:os";import{buildReportedSkills as _}from"../default-skills/index.js";import{buildWireSkills as b}from"../core/skill-sync/sync-state.js";import{uploadSkill as L}from"../core/skill-sync/skill-upload.js";import{deleteLocalSkill as R}from"../core/skill-sync/skill-delete.js";import{buildLibrarySkills as E}from"../core/skill-sync/library-skills.js";import{enableSkill as y,disableSkill as w,SkillEnableError as g}from"../core/skill-sync/skill-enable.js";import{resolveSkillScanMode as m}from"../adapter/claude/skill-scanner.js";import{resolveHermesHomeDir as H}from"../adapter/shared/native-provider-config.js";import{buildProviderEnv as I}from"../core/config/provider-env.js";import{log as p,GRIX_PATHS as f}from"../core/log/index.js";function k(e,i){return JSON.stringify({skills:e,library_skills:i})}const B=["computeSkillReport","buildLibrarySkillsReport","skillLookupEnv","forceRefreshSkills"],F=["name","config","aibotHandle","bindingStore","sessionBindings","lastReportedSkillsHash","lastReportedSkillsWireHash","providerResolver"];async function W(e,i){const n=i.params??{},r=String(n.name??"").trim(),t=String(n.session_id??"").trim();if(!r){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"MISSING_SKILL_NAME",error_msg:"name is required"});return}const l=m(e.config.adapterType,e.config.aibot.clientType),a=e.bindingStore.get(t)?.cwd||e.sessionBindings.get(t)||void 0;try{const o=await R(r,{mode:l,projectDir:a});e.forceRefreshSkills(t||void 0,{force:!0})||p.warn(e.name,`skill_delete refresh push failed name=${o.name}; toolbar may keep a stale entry until next scan`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{name:o.name,path:o.path}}),p.info(e.name,`skill_delete name=${o.name} path=${o.path}`)}catch(o){p.warn(e.name,`skill_delete failed name=${r}: ${o instanceof Error?o.message:String(o)}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"SKILL_DELETE_FAILED",error_msg:o instanceof Error?o.message:String(o)})}}async function U(e,i){const n=i.params??{},r=String(n.name??"").trim(),t=String(n.session_id??"").trim();if(!r){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"MISSING_SKILL_NAME",error_msg:"name is required"});return}const l=m(e.config.adapterType,e.config.aibot.clientType),a=e.bindingStore.get(t)?.cwd||e.sessionBindings.get(t)||void 0,o=l==="kiro"?a:a||process.cwd();try{await L(r,{mode:l,projectDir:o},{apiKey:e.config.aibot.apiKey,wsUrl:e.config.aibot.url}),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{name:r}})}catch(d){p.warn(e.name,`skill_upload failed name=${r}: ${d instanceof Error?d.message:String(d)}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"SKILL_UPLOAD_FAILED",error_msg:d instanceof Error?d.message:String(d)})}}async function h(e,i){const n=i.params??{},r=String(n.name??"").trim(),t=String(n.session_id??"").trim(),l=String(n.scope??"").trim(),a=String(n.actor_id??"").trim(),o=n.force==="replace_link"||n.force==="replace_with_link"?n.force:void 0,d=m(e.config.adapterType,e.config.aibot.clientType),c=e.bindingStore.get(t)?.cwd||e.sessionBindings.get(t)||void 0;try{const s=await y({skillsDir:f.skills,mode:d,home:S(),cwd:c,env:e.skillLookupEnv()},{name:r,scope:l,actorId:a,force:o});p.info(e.name,`skill_enable name=${r} scope=${l} actor=${a||"-"} changed=${s.changed}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{name:s.name,scope:s.scope,path:s.path,changed:s.changed,enable_state:s.status,uninstallable:!0,...s.hermes_trust?{hermes_trust:s.hermes_trust}:{}}})}catch(s){const u=s instanceof g?s.code:"SKILL_ENABLE_FAILED";p.warn(e.name,`skill_enable failed name=${r} scope=${l}: ${s instanceof Error?s.message:String(s)}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:u,error_msg:s instanceof Error?s.message:String(s),result:{conflict_kind:u==="CONFLICT"||u==="NEEDS_FORCE"||u==="BLOCKED"?u.toLowerCase():void 0}})}e.forceRefreshSkills()}function q(e,i){const n=i.params??{},r=String(n.session_id??"").trim();if(e.forceRefreshSkills(r||void 0,{force:!0})){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{session_id:r||void 0}});return}p.warn(e.name,`skill_refresh produced no report session=${r||"-"}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"SKILL_REFRESH_FAILED",error_msg:"skill rescan produced no report (scan error or empty skill set)"})}async function P(e,i){const n=i.params??{},r=String(n.name??"").trim(),t=String(n.session_id??"").trim(),l=String(n.scope??"").trim(),a=String(n.actor_id??"").trim(),o=m(e.config.adapterType,e.config.aibot.clientType),d=e.bindingStore.get(t)?.cwd||e.sessionBindings.get(t)||void 0;try{const c=await w({skillsDir:f.skills,mode:o,home:S(),cwd:d,env:e.skillLookupEnv()},{name:r,scope:l,actorId:a});p.info(e.name,`skill_disable name=${r} scope=${l} actor=${a||"-"} removed=${c.removed}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{name:c.name,scope:c.scope,path:c.path,removed:c.removed,enable_state:"none",uninstallable:!1}})}catch(c){const s=c instanceof g?c.code:"SKILL_DISABLE_FAILED";p.warn(e.name,`skill_disable failed name=${r} scope=${l}: ${c instanceof Error?c.message:String(c)}`),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:s,error_msg:c instanceof Error?c.message:String(c),result:{conflict_kind:s==="CONFLICT"||s==="BLOCKED"?s.toLowerCase():void 0}})}e.forceRefreshSkills()}function G(e,i){const n=m(e.config.adapterType,e.config.aibot.clientType),r=n==="kiro"?i:i||process.cwd();let t;try{t=_({mode:n,projectDir:r,env:e.skillLookupEnv()})}catch{return null}if(t.length===0)return null;const l=JSON.stringify(t.map(a=>`${a.source}:${a.name}`));return{skills:b(t,f.skills),hash:l}}function j(e,i){const n=e.bindingStore.get(i)?.cwd||e.sessionBindings.get(i)||void 0,r=e.computeSkillReport(n);if(!r)return;const t=e.buildLibrarySkillsReport(n),l=k(r.skills,t);if(!(r.hash===e.lastReportedSkillsHash&&l===e.lastReportedSkillsWireHash)){e.lastReportedSkillsHash=r.hash,e.lastReportedSkillsWireHash=l;try{e.aibotHandle.sendSkillsUpdate({skills:r.skills,library_skills:t})}catch{}}}function J(e){const i=String(e.config.aibot.clientType??"").trim().toLowerCase()||"unknown",n=String(e.config.aibot.sharedOwnerId??"").trim();return n?`shared:${n}:${i}`:`primary:${i}`}function X(e,i,n){const r=i?.trim(),t=r||e.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),l=r?e.bindingStore.get(r)?.cwd||e.sessionBindings.get(r)||void 0:t?e.bindingStore.get(t)?.cwd:void 0,a=e.computeSkillReport(l);if(!a)return!1;const o=e.buildLibrarySkillsReport(l),d=k(a.skills,o);if(!n?.force&&d===e.lastReportedSkillsWireHash)return e.lastReportedSkillsHash=a.hash,!0;e.lastReportedSkillsHash=a.hash,e.lastReportedSkillsWireHash=d;try{return e.aibotHandle.sendSkillsUpdate({skills:a.skills,library_skills:o,...n?.ownerLibrarySync?{owner_library_sync:!0}:{}}),!0}catch{return!1}}function z(e){const i=e.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),n=i?e.bindingStore.get(i)?.cwd:void 0,r=e.computeSkillReport(n);if(!r)return;const t=e.buildLibrarySkillsReport(n);e.lastReportedSkillsHash=r.hash,e.lastReportedSkillsWireHash=k(r.skills,t)}function Q(e,i){const n=m(e.config.adapterType,e.config.aibot.clientType);return E({skillsDir:f.skills,mode:n,home:S(),cwd:i,env:e.skillLookupEnv()})}function V(e){const i={...process.env,...e.config.agent.env};if((e.config.agent.clientType??"").trim().toLowerCase()==="hermes"&&!i.HERMES_HOME?.trim()){const n=e.providerResolver?e.providerResolver():e.config.agent.provider,r={...I(e.config.agent.clientType,n),...i};i.HERMES_HOME=H(r,e.name)}return i}export{F as SKILL_ACTIONS_HOST_FIELDS,B as SKILL_ACTIONS_HOST_METHODS,z as adoptSkillsWireHashFromDisk,Q as buildLibrarySkillsReport,G as computeSkillReport,X as forceRefreshSkills,W as handleSkillDeleteLocalAction,P as handleSkillDisableLocalAction,h as handleSkillEnableLocalAction,q as handleSkillRefreshLocalAction,U as handleSkillUploadLocalAction,j as reportSessionSkills,V as skillLookupEnv,J as skillsSyncGroupKey};
@@ -0,0 +1 @@
1
+ import{ClaudeAdapter as C}from"../adapter/claude/index.js";import{getCachedModels as y}from"../adapter/claude/model-list.js";import{SESSION_CONTROL_ERROR_CODES as I,SESSION_MODE_IDS as m}from"../adapter/claude/protocol-contract.js";import{CursorAdapter as x,CURSOR_MODE_OPTIONS as A}from"../adapter/cursor/index.js";import{getCachedAgyModels as b,resolveAgyToolbarModelId as S}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as _,refreshAgyQuotaInfo as p}from"../adapter/agy/quota.js";import{normalizeClaudeEffort as M,CLAUDE_EFFORT_LEVELS as L}from"../core/config/claude-direct-env.js";import{log as v}from"../core/log/index.js";const H=["isRateLimitsCacheFresh","getFreshClaudeRateLimitState","maybeQueryProviderQuota","providerQuotaToRateLimits","normalizeClaudeModeId","resolveSessionModelId","resolveCursorSessionModeId","resolveClaudeSessionEffort","resolveClaudeSessionModeId","currentClaudeModeId","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard"],N=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","providerResolver","cachedClaudeRateLimitState","cachedProviderQuota","cachedProviderQuotaSampledAtMs"];function z(e,i){return String(i??"").trim().toLowerCase()===m.approval?m.approval:m.fullAuto}function B(e,i,n,t){const r=Array.isArray(t?.options)?t.options:[];if(r.length===0)return;const l=e.bindingStore.get(i)?.cwd??"",u={};if(n==="model"){u.available_models=r.map(a=>({id:a.id,displayName:a.label}));const c=r.find(a=>a.current);c&&(u.model_id=c.id)}else if(n==="mode"){u.available_modes=r.map(a=>({id:a.id,displayName:a.label}));const c=r.find(a=>a.current);c&&(u.mode_id=c.id)}else u[`${n}_options`]=r;e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:l,meta:u})}function F(e,i){const n=e.bindingStore.getModelId(i);if(n)return n;const t=String(e.globalConfigStore?.get(e.name)?.modelId??"").trim();if(t)return e.bindingStore.setModelId(i,t),t}function k(e,i){const n=e.bindingStore.getModeId(i);if(n)return n;const t=String(e.globalConfigStore?.get(e.name)?.modeId??"").trim();if(t)return e.bindingStore.setModeId(i,t),t}function U(e,i){const n=e.bindingStore.getCursorModeId(i);if(n)return n;const t=String(e.globalConfigStore?.get(e.name)?.cursorModeId??"").trim();if(t)return e.bindingStore.setCursorModeId(i,t),t}function $(e,i){const n=e.bindingStore.getEffort(i);if(n)return n;if(e.bindingStore.get(i)?.claudeSessionId)return;const r=M(e.globalConfigStore?.get(e.name)?.effort);if(r)return e.bindingStore.setEffort(i,r),r}function G(e,i){const n=e.bindingStore.getModeId(i);if(n)return n;if(e.bindingStore.get(i)?.claudeSessionId)return;const r=String(e.globalConfigStore?.get(e.name)?.modeId??"").trim();if(!r)return;const o=e.normalizeClaudeModeId(r);return e.bindingStore.setModeId(i,o),o}function J(e,i){return e.normalizeClaudeModeId(e.resolveClaudeSessionModeId(i))}function V(e,i){const n=e.bindingStore.getCodexModelId(i);if(n)return n;if(e.bindingStore.getCodexThreadId(i))return;const t=String(e.globalConfigStore?.get(e.name)?.codexModelId??"").trim();if(t)return e.bindingStore.setCodexModelId(i,t),t}function W(e,i,n,t){const r=String(n??"").trim();if(r&&!e.bindingStore.getCodexThreadId(i))return t(r),r}function j(e,i,n){const t=String(i??"").trim();if(t)return n(t),t}function K(e,i){const n=e.pool.getSlot(i);if(n?.adapter instanceof x)return n.adapter.getToolbarMeta(i);const t=e.bindingStore.getModelId(i)??"auto",r=e.resolveCursorSessionModeId(i)??"full_auto";return{model_id:t,mode_id:r,currentModelId:t,currentModeId:r,available_models:[],available_modes:A.map(o=>({...o}))}}function X(e,i,n){if(!e.bindingStore.get(i))return;const r=b(e.config.agent.command),o=r.length>0?r[0].id:"";let l=S(e.resolveSessionModelId(i)||"",r)||o;r.length>0&&!r.some(c=>c.id===l)&&(l=o);const u=n??_(e.config.agent.command);return{model_id:l,currentModelId:l,available_models:r.map(c=>({id:c.id,displayName:c.displayName})),...e.buildAgyQuotaMeta(u)}}function Y(e,i){const n={rate_limits:null,extra_limits:null};return i.rateLimits&&(n.rate_limits={primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()},i.rateLimits.extras&&i.rateLimits.extras.length>0&&(n.extra_limits=i.rateLimits.extras)),{...n,...i.plan!==void 0&&{plan:i.plan},...i.quota_exhausted!==void 0&&{quota_exhausted:i.quota_exhausted},...i.quota_reset_at!==void 0&&{quota_reset_at:i.quota_reset_at},...i.available_credits!==void 0&&{available_credits:i.available_credits}}}function Z(e,i,n,t){const r=t??e.buildAgyToolbarMeta(i);return e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:n,...r?{meta:r}:{}}),r}async function q(e,i,n=!1){const t=await p(e.config.agent.command,n),r=e.bindingStore.get(i);return r?.cwd&&e.sendAgyBindingCard(i,r.cwd,e.buildAgyToolbarMeta(i,t)),t}async function h(e,i,n){const t=i.params??{},r=b(e.config.agent.command),o=S(String(t.model_id??t.modelId??""),r);if(!n){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for set_model"});return}if(!o){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"set_model_invalid",error_msg:"model_id is required"});return}const l=e.bindingStore.get(n);if(!l?.cwd){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:I.bindingMissing,error_msg:"session binding was not found"});return}l.modelId!==o&&(e.bindingStore.setModelId(n,o),e.globalConfigStore?.set(e.name,{modelId:o}));const u=await p(e.config.agent.command,!0).catch(()=>_(e.config.agent.command));e.sendAgyBindingCard(n,l.cwd,e.buildAgyToolbarMeta(n,u)),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{outcome:"model_set",model_id:o,binding:{cwd:l.cwd,model_id:o}}})}function ee(e,i){if(!e.bindingStore.get(i))return;const t=y(),r=t.length>0?t[0].id:"";let o=e.resolveSessionModelId(i)||r;t.length>0&&!t.some(d=>d.id===o)&&(o=r);const l=e.currentClaudeModeId(i);let u;try{const d=e.providerResolver?e.providerResolver():e.config.agent.provider;u=M(d?.effort)}catch{}const c=e.resolveClaudeSessionEffort(i)??u??"auto",a={model_id:o,mode_id:l,currentModelId:o,currentModeId:l,available_efforts:[...L],effort:c,reasoning_effort:c,available_models:t.map(d=>({id:d.id,displayName:d.displayName}))},s=e.pool.getSlot(i),f=s?.adapter instanceof C?s.adapter.getSessionState():null;(f?.rateLimits?.fiveHour||f?.rateLimits?.sevenDay)&&(e.cachedClaudeRateLimitState=f);const g=f??e.getFreshClaudeRateLimitState();if(g){const d=g.rateLimits;d&&(d.fiveHour||d.sevenDay)&&(a.rate_limits={...d.fiveHour?{fiveHour:d.fiveHour}:{},...d.sevenDay?{sevenDay:d.sevenDay}:{},sampledAt:g.sampledAt||Date.now()})}if(f){const d=f.contextWindow;d.usedPercentage!=null&&(a.context_window={usedPercentage:d.usedPercentage,remainingPercentage:d.remainingPercentage})}if(!a.rate_limits&&e.cachedProviderQuota?.success){e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)||e.maybeQueryProviderQuota().catch(()=>{});const d=e.providerQuotaToRateLimits(e.cachedProviderQuota);d&&(a.rate_limits=d),v.info(e.name,`[toolbar-meta] provider quota fallback: hasCached=${!!e.cachedProviderQuota} fromProvider=${JSON.stringify(d)}`)}return a.rate_limits&&v.info(e.name,`[toolbar-meta] rate_limits included: ${JSON.stringify(a.rate_limits)}`),a}export{N as TOOLBAR_META_HOST_FIELDS,H as TOOLBAR_META_HOST_METHODS,Y as buildAgyQuotaMeta,X as buildAgyToolbarMeta,ee as buildClaudeToolbarMeta,K as buildCursorToolbarMeta,J as currentClaudeModeId,h as handleAgySetModel,B as handleExecCommandOptions,z as normalizeClaudeModeId,j as pinCodexGlobalDefault,q as refreshAndPushAgyQuota,$ as resolveClaudeSessionEffort,G as resolveClaudeSessionModeId,W as resolveCodexNewSessionGlobalDefault,V as resolveCodexSessionModelId,U as resolveCursorSessionModeId,k as resolveSessionModeId,F as resolveSessionModelId,Z as sendAgyBindingCard};
@@ -1 +1 @@
1
- import{readJSONFile as o,writeJSONFileAtomic as i}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(e=>typeof e=="string"&&e.trim().length>0):[]}async function s(t,r){await i(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
1
+ import{readJSONFile as o,writeJSONFileAtomic as e}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(i=>typeof i=="string"&&i.trim().length>0):[]}async function s(t,r){await e(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
@@ -1 +1 @@
1
- import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const i of c){if(!p&&i.name.startsWith("."))continue;const t=l(a,i.name),e={id:t,name:i.name,is_directory:i.isDirectory()};try{if(i.isDirectory()){const o=await m(t);e.modified_at=o.mtime.toISOString()}else{const o=await m(t);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(i.name)}}catch{}s.push(e)}return s.sort((i,t)=>i.is_directory!==t.is_directory?i.is_directory?-1:1:i.name.localeCompare(t.name)),s}export{f as listFiles,n as resolveMimeType};
1
+ import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const t of c){if(!p&&t.name.startsWith("."))continue;const i=l(a,t.name),e={id:i,name:t.name,is_directory:t.isDirectory()};try{if(t.isDirectory()){const o=await m(i);e.modified_at=o.mtime.toISOString()}else{const o=await m(i);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(t.name)}}catch{}s.push(e)}return s.sort((t,i)=>t.is_directory!==i.is_directory?t.is_directory?-1:1:t.name.localeCompare(i.name)),s}export{f as listFiles,n as resolveMimeType};
@@ -1 +1 @@
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};
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 d}from"../util/display-path.js";const p=".grix-sync.json";function m(t){return u("sha256").update(t,"utf8").digest("hex")}function g(t){const e=new Map;try{const c=s(f(t,p),"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=m(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=t.source==="connector"?void 0:d(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,m as computeContentDigest,h as toWireSkill};
package/dist/log.js CHANGED
@@ -1,3 +1,3 @@
1
- import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as i}from"node:path";import{homedir as m}from"node:os";const n=i(m(),".grix"),s={base:n,config:i(n,"config"),log:i(n,"log"),data:i(n,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=i(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...t){const e=`${c()} [${o}] ${r}${t.length?" "+t.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
- `)},error(o,r,...t){const e=`${c()} [${o}] ERROR ${r}${t.length?" "+t.map(String).join(" "):""}`;console.error(e),a?.write(e+`
1
+ import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as t}from"node:path";import{homedir as m}from"node:os";const i=t(m(),".grix"),s={base:i,config:t(i,"config"),log:t(i,"log"),data:t(i,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=t(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...n){const e=`${c()} [${o}] ${r}${n.length?" "+n.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
+ `)},error(o,r,...n){const e=`${c()} [${o}] ERROR ${r}${n.length?" "+n.map(String).join(" "):""}`;console.error(e),a?.write(e+`
3
3
  `)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
@@ -1 +1 @@
1
- import*as n from"node:net";const i={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function s(u){const e={bind:u?.bind??i.bind,port:u?.port??i.port,endpoint:u?.endpoint??i.endpoint,sessionTimeoutMs:u?.sessionTimeoutMs??i.sessionTimeoutMs,invokeTimeoutMs:u?.invokeTimeoutMs??i.invokeTimeoutMs,allowedOrigins:u?.allowedOrigins,allowedHosts:u?.allowedHosts};return t(e.bind),e.port!==0&&o(e.port),r(e.sessionTimeoutMs),e}function t(u){if(!u||!n.isIPv4(u)&&!n.isIPv6(u))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${u}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function o(u){if(!Number.isInteger(u)||u<1||u>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(u){if(!Number.isInteger(u)||u<1e3||u>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{s as createDefaultGatewayConfig};
1
+ import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
@@ -1 +1 @@
1
- const a=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
1
+ const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
@@ -1 +1 @@
1
- import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(r,e,t,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,t);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(r.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${r.status}`);if(p(e))return this.executeEventTool(r,e,t);const o=i(e,t);try{const u=await r.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(r){if(r==null||typeof r!="object")return this.successResult(r??null);const e=r,t=typeof e.code=="number"?e.code:0;if(t===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${t}]: ${n}`)}successResult(r){return{content:[{type:"text",text:JSON.stringify(r)}],isError:!1}}errorResult(r){return{content:[{type:"text",text:r}],isError:!0}}async executeEventTool(r,e,t){return e==="grix_access_control"?this.executeAccessControl(r,t):d(r,e,t)}async executeAccessControl(r,e){const t=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[t];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${t}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await r.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
1
+ import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
@@ -1 +1 @@
1
- import{TOOLS as o,EVENT_TOOLS as s}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...o.filter(t=>e.has(t.name)),...s.filter(t=>r.has(t.name))],this.toolMap=new Map(this.tools.map(t=>[t.name,t]))}getTools(){return this.tools}getTool(t){return this.toolMap.get(t)}hasTool(t){return this.toolMap.has(t)}}export{a as ToolRegistryImpl};
1
+ import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
@@ -1 +1 @@
1
- const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(r,t){const e=C[r];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${r}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,u]of Object.entries(t)){if(u==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,u,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(r,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${r} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${r} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const u=t[i];if(e.items.type==="string"&&typeof u!="string")return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.type==="integer"){if(typeof u!="number"||!Number.isInteger(u))return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.enum&&!e.items.enum.includes(u))return`\u53C2\u6570 ${r}[${i}] \u503C ${u} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
1
+ const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "4.2.7",
3
+ "version": "4.2.8",
4
4
  "description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,6 +35,7 @@
35
35
  "test:e2e": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e",
36
36
  "test:e2e:smoke": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/smoke.test.ts",
37
37
  "test:e2e:direct-relay": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/direct-relay-live.test.ts",
38
+ "test:e2e:relay": "node scripts/relay-e2e.mjs",
38
39
  "test:e2e:codex-developer-instructions": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/codex-developer-instructions-protocol.test.ts",
39
40
  "test:e2e:claude-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/claude-audit-replay.test.ts",
40
41
  "test:e2e:codex-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/codex-audit-replay.test.ts",