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.
- package/dist/adapter/claude/claude-bridge-server.js +1 -1
- package/dist/adapter/claude/claude-tools.js +1 -1
- package/dist/adapter/claude/claude-worker-client.js +1 -1
- package/dist/adapter/claude/mcp-http-launcher.js +2 -2
- package/dist/adapter/claude/result-timeout.js +1 -1
- package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
- package/dist/adapter/codewhale/codewhale-provider-config.js +2 -2
- package/dist/adapter/deepseek-harness/dsh-provider-config.js +7 -7
- package/dist/assets/dsh-bridge/grix-dsh-bridge-4.2.8.tgz +0 -0
- package/dist/assets/dsh-bridge/manifest.json +5 -5
- package/dist/bridge/bridge.js +5 -9
- package/dist/bridge/cli-install-flow.js +1 -0
- package/dist/bridge/connector-ops.js +1 -0
- package/dist/bridge/event-stop.js +1 -0
- package/dist/bridge/host-contract.js +0 -0
- package/dist/bridge/provider-quota.js +1 -0
- package/dist/bridge/rate-limits.js +1 -0
- package/dist/bridge/session-control-open.js +1 -0
- package/dist/bridge/session-control-router.js +3 -0
- package/dist/bridge/session-list.js +3 -0
- package/dist/bridge/session-usage.js +1 -0
- package/dist/bridge/skill-actions.js +1 -0
- package/dist/bridge/toolbar-meta.js +1 -0
- package/dist/core/access/allowlist-store.js +1 -1
- package/dist/core/file-ops/list-files.js +1 -1
- package/dist/core/skill-sync/sync-state.js +1 -1
- package/dist/log.js +2 -2
- package/dist/mcp/stream-http/config.js +1 -1
- package/dist/mcp/stream-http/connection-binding.js +1 -1
- package/dist/mcp/stream-http/tool-executor.js +1 -1
- package/dist/mcp/stream-http/tool-registry.js +1 -1
- package/dist/mcp/stream-http/tool-schemas.js +1 -1
- package/package.json +2 -1
- 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
|
|
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
|
|
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
|
|
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
|
|
2
|
-
`)},error(o,r,...
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
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",
|
|
Binary file
|