grix-connector 4.9.6 → 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/adapter/acp/acp-adapter.js +13 -14
  2. package/dist/adapter/acp/mcode-provider-config.js +2 -0
  3. package/dist/adapter/acp/session-activity.js +1 -1
  4. package/dist/adapter/acp/session-scanner.js +3 -3
  5. package/dist/adapter/claude/skill-scanner.js +2 -2
  6. package/dist/adapter/deepseek-harness/jsonrpc-adapter.js +1 -1
  7. package/dist/adapter/opencode/opencode-adapter.js +5 -5
  8. package/dist/adapter/opencode/session-history.js +2 -2
  9. package/dist/adapter/opencode/session-scanner.js +3 -3
  10. package/dist/adapter/pi/omp-mcp-config.js +3 -0
  11. package/dist/adapter/pi/pi-adapter.js +6 -6
  12. package/dist/adapter/pi/pi-provider-config.js +3 -3
  13. package/dist/adapter/pi/session-history.js +2 -2
  14. package/dist/adapter/shared/identity-injector.js +2 -2
  15. package/dist/adapter/shared/native-provider-config.js +7 -5
  16. package/dist/adapter/shared/serialize-on-file.js +1 -0
  17. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.11.0.tgz +0 -0
  18. package/dist/assets/dsh-bridge/manifest.json +6 -6
  19. package/dist/audit/adapters/acp/generic-acp-audit-adapter.js +2 -2
  20. package/dist/audit/adapters/opencode/opencode-audit-adapter.js +1 -1
  21. package/dist/bridge/bridge.js +2 -2
  22. package/dist/bridge/native-provider-sweep.js +1 -1
  23. package/dist/bridge/provider-quota.js +1 -1
  24. package/dist/bridge/session-identity.js +1 -1
  25. package/dist/bridge/session-list.js +3 -3
  26. package/dist/bridge/session-scan-cache.js +1 -1
  27. package/dist/bridge/session-usage.js +1 -1
  28. package/dist/core/config/provider-env.js +1 -1
  29. package/dist/core/installer/preflight.js +4 -4
  30. package/dist/core/installer/prereq-installer.js +3 -3
  31. package/dist/core/installer/registry.js +1 -1
  32. package/dist/core/mcp/tools.js +1 -1
  33. package/dist/core/persistence/session-binding-store.js +2 -2
  34. package/dist/core/probe/installed-clients.js +1 -1
  35. package/dist/core/provider-quota/providers.js +2 -2
  36. package/dist/core/skill-sync/enable-roots.js +1 -1
  37. package/dist/default-skills/grix-task-flow/SKILL.md +534 -0
  38. package/dist/default-skills/index.js +1 -1
  39. package/dist/default-skills/message-edit/SKILL.md +45 -0
  40. package/dist/manager.js +1 -1
  41. package/dist/protocol/acp-client.js +1 -1
  42. package/dist/types/events.js +1 -1
  43. package/openclaw-plugin/audit-recorder-worker.js +110 -5
  44. package/openclaw-plugin/index.js +37 -0
  45. package/openclaw.plugin.json +1 -0
  46. package/package.json +1 -1
  47. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.9.6.tgz +0 -0
@@ -1,3 +1,3 @@
1
1
  import{createHash as E,randomUUID as x}from"node:crypto";import{EventEmitter as U}from"node:events";import{copyFileSync as ce,existsSync as W,mkdirSync as ue}from"node:fs";import{dirname as pe,join as T,resolve as G}from"node:path";import{fileURLToPath as z}from"node:url";import{log as f}from"../../core/log/index.js";import{syncDefaultSkillsToDir as ge}from"../../default-skills/index.js";import{resolveCliPath as fe}from"../../core/util/cli-probe.js";import{DshWireCapture as me}from"./audit-boundary.js";import{dsmlToolCallKey as ve,projectVisibleDsmlText as be}from"./dsml-text-filter.js";import{mapDshSessionEvent as _e,unwrapDshSessionEvent as Se}from"./event-mapper.js";import{buildDshUserPrompt as Q,extractQuotedMessageMarker as K}from"./prompt-builder.js";import{DshProcessRuntime as ke}from"./process-runtime.js";import{DshProfileRuntime as Ie}from"./profile-runtime.js";import{compareDshVersions as X}from"./dsh-version.js";import{createDshWebProfile as we}from"./profile-catalog.js";import{listDshPlugins as M,resolveDshPlugin as Te,updateDshPluginIds as Pe}from"./plugin-manager.js";import{listDshSkills as R,resolveDshSkill as ye,updateDshSkillIds as De}from"./skill-manager.js";import{prepareDshSessionPluginOverlay as Ce}from"./session-plugin-overlay.js";import{assertSelectableDshProfileName as Ee,discoverDshBridgeEndpoints as xe,listDshProfiles as Me,resolveDshConnectorProfileDataDir as Re,resolveDshHome as Ae,resolveDshSelectedProfileName as He}from"./profile-resolver.js";import{DshBridgeInstaller as A,errorForDshBridgeReadiness as H,readDshCliVersion as $e}from"./bridge-installer.js";import{ensureDshBridgeReady as Be,prepareDshProfileBridge as qe}from"./profile-supervisor.js";import{DSH_RUNTIME_ENSURE_MAX_ATTEMPTS as J,dshRuntimeEnsureBackoffMs as Fe,isRetryableDshRuntimeError as Ne}from"./runtime-ensure.js";import{runDshProtocolProbe as Le}from"./probe.js";import{buildDshSystemPrompt as je,describeDshSystemPrompt as Ve}from"./system-prompt.js";import{DshActionCoordinator as Oe}from"./toolbar-actions.js";import{adoptDshProfileModels as Ue,adoptLiveDshProviderSelection as We,buildDshToolbarMeta as Ge,DEFAULT_DSH_MAX_TOKENS as ze,DEFAULT_DSH_MODELS as Qe,DEFAULT_DSH_PRESETS as Ke,DEFAULT_DSH_PROVIDER_ID as $,DEFAULT_DSH_REASONING_EFFORT as Xe,DEFAULT_DSH_THINKING as Je,normalizeDshPresets as Ye,normalizeDshProviders as Ze,normalizeDshReasoningEffort as B,normalizeDshThinking as q,permissionModeFor as Y,resolveDshAgentPreset as Z,resolveDshModeId as et,resolveDshProviderId as tt,retainRequestedDshProvider as it}from"./toolbar-state.js";import{modelsForDshProvider as st,resolveDshCatalogForToolbar as nt,writeDshCatalogCache as ot}from"./catalog-cache.js";import{TurnCorrelator as rt}from"./turn-correlator.js";import{effectiveDshReasoningEffort as at}from"./types.js";import{getDshSessionUsageStore as dt,normalizeDshUsage as ee}from"./usage.js";import{toolCallToInvoke as lt}from"../../core/mcp/tools.js";import{isEventTool as ht}from"../../core/mcp/event-tool-executor.js";import{isDshBridgedGrixTool as ct}from"./grix-tool-bridge.js";import{DSH_GRIX_PROVIDER_ID as v,dshCredentialsLayoutFor as ut,isDshGrixProviderConfigured as te,removeDshGrixProvider as pt,writeDshGrixProvider as gt}from"./dsh-provider-config.js";const m="deepseek-harness-adapter",ie=20*6e4,se=6e4,ne=9e4,oe=30*6e4,re="0.1.0-rc.8",ae="0.1.0-rc.8";class ft extends U{adapterSessionId;cancelFn;constructor(e,t){super(),this.adapterSessionId=e,this.cancelFn=t}cancel(){return this.cancelFn()}}class ai extends U{config;callbacks;type="deepseek-harness";alive=!1;stopped=!1;runtime=null;capture=null;runtimeGeneration=0;runtimeSessionId="";applied;active=null;correlator=null;timeoutTimer=null;hardTimeoutTimer=null;activeTimeoutMs=ie;intentionalRuntimeStop=!1;personaDirty=!1;profileRevision=0;appliedProfileRevision=-1;rebuildPromise=null;runtimeStartPromise=null;contextWindow=null;reportedContextCapacity=null;providerQuota=null;settingsState="applied";settingsErrorCode=null;injectedMessageIds=new Set;auditBoundaries=new Map;actionCoordinator=new Oe;activeWireStart=0;activeUsage=de();activeUsageSeq=-1;activeCommittedUsageSeqs=new Set;permissionHandler=null;quotedMessageId;cancelRequested=!1;runtimeReadiness="unknown";bridgeCapabilities=null;profileDshVersion=null;bridgeAckCursor=0;pendingFinalBridgeAck=null;finishingTurn=!1;pendingApprovals=new Map;options;models=Qe;providers=[];presets=[...Ke];catalogProviderId;constructor(e,t,i){super(),this.config=e,this.callbacks=t,this.options=i,this.hydrateCatalogFromCache()}async start(){this.alive=!0,this.stopped=!1,this.settingsState="applied",this.settingsErrorCode=null,this.hydrateCatalogFromCache();const e=this.options.bindingStore.get(this.options.aibotSessionId);if(e?.cwd&&this.seedSessionToolbarFromGlobal(),this.syncGrixProvider(),e&&await this.options.bindingStore.flush(),this.resolveIntegrationMode()==="profile_bridge")try{const t=await this.attachSelectedProfile();await this.healBridgeUpdate(t)}catch(t){this.runtimeReadiness=String(t?.code??"bridge_probe_failed"),this.settingsErrorCode=this.runtimeReadiness}else this.runtimeReadiness="ready";this.pushToolbarMeta(),this.refreshProviderQuota(!1)}async stop(){this.stopped=!0,this.clearPendingApprovals("cancelled"),this.clearTimeout(),this.active&&this.finishActive("canceled","connector shutdown"),this.applied=void 0,this.contextWindow=null,this.reportedContextCapacity=null,this.settingsState==="pending"&&(this.settingsState="applied"),this.settingsErrorCode=null,this.pushToolbarMeta(),await this.rebuildPromise?.catch(()=>{}),await this.stopRuntime(!0),await this.usageStore().flush(),this.alive=!1}isAlive(){return this.alive&&!this.stopped}async createSession(e){return this.options.aibotSessionId}async resumeSession(e,t){}async destroySession(e){e===this.options.aibotSessionId&&(this.usageStore().delete(e),await this.usageStore().flush(),await this.stopRuntime(!0))}sendPrompt(e){const t=new ft(e.adapterSessionId,()=>this.cancel(e.adapterSessionId));return queueMicrotask(()=>t.emit("done",{status:"failed",error:"Use deliverInboundEvent for platform prompts"})),t}async cancel(e){await this.cancelActive("user canceled")}deliverInboundEvent(e){if(!this.isAlive()){this.failEvent(e,"adapter is not alive");return}if(e.attachments_json&&e.attachments_json!=="[]"){this.failEvent(e,"DeepSeek Harness first version supports text only; attachments must be materialized in the bound workspace");return}if(this.active){this.failEvent(e,"concurrent prompt rejected");return}this.runInboundEvent(e)}deliverStopEvent(e,t){this.active&&e===this.active.inbound.event_id&&(t&&t!==this.active.inbound.session_id||this.cancelActive("user canceled"))}async handleLocalAction(e){if(!["set_model","set_mode","set_provider","set_thinking","set_reasoning_effort","set_preset","set_profile","create_profile","get_session_usage","get_rate_limits","dsh_bridge_status","dsh_install_bridge","dsh_list_plugins","dsh_enable_plugin","dsh_disable_plugin","dsh_refresh_plugins","dsh_list_skills","dsh_enable_skill","dsh_disable_skill","dsh_list_mcp","dsh_list_tools","dsh_list_jobs","dsh_list_goals","exec_approve","exec_reject","permission_approve","permission_reject"].includes(e.action_type))return{handled:!1,kind:""};const t=await this.actionCoordinator.run(e.action_id,()=>this.executeLocalAction(e));return this.callbacks.sendLocalActionResult(e.action_id,t.status,t.result,t.errorCode,t.errorMsg),{handled:!0,kind:e.action_type}}async handleExecApprovalEvent(e){const t=String(e.approval_command_id??e.approval_id??e.tool_call_id??"").trim(),i=this.pendingApprovals.get(t);return i?(clearTimeout(i.timer),this.pendingApprovals.delete(t),i.resolve(e.decision==="deny"?"rejected":"allowed-once"),{delivered:!0}):{delivered:!1,errorCode:"approval_not_found",errorMsg:"That DSH approval request is no longer pending"}}setPermissionHandler(e){this.permissionHandler=e}async ping(e){return this.isAlive()&&(!this.runtime||this.runtime.isConnected())}getStatus(){return{alive:this.isAlive()&&!!this.runtime,busy:!!this.active||this.intentionalRuntimeStop||!!this.rebuildPromise||!!this.runtimeStartPromise,backgroundBusy:!1,sessions:this.runtime?1:0,details:{runtimeGeneration:this.runtimeGeneration,runtimeSessionId:this.runtimeSessionId||void 0}}}getActiveEventIds(){return this.active?[this.active.inbound.event_id]:[]}takeAuditBoundary(e){const t=this.auditBoundaries.get(e);return this.auditBoundaries.delete(e),t}clearActiveEventForShutdown(){this.active=null,this.correlator=null,this.clearTimeout()}getMcpConfig(){return null}async hasBackgroundWork(){return this.runtime?.hasBackgroundWork()??!1}onAgentProfileChanged(){this.profileRevision+=1,this.personaDirty=!0,!this.active&&this.runtime&&this.rebuildRuntime("persona_changed")}updateProviderQuotaSnapshot(e){this.providerQuota=e??null;const t=this.options.bindingStore.get(this.options.aibotSessionId);this.callbacks.sendUpdateBindingCard(this.options.aibotSessionId,this.stopped?"stopped":this.active?"busy":"ready",t?.cwd,{provider_quota:this.providerQuota})}async probe(e={}){const t=this.resolveIntegrationMode(),i=t==="embedded_jsonrpc"?this.config.command||"dsh-jsonrpc-agent":"dsh",s=await fe(i),n=!!s;let a={ok:e.conversation!==!0,latency:null};if(n&&e.conversation===!0&&s)if(t==="embedded_jsonrpc")try{const d=await Le({command:s,args:this.config.args,cordisPath:G(this.options.cordisPath??z(new URL("./grix-jsonrpc.cordis.yml",import.meta.url))),settings:this.resolveDesiredSettings(),timeoutMs:e.timeoutMs});a={ok:!0,latency:d.latencyMs,serverName:d.serverName,serverVersion:d.serverVersion}}catch(d){a={ok:!1,latency:null,error:this.redactError(d)}}else{const d=Date.now();try{const r=new A({command:"dsh",dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile()}),p=await Be({installer:r,autoStart:!1}),u=H(p);if(u)throw u;const o=xe(p.identity);if(o.length===0)throw Object.assign(new Error(`No live Grix Bridge endpoint in DSH profile "${p.identity.profileName}"`),{code:"bridge_missing"});a={ok:!0,latency:Date.now()-d,serverName:"grix-dsh-profile-bridge",serverVersion:o[0].bridgeVersion}}catch(r){a={ok:!1,latency:null,error:this.redactError(r)}}}return{cli:{command:i,installed:n,path:s,version:null,...n?{}:{error:{code:"cli_not_found",message:`${i} not found`}}},conversation:{attempted:e.conversation===!0,ok:a.ok,latency_ms:a.latency,...a.ok?{}:{error:{code:"conversation_failed",message:a.error??"initialize/shutdown probe failed"}}},config:{model:this.resolveDesiredSettings().modelId,base_url:this.config.env?.DEEPSEEK_BASE_URL??null,source:{model:"config",base_url:this.config.env?.DEEPSEEK_BASE_URL?"env":"unknown"},extras:{protocol:t==="profile_bridge"?"grix-dsh/1":"jsonrpc-v1",profile:this.resolveSelectedProfile(),serverName:a.serverName,serverVersion:a.serverVersion}},process:{started:!!this.runtime,alive:this.runtime?.isConnected()??!1,busy:!!this.active}}}async runInboundEvent(e){const t={inbound:e,admitted:!1,claimed:!1,turnEnded:!1,rootIdle:!1,text:"",sentText:"",seq:0,startedAt:Date.now()};this.active=t,this.correlator=new rt(t),this.activeUsage=de(),this.activeUsageSeq=-1,this.activeCommittedUsageSeqs.clear(),this.quotedMessageId=void 0,this.cancelRequested=!1,this.emit("eventStarted",e.event_id,e.session_id);try{if(await this.ensureRuntimeWithRetry(),this.cancelRequested||this.active!==t)return;this.activeWireStart=this.capture?.offset??0;const i=Q(e,this.injectedMessageIds);this.startTimeout(e.timeoutMs);const s=await this.runtime.client.prompt({sessionId:this.runtimeSessionId,contentBlocks:[{type:"text",text:i.text}]});if(!s?.messageId)throw Object.assign(new Error("session/prompt response missing messageId"),{code:"protocol_invalid_prompt_result"});this.correlator.setPromptMessageId(s.messageId)}catch(i){const s=this.redactError(i,e.content);this.finishActive(this.cancelRequested?"canceled":"failed",this.cancelRequested?"user canceled":s)}}async ensureRuntime(){if(this.stopped)throw new Error("adapter stopped");if(this.runtime)return;this.syncGrixProvider(),await this.writeGrixProviderFile();const t=this.options.bindingStore.get(this.options.aibotSessionId)?.cwd;if(!t)throw Object.assign(new Error("Session binding missing. Open a workspace first."),{code:"binding_missing"});const i=this.projectConnectorSkills();let s=this.resolveDesiredSettings();const n=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),a={};n?.modelId||(a.modelId=s.modelId),!n?.providerId&&s.providerId&&(a.providerId=s.providerId),n?.thinking||(a.thinking=s.thinking),n?.reasoningEffort||(a.reasoningEffort=s.reasoningEffort),Object.keys(a).length>0&&(this.options.bindingStore.updateDshSettings(this.options.aibotSessionId,a),await this.options.bindingStore.flush(),s=this.resolveDesiredSettings());const d=this.callbacks.getAgentProfile(),r=this.profileRevision,p=je({...d,grixSessionId:this.options.aibotSessionId,agentId:this.callbacks.getAgentId()}),u=Ve(p);this.runtimeGeneration+=1;const o=this.resolveIntegrationMode(),l=this.resolveSelectedProfile();if(o==="profile_bridge")try{await this.ensureProfileReadyForChat(),this.pushToolbarMeta()}catch(g){throw this.settingsState="failed",this.settingsErrorCode=String(g?.code??"runtime_initialize_failed"),this.runtimeReadiness=this.settingsErrorCode,this.pushToolbarMeta(),g}let c=o==="profile_bridge"?this.options.bindingStore.getDshProfileBinding(this.options.aibotSessionId,l):void 0;o==="profile_bridge"&&!c&&(c={profileName:l,sessionId:_t(this.options.aibotSessionId),sessionCreated:!1,eventCursor:0},this.options.bindingStore.setDshProfileBinding(this.options.aibotSessionId,c),await this.options.bindingStore.flush()),this.runtimeSessionId=c?.sessionId??bt(this.options.aibotSessionId,this.runtimeGeneration);const b=this.profileDataDir(l),F=G(this.options.cordisPath??z(new URL("./grix-jsonrpc.cordis.yml",import.meta.url))),N=Ce({dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:l,pluginIds:s.pluginIds??[],overlayId:E("sha256").update(this.options.aibotSessionId).digest("hex").slice(0,24),baseCordisPath:F}),he=T(b,"audit-source",`${this.runtimeSessionId}.jsonl`);this.capture=new me(he);const _=o==="embedded_jsonrpc"?new ke({command:this.config.command||"dsh-jsonrpc-agent",args:this.config.args,cwd:t,cordisPath:N.embeddedCordisPath??F,home:b,sessionRoot:T(b,"sessions"),skillsDir:i,env:this.config.env,systemPrompt:p,settings:s,capture:this.capture,maxLineBytes:this.options.maxLineBytes}):new Ie({dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:l,cwd:t,ownerId:`${this.callbacks.getAgentId()}:${this.options.aibotSessionId}`,sessionId:this.runtimeSessionId,resumeSession:c?.sessionCreated===!0,lastAckCursor:c?.eventCursor??0,systemPrompt:p,settings:s,skillsDir:i,pluginOverlayPath:N.bridgeOverlayPath,capture:this.capture,maxFrameBytes:this.options.maxLineBytes,onApproval:g=>this.handleBridgeApproval(g),onToolInvoke:(g,P,I)=>this.invokeGrixTool(g,P,I),onCursorAck:g=>{!c||g<=c.eventCursor||(c={...c,eventCursor:g},this.options.bindingStore.setDshProfileBinding(this.options.aibotSessionId,c))}});this.runtime=_,this.bridgeAckCursor=c?.eventCursor??0,this.pendingFinalBridgeAck=null,this.finishingTurn=!1,this.intentionalRuntimeStop=!1;try{const g=await _.start();if(!_.isConnected())throw Object.assign(new Error("Harness runtime disconnected immediately after initialize"),{code:"runtime_exited"});_.client?.on("notification",(S,k)=>this.onNotification(S,k)),_.client?.on("protocolError",S=>this.onProtocolError(S)),_.onExit(()=>this.onRuntimeExit()),_.client?.activateNotifications?.();let P=!1;if(o==="profile_bridge"){const S=Ze(g.providers),k=We({requestedProviderId:s.providerId,liveProviders:S,liveSelectedProvider:String(g.selectedProvider??"")});this.providers=it(S,k.providerId,this.providers),s={...s,providerId:k.providerId},P=k.persistFallback;const D=k.providerId,j=Object.prototype.hasOwnProperty.call(g,"models")?g.models:void 0,V=!!this.catalogProviderId&&!!D&&D!==this.catalogProviderId;this.models=Ue({current:this.models,fetched:j,providerChanged:V}),(j!==void 0||V)&&(this.catalogProviderId=D||this.catalogProviderId);const C=String(g.selectedModel??"");C&&C!==s.modelId&&(s={...s,modelId:C});const O=Ye(g.presets);O.length>0&&(this.presets=O);const y=String(g.selectedPreset??"");y&&y!==s.agentPreset&&(s={...s,agentPreset:y},this.options.bindingStore.getDshAgentPreset(this.options.aibotSessionId)||this.options.bindingStore.setDshAgentPreset(this.options.aibotSessionId,y))}const I=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),L=(I?.revision??0)!==s.revision,w={};!L&&P&&(I?.providerId??"")!==(s.providerId??"")&&(w.providerId=s.providerId),!L&&(I?.modelId??"")!==s.modelId&&(w.modelId=s.modelId),(w.providerId||w.modelId)&&(s.revision=this.options.bindingStore.updateDshSettings(this.options.aibotSessionId,w)??s.revision,await this.options.bindingStore.flush(),f.warn(m,`replaced unavailable persisted DSH catalog selection provider=${s.providerId} model=${s.modelId}`)),this.applied={runtimeGeneration:this.runtimeGeneration,appliedRevision:s.revision,providerId:s.providerId??$,modelId:s.modelId,modeId:s.modeId,thinking:s.thinking,reasoningEffort:at(s)},this.runtimeReadiness="ready",this.bridgeCapabilities=g.capabilities??null,o==="profile_bridge"&&c&&!c.sessionCreated&&(c={...c,sessionCreated:!0},this.options.bindingStore.setDshProfileBinding(this.options.aibotSessionId,c),await this.options.bindingStore.flush()),this.settingsState=this.resolveDesiredSettings().revision===s.revision?"applied":"pending",this.settingsErrorCode=null,this.appliedProfileRevision=r,this.personaDirty=this.appliedProfileRevision!==this.profileRevision,f.info(m,`runtime initialized generation=${this.runtimeGeneration} prompt_schema=${u.schemaVersion} prompt_sha256=${u.sha256} prompt_length=${u.length}`),await this.persistCatalogCache(s.providerId??$),this.pushToolbarMeta(),this.settingsState==="pending"&&!this.active&&!this.stopped&&this.rebuildRuntime("settings_changed_during_start")}catch(g){throw this.settingsState="failed",this.settingsErrorCode=String(g?.code??"runtime_initialize_failed"),this.runtimeReadiness=this.settingsErrorCode,this.applied=void 0,this.pushToolbarMeta(),await this.stopRuntime(!0),g}}ensureRuntimeWithRetry(){if(this.runtimeStartPromise)return this.runtimeStartPromise;const e=this.ensureRuntimeWithRetryLoop();this.runtimeStartPromise=e;const t=()=>{this.runtimeStartPromise===e&&(this.runtimeStartPromise=null)};return e.then(t,t),e}async ensureRuntimeWithRetryLoop(){let e;for(let t=1;t<=J;t++)try{await this.ensureRuntime();return}catch(i){e=i;const s=String(i?.code??"");if(this.cancelRequested||!Ne(s)||t===J)throw i;f.warn(m,`runtime ensure retry attempt=${t} code=${s||"unknown"}`),this.settingsState="pending",this.settingsErrorCode=s||"runtime_initialize_failed",this.runtimeReadiness=this.settingsErrorCode,this.pushToolbarMeta(),await this.stopRuntime(!0),await vt(Fe(t))}throw e}onNotification(e,t){const i=mt(t);if(e==="session.event"){const s=Se(t);if(!s){this.onProtocolError(new Error("malformed session.event"));return}const n=this.onSessionEvent(s);this.advanceBridgeAck(i,n);return}if(e==="session.status"){const s=t&&typeof t=="object"?t:{};if(String(s.sessionId??"")===this.runtimeSessionId){this.touchActivity(),this.correlator?.markRootStatus(String(s.status??"")),s.status==="idle"&&this.active&&this.correlator&&f.debug(m,`turn correlation idle admitted=${this.active.admitted} claimed=${this.active.claimed} ended=${this.active.turnEnded} complete=${this.correlator.complete}`);const a=!!this.correlator?.complete;a&&this.finishFromTurnOutcome(),this.advanceBridgeAck(i,a)}else i>0&&this.advanceBridgeAck(i,!1);return}if(e==="subagent.started"||e==="subagent.finished"){this.touchActivity(3);const s=t&&typeof t=="object"?t:{},n=String(s.childSessionId??s.sessionId??"");n&&this.capture?.addChild(n),this.active&&this.callbacks.sendRawEventEnvelope(this.active.inbound.event_id,this.active.inbound.session_id,{type:e,payload:s},e==="subagent.started"?"[subagent started]":"[subagent finished]"),this.advanceBridgeAck(i,!1);return}this.onProtocolError(new Error(`unknown required JSON-RPC notification: ${e}`))}onSessionEvent(e){if(!this.active||!this.correlator)return!1;this.touchActivity(e.type==="tool/call"||e.type==="tool/result"?3:1);const t=_e(e);if(t.kind==="unknown"&&!Pt(e)&&e.ignorable!==!0)return this.onProtocolError(new Error(`unknown required SessionEvent: ${e.type}`)),!1;if(e.sessionId&&e.sessionId!==this.runtimeSessionId)return!1;const i=this.correlator.accept(e);if((e.type==="agent/inbox/spliced"||e.type==="user/message"||e.type==="turn/end")&&f.debug(m,`turn correlation event=${e.type} belongs=${i} admitted=${this.active.admitted} claimed=${this.active.claimed} ended=${this.active.turnEnded}`),e.type==="agent/inbox/spliced"&&this.active.admitted){const s=Q(this.active.inbound,this.injectedMessageIds);for(const n of s.contextIds)this.injectedMessageIds.add(n);s.currentMessageId&&this.injectedMessageIds.add(s.currentMessageId)}return i?It(e)?(this.flushPendingTextAsThinking(),!1):t.kind==="text"?(t.payload?.committed===!0?(t.payload?.hasToolCall===!0?this.applyCommittedToolStepText(t.text??""):this.applyCommittedText(t.text??""),t.usage&&this.collectCommittedUsage(t.usage,Number(e.seq??e.step??Date.now()))):this.applyTextDelta(t.text??""),!1):t.kind==="thinking"?(this.thinkingEnabled()&&this.callbacks.sendThinking(this.active.inbound.event_id,this.active.inbound.session_id,t.text??""),!1):t.kind==="tool_call"?(this.flushPendingTextAsThinking(),this.toolEventsEnabled()&&this.sendRaw("tool_call",{call_id:t.callId,tool_name:t.name,tool_input:t.input},`[tool] ${t.name}`),!1):t.kind==="tool_result"?(this.toolEventsEnabled()&&this.sendRaw("tool_result",{call_id:t.callId,result:t.output},`[tool result] ${t.callId??""}`),!1):t.kind==="todo"||t.kind==="compaction"?!1:t.kind==="context"?(this.updateContextCapacity(t.payload),!1):t.kind==="usage"?(this.updateContextWindow(t.usage),!1):t.kind==="turn_end"&&this.correlator.complete?(this.finishFromTurnOutcome(),!0):!1:!1}applyTextDelta(e){this.active.pendingText=`${this.active.pendingText??""}${e}`}applyCommittedText(e){const t=this.active;if(t.pendingText=void 0,e.startsWith(t.text))t.text=e;else if(!t.text.startsWith(e)){f.warn(m,`committed assistant text diverged event=${t.inbound.event_id}`);const i=K(e).quotedMessageId;i&&(this.quotedMessageId=i),t.text=t.sentText}this.flushVisibleText(!1)}flushPendingTextAsThinking(){const e=this.active,t=e?.pendingText;!e||!t||(e.pendingText=void 0,this.thinkingEnabled()&&t.trim()&&this.callbacks.sendThinking(e.inbound.event_id,e.inbound.session_id,t),e.lastThinkingText=t)}applyCommittedToolStepText(e){const t=this.active;t&&(t.pendingText=void 0,e.trim()&&t.lastThinkingText!==e&&this.thinkingEnabled()&&(this.callbacks.sendThinking(t.inbound.event_id,t.inbound.session_id,e),t.lastThinkingText=e))}promotePendingTextToVisible(){const e=this.active,t=e?.pendingText;!e||!t||(e.pendingText=void 0,e.text+=t)}flushVisibleText(e,t={}){const i=this.active;if(!i)return;const s=K(i.text);s.quotedMessageId&&(this.quotedMessageId=s.quotedMessageId);const n=s.text.replace(/\[\[quoted_message_id:[^\]]*$/g,""),a=be(n,{finalize:t.finalizeDsml===!0||e});this.surfaceSuppressedDsmlToolCalls(a.suppressedToolCalls);const d=a.visible;this.observeVisibleTextAfterToolCall(d);let r="";d.startsWith(i.sentText)?r=d.slice(i.sentText.length):(e||t.finalizeDsml)&&(r=d),!(!r&&!e)&&(i.repliedViaTool||(i.seq+=1,this.callbacks.sendStreamChunk(i.inbound.event_id,i.inbound.session_id,r,i.seq,e,`${i.inbound.event_id}-dsh`,this.quotedMessageId)),i.sentText=d)}surfaceSuppressedDsmlToolCalls(e){if(!this.active||e.length===0)return;const t=this.active.dsmlSuppressedKeys??new Set;this.active.dsmlSuppressedKeys=t;for(const i of e){const s=ve(i);if(t.has(s)||(t.add(s),this.markToolCallAwaitingFinalText(),f.warn(m,`suppressed leaked DSML tool markup name=${i.name} event=${this.active.inbound.event_id}`),!this.toolEventsEnabled()))continue;let n=i.arguments;try{n=JSON.parse(i.arguments)}catch{}this.sendRaw("tool_call",{call_id:`dsml-${t.size}`,tool_name:i.name,tool_input:n,source:"dsml_text_leak",executed:!1},`[tool] ${i.name}`)}}markToolCallAwaitingFinalText(){const e=this.active;e&&(e.toolCallAwaitingFinalText=!0,e.toolCallVisibleTextLength=e.sentText.length)}observeVisibleTextAfterToolCall(e){const t=this.active;if(!t?.toolCallAwaitingFinalText)return;const i=t.toolCallVisibleTextLength??t.sentText.length;e.slice(i).trim().length!==0&&(t.toolCallAwaitingFinalText=!1,t.toolCallVisibleTextLength=void 0)}collectCommittedUsage(e,t){if(this.activeCommittedUsageSeqs.has(t))return;this.activeCommittedUsageSeqs.add(t);const i=ee(e);this.activeUsage.inputTokens+=i.inputTokens,this.activeUsage.outputTokens+=i.outputTokens,this.activeUsage.cacheReadInputTokens+=i.cacheReadInputTokens,this.activeUsage.cacheCreationInputTokens+=i.cacheCreationInputTokens,this.activeUsage.reasoningTokens+=i.reasoningTokens,this.activeUsageSeq=Math.max(this.activeUsageSeq,t),this.updateContextWindow(i)}updateContextWindow(e){const t=ee(e),i=this.resolveDesiredSettings(),s=this.models.find(a=>a.id===i.modelId),n=this.reportedContextCapacity??s?.contextWindow;if(n&&n>0){const a=t.inputTokens+t.cacheReadInputTokens+t.cacheCreationInputTokens;this.contextWindow={usedTokens:a,totalTokens:n,remainingTokens:Math.max(0,n-a),usedPercentage:a/n*100,remainingPercentage:Math.max(0,100-a/n*100)},this.pushToolbarMeta()}}updateContextCapacity(e){const t=Number(e?.contextWindow);if(!Number.isFinite(t)||t<=0)return;this.reportedContextCapacity=t;const i=this.contextWindow&&typeof this.contextWindow=="object"?this.contextWindow:{},s=Math.max(0,Number(i.usedTokens)||0);this.contextWindow={usedTokens:s,totalTokens:t,remainingTokens:Math.max(0,t-s),usedPercentage:s/t*100,remainingPercentage:Math.max(0,100-s/t*100)},this.pushToolbarMeta()}finishFromTurnOutcome(){if(!this.active)return;this.finishingTurn=!0;const e=this.active.outcome??"completed",t=this.active.outcomeDetail?.trim();e==="completed"?this.finishActive("responded"):e==="aborted"?this.finishActive("canceled"):e==="max-tokens"&&this.active.sentText?this.finishActive("responded","Response truncated at model token limit"):this.finishActive("failed",t?t.toLowerCase().includes(e.toLowerCase())?`Harness turn ended: ${t}`:`Harness turn ended: ${e}: ${t}`:`Harness turn ended: ${e}`)}finishActive(e,t){const i=this.active;if(!i)return;let s=this.cancelRequested?"canceled":e,n=this.cancelRequested?"user canceled":t;this.finishingTurn=!0,this.clearTimeout(),this.promotePendingTextToVisible(),this.flushVisibleText(!1,{finalizeDsml:!0}),s==="responded"&&i.toolCallAwaitingFinalText&&!i.repliedViaTool&&(s="failed",n="DeepSeek Harness ended after a tool call without returning final assistant text",f.warn(m,`${n} event=${i.inbound.event_id}`)),i.text=i.sentText;const a=s==="failed"&&!!n?.trim();a&&(i.text+=`
2
2
 
3
- Error: ${n}`,this.flushVisibleText(!1,{finalizeDsml:!0})),s==="responded"&&this.activeUsageSeq>=0&&(this.usageStore().commit(i.inbound.session_id,this.runtimeSessionId,this.activeUsageSeq,this.applied?.modelId??this.resolveDesiredSettings().modelId,this.activeUsage),this.usageStore().flush()),i.inbound.audit?.enabled&&this.capture&&this.auditBoundaries.set(i.inbound.event_id,this.capture.boundary({runtimeSessionId:this.runtimeSessionId,rootSessionId:this.runtimeSessionId,startOffset:this.activeWireStart,turn:i.turn,messageId:i.messageId}));const d=this.personaDirty&&!!this.runtime,r=!!this.runtime&&!!this.applied&&this.applied.appliedRevision!==this.resolveDesiredSettings().revision;d&&this.emit("pauseIntake","barrier"),this.active=null,this.correlator=null;const p=`${i.inbound.event_id}-dsh`,u=(o,l,c=!1)=>{this.callbacks.sendEventResult(i.inbound.event_id,o,l,c),this.emit("eventDone",i.inbound.event_id),d?this.rebuildRuntime("persona_changed"):r&&this.rebuildRuntime("settings_changed")};if(i.repliedViaTool&&i.seq===0){this.flushPendingFinalBridgeAck(!0).then(()=>u(s,n,a),()=>u(s,n,a));return}this.callbacks.sendFinalStreamChunkReliable(i.inbound.event_id,i.inbound.session_id,p).then(async()=>{await this.flushPendingFinalBridgeAck(!0),u(s,n,a)},async o=>{await this.flushPendingFinalBridgeAck(!1),u(s==="responded"?"failed":s,s==="responded"?`Final output delivery failed: ${this.redactError(o,i.inbound.content)}`:n)})}advanceBridgeAck(e,t){if(!(e<=0)){if(t||this.finishingTurn||this.pendingFinalBridgeAck!==null){this.pendingFinalBridgeAck=Math.max(this.pendingFinalBridgeAck??0,e);return}this.ackBridgeCursor(e)}}async flushPendingFinalBridgeAck(e){const t=this.pendingFinalBridgeAck;this.pendingFinalBridgeAck=null,this.finishingTurn=!1,!(!e||t===null)&&await this.ackBridgeCursor(t)}async ackBridgeCursor(e){if(e<=this.bridgeAckCursor)return;const t=this.runtime?.client?.ack;if(!t){this.bridgeAckCursor=Math.max(this.bridgeAckCursor,e);return}try{await t.call(this.runtime.client,e),this.bridgeAckCursor=Math.max(this.bridgeAckCursor,e)}catch(i){this.onProtocolError(i instanceof Error?i:new Error(String(i)))}}async cancelActive(e){this.active&&(this.cancelRequested=!0,this.clearPendingApprovals("cancelled"),this.resolveIntegrationMode()==="embedded_jsonrpc"?(this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="applied",this.pushToolbarMeta(),this.runtimeStartPromise&&this.runtime&&await this.runtime.terminate().catch(()=>{}),await this.runtimeStartPromise?.catch(()=>{}),await this.stopRuntime(!0)):(await this.runtimeStartPromise?.catch(()=>{}),await this.runtime?.cancel(this.runtimeSessionId).catch(()=>{}),this.runtime&&!this.runtime.isConnected()&&await this.stopRuntime(!0)),this.finishActive("canceled",e))}async handleBridgeApproval(e){const t=this.permissionHandler,i=String(e.interactionId??e.callId??x());if(t)try{return await t({adapterSessionId:this.options.aibotSessionId,requestId:i,description:String(e.reason??`Allow ${String(e.toolName??"operation")}?`),options:[{id:"allow_once",label:"Allow once",isAllow:!0},{id:"reject",label:"Reject",isAllow:!1}]})==="allow_once"?"allowed-once":"rejected"}catch{return"cancelled"}const s=this.active;return s?(this.callbacks.sendPermissionCard({eventId:s.inbound.event_id,sessionId:s.inbound.session_id,approvalId:i,toolName:String(e.toolName??"operation"),toolTitle:String(e.reason??`Allow ${String(e.toolName??"operation")}?`)}),new Promise(n=>{const a=setTimeout(()=>{this.pendingApprovals.delete(i),n("unavailable")},3e5);a.unref?.(),this.pendingApprovals.set(i,{resolve:n,timer:a})})):"unavailable"}async invokeGrixTool(e,t,i){if(!ct(e))throw Object.assign(new Error(`grix tool "${e}" is not exposed to DSH`),{code:"capability_unavailable"});if(ht(e)){if(!this.callbacks.eventToolInvoke)throw Object.assign(new Error(`grix event tool "${e}" has no connector-side runner`),{code:"capability_unavailable"});const n=this.active,a=await this.callbacks.eventToolInvoke(e,t);if(e==="grix_reply"&&n){const d=String(t.session_id??"").trim();(!d||d===n.inbound.session_id)&&(n.repliedViaTool=!0)}return a}if(!this.callbacks.agentInvoke)throw Object.assign(new Error(`grix tool "${e}" has no connector-side action runner`),{code:"capability_unavailable"});const s=lt(e,t);return this.callbacks.agentInvoke(s.action,s.params,i??s.timeoutMs)}projectConnectorSkills(){const e=T(this.options.dataRoot,"dsh-session-skills"),t=ge(e);return t.length>0&&f.info(m,`Synced connector skills to ${e}: [${t.join(", ")}]`),e}rebuildRuntime(e){if(this.stopped||this.active)return Promise.resolve();if(this.rebuildPromise)return this.rebuildPromise;const t=(async()=>{this.emit("pauseIntake","barrier"),this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="pending",this.pushToolbarMeta();try{await this.stopRuntime(!0),await this.ensureRuntime()}catch(i){f.warn(m,`${e} rebuild failed: ${this.redactError(i)}`)}finally{this.emit("resumeIntake","barrier")}})();return this.rebuildPromise=t.finally(()=>{this.rebuildPromise=null;const i=this.resolveDesiredSettings().revision;!this.stopped&&!this.active&&(this.personaDirty||this.applied&&this.applied.appliedRevision!==i)&&this.rebuildRuntime("coalesced_state_changed")}),this.rebuildPromise}async stopRuntime(e){const t=this.runtime;t&&(this.intentionalRuntimeStop=e,this.runtime=null,await t.shutdown().catch(()=>t.terminate()),this.capture?.close(),this.capture=null,this.intentionalRuntimeStop=!1)}onRuntimeExit(){this.intentionalRuntimeStop||this.stopped||(this.runtime=null,this.capture?.close(),this.capture=null,this.applied=void 0,this.contextWindow=null,this.reportedContextCapacity=null,this.settingsState="failed",this.settingsErrorCode="runtime_exited",this.pushToolbarMeta(),this.active&&this.finishActive("failed","Harness runtime exited; prompt was not replayed"),this.emit("exit",1))}onProtocolError(e){if(this.stopped||!this.runtime&&!this.active)return;const t=this.redactError(e,this.active?.inbound.content);this.clearPendingApprovals("unavailable"),this.contextWindow=null,this.reportedContextCapacity=null,this.settingsState="failed",this.settingsErrorCode="protocol_error",this.pushToolbarMeta();const i=this.runtime;this.runtime=null,this.intentionalRuntimeStop=!0,i?.client?.close(e),this.active&&this.finishActive("failed",`Harness protocol error: ${t}`),i?.terminate().finally(()=>{this.intentionalRuntimeStop=!1}),this.emit("exit",1)}async executeLocalAction(e){const t=e.params??{},i=String(t.session_id??"");if(!i||i!==this.options.aibotSessionId)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing"};if(["exec_approve","exec_reject","permission_approve","permission_reject"].includes(e.action_type)){const o=String(t.approval_command_id??t.approval_id??t.request_id??"").trim(),l=this.pendingApprovals.get(o);if(!l)return{status:"failed",errorCode:"unknown_or_expired_approval_id",errorMsg:"That DSH approval request is no longer pending"};clearTimeout(l.timer),this.pendingApprovals.delete(o);const c=e.action_type==="exec_approve"||e.action_type==="permission_approve";return l.resolve(c?"allowed-once":"rejected"),{status:"ok",result:{approval_id:o,decision:c?"allow-once":"deny"}}}if(e.action_type==="get_session_usage")return{status:"ok",result:{adapterType:"deepseek-harness",available:!0,dsh_profile:this.resolveSelectedProfile(),...this.usageStore().get(i)}};if(e.action_type==="get_rate_limits"){this.providerQuota=null,this.pushToolbarMeta();try{this.providerQuota=await this.callbacks.queryProviderQuota(!0)??{provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}catch(o){this.providerQuota={provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:this.redactError(o)}}return this.pushToolbarMeta(),{status:"ok",result:{sampledAt:new Date().toISOString(),contextWindow:this.contextWindow,providerQuota:this.providerQuota}}}if(e.action_type==="dsh_bridge_status"||e.action_type==="dsh_install_bridge"){if(this.resolveIntegrationMode()!=="profile_bridge")return{status:"unsupported",errorCode:"capability_unavailable",errorMsg:"Bridge management requires Profile Bridge mode"};if(this.active||this.runtime)return{status:"failed",errorCode:"worker_busy",errorMsg:"Stop the active DSH session before changing its Profile plugin"};try{const o=new A({command:"dsh",dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile()}),l=e.action_type==="dsh_install_bridge"?await o.install():await o.status();return this.runtimeReadiness=l.readiness,this.settingsErrorCode=l.readiness==="ready"?null:l.readiness,this.pushToolbarMeta(),{status:"ok",result:wt(l)}}catch(o){const l=String(o?.code??"bridge_install_failed");return this.runtimeReadiness=l,this.settingsErrorCode=l,this.pushToolbarMeta(),{status:"failed",errorCode:l,errorMsg:this.redactError(o)}}}if(e.action_type==="dsh_list_plugins"||e.action_type==="dsh_refresh_plugins"||e.action_type==="dsh_enable_plugin"||e.action_type==="dsh_disable_plugin")return this.executePluginAction(e.action_type,t,i);if(e.action_type==="dsh_list_skills"||e.action_type==="dsh_enable_skill"||e.action_type==="dsh_disable_skill")return this.executeSkillAction(e.action_type,t,i);const n={dsh_list_mcp:"mcp/list",dsh_list_tools:"tools/list",dsh_list_jobs:"jobs/list",dsh_list_goals:"goals/list"}[e.action_type];if(n){if(this.resolveIntegrationMode()!=="profile_bridge")return{status:"unsupported",errorCode:"capability_unavailable",errorMsg:"DSH resources require Profile Bridge mode"};if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot query DSH resources during an active turn"};try{return await this.ensureRuntimeWithRetry(),{status:"ok",result:await this.runtime?.client?.call(n,{cwd:this.options.bindingStore.get(i)?.cwd})}}catch(o){const l=String(o?.code??"resource_query_failed");return{status:l==="capability_unavailable"?"unsupported":"failed",errorCode:l,errorMsg:this.redactError(o)}}}if(e.action_type==="set_profile"||e.action_type==="create_profile"){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness Profile during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};let o;try{o=Ee(String(t.profile_id??t.dsh_profile??t.profile_name??t.name??""))}catch(c){return{status:"failed",errorCode:"profile_invalid",errorMsg:this.redactError(c)}}if(this.options.bindingStore.isDshProfileLocked(i)){const c=this.resolveSelectedProfile();return e.action_type==="create_profile"||c!==o?{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}:this.finishProfileSelection(o,!1)}if(e.action_type==="create_profile")try{const c=this.options.createDshProfile?await this.options.createDshProfile(o):await we({profileName:o,dshHome:this.options.dshHome??this.config.env?.DSH_HOME}),b=c.identity?.profileName??o;return this.persistSelectedProfile(b)?(await this.flushSelectedProfile(),this.finishProfileSelection(b,c.created)):{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}}catch(c){return{status:"failed",errorCode:String(c?.code??"profile_create_failed"),errorMsg:this.redactError(c)}}return this.listProfiles().some(c=>c.id===o)?this.persistSelectedProfile(o)?(await this.flushSelectedProfile(),this.finishProfileSelection(o,!1)):{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}:{status:"failed",errorCode:"profile_not_found",errorMsg:"Requested DSH profile is not in the local catalog"}}if(e.action_type==="set_preset"){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness settings during an active turn"};if(!this.options.bindingStore.get(i)?.cwd)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const l=String(t.agent_preset_id??t.preset_id??"").trim();if(!this.presets.some(b=>b.id===l))return{status:"failed",errorCode:"preset_not_found",errorMsg:"Requested agent preset is not in the Harness catalog"};const c=Z(this.resolveDesiredSettings().agentPreset,this.presets);return this.options.bindingStore.isDshAgentPresetLocked(i)?c===l?{status:"ok",result:this.presetActionResult(l,!0)}:{status:"failed",errorCode:"agent_preset_locked",errorMsg:"This conversation scene is locked after the session is created"}:c===l?(this.options.bindingStore.setDshAgentPreset(i,l),await this.persistGlobalToolbarDefaults({dshAgentPreset:l}),await this.options.bindingStore.flush(),this.pushToolbarMeta(),{status:"ok",result:this.presetActionResult(l,!1)}):this.options.bindingStore.setDshAgentPreset(i,l)?(await this.persistGlobalToolbarDefaults({dshAgentPreset:l}),await this.options.bindingStore.flush(),this.pushToolbarMeta(),{status:"ok",result:this.presetActionResult(l,!1)}):{status:"failed",errorCode:"agent_preset_locked",errorMsg:"This conversation scene is locked after the session is created"}}if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness settings during an active turn"};if(!this.options.bindingStore.get(i)?.cwd)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const d=this.resolveDesiredSettings();let r;if(e.action_type==="set_provider"){const o=String(t.provider_id??"").trim();if(!this.providers.some(l=>l.id===o))return{status:"failed",errorCode:"provider_not_found",errorMsg:"Requested provider is not in the Harness catalog"};r={providerId:o},o!==d.providerId&&(this.models=st(this.options.dataRoot,o),this.catalogProviderId=o,this.models.some(l=>l.id===d.modelId)||(r.modelId=this.models[0]?.id))}else if(e.action_type==="set_model"){const o=String(t.model_id??"").trim();if(!this.models.some(l=>l.id===o))return{status:"failed",errorCode:"model_not_found",errorMsg:"Requested model is not in the Harness catalog"};r={modelId:o}}else if(e.action_type==="set_thinking"){const o=q(t.thinking_mode??t.thinking);if(!o)return{status:"failed",errorCode:"thinking_invalid",errorMsg:"thinking_mode must be enabled or disabled"};r={thinking:o}}else if(e.action_type==="set_reasoning_effort"){const o=B(t.reasoning_effort??t.reasoningEffort);if(!o)return{status:"failed",errorCode:"reasoning_effort_invalid",errorMsg:"reasoning_effort must be high or max"};r={reasoningEffort:o}}else{const o=String(t.mode_id??"").trim();if(o!=="approval"&&o!=="full_auto")return{status:"failed",errorCode:"mode_invalid",errorMsg:"mode_id must be approval or full_auto"};r={modeId:o}}if((r.providerId===void 0||r.providerId===d.providerId)&&(r.modelId===void 0||r.modelId===d.modelId)&&(r.modeId===void 0||r.modeId===d.modeId)&&(r.thinking===void 0||r.thinking===d.thinking)&&(r.reasoningEffort===void 0||r.reasoningEffort===d.reasoningEffort)&&this.applied?.appliedRevision===d.revision)return{status:"ok",result:this.settingsActionResult(e.action_type,r,d.revision,"already_applied",!0)};const u=this.options.bindingStore.updateDshSettings(i,r)??d.revision;if(await this.options.bindingStore.flush(),(r.providerId||r.modelId||r.modeId||r.thinking||r.reasoningEffort)&&await this.persistGlobalToolbarDefaults({...r.providerId?{dshProviderId:r.providerId}:{},...r.modelId?{dshModelId:r.modelId}:{},...r.modeId?{dshModeId:r.modeId}:{},...r.thinking?{dshThinking:r.thinking}:{},...r.reasoningEffort?{dshReasoningEffort:r.reasoningEffort}:{}}),this.contextWindow=null,this.reportedContextCapacity=null,this.settingsErrorCode=null,this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!1)};if(this.active)return this.applied&&this.applied.appliedRevision>=u?(this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!0)}):(this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"pending",!0)});this.settingsState="pending",this.pushToolbarMeta();try{if(await this.rebuildRuntime("settings_changed"),!this.applied||this.applied.appliedRevision<u)throw new Error("new runtime did not apply requested revision");return this.refreshProviderQuota(!0),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!0)}}catch(o){return{status:"failed",result:this.settingsActionResult(e.action_type,r,u,"failed",!1,this.redactError(o)),errorCode:"settings_apply_failed",errorMsg:this.redactError(o)}}}async finishProfileSelection(e,t){if(this.resolveIntegrationMode()==="profile_bridge")try{await this.prepareSelectedProfile()}catch(i){const s=String(i?.code??"profile_start_failed");return this.runtimeReadiness=s,this.settingsErrorCode=s,this.pushToolbarMeta(),{status:"failed",errorCode:s,errorMsg:this.redactError(i)}}return this.pushToolbarMeta(),{status:"ok",result:this.profileActionResult(e,t)}}createBridgeInstaller(){const e=this.options.bridgeInstallerOptions??{};return new A({command:e.command??"dsh",dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile(),...e.tarballPath?{tarballPath:e.tarballPath}:{}})}async healBridgeUpdate(e){return e.readiness!=="bridge_update_required"||this.options.autoInstallBridge===!1?e:(f.info(m,`auto-updating stale Bridge profile=${e.identity.profileName} installed=${e.installedBridgeVersion??"none"} bundled=${e.bundledBridgeVersion}`),await this.prepareSelectedProfile(),this.attachSelectedProfile())}async ensureProfileReadyForChat(){if(!(this.options.autoInstallBridge!==!1||this.options.autoStartProfile!==!1)){const s=await this.attachSelectedProfile(),n=H(s);if(n)throw n;return}this.settingsState="pending",this.pushToolbarMeta(),await this.prepareSelectedProfile();let t=await this.attachSelectedProfile();t.readiness==="bridge_update_required"&&(t=await this.healBridgeUpdate(t));const i=H(t);if(i)throw i}async attachSelectedProfile(){const t=await this.createBridgeInstaller().status();return this.runtimeReadiness=t.readiness,this.profileDshVersion=t.runningDshVersion??t.dshVersion??null,this.settingsErrorCode=t.readiness==="ready"?null:t.readiness,t}async prepareSelectedProfile(){const e=this.createBridgeInstaller(),t=await qe({installer:e,autoInstall:this.options.autoInstallBridge!==!1,autoStart:this.options.autoStartProfile!==!1});this.runtimeReadiness=t.readiness,this.profileDshVersion=t.runningDshVersion??t.dshVersion??null,this.settingsErrorCode=t.readiness==="ready"?null:t.readiness}profileActionResult(e,t){return{outcome:t?"profile_created":"profile_set",profile_id:e,dsh_profile:e,created:t,dsh_profile_locked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),dsh_profile_create:!this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),available_profiles:this.listProfiles(),session_context:{dsh_profile:e,dsh_profile_locked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),dsh_profile_create:!this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId)}}}persistSelectedProfile(e){return this.options.bindingStore.setDshSelectedProfile(this.options.aibotSessionId,e)?(this.options.globalConfigStore?.set(this.options.agentName,{dshProfile:e}),!0):!1}async persistGlobalToolbarDefaults(e){this.options.globalConfigStore&&Object.values(e).some(t=>t!==void 0)&&(this.options.globalConfigStore.set(this.options.agentName,e),await this.options.globalConfigStore.flush())}seedSessionToolbarFromGlobal(){const e=this.options.aibotSessionId,t=this.options.bindingStore.get(e);if(!t?.cwd)return;const i=this.resolveDesiredSettings(),s={};t.dshProviderId||(s.providerId=i.providerId),t.dshModelId||(s.modelId=i.modelId),t.dshModeId||(s.modeId=i.modeId),t.dshThinking||(s.thinking=i.thinking),t.dshReasoningEffort||(s.reasoningEffort=i.reasoningEffort),Object.keys(s).length>0&&this.options.bindingStore.updateDshSettings(e,s),!this.options.bindingStore.getDshAgentPreset(e)&&i.agentPreset&&this.options.bindingStore.setDshAgentPreset(e,i.agentPreset),this.options.bindingStore.getDshSelectedProfile(e)||this.options.bindingStore.setDshSelectedProfile(e,this.resolveSelectedProfile())}async flushSelectedProfile(){await this.options.bindingStore.flush(),await this.options.globalConfigStore?.flush()}listProfiles(){return Me({dshHome:this.options.dshHome??this.config.env?.DSH_HOME})}pluginCommandContext(){return{dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile(),enabledPluginIds:this.options.bindingStore.getDshEnabledPlugins(this.options.aibotSessionId)}}skillCommandContext(){return{skillsDir:this.projectConnectorSkills(),enabledSkillIds:this.options.bindingStore.getDshEnabledSkills(this.options.aibotSessionId)}}currentPlugins(){try{return M(this.pluginCommandContext())}catch{return[]}}currentSkills(){return this.sessionSkillControlUnavailable()?[]:R(this.skillCommandContext())}pluginRestartRequired(){return!1}async executePluginAction(e,t,i){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek plugins during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const s=this.pluginCommandContext();try{if(e==="dsh_list_plugins"||e==="dsh_refresh_plugins"){const o=M(s);return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(o,!1)}}const n=String(t.name??t.plugin_name??"").trim(),a=this.options.bindingStore.getDshEnabledPlugins(i);let d=n;try{const{plugin:o}=Te({...s,name:n});d=o.name}catch(o){const l=String(o?.code??"");if(e!=="dsh_disable_plugin"||l!=="plugin_not_found"||!a.includes(n))throw o}const r=Pe(a,d,e==="dsh_enable_plugin"),p=this.options.bindingStore.setDshEnabledPlugins(i,r.pluginIds)??this.resolveDesiredSettings().revision;await this.options.bindingStore.flush();const u=M({...s,enabledPluginIds:r.pluginIds});if(!r.changed)return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!1,"skipped")};if(this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"skipped")};if(this.active)return this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"pending")};if(this.settingsState="pending",this.pushToolbarMeta(),await this.rebuildRuntime("plugin_changed"),!this.applied||this.applied.appliedRevision<p)throw new Error("new runtime did not apply requested plugin revision");return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"restarted")}}catch(n){return{status:"failed",errorCode:String(n?.code??"plugin_action_failed"),errorMsg:this.redactError(n)}}}async executeSkillAction(e,t,i){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek skills during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};if(this.sessionSkillControlUnavailable())return this.pushToolbarMeta(),{status:"unsupported",errorCode:"capability_unavailable",errorMsg:`DSH session skills require @deepseek-ai/dsh ${re} or newer`};const s=this.skillCommandContext();try{if(e==="dsh_list_skills"){const o=R(s);return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(o,!1)}}const n=String(t.name??t.skill_name??"").trim(),a=this.options.bindingStore.getDshEnabledSkills(i);let d=n;try{d=ye({...s,name:n}).name}catch(o){const l=String(o?.code??"");if(e!=="dsh_disable_skill"||l!=="skill_not_found"||!a.includes(n))throw o}const r=De(a,d,e==="dsh_enable_skill"),p=this.options.bindingStore.setDshEnabledSkills(i,r.skillIds)??this.resolveDesiredSettings().revision;await this.options.bindingStore.flush();const u=R({...s,enabledSkillIds:r.skillIds});if(!r.changed)return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!1,"skipped")};if(this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"skipped")};if(this.active)return this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"pending")};if(this.settingsState="pending",this.pushToolbarMeta(),await this.rebuildRuntime("skill_changed"),!this.applied||this.applied.appliedRevision<p)throw new Error("new runtime did not apply requested skill revision");return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"restarted")}}catch(n){return{status:"failed",errorCode:String(n?.code??"skill_action_failed"),errorMsg:this.redactError(n)}}}pluginActionResult(e,t,i="skipped"){const s=this.resolveSelectedProfile(),n=this.pluginRestartRequired();return{outcome:t?i==="restarted"?"plugin_applied":"plugin_updated":"plugin_unchanged",dsh_profile:s,dsh_plugins:e,dsh_plugin_restart_required:n,restart:i,session_context:{dsh_profile:s,dsh_plugins:e,dsh_plugin_restart_required:n}}}skillActionResult(e,t,i="skipped"){return{outcome:t?i==="restarted"?"skill_applied":"skill_updated":"skill_unchanged",dsh_skills:e,restart:i,session_context:{dsh_skills:e}}}resolveSelectedProfile(){const e=this.options.bindingStore.getDshSelectedProfile(this.options.aibotSessionId),t=He({binding:e,global:this.options.globalConfigStore?.get(this.options.agentName)?.dshProfile,adapter:this.options.dshProfile});return this.options.bindingStore.get(this.options.aibotSessionId)&&e!==t&&this.options.bindingStore.setDshSelectedProfile(this.options.aibotSessionId,t),t}profileDataDir(e=this.resolveSelectedProfile()){return Re(this.options.dataRoot,e)}usageStore(){const e=this.resolveSelectedProfile(),t=T(this.profileDataDir(e),"session-usage.json"),i=T(this.options.dataRoot,"session-usage.json");return!W(t)&&W(i)&&(ue(pe(t),{recursive:!0,mode:448}),ce(i,t)),dt(t)}presetActionResult(e,t){const i=this.resolveDesiredSettings();return{outcome:"preset_set",agentPreset:e,agent_preset_id:e,agent_preset_locked:t,available_presets:[...this.presets],session_context:{agent_preset_id:i.agentPreset??e,agent_preset_locked:t}}}settingsActionResult(e,t,i,s,n,a){const d=this.resolveDesiredSettings(),r=d.revision||i,p={provider_id:d.providerId,model_id:d.modelId,mode_id:d.modeId,thinking_mode:d.thinking,reasoning_effort:d.reasoningEffort,applied_provider_id:this.applied?.providerId??null,applied_model_id:this.applied?.modelId??null,applied_mode_id:this.applied?.modeId??null,applied_thinking_mode:this.applied?.thinking??null,applied_reasoning_effort:this.applied?.reasoningEffort??null,applied_settings_revision:this.applied?.appliedRevision??null,settings_state:this.settingsState,settings_revision:r};return e==="set_mode"&&(p.sandbox_mode=Y(d.modeId),p.approval_policy=d.modeId==="full_auto"?"never":"ask"),{outcome:`${e==="set_provider"?"provider":e==="set_model"?"model":e==="set_thinking"?"thinking":e==="set_reasoning_effort"?"reasoning_effort":"mode"}_set${s==="pending"||s==="failed"?"_pending":""}`,...t.providerId?{providerId:t.providerId,provider_id:t.providerId}:{},...t.modelId?{modelId:t.modelId,model_id:t.modelId}:{},...t.modeId?{modeId:t.modeId,mode_id:t.modeId,sandbox_mode:Y(t.modeId),approval_policy:t.modeId==="full_auto"?"never":"ask"}:{},...t.thinking?{thinking:t.thinking,thinking_mode:t.thinking}:{},...t.reasoningEffort?{reasoningEffort:t.reasoningEffort,reasoning_effort:t.reasoningEffort}:{},settingsRevision:r,settings_revision:r,sessionAlive:n,available_providers:[...this.providers],available_models:[...this.models],session_context:p,...a?{error:a}:{}}}hydrateCatalogFromCache(){const e=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),t=this.options.globalConfigStore?.get(this.options.agentName),i=nt({dataRoot:this.options.dataRoot,providerId:e?.providerId??t?.dshProviderId});this.providers=i.providers,this.models=this.options.models?.length?this.options.models:i.models,this.catalogProviderId=i.providerId}async persistCatalogCache(e){try{await ot({dataRoot:this.options.dataRoot,providers:this.providers,providerId:e,models:this.models})}catch(t){f.warn(m,`failed to persist DSH catalog cache: ${t instanceof Error?t.message:String(t)}`)}}async writeGrixProviderFile(){const e=Ae(this.options.dshHome??this.config.env?.DSH_HOME),t=await this.resolveCredentialsLayout(e);try{if(te(this.options.provider)){await gt(e,v,this.options.provider??{},t)==="skipped"&&f.warn(m,`Grix provider not written to DSH settings (user-owned "${v}" route or unreadable YAML); relay will not take effect`);return}await pt(e,v)}catch(i){f.warn(m,`Failed to sync Grix provider into DSH settings: ${this.redactError(i)}`)}}async resolveCredentialsLayout(e){let t=this.profileDshVersion;if(!t)try{t=await $e(this.options.bridgeInstallerOptions?.command??"dsh",e)}catch(s){f.warn(m,`could not read dsh version, assuming the current credentials layout: ${this.redactError(s)}`)}const i=ut(t);return St(t)&&f.warn(m,`dsh ${t} predates ${ae}: it drops the supportsDeveloperRole / maxTokensField switches, so relayed requests keep the OpenAI-style wire format and the gateway rejects them. Upgrade dsh to use the Grix relay.`),i}syncGrixProvider(){if(te(this.options.provider)){this.providers.some(s=>s.id===v)||(this.providers=[{id:v,displayName:"Grix"},...this.providers]);const e=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),t=this.options.globalConfigStore?.get(this.options.agentName),i=e?.providerId??t?.dshProviderId;(!i||i===$||i===v)&&this.options.bindingStore.updateDshSettings(this.options.aibotSessionId,{providerId:v});return}this.providers=this.providers.filter(e=>e.id!==v)}resolveDesiredSettings(){const e=this.options.bindingStore.get(this.options.aibotSessionId),t=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),i=this.options.globalConfigStore?.get(this.options.agentName),s=t?.providerId??i?.dshProviderId,n=this.providers.some(p=>p.id===v)?v:void 0,a=tt(s||n,this.providers),d=[t?.modelId,i?.dshModelId,this.options.defaultModel,this.models[0]?.id].find(p=>!!p&&this.models.some(u=>u.id===p))??"deepseek-chat",r=Z(t?.agentPreset??i?.dshAgentPreset,this.presets);return{providerId:a,modelId:d,modeId:et(e?.dshModeId,i?.dshModeId),thinking:q(t?.thinking)??q(i?.dshThinking)??Je,reasoningEffort:B(t?.reasoningEffort)??B(i?.dshReasoningEffort)??Xe,agentPreset:r,pluginIds:this.options.bindingStore.getDshEnabledPlugins(this.options.aibotSessionId),skillIds:this.options.bindingStore.getDshEnabledSkills(this.options.aibotSessionId),skillIdsExplicit:Array.isArray(e?.dshSkillIds),maxTokens:t?.maxTokens??this.options.maxTokens??ze,revision:t?.revision??0}}resolveIntegrationMode(){return this.options.integrationMode?this.options.integrationMode:(this.config.command||"").includes("dsh-jsonrpc-agent")?"embedded_jsonrpc":"profile_bridge"}sessionSkillControlUnavailable(){return this.resolveIntegrationMode()!=="profile_bridge"?!1:this.bridgeCapabilities&&typeof this.bridgeCapabilities=="object"?this.bridgeCapabilities.sessionSkillAllowlist!==!0:kt(this.profileDshVersion)}pushToolbarMeta(){const e=this.options.bindingStore.get(this.options.aibotSessionId);this.callbacks.sendUpdateBindingCard(this.options.aibotSessionId,this.stopped?"stopped":this.active?"busy":"ready",e?.cwd,Ge({desired:this.resolveDesiredSettings(),applied:this.applied,models:this.models,providers:this.providers,presets:this.presets,agentPresetLocked:this.options.bindingStore.isDshAgentPresetLocked(this.options.aibotSessionId),state:this.settingsState,errorCode:this.settingsErrorCode,contextWindow:this.contextWindow,providerQuota:this.providerQuota,integrationMode:this.resolveIntegrationMode(),profileName:this.resolveSelectedProfile(),profiles:this.listProfiles(),profileLocked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),plugins:this.currentPlugins(),skills:this.currentSkills(),pluginRestartRequired:this.pluginRestartRequired(),runtimeReadiness:this.runtimeReadiness,bridgeCapabilities:this.bridgeCapabilities}))}async refreshProviderQuota(e){this.providerQuota=null,this.pushToolbarMeta();try{this.providerQuota=await this.callbacks.queryProviderQuota(e)??{provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}catch{this.providerQuota={provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}this.pushToolbarMeta()}clearPendingApprovals(e){for(const t of this.pendingApprovals.values())clearTimeout(t.timer),t.resolve(e);this.pendingApprovals.clear()}thinkingEnabled(){const e=this.active?.inbound.connector_runtime_config?.thinking_events??this.active?.inbound.connector_runtime_config?.thinkingEvents;return e!=="off"&&e!=="hidden"&&e!=="none"}toolEventsEnabled(){const e=this.active?.inbound.connector_runtime_config?.tool_events;return e!=="off"&&e!=="hidden"&&e!=="none"}sendRaw(e,t,i){this.active&&this.callbacks.sendRawEventEnvelope(this.active.inbound.event_id,this.active.inbound.session_id,{type:e,payload:t},i)}failEvent(e,t){this.callbacks.sendEventResult(e.event_id,"failed",t),this.emit("eventDone",e.event_id)}startTimeout(e){this.activeTimeoutMs=e??this.options.promptTimeoutMs??ie,this.noteRuntimeActivity(),this.armTimeout(this.activeIdleTimeoutMs()),this.armHardTimeout(this.activeTimeoutMs)}touchActivity(e=1){!this.active||!this.timeoutTimer||(this.noteRuntimeActivity(),this.armTimeout(this.activeIdleTimeoutMs()))}noteRuntimeActivity(){this.active&&(this.active.lastRuntimeActivityAt=Date.now(),this.active.livenessExtendStartAt=void 0)}activeIdleTimeoutMs(){const e=this.options.activeIdleTimeoutMs??se,t=Number.isFinite(e)&&e>0?e:se;return Math.min(t,this.activeTimeoutMs)}livenessFreshMs(){const e=this.options.livenessFreshMs??ne;return Number.isFinite(e)&&e>0?e:ne}livenessMaxExtendMs(){const e=this.options.livenessMaxExtendMs??oe;return Number.isFinite(e)&&e>0?e:oe}armTimeout(e){this.clearIdleTimeout(),this.timeoutTimer=setTimeout(()=>{this.handlePromptTimeout()},e),this.timeoutTimer.unref?.()}armHardTimeout(e){this.clearHardTimeout(),this.hardTimeoutTimer=setTimeout(()=>{this.handlePromptHardTimeout()},e),this.hardTimeoutTimer.unref?.()}async handlePromptTimeout(){const e=this.active;if(e){if(this.pendingApprovals.size>0){f.info(m,`Idle timeout skipped: pendingApprovals=${this.pendingApprovals.size} event=${e.inbound.event_id}`),this.armTimeout(this.activeIdleTimeoutMs());return}if(this.shouldExtendByLiveness(e.inbound.event_id)){this.armTimeout(this.activeIdleTimeoutMs());return}await this.failActiveTimeout("idle","Harness prompt idle timeout and the runtime was terminated")}}async handlePromptHardTimeout(){const e=this.active;if(e&&this.shouldExtendByLiveness(e.inbound.event_id)){this.armHardTimeout(this.activeTimeoutMs);return}await this.failActiveTimeout("hard","Harness prompt exceeded max duration and the runtime was terminated")}shouldExtendByLiveness(e){const t=this.active;if(!t||t.inbound.event_id!==e||!this.runtime?.isConnected()||!(!t.turnEnded&&(!!t.messageId||t.admitted||t.claimed)))return!1;const s=Date.now(),n=t.lastRuntimeActivityAt??t.startedAt,a=Math.max(0,s-n);if(a<this.livenessFreshMs())return t.livenessExtendStartAt=s,f.info(m,`Liveness check: recent DSH activity for ${e} (quietMs=${a}), extending`),!0;const d=t.livenessExtendStartAt??n;t.livenessExtendStartAt=d;const r=s-d;return r>this.livenessMaxExtendMs()?(f.warn(m,`Liveness extension budget exhausted for ${e} (quietMs=${a}, extendMs=${r}), allowing close`),!1):(f.info(m,`Liveness check: DSH turn still open for ${e} (claimed=${t.claimed}, turnEnded=${t.turnEnded}, quietMs=${a}), extending`),!0)}async failActiveTimeout(e,t){if(!this.active)return;const i=this.active;this.clearTimeout();const s=this.runtime;this.runtime=null,this.intentionalRuntimeStop=!0,this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="applied",this.settingsErrorCode=null,this.pushToolbarMeta(),await s?.cancel(this.runtimeSessionId).catch(()=>{}),s&&await s.shutdown().catch(()=>s.terminate()),this.intentionalRuntimeStop=!1,!(this.active!==i||this.stopped)&&(f.error(m,`Active DSH turn ${e} timeout: ${i.inbound.event_id}`),this.finishActive("failed",t),this.emit("exit",1))}clearTimeout(){this.clearIdleTimeout(),this.clearHardTimeout()}clearIdleTimeout(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),this.timeoutTimer=null}clearHardTimeout(){this.hardTimeoutTimer&&clearTimeout(this.hardTimeoutTimer),this.hardTimeoutTimer=null}redactError(e,t){let i=e instanceof Error?e.message:String(e);const s=this.config.env?.DEEPSEEK_API_KEY;return s&&(i=i.split(s).join("[REDACTED]")),i=i.replace(/(api[_-]?key|authorization|bearer)\s*[:=]\s*\S+/gi,"$1=[REDACTED]"),t&&t.length>=16&&i.includes(t)&&(i="Harness request failed (prompt echo redacted)"),(i.includes("[aibot-system-prompt]")||i.includes("[base-behavior]"))&&(i="Harness runtime failed (system prompt echo redacted)"),i.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g,"").slice(0,2e3)}}function mt(h){const e=Number(h&&typeof h=="object"?h.cursor:0);return Number.isSafeInteger(e)&&e>0?e:0}function vt(h){return new Promise(e=>setTimeout(e,h))}function bt(h,e){return`grix-${E("sha256").update(h).digest("hex").slice(0,12)}-${e}-${x().slice(0,8)}`}function _t(h){return`grix-${E("sha256").update(h).digest("hex").slice(0,16)}-${x().slice(0,8)}`}function de(){return{inputTokens:0,outputTokens:0,cacheReadInputTokens:0,cacheCreationInputTokens:0,reasoningTokens:0}}function St(h){const e=X(h,ae);return e!==null&&e<0}function kt(h){const e=X(h,re);return e!==null&&e<0}function le(h){const e=h.data?.chunk&&typeof h.data.chunk=="object"?h.data.chunk:h.data;return String(e?.type??"")}function It(h){return h.type==="assistant/chunk:tool-call-delta"||h.type==="assistant/chunk"&&le(h)==="tool-call-delta"}function wt(h){return{readiness:h.readiness,profile:h.identity.profileName,dshVersion:h.dshVersion,runningDshVersion:h.runningDshVersion,installedBridgeVersion:h.installedBridgeVersion,bundledBridgeVersion:h.bundledBridgeVersion,runningBridgeVersion:h.runningBridgeVersion,endpointCount:h.endpointCount,requiresProfileRestart:h.readiness==="profile_restart_required"}}const Tt=new Set(["turn/start","step/start","step/end","agent/inbox/spliced","user/message","request/header","session/title","session/title-llm-request","session/end-seed","web/deepseek-search-llm-request","assistant/chunk:tool-call-delta","permission/preset","sandbox/mode","approval/policy","approval/asked","approval/decided","plan/mode","agent-preset/selected","llm/retry","llm/retry-started","goal/change","schedule/change","feedback/record","hook/invoked","hook/result","command/run","command/done","subagent/descriptor","tool-workflow/agent-start","tool-workflow/agent-end","tool-workflow/run-start","tool-workflow/run-end","tool/code-dispatch","tool/code-dispatch-start"]);function Pt(h){const e=le(h);return Tt.has(h.type)||h.type==="assistant/chunk"&&["block-start","block-end","tool-call-delta","finish"].includes(e)}export{ai as DshJsonRpcAdapter};
3
+ Error: ${n}`,this.flushVisibleText(!1,{finalizeDsml:!0})),s==="responded"&&this.activeUsageSeq>=0&&(this.usageStore().commit(i.inbound.session_id,this.runtimeSessionId,this.activeUsageSeq,this.applied?.modelId??this.resolveDesiredSettings().modelId,this.activeUsage),this.usageStore().flush()),i.inbound.audit?.enabled&&this.capture&&this.auditBoundaries.set(i.inbound.event_id,this.capture.boundary({runtimeSessionId:this.runtimeSessionId,rootSessionId:this.runtimeSessionId,startOffset:this.activeWireStart,turn:i.turn,messageId:i.messageId}));const d=this.personaDirty&&!!this.runtime,r=!!this.runtime&&!!this.applied&&this.applied.appliedRevision!==this.resolveDesiredSettings().revision;d&&this.emit("pauseIntake","barrier"),this.active=null,this.correlator=null;const p=`${i.inbound.event_id}-dsh`,u=(o,l,c=!1)=>{this.callbacks.sendEventResult(i.inbound.event_id,o,l,c),this.emit("eventDone",i.inbound.event_id),d?this.rebuildRuntime("persona_changed"):r&&this.rebuildRuntime("settings_changed")};if(i.repliedViaTool&&i.seq===0){this.flushPendingFinalBridgeAck(!0).then(()=>u(s,n,a),()=>u(s,n,a));return}this.callbacks.sendFinalStreamChunkReliable(i.inbound.event_id,i.inbound.session_id,p).then(async()=>{await this.flushPendingFinalBridgeAck(!0),u(s,n,a)},async o=>{await this.flushPendingFinalBridgeAck(!1),u(s==="responded"?"failed":s,s==="responded"?`Final output delivery failed: ${this.redactError(o,i.inbound.content)}`:n)})}advanceBridgeAck(e,t){if(!(e<=0)){if(t||this.finishingTurn||this.pendingFinalBridgeAck!==null){this.pendingFinalBridgeAck=Math.max(this.pendingFinalBridgeAck??0,e);return}this.ackBridgeCursor(e)}}async flushPendingFinalBridgeAck(e){const t=this.pendingFinalBridgeAck;this.pendingFinalBridgeAck=null,this.finishingTurn=!1,!(!e||t===null)&&await this.ackBridgeCursor(t)}async ackBridgeCursor(e){if(e<=this.bridgeAckCursor)return;const t=this.runtime?.client?.ack;if(!t){this.bridgeAckCursor=Math.max(this.bridgeAckCursor,e);return}try{await t.call(this.runtime.client,e),this.bridgeAckCursor=Math.max(this.bridgeAckCursor,e)}catch(i){this.onProtocolError(i instanceof Error?i:new Error(String(i)))}}async cancelActive(e){this.active&&(this.cancelRequested=!0,this.clearPendingApprovals("cancelled"),this.resolveIntegrationMode()==="embedded_jsonrpc"?(this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="applied",this.pushToolbarMeta(),this.runtimeStartPromise&&this.runtime&&await this.runtime.terminate().catch(()=>{}),await this.runtimeStartPromise?.catch(()=>{}),await this.stopRuntime(!0)):(await this.runtimeStartPromise?.catch(()=>{}),await this.runtime?.cancel(this.runtimeSessionId).catch(()=>{}),this.runtime&&!this.runtime.isConnected()&&await this.stopRuntime(!0)),this.finishActive("canceled",e))}async handleBridgeApproval(e){const t=this.permissionHandler,i=String(e.interactionId??e.callId??x());if(t)try{return await t({adapterSessionId:this.options.aibotSessionId,requestId:i,description:String(e.reason??`Allow ${String(e.toolName??"operation")}?`),options:[{id:"allow_once",label:"Allow once",isAllow:!0},{id:"reject",label:"Reject",isAllow:!1}]})==="allow_once"?"allowed-once":"rejected"}catch{return"cancelled"}const s=this.active;return s?(this.callbacks.sendPermissionCard({eventId:s.inbound.event_id,sessionId:s.inbound.session_id,approvalId:i,toolName:String(e.toolName??"operation"),toolTitle:String(e.reason??`Allow ${String(e.toolName??"operation")}?`)}),new Promise(n=>{const a=setTimeout(()=>{this.pendingApprovals.delete(i),n("unavailable")},3e5);a.unref?.(),this.pendingApprovals.set(i,{resolve:n,timer:a})})):"unavailable"}async invokeGrixTool(e,t,i){if(!ct(e))throw Object.assign(new Error(`grix tool "${e}" is not exposed to DSH`),{code:"capability_unavailable"});if(ht(e)){if(!this.callbacks.eventToolInvoke)throw Object.assign(new Error(`grix event tool "${e}" has no connector-side runner`),{code:"capability_unavailable"});const n=this.active,a=await this.callbacks.eventToolInvoke(e,t);if(e==="grix_reply"&&n){const d=String(t.session_id??"").trim();(!d||d===n.inbound.session_id)&&(n.repliedViaTool=!0)}return a}if(!this.callbacks.agentInvoke)throw Object.assign(new Error(`grix tool "${e}" has no connector-side action runner`),{code:"capability_unavailable"});const s=lt(e,t);return this.callbacks.agentInvoke(s.action,s.params,i??s.timeoutMs)}projectConnectorSkills(){const e=T(this.options.dataRoot,"dsh-session-skills"),t=ge(e);return t.length>0&&f.info(m,`Synced connector skills to ${e}: [${t.join(", ")}]`),e}rebuildRuntime(e){if(this.stopped||this.active)return Promise.resolve();if(this.rebuildPromise)return this.rebuildPromise;const t=(async()=>{this.emit("pauseIntake","barrier"),this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="pending",this.pushToolbarMeta();try{await this.stopRuntime(!0),await this.ensureRuntime()}catch(i){f.warn(m,`${e} rebuild failed: ${this.redactError(i)}`)}finally{this.emit("resumeIntake","barrier")}})();return this.rebuildPromise=t.finally(()=>{this.rebuildPromise=null;const i=this.resolveDesiredSettings().revision;!this.stopped&&!this.active&&(this.personaDirty||this.applied&&this.applied.appliedRevision!==i)&&this.rebuildRuntime("coalesced_state_changed")}),this.rebuildPromise}async stopRuntime(e){const t=this.runtime;t&&(this.intentionalRuntimeStop=e,this.runtime=null,await t.shutdown().catch(()=>t.terminate()),this.capture?.close(),this.capture=null,this.intentionalRuntimeStop=!1)}onRuntimeExit(){this.intentionalRuntimeStop||this.stopped||(this.runtime=null,this.capture?.close(),this.capture=null,this.applied=void 0,this.contextWindow=null,this.reportedContextCapacity=null,this.settingsState="failed",this.settingsErrorCode="runtime_exited",this.pushToolbarMeta(),this.active&&this.finishActive("failed","Harness runtime exited; prompt was not replayed"),this.emit("exit",1))}onProtocolError(e){if(this.stopped||!this.runtime&&!this.active)return;const t=this.redactError(e,this.active?.inbound.content);this.clearPendingApprovals("unavailable"),this.contextWindow=null,this.reportedContextCapacity=null,this.settingsState="failed",this.settingsErrorCode="protocol_error",this.pushToolbarMeta();const i=this.runtime;this.runtime=null,this.intentionalRuntimeStop=!0,i?.client?.close(e),this.active&&this.finishActive("failed",`Harness protocol error: ${t}`),i?.terminate().finally(()=>{this.intentionalRuntimeStop=!1}),this.emit("exit",1)}async executeLocalAction(e){const t=e.params??{},i=String(t.session_id??"");if(!i||i!==this.options.aibotSessionId)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing"};if(["exec_approve","exec_reject","permission_approve","permission_reject"].includes(e.action_type)){const o=String(t.approval_command_id??t.approval_id??t.request_id??"").trim(),l=this.pendingApprovals.get(o);if(!l)return{status:"failed",errorCode:"unknown_or_expired_approval_id",errorMsg:"That DSH approval request is no longer pending"};clearTimeout(l.timer),this.pendingApprovals.delete(o);const c=e.action_type==="exec_approve"||e.action_type==="permission_approve";return l.resolve(c?"allowed-once":"rejected"),{status:"ok",result:{approval_id:o,decision:c?"allow-once":"deny"}}}if(e.action_type==="get_session_usage")return{status:"ok",result:{adapterType:"deepseek-harness",available:!0,dsh_profile:this.resolveSelectedProfile(),...this.usageStore().get(i)}};if(e.action_type==="get_rate_limits"){this.providerQuota=null,this.pushToolbarMeta();try{this.providerQuota=await this.callbacks.queryProviderQuota(!0)??{provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}catch(o){this.providerQuota={provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:this.redactError(o)}}return this.pushToolbarMeta(),{status:"ok",result:{sampledAt:new Date().toISOString(),contextWindow:this.contextWindow,providerQuota:this.providerQuota}}}if(e.action_type==="dsh_bridge_status"||e.action_type==="dsh_install_bridge"){if(this.resolveIntegrationMode()!=="profile_bridge")return{status:"unsupported",errorCode:"capability_unavailable",errorMsg:"Bridge management requires Profile Bridge mode"};if(this.active||this.runtime)return{status:"failed",errorCode:"worker_busy",errorMsg:"Stop the active DSH session before changing its Profile plugin"};try{const o=new A({command:"dsh",dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile()}),l=e.action_type==="dsh_install_bridge"?await o.install():await o.status();return this.runtimeReadiness=l.readiness,this.settingsErrorCode=l.readiness==="ready"?null:l.readiness,this.pushToolbarMeta(),{status:"ok",result:wt(l)}}catch(o){const l=String(o?.code??"bridge_install_failed");return this.runtimeReadiness=l,this.settingsErrorCode=l,this.pushToolbarMeta(),{status:"failed",errorCode:l,errorMsg:this.redactError(o)}}}if(e.action_type==="dsh_list_plugins"||e.action_type==="dsh_refresh_plugins"||e.action_type==="dsh_enable_plugin"||e.action_type==="dsh_disable_plugin")return this.executePluginAction(e.action_type,t,i);if(e.action_type==="dsh_list_skills"||e.action_type==="dsh_enable_skill"||e.action_type==="dsh_disable_skill")return this.executeSkillAction(e.action_type,t,i);const n={dsh_list_mcp:"mcp/list",dsh_list_tools:"tools/list",dsh_list_jobs:"jobs/list",dsh_list_goals:"goals/list"}[e.action_type];if(n){if(this.resolveIntegrationMode()!=="profile_bridge")return{status:"unsupported",errorCode:"capability_unavailable",errorMsg:"DSH resources require Profile Bridge mode"};if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot query DSH resources during an active turn"};try{return await this.ensureRuntimeWithRetry(),{status:"ok",result:await this.runtime?.client?.call(n,{cwd:this.options.bindingStore.get(i)?.cwd})}}catch(o){const l=String(o?.code??"resource_query_failed");return{status:l==="capability_unavailable"?"unsupported":"failed",errorCode:l,errorMsg:this.redactError(o)}}}if(e.action_type==="set_profile"||e.action_type==="create_profile"){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness Profile during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};let o;try{o=Ee(String(t.profile_id??t.dsh_profile??t.profile_name??t.name??""))}catch(c){return{status:"failed",errorCode:"profile_invalid",errorMsg:this.redactError(c)}}if(this.options.bindingStore.isDshProfileLocked(i)){const c=this.resolveSelectedProfile();return e.action_type==="create_profile"||c!==o?{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}:this.finishProfileSelection(o,!1)}if(e.action_type==="create_profile")try{const c=this.options.createDshProfile?await this.options.createDshProfile(o):await we({profileName:o,dshHome:this.options.dshHome??this.config.env?.DSH_HOME}),b=c.identity?.profileName??o;return this.persistSelectedProfile(b)?(await this.flushSelectedProfile(),this.finishProfileSelection(b,c.created)):{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}}catch(c){return{status:"failed",errorCode:String(c?.code??"profile_create_failed"),errorMsg:this.redactError(c)}}return this.listProfiles().some(c=>c.id===o)?this.persistSelectedProfile(o)?(await this.flushSelectedProfile(),this.finishProfileSelection(o,!1)):{status:"failed",errorCode:"profile_locked",errorMsg:"This conversation Profile is locked after the session is created"}:{status:"failed",errorCode:"profile_not_found",errorMsg:"Requested DSH profile is not in the local catalog"}}if(e.action_type==="set_preset"){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness settings during an active turn"};if(!this.options.bindingStore.get(i)?.cwd)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const l=String(t.agent_preset_id??t.preset_id??"").trim();if(!this.presets.some(b=>b.id===l))return{status:"failed",errorCode:"preset_not_found",errorMsg:"Requested agent preset is not in the Harness catalog"};const c=Z(this.resolveDesiredSettings().agentPreset,this.presets);return this.options.bindingStore.isDshAgentPresetLocked(i)?c===l?{status:"ok",result:this.presetActionResult(l,!0)}:{status:"failed",errorCode:"agent_preset_locked",errorMsg:"This conversation scene is locked after the session is created"}:c===l?(this.options.bindingStore.setDshAgentPreset(i,l),await this.persistGlobalToolbarDefaults({dshAgentPreset:l}),await this.options.bindingStore.flush(),this.pushToolbarMeta(),{status:"ok",result:this.presetActionResult(l,!1)}):this.options.bindingStore.setDshAgentPreset(i,l)?(await this.persistGlobalToolbarDefaults({dshAgentPreset:l}),await this.options.bindingStore.flush(),this.pushToolbarMeta(),{status:"ok",result:this.presetActionResult(l,!1)}):{status:"failed",errorCode:"agent_preset_locked",errorMsg:"This conversation scene is locked after the session is created"}}if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek Harness settings during an active turn"};if(!this.options.bindingStore.get(i)?.cwd)return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const d=this.resolveDesiredSettings();let r;if(e.action_type==="set_provider"){const o=String(t.provider_id??"").trim();if(!this.providers.some(l=>l.id===o))return{status:"failed",errorCode:"provider_not_found",errorMsg:"Requested provider is not in the Harness catalog"};r={providerId:o},o!==d.providerId&&(this.models=st(this.options.dataRoot,o),this.catalogProviderId=o,this.models.some(l=>l.id===d.modelId)||(r.modelId=this.models[0]?.id))}else if(e.action_type==="set_model"){const o=String(t.model_id??"").trim();if(!this.models.some(l=>l.id===o))return{status:"failed",errorCode:"model_not_found",errorMsg:"Requested model is not in the Harness catalog"};r={modelId:o}}else if(e.action_type==="set_thinking"){const o=q(t.thinking_mode??t.thinking);if(!o)return{status:"failed",errorCode:"thinking_invalid",errorMsg:"thinking_mode must be enabled or disabled"};r={thinking:o}}else if(e.action_type==="set_reasoning_effort"){const o=B(t.reasoning_effort??t.reasoningEffort);if(!o)return{status:"failed",errorCode:"reasoning_effort_invalid",errorMsg:"reasoning_effort must be high or max"};r={reasoningEffort:o}}else{const o=String(t.mode_id??"").trim();if(o!=="approval"&&o!=="full_auto")return{status:"failed",errorCode:"mode_invalid",errorMsg:"mode_id must be approval or full_auto"};r={modeId:o}}if((r.providerId===void 0||r.providerId===d.providerId)&&(r.modelId===void 0||r.modelId===d.modelId)&&(r.modeId===void 0||r.modeId===d.modeId)&&(r.thinking===void 0||r.thinking===d.thinking)&&(r.reasoningEffort===void 0||r.reasoningEffort===d.reasoningEffort)&&this.applied?.appliedRevision===d.revision)return{status:"ok",result:this.settingsActionResult(e.action_type,r,d.revision,"already_applied",!0)};const u=this.options.bindingStore.updateDshSettings(i,r)??d.revision;if(await this.options.bindingStore.flush(),(r.providerId||r.modelId||r.modeId||r.thinking||r.reasoningEffort)&&await this.persistGlobalToolbarDefaults({...r.providerId?{dshProviderId:r.providerId}:{},...r.modelId?{dshModelId:r.modelId}:{},...r.modeId?{dshModeId:r.modeId}:{},...r.thinking?{dshThinking:r.thinking}:{},...r.reasoningEffort?{dshReasoningEffort:r.reasoningEffort}:{}}),this.contextWindow=null,this.reportedContextCapacity=null,this.settingsErrorCode=null,this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!1)};if(this.active)return this.applied&&this.applied.appliedRevision>=u?(this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!0)}):(this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"pending",!0)});this.settingsState="pending",this.pushToolbarMeta();try{if(await this.rebuildRuntime("settings_changed"),!this.applied||this.applied.appliedRevision<u)throw new Error("new runtime did not apply requested revision");return this.refreshProviderQuota(!0),{status:"ok",result:this.settingsActionResult(e.action_type,r,u,"applied",!0)}}catch(o){return{status:"failed",result:this.settingsActionResult(e.action_type,r,u,"failed",!1,this.redactError(o)),errorCode:"settings_apply_failed",errorMsg:this.redactError(o)}}}async finishProfileSelection(e,t){if(this.resolveIntegrationMode()==="profile_bridge")try{await this.prepareSelectedProfile()}catch(i){const s=String(i?.code??"profile_start_failed");return this.runtimeReadiness=s,this.settingsErrorCode=s,this.pushToolbarMeta(),{status:"failed",errorCode:s,errorMsg:this.redactError(i)}}return this.pushToolbarMeta(),{status:"ok",result:this.profileActionResult(e,t)}}createBridgeInstaller(){const e=this.options.bridgeInstallerOptions??{};return new A({command:e.command??"dsh",dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile(),...e.tarballPath?{tarballPath:e.tarballPath}:{}})}async healBridgeUpdate(e){return e.readiness!=="bridge_update_required"||this.options.autoInstallBridge===!1?e:(f.info(m,`auto-updating stale Bridge profile=${e.identity.profileName} installed=${e.installedBridgeVersion??"none"} bundled=${e.bundledBridgeVersion}`),await this.prepareSelectedProfile(),this.attachSelectedProfile())}async ensureProfileReadyForChat(){if(!(this.options.autoInstallBridge!==!1||this.options.autoStartProfile!==!1)){const s=await this.attachSelectedProfile(),n=H(s);if(n)throw n;return}this.settingsState="pending",this.pushToolbarMeta(),await this.prepareSelectedProfile();let t=await this.attachSelectedProfile();t.readiness==="bridge_update_required"&&(t=await this.healBridgeUpdate(t));const i=H(t);if(i)throw i}async attachSelectedProfile(){const t=await this.createBridgeInstaller().status();return this.runtimeReadiness=t.readiness,this.profileDshVersion=t.runningDshVersion??t.dshVersion??null,this.settingsErrorCode=t.readiness==="ready"?null:t.readiness,t}async prepareSelectedProfile(){const e=this.createBridgeInstaller(),t=await qe({installer:e,autoInstall:this.options.autoInstallBridge!==!1,autoStart:this.options.autoStartProfile!==!1});this.runtimeReadiness=t.readiness,this.profileDshVersion=t.runningDshVersion??t.dshVersion??null,this.settingsErrorCode=t.readiness==="ready"?null:t.readiness}profileActionResult(e,t){return{outcome:t?"profile_created":"profile_set",profile_id:e,dsh_profile:e,created:t,dsh_profile_locked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),dsh_profile_create:!this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),available_profiles:this.listProfiles(),session_context:{dsh_profile:e,dsh_profile_locked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),dsh_profile_create:!this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId)}}}persistSelectedProfile(e){return this.options.bindingStore.setDshSelectedProfile(this.options.aibotSessionId,e)?(this.options.globalConfigStore?.set(this.options.agentName,{dshProfile:e}),!0):!1}async persistGlobalToolbarDefaults(e){this.options.globalConfigStore&&Object.values(e).some(t=>t!==void 0)&&(this.options.globalConfigStore.set(this.options.agentName,e),await this.options.globalConfigStore.flush())}seedSessionToolbarFromGlobal(){const e=this.options.aibotSessionId,t=this.options.bindingStore.get(e);if(!t?.cwd)return;const i=this.resolveDesiredSettings(),s={};t.dshProviderId||(s.providerId=i.providerId),t.dshModelId||(s.modelId=i.modelId),t.dshModeId||(s.modeId=i.modeId),t.dshThinking||(s.thinking=i.thinking),t.dshReasoningEffort||(s.reasoningEffort=i.reasoningEffort),Object.keys(s).length>0&&this.options.bindingStore.updateDshSettings(e,s),!this.options.bindingStore.getDshAgentPreset(e)&&i.agentPreset&&this.options.bindingStore.setDshAgentPreset(e,i.agentPreset),this.options.bindingStore.getDshSelectedProfile(e)||this.options.bindingStore.setDshSelectedProfile(e,this.resolveSelectedProfile())}async flushSelectedProfile(){await this.options.bindingStore.flush(),await this.options.globalConfigStore?.flush()}listProfiles(){return Me({dshHome:this.options.dshHome??this.config.env?.DSH_HOME})}pluginCommandContext(){return{dshHome:this.options.dshHome??this.config.env?.DSH_HOME,profileName:this.resolveSelectedProfile(),enabledPluginIds:this.options.bindingStore.getDshEnabledPlugins(this.options.aibotSessionId)}}skillCommandContext(){return{skillsDir:this.projectConnectorSkills(),enabledSkillIds:this.options.bindingStore.getDshEnabledSkills(this.options.aibotSessionId)}}currentPlugins(){try{return M(this.pluginCommandContext())}catch{return[]}}currentSkills(){return this.sessionSkillControlUnavailable()?[]:R(this.skillCommandContext())}pluginRestartRequired(){return!1}async executePluginAction(e,t,i){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek plugins during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};const s=this.pluginCommandContext();try{if(e==="dsh_list_plugins"||e==="dsh_refresh_plugins"){const o=M(s);return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(o,!1)}}const n=String(t.name??t.plugin_name??"").trim(),a=this.options.bindingStore.getDshEnabledPlugins(i);let d=n;try{const{plugin:o}=Te({...s,name:n});d=o.name}catch(o){const l=String(o?.code??"");if(e!=="dsh_disable_plugin"||l!=="plugin_not_found"||!a.includes(n))throw o}const r=Pe(a,d,e==="dsh_enable_plugin"),p=this.options.bindingStore.setDshEnabledPlugins(i,r.pluginIds)??this.resolveDesiredSettings().revision;await this.options.bindingStore.flush();const u=M({...s,enabledPluginIds:r.pluginIds});if(!r.changed)return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!1,"skipped")};if(this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"skipped")};if(this.active)return this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"pending")};if(this.settingsState="pending",this.pushToolbarMeta(),await this.rebuildRuntime("plugin_changed"),!this.applied||this.applied.appliedRevision<p)throw new Error("new runtime did not apply requested plugin revision");return this.pushToolbarMeta(),{status:"ok",result:this.pluginActionResult(u,!0,"restarted")}}catch(n){return{status:"failed",errorCode:String(n?.code??"plugin_action_failed"),errorMsg:this.redactError(n)}}}async executeSkillAction(e,t,i){if(this.active)return{status:"failed",errorCode:"worker_busy",errorMsg:"Cannot change DeepSeek skills during an active turn"};if(!this.options.bindingStore.get(i))return{status:"failed",errorCode:"binding_missing",errorMsg:"Session binding missing. Open a workspace first."};if(this.sessionSkillControlUnavailable())return this.pushToolbarMeta(),{status:"unsupported",errorCode:"capability_unavailable",errorMsg:`DSH session skills require @deepseek-ai/dsh ${re} or newer`};const s=this.skillCommandContext();try{if(e==="dsh_list_skills"){const o=R(s);return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(o,!1)}}const n=String(t.name??t.skill_name??"").trim(),a=this.options.bindingStore.getDshEnabledSkills(i);let d=n;try{d=ye({...s,name:n}).name}catch(o){const l=String(o?.code??"");if(e!=="dsh_disable_skill"||l!=="skill_not_found"||!a.includes(n))throw o}const r=De(a,d,e==="dsh_enable_skill"),p=this.options.bindingStore.setDshEnabledSkills(i,r.skillIds)??this.resolveDesiredSettings().revision;await this.options.bindingStore.flush();const u=R({...s,enabledSkillIds:r.skillIds});if(!r.changed)return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!1,"skipped")};if(this.runtimeStartPromise&&await this.runtimeStartPromise.catch(()=>{}),!this.runtime)return this.settingsState="applied",this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"skipped")};if(this.active)return this.settingsState="pending",this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"pending")};if(this.settingsState="pending",this.pushToolbarMeta(),await this.rebuildRuntime("skill_changed"),!this.applied||this.applied.appliedRevision<p)throw new Error("new runtime did not apply requested skill revision");return this.pushToolbarMeta(),{status:"ok",result:this.skillActionResult(u,!0,"restarted")}}catch(n){return{status:"failed",errorCode:String(n?.code??"skill_action_failed"),errorMsg:this.redactError(n)}}}pluginActionResult(e,t,i="skipped"){const s=this.resolveSelectedProfile(),n=this.pluginRestartRequired();return{outcome:t?i==="restarted"?"plugin_applied":"plugin_updated":"plugin_unchanged",dsh_profile:s,dsh_plugins:e,dsh_plugin_restart_required:n,restart:i,session_context:{dsh_profile:s,dsh_plugins:e,dsh_plugin_restart_required:n}}}skillActionResult(e,t,i="skipped"){return{outcome:t?i==="restarted"?"skill_applied":"skill_updated":"skill_unchanged",dsh_skills:e,restart:i,session_context:{dsh_skills:e}}}resolveSelectedProfile(){const e=this.options.bindingStore.getDshSelectedProfile(this.options.aibotSessionId),t=He({binding:e,global:this.options.globalConfigStore?.get(this.options.agentName)?.dshProfile,adapter:this.options.dshProfile});return this.options.bindingStore.get(this.options.aibotSessionId)&&e!==t&&this.options.bindingStore.setDshSelectedProfile(this.options.aibotSessionId,t),t}profileDataDir(e=this.resolveSelectedProfile()){return Re(this.options.dataRoot,e)}usageStore(){const e=this.resolveSelectedProfile(),t=T(this.profileDataDir(e),"session-usage.json"),i=T(this.options.dataRoot,"session-usage.json");return!W(t)&&W(i)&&(ue(pe(t),{recursive:!0,mode:448}),ce(i,t)),dt(t)}presetActionResult(e,t){const i=this.resolveDesiredSettings();return{outcome:"preset_set",agentPreset:e,agent_preset_id:e,agent_preset_locked:t,available_presets:[...this.presets],session_context:{agent_preset_id:i.agentPreset??e,agent_preset_locked:t}}}settingsActionResult(e,t,i,s,n,a){const d=this.resolveDesiredSettings(),r=d.revision||i,p={provider_id:d.providerId,model_id:d.modelId,mode_id:d.modeId,thinking_mode:d.thinking,reasoning_effort:d.reasoningEffort,applied_provider_id:this.applied?.providerId??null,applied_model_id:this.applied?.modelId??null,applied_mode_id:this.applied?.modeId??null,applied_thinking_mode:this.applied?.thinking??null,applied_reasoning_effort:this.applied?.reasoningEffort??null,applied_settings_revision:this.applied?.appliedRevision??null,settings_state:this.settingsState,settings_revision:r};return e==="set_mode"&&(p.sandbox_mode=Y(d.modeId),p.approval_policy=d.modeId==="full_auto"?"never":"ask"),{outcome:`${e==="set_provider"?"provider":e==="set_model"?"model":e==="set_thinking"?"thinking":e==="set_reasoning_effort"?"reasoning_effort":"mode"}_set${s==="pending"||s==="failed"?"_pending":""}`,...t.providerId?{providerId:t.providerId,provider_id:t.providerId}:{},...t.modelId?{modelId:t.modelId,model_id:t.modelId}:{},...t.modeId?{modeId:t.modeId,mode_id:t.modeId,sandbox_mode:Y(t.modeId),approval_policy:t.modeId==="full_auto"?"never":"ask"}:{},...t.thinking?{thinking:t.thinking,thinking_mode:t.thinking}:{},...t.reasoningEffort?{reasoningEffort:t.reasoningEffort,reasoning_effort:t.reasoningEffort}:{},settingsRevision:r,settings_revision:r,sessionAlive:n,available_providers:[...this.providers],available_models:[...this.models],session_context:p,...a?{error:a}:{}}}hydrateCatalogFromCache(){const e=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),t=this.options.globalConfigStore?.get(this.options.agentName),i=nt({dataRoot:this.options.dataRoot,providerId:e?.providerId??t?.dshProviderId});this.providers=i.providers,this.models=this.options.models?.length?this.options.models:i.models,this.catalogProviderId=i.providerId}async persistCatalogCache(e){try{await ot({dataRoot:this.options.dataRoot,providers:this.providers,providerId:e,models:this.models})}catch(t){f.warn(m,`failed to persist DSH catalog cache: ${t instanceof Error?t.message:String(t)}`)}}async writeGrixProviderFile(){const e=Ae(this.options.dshHome??this.config.env?.DSH_HOME),t=await this.resolveCredentialsLayout(e);try{if(te(this.options.provider)){await gt(e,v,this.options.provider??{},t)==="skipped"&&f.warn(m,`Grix provider not written to DSH settings (user-owned "${v}" route or unreadable YAML); relay will not take effect`);return}await pt(e,v)}catch(i){f.warn(m,`Failed to sync Grix provider into DSH settings: ${this.redactError(i)}`)}}async resolveCredentialsLayout(e){let t=this.profileDshVersion;if(!t)try{t=await $e(this.options.bridgeInstallerOptions?.command??"dsh",e)}catch(s){f.warn(m,`could not read dsh version, assuming the current credentials layout: ${this.redactError(s)}`)}const i=ut(t);return St(t)&&f.warn(m,`dsh ${t} predates ${ae}: it drops the supportsDeveloperRole / maxTokensField switches, so relayed requests keep the OpenAI-style wire format and the gateway rejects them. Upgrade dsh to use the Grix relay.`),i}syncGrixProvider(){if(te(this.options.provider)){this.providers.some(s=>s.id===v)||(this.providers=[{id:v,displayName:"Grix"},...this.providers]);const e=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),t=this.options.globalConfigStore?.get(this.options.agentName),i=e?.providerId??t?.dshProviderId;(!i||i===$||i===v)&&this.options.bindingStore.updateDshSettings(this.options.aibotSessionId,{providerId:v});return}this.providers=this.providers.filter(e=>e.id!==v)}resolveDesiredSettings(){const e=this.options.bindingStore.get(this.options.aibotSessionId),t=this.options.bindingStore.getDshSettings(this.options.aibotSessionId),i=this.options.globalConfigStore?.get(this.options.agentName),s=t?.providerId??i?.dshProviderId,n=this.providers.some(p=>p.id===v)?v:void 0,a=tt(s||n,this.providers),d=[t?.modelId,i?.dshModelId,this.options.defaultModel,this.models[0]?.id].find(p=>!!p&&this.models.some(u=>u.id===p))??"deepseek-chat",r=Z(t?.agentPreset??i?.dshAgentPreset,this.presets);return{providerId:a,modelId:d,modeId:et(e?.dshModeId,i?.dshModeId),thinking:q(t?.thinking)??q(i?.dshThinking)??Je,reasoningEffort:B(t?.reasoningEffort)??B(i?.dshReasoningEffort)??Xe,agentPreset:r,pluginIds:this.options.bindingStore.getDshEnabledPlugins(this.options.aibotSessionId),skillIds:this.options.bindingStore.getDshEnabledSkills(this.options.aibotSessionId),skillIdsExplicit:Array.isArray(e?.dshSkillIds),maxTokens:t?.maxTokens??this.options.maxTokens??ze,revision:t?.revision??0}}resolveIntegrationMode(){return this.options.integrationMode?this.options.integrationMode:(this.config.command||"").includes("dsh-jsonrpc-agent")?"embedded_jsonrpc":"profile_bridge"}sessionSkillControlUnavailable(){return this.resolveIntegrationMode()!=="profile_bridge"?!1:this.bridgeCapabilities&&typeof this.bridgeCapabilities=="object"?this.bridgeCapabilities.sessionSkillAllowlist!==!0:kt(this.profileDshVersion)}pushToolbarMeta(){const e=this.options.bindingStore.get(this.options.aibotSessionId);this.callbacks.sendUpdateBindingCard(this.options.aibotSessionId,this.stopped?"stopped":this.active?"busy":"ready",e?.cwd,Ge({desired:this.resolveDesiredSettings(),applied:this.applied,models:this.models,providers:this.providers,presets:this.presets,agentPresetLocked:this.options.bindingStore.isDshAgentPresetLocked(this.options.aibotSessionId),state:this.settingsState,errorCode:this.settingsErrorCode,contextWindow:this.contextWindow,providerQuota:this.providerQuota,integrationMode:this.resolveIntegrationMode(),profileName:this.resolveSelectedProfile(),profiles:this.listProfiles(),profileLocked:this.options.bindingStore.isDshProfileLocked(this.options.aibotSessionId),plugins:this.currentPlugins(),skills:this.currentSkills(),pluginRestartRequired:this.pluginRestartRequired(),runtimeReadiness:this.runtimeReadiness,bridgeCapabilities:this.bridgeCapabilities}))}async refreshProviderQuota(e){this.providerQuota=null,this.pushToolbarMeta();try{this.providerQuota=await this.callbacks.queryProviderQuota(e)??{provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}catch{this.providerQuota={provider:"deepseek",providerLabel:"DeepSeek",success:!1,error:"unavailable"}}this.pushToolbarMeta()}clearPendingApprovals(e){for(const t of this.pendingApprovals.values())clearTimeout(t.timer),t.resolve(e);this.pendingApprovals.clear()}thinkingEnabled(){const e=this.active?.inbound.connector_runtime_config?.thinking_events??this.active?.inbound.connector_runtime_config?.thinkingEvents;return e!=="off"&&e!=="hidden"&&e!=="none"}toolEventsEnabled(){const e=this.active?.inbound.connector_runtime_config?.tool_events;return e!=="off"&&e!=="hidden"&&e!=="none"}sendRaw(e,t,i){this.active&&this.callbacks.sendRawEventEnvelope(this.active.inbound.event_id,this.active.inbound.session_id,{type:e,payload:t},i)}failEvent(e,t){this.callbacks.sendEventResult(e.event_id,"failed",t),this.emit("eventDone",e.event_id)}startTimeout(e){this.activeTimeoutMs=e??this.options.promptTimeoutMs??ie,this.noteRuntimeActivity(),this.armTimeout(this.activeIdleTimeoutMs()),this.armHardTimeout(this.activeTimeoutMs)}touchActivity(e=1){!this.active||!this.timeoutTimer||(this.noteRuntimeActivity(),this.armTimeout(this.activeIdleTimeoutMs()))}noteRuntimeActivity(){this.active&&(this.active.lastRuntimeActivityAt=Date.now(),this.active.livenessExtendStartAt=void 0)}activeIdleTimeoutMs(){const e=this.options.activeIdleTimeoutMs??se,t=Number.isFinite(e)&&e>0?e:se;return Math.min(t,this.activeTimeoutMs)}livenessFreshMs(){const e=this.options.livenessFreshMs??ne;return Number.isFinite(e)&&e>0?e:ne}livenessMaxExtendMs(){const e=this.options.livenessMaxExtendMs??oe;return Number.isFinite(e)&&e>0?e:oe}armTimeout(e){this.clearIdleTimeout(),this.timeoutTimer=setTimeout(()=>{this.handlePromptTimeout()},e),this.timeoutTimer.unref?.()}armHardTimeout(e){this.clearHardTimeout(),this.hardTimeoutTimer=setTimeout(()=>{this.handlePromptHardTimeout()},e),this.hardTimeoutTimer.unref?.()}async handlePromptTimeout(){const e=this.active;if(e){if(this.pendingApprovals.size>0){f.info(m,`Idle timeout skipped: pendingApprovals=${this.pendingApprovals.size} event=${e.inbound.event_id}`),this.armTimeout(this.activeIdleTimeoutMs());return}if(this.shouldExtendByLiveness(e.inbound.event_id)){this.armTimeout(this.activeIdleTimeoutMs());return}await this.failActiveTimeout("idle","Harness prompt idle timeout and the runtime was terminated")}}async handlePromptHardTimeout(){const e=this.active;if(e&&this.shouldExtendByLiveness(e.inbound.event_id)){this.armHardTimeout(this.activeTimeoutMs);return}await this.failActiveTimeout("hard","Harness prompt exceeded max duration and the runtime was terminated")}shouldExtendByLiveness(e){const t=this.active;if(!t||t.inbound.event_id!==e||!this.runtime?.isConnected()||!(!t.turnEnded&&(!!t.messageId||t.admitted||t.claimed)))return!1;const s=Date.now(),n=t.lastRuntimeActivityAt??t.startedAt,a=Math.max(0,s-n);if(a<this.livenessFreshMs())return t.livenessExtendStartAt=s,f.info(m,`Liveness check: recent DSH activity for ${e} (quietMs=${a}), extending`),!0;const d=t.livenessExtendStartAt??n;t.livenessExtendStartAt=d;const r=s-d;return r>this.livenessMaxExtendMs()?(f.warn(m,`Liveness extension budget exhausted for ${e} (quietMs=${a}, extendMs=${r}), allowing close`),!1):(f.info(m,`Liveness check: DSH turn still open for ${e} (claimed=${t.claimed}, turnEnded=${t.turnEnded}, quietMs=${a}), extending`),!0)}async failActiveTimeout(e,t){if(!this.active)return;const i=this.active;this.clearTimeout();const s=this.runtime;this.runtime=null,this.intentionalRuntimeStop=!0,this.contextWindow=null,this.reportedContextCapacity=null,this.applied=void 0,this.settingsState="applied",this.settingsErrorCode=null,this.pushToolbarMeta(),await s?.cancel(this.runtimeSessionId).catch(()=>{}),s&&await s.shutdown().catch(()=>s.terminate()),this.intentionalRuntimeStop=!1,!(this.active!==i||this.stopped)&&(f.error(m,`Active DSH turn ${e} timeout: ${i.inbound.event_id}`),this.finishActive("failed",t),this.emit("exit",1))}clearTimeout(){this.clearIdleTimeout(),this.clearHardTimeout()}clearIdleTimeout(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),this.timeoutTimer=null}clearHardTimeout(){this.hardTimeoutTimer&&clearTimeout(this.hardTimeoutTimer),this.hardTimeoutTimer=null}redactError(e,t){let i=e instanceof Error?e.message:String(e);const s=this.config.env?.DEEPSEEK_API_KEY;return s&&(i=i.split(s).join("[REDACTED]")),i=i.replace(/(api[_-]?key|authorization|bearer)\s*[:=]\s*\S+/gi,"$1=[REDACTED]"),t&&t.length>=16&&i.includes(t)&&(i="Harness request failed (prompt echo redacted)"),(i.includes("[aibot-system-prompt]")||i.includes("[base-behavior]"))&&(i="Harness runtime failed (system prompt echo redacted)"),i.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g,"").slice(0,2e3)}}function mt(h){const e=Number(h&&typeof h=="object"?h.cursor:0);return Number.isSafeInteger(e)&&e>0?e:0}function vt(h){return new Promise(e=>setTimeout(e,h))}function bt(h,e){return`grix-${E("sha256").update(h).digest("hex").slice(0,12)}-${e}-${x().slice(0,8)}`}function _t(h){return`grix-${E("sha256").update(h).digest("hex").slice(0,16)}-${x().slice(0,8)}`}function de(){return{inputTokens:0,outputTokens:0,cacheReadInputTokens:0,cacheCreationInputTokens:0,reasoningTokens:0}}function St(h){const e=X(h,ae);return e!==null&&e<0}function kt(h){const e=X(h,re);return e!==null&&e<0}function le(h){const e=h.data?.chunk&&typeof h.data.chunk=="object"?h.data.chunk:h.data;return String(e?.type??"")}function It(h){return h.type==="assistant/chunk:tool-call-delta"||h.type==="assistant/chunk"&&le(h)==="tool-call-delta"}function wt(h){return{readiness:h.readiness,profile:h.identity.profileName,dshVersion:h.dshVersion,runningDshVersion:h.runningDshVersion,installedBridgeVersion:h.installedBridgeVersion,bundledBridgeVersion:h.bundledBridgeVersion,runningBridgeVersion:h.runningBridgeVersion,endpointCount:h.endpointCount,requiresProfileRestart:h.readiness==="profile_restart_required"}}const Tt=new Set(["turn/start","step/start","step/end","agent/inbox/spliced","user/message","request/header","system/message","assistant/attempt","session/title","session/title-llm-request","session/end-seed","web/deepseek-search-llm-request","assistant/chunk:tool-call-delta","permission/preset","sandbox/mode","approval/policy","approval/asked","approval/decided","plan/mode","agent-preset/selected","llm/retry","llm/retry-started","goal/change","schedule/change","feedback/record","hook/invoked","hook/result","command/run","command/done","subagent/descriptor","tool-workflow/agent-start","tool-workflow/agent-end","tool-workflow/run-start","tool-workflow/run-end","tool/code-dispatch","tool/code-dispatch-start"]);function Pt(h){const e=le(h);return Tt.has(h.type)||h.type==="assistant/chunk"&&["block-start","block-end","tool-call-delta","finish"].includes(e)}export{ai as DshJsonRpcAdapter};
@@ -1,7 +1,7 @@
1
- import{EventEmitter as T}from"node:events";import{stat as E}from"node:fs/promises";import{existsSync as M,mkdirSync as $,readFileSync as O,writeFileSync as F}from"node:fs";import{join as S,resolve as D,dirname as B}from"node:path";import{homedir as L}from"node:os";import{fileURLToPath as N}from"node:url";import{resolveCommandPath as j,spawnCommand as Q,killProcessGroup as y,hasChildProcesses as U}from"../../core/runtime/spawn.js";import{InternalApiServer as q}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as H,pruneLegacyMcpServerEntries as J}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as W}from"../shared/inbound-message-id-injector.js";import{IdentityInjector as z}from"../shared/identity-injector.js";import{syncDefaultSkillsToDir as G}from"../../default-skills/index.js";import{buildSimpleProbeReport as V}from"../shared/probe-util.js";import{compactToolInputForWire as X}from"../shared/tool-wire-payload.js";import{normalizeOCProviderModels as Y}from"./opencode-types.js";import{buildOpencodeConfigContent as K}from"./opencode-config.js";import{formatOpenCodeErrorMessage as k}from"./format-error.js";import{OpenCodeTransport as Z}from"./opencode-transport.js";import{log as r}from"../../core/log/index.js";import{splitTextForAibotProtocol as A}from"../../core/protocol/index.js";class ee extends T{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitError(e){if(this.listenerCount("error")===0){r.warn("opencode-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}const te=200,se=2e3,ie=12e4,ne=90*1e3,x=1800*1e3,P=3e4,R=600*1e3,oe="claude_interaction_reply",re="set_mode",ae="set_model",de="127.0.0.1",ce=0,le=1e3,m={fullAuto:"full_auto",approval:"approval"},b=[{id:m.fullAuto,displayName:"Full Auto"},{id:m.approval,displayName:"Approval"}],he=[{permission:"*",pattern:"*",action:"allow"}],pe=[{permission:"doom_loop",pattern:"*",action:"ask"},{permission:"external_directory",pattern:"*",action:"ask"},{permission:"question",pattern:"*",action:"deny"},{permission:"plan_enter",pattern:"*",action:"deny"},{permission:"plan_exit",pattern:"*",action:"deny"},{permission:"repo_clone",pattern:"*",action:"deny"},{permission:"repo_overview",pattern:"*",action:"deny"},{permission:"read",pattern:"*.env",action:"ask"},{permission:"read",pattern:"*.env.*",action:"ask"},{permission:"read",pattern:"*.env.example",action:"allow"}];function w(v){const e=String(v??"").trim().toLowerCase();if(e==="full_auto"||e==="fullauto")return m.fullAuto;if(e==="approval"||e==="ask"||e==="autoedit"||e==="auto_edit")return m.approval}function C(v){try{return process.kill(v,0),!0}catch(e){return e.code==="EPERM"}}class $e extends T{type="opencode";config;callbacks;options;identity;inboundMessageIds=new W;process=null;transport=new Z;alive=!1;stopped=!1;internalApi=null;sessions=new Map;sessionModes=new Map;sessionModels=new Map;availableModels=[];modelContextLimits=new Map;contextTokensBySession=new Map;activeRun=null;completedEvents=new Set;clientMsgSeq=0;auditCaptures=new Map;completedAuditBoundaries=new Map;idleTimer=null;lastSseAt=0;livenessExtendStartAt;toolCallsInFlight=new Set;toolCardsSent=new Set;messageRoles=new Map;pendingPartChunks=new Map;pendingPermissions=new Map;pendingQuestions=new Map;permissionHandler=null;constructor(e,s,t){super(),this.config=e,this.callbacks=s,this.options=t??{},this.identity=new z("opencode-adapter",s.getAgentProfile)}onAgentProfileChanged(){this.identity.onProfileChanged()}async start(){await this.startInternalApiAndInjectMcp();const e=this.options.hostname??de,s=this.options.port??ce,t=await this.spawnAndWait(e,s),i=this.resolveCwd();await this.transport.connect(t,i),this.transport.on("event",n=>this.handleSseEvent(n));try{await this.refreshModels()}catch(n){r.warn("opencode-adapter",`Failed to fetch providers for toolbar models: ${n instanceof Error?n.message:String(n)}`)}r.info("opencode-adapter",`Ready (pid=${this.process?.pid}, url=${t})`)}async refreshModels(e){const s=await this.transport.listProviders(e),t=[],i=new Map;for(const n of s)for(const o of Y(n.models)){t.push({id:`${n.id}/${o.id}`,displayName:o.name||o.id});const a=o.limit?.context;typeof a=="number"&&a>0&&i.set(`${n.id}/${o.id}`,a)}t.sort((n,o)=>{const a=n.displayName.toLowerCase().localeCompare(o.displayName.toLowerCase());return a!==0?a:n.id.localeCompare(o.id)}),this.availableModels=t,this.modelContextLimits=i,r.info("opencode-adapter",`Fetched ${t.length} models from ${s.length} providers (directory=${e??"current"})`)}resolveContextLimit(e,s){const t=this.modelContextLimits.get(`${e}/${s}`);if(t)return t;let i;for(const[n,o]of this.modelContextLimits)n.startsWith(`${e}/`)&&(i=i===void 0?o:Math.max(i,o));return i}buildContextWindowMeta(e,s,t,i){if(!i||i<=0)return;const n=this.resolveContextLimit(s,t);if(!n)return;const o=Math.min(100,i/n*100);return{context_window:{used:i,size:n,usedPercentage:o,remainingPercentage:100-o}}}async stop(){if(this.stopped=!0,this.alive=!1,this.stopComposing(),this.stopIdleTimer(),this.stopTextFlush(),this.transport.disconnect(),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null),this.process){const e=this.process;try{y(e,"SIGTERM")}catch{}const s=setTimeout(()=>{try{y(e,"SIGKILL")}catch{}},5e3);e.on("exit",()=>clearTimeout(s)),this.process=null}}isAlive(){return this.alive}async createSession(e){const s=e.cwd??this.resolveCwd();await this.transport.useDirectory(s);const t=await this.transport.createSession({title:`grix-${Date.now()}`},s);return this.sessions.set(t.id,{ocSessionId:t.id,cwd:s}),r.info("opencode-adapter",`Created OC session ${t.id} for cwd=${s}`),await this.applySessionPermission(t.id,t.id,s),t.id}async resumeSession(e,s){const t=this.sessions.get(e);if(t?.ocSessionId)try{await this.transport.useDirectory(t.cwd),await this.transport.getSession(t.ocSessionId,t.cwd),await this.applySessionPermission(e,t.ocSessionId,t.cwd)}catch{r.warn("opencode-adapter",`OC session ${t.ocSessionId} gone, will create new on next prompt`),t.ocSessionId=""}}async destroySession(e){const s=this.sessions.get(e),t=s?s.ocSessionId:e;if(t)try{await this.transport.deleteSession(t,s?.cwd)}catch{}this.sessions.delete(e),this.contextTokensBySession.delete(e),this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e)}sendPrompt(e){const s=new ee(e.adapterSessionId);return this.sendOcPrompt(e.adapterSessionId,this.buildPromptText(e)).catch(t=>{s.emitError(t instanceof Error?t:new Error(String(t)))}),s}async cancel(e){if(this.activeRun)try{await this.transport.abortSession(this.activeRun.ocSessionId,this.activeRun.cwd)}catch{}}deliverInboundEvent(e){const{event_id:s,session_id:t,content:i}=e;if(this.completedEvents.has(s)){r.info("opencode-adapter",`Dropping duplicate event ${s}`),this.callbacks.sendEventAck(s,t),this.callbacks.sendEventResult(s,"responded");return}if(!this.alive){r.warn("opencode-adapter",`Dropping event ${s}: process not alive`),this.callbacks.sendEventAck(s,t),this.callbacks.sendEventResult(s,"failed","Agent process not running");return}this.activeRun&&this.activeRun.eventId!==s&&(r.info("opencode-adapter",`steer: ${this.activeRun.eventId} -> ${s}`),this.flushTextBuffer(),this.callbacks.sendEventResult(this.activeRun.eventId,"canceled","steered to new event"),this.clearRun()),r.info("opencode-adapter",`prompt: event=${s} session=${t}`),this.callbacks.sendEventAck(s,t),this.startRun(s,t,e.audit?.enabled===!0),this.startComposing(t),this.resetIdleTimer();const n=this.buildPromptTextFromEvent(e);this.sendOcPrompt(t,n).catch(o=>{r.error("opencode-adapter",`prompt_async failed: ${o}`),this.finishRun("failed",String(o))})}deliverStopEvent(e,s){this.activeRun&&this.activeRun.eventId===e&&(r.info("opencode-adapter",`stop: event=${e}`),this.rejectAllPendingInteractions(),this.transport.abortSession(this.activeRun.ocSessionId,this.activeRun.cwd).catch(()=>{}),this.flushTextBuffer(),this.finishRun("canceled","stopped by user"))}setPermissionHandler(e){this.permissionHandler=e}async ping(e){return this.transport.healthCheck()}getStatus(){return{alive:this.alive,busy:this.activeRun!==null,sessions:this.sessions.size}}getActiveEventIds(){return this.activeRun?[this.activeRun.eventId]:[]}takeAuditBoundary(e){const s=this.completedAuditBoundaries.get(e);return s&&this.completedAuditBoundaries.delete(e),s}clearActiveEventForShutdown(){this.stopIdleTimer(),this.stopTextFlush(),this.rejectAllPendingInteractions(),this.activeRun&&this.snapshotAuditBoundary(this.activeRun),this.activeRun=null}getMcpConfig(){if(!this.internalApi)return null;const e=D(N(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:H(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?U(e,[e]):!1}async probe(e){const s=this.getStatus();return V(this.config.command||"opencode",{alive:s.alive,busy:s.busy,started:!!this.process},e)}async startInternalApiAndInjectMcp(){try{this.internalApi=new q,this.internalApi.setInvokeHandler(async(f,d,h,c)=>this.callbacks.agentInvoke(f,d,c)),await this.internalApi.start(0),r.info("opencode-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),s=process.env.XDG_CONFIG_HOME||S(L(),".config"),t=S(s,"opencode","opencode.json");$(B(t),{recursive:!0});let i={};try{M(t)&&(i=JSON.parse(O(t,"utf8")))}catch{}const n=i.mcp&&typeof i.mcp=="object"?i.mcp:{};J(n,this.internalApi.url),n[e.name]={type:"local",command:[e.command,...e.args??[]],enabled:!0},i.mcp=n,F(t,`${JSON.stringify(i,null,2)}
2
- `,"utf8"),r.info("opencode-adapter",`MCP config injected into ${t}`);const o=S(s,"opencode","skills"),a=G(o);a.length>0&&r.info("opencode-adapter",`Synced connector skills to ${o}: [${a.join(", ")}]`)}catch(e){r.warn("opencode-adapter",`Failed to inject MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}async handleLocalAction(e){const{action_type:s}=e;if(s==="exec_approve"||s==="exec_reject"||s==="permission_approve"||s==="permission_reject")return this.handlePermissionAction(e);if(s===re)return this.handleSetModeAction(e);if(s===ae)return this.handleSetModelAction(e);if(s===oe){const t=e.params??{};if(String(t.kind??"")==="permission"){const i=t.resolution??{},n=String(i.value??"");return this.handlePermissionAction({...e,action_type:n==="allow"?"exec_approve":"exec_reject",params:{...t,approval_command_id:t.request_id}})}return this.handleQuestionReplyAction(e)}return{handled:!1,kind:""}}handleQuestionReplyEvent(e){let s;if(e.action)s={type:"action",value:e.action};else if(e.response?.type==="single")s={type:"text",value:e.response.value};else if(e.response?.type==="map")s={type:"map",entries:e.response.entries};else return{delivered:!1,errorCode:"resolution_invalid",errorMsg:"Question reply response is invalid."};return this.deliverQuestionReply({request_id:e.request_id,resolution:s})}async bindSession(e,s){if(r.info("opencode-adapter",`bindSession: ${e} \u2192 ${s}`),!this.sessions.has(e))this.sessions.set(e,{ocSessionId:"",cwd:s});else{const t=this.sessions.get(e);t.cwd=s}try{await this.refreshModels(s)}catch(t){r.warn("opencode-adapter",`Failed to refresh models on bind: ${t instanceof Error?t.message:String(t)}`)}this.callbacks.sendUpdateBindingCard(e,"ready",s,this.buildToolbarMeta(e))}resolveModeId(e){if(e){const t=this.sessionModes.get(e);if(t)return t}const s=w(this.options.permissionPolicy);if(s)return s;if(e){const t=w(this.options.bindingStore?.get(e)?.modeId);if(t)return t}return m.fullAuto}buildModeToolbarMeta(e){const s=this.resolveModeId(e);return{mode_id:s,currentModeId:s,available_modes:b.map(t=>({...t}))}}async applySessionPermission(e,s,t){const i=this.resolveModeId(e),n=i===m.fullAuto?he:pe;try{await this.transport.updateSessionPermission(s,n,t),r.info("opencode-adapter",`Applied session permission ruleset (${i}) to ${s}`)}catch(o){r.warn("opencode-adapter",`Failed to apply session permission ruleset: ${o instanceof Error?o.message:String(o)}`)}}async handleSetModeAction(e){const s=e.params??{},t=String(s.session_id??this.options.aibotSessionId??"").trim(),i=w(s.mode_id);if(!i||!t)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","mode_id must be full_auto or approval and session_id is required"),{handled:!0,kind:"set_mode"};this.sessionModes.set(t,i);const n=this.sessions.get(t);n?.ocSessionId&&await this.applySessionPermission(t,n.ocSessionId,n.cwd);const o=n?.cwd??this.getSessionCwd(t);return this.callbacks.sendUpdateBindingCard(t,"ready",o,this.buildToolbarMeta(t)),this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"mode_set",session_context:{mode_id:i,modeId:i},mode_id:i,available_modes:b.map(a=>({...a}))}),{handled:!0,kind:"set_mode"}}resolveModelId(e){if(e){const t=this.sessionModels.get(e);if(t)return t}const s=String(this.options.model??"").trim();if(s)return s;if(e){const t=String(this.options.bindingStore?.get(e)?.modelId??"").trim();if(t)return t}return""}buildModelToolbarMeta(e){const s=this.resolveModelId(e);return{model_id:s,currentModelId:s,available_models:this.availableModels.map(t=>({...t}))}}buildToolbarMeta(e){return{...this.buildModelToolbarMeta(e),...this.buildModeToolbarMeta(e)}}handleSetModelAction(e){const s=e.params??{},t=String(s.session_id??this.options.aibotSessionId??"").trim(),i=String(s.model_id??"").trim();if(!i||!t)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","model_id and session_id are required"),{handled:!0,kind:"set_model"};this.sessionModels.set(t,i);const n=this.sessions.get(t)?.cwd??this.getSessionCwd(t);return this.callbacks.sendUpdateBindingCard(t,"ready",n,this.buildToolbarMeta(t)),this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"model_set",session_context:{model_id:i,modelId:i},model_id:i,available_models:this.availableModels.map(o=>({...o}))}),{handled:!0,kind:"set_model"}}async spawnAndWait(e,s){const t=this.resolveCwd();try{if(!(await E(t)).isDirectory())throw new Error(`Bound path is not a directory: ${t}`)}catch(i){throw String(i?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${t}. Please rebind with /grix open <valid-directory>.`):i}return new Promise((i,n)=>{const o=this.config.command||"opencode",f=[...this.config.args??["serve"],`--hostname=${e}`,`--port=${s}`],d={...process.env,...this.config.env},h=K({model:this.options.model,permissionPolicy:this.options.permissionPolicy,provider:this.options.provider});h&&(d.OPENCODE_CONFIG_CONTENT=JSON.stringify(h));const c=j(o,typeof d.PATH=="string"?d.PATH:void 0);r.info("opencode-adapter",`Spawning: ${c} ${f.join(" ")} (cwd=${t})`),this.process=Q(c,f,{env:d,cwd:t}).process;let u="",p=!1;const I=setTimeout(()=>{p||(p=!0,n(new Error(`opencode serve did not start after ${P/1e3}s`)))},P);this.process.stdout?.on("data",l=>{if(u+=l.toString(),!p)for(const g of u.split(`
3
- `)){const _=g.match(/opencode server listening on (https?:\/\/[^\s]+)/);if(_){clearTimeout(I),p=!0,this.alive=!0,i(_[1]);return}}}),this.process.stderr?.on("data",l=>{const g=l.toString().trim();g&&r.info("opencode-adapter",`[stderr] ${g}`)}),this.process.on("error",l=>{r.error("opencode-adapter",`Spawn error: ${l.message}`),clearTimeout(I),this.alive=!1,this.transport.disconnect(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`Spawn error: ${l.message}`),this.clearRun()),p?this.stopped||this.emit("exit",1):(p=!0,n(l))}),this.process.on("exit",l=>{r.info("opencode-adapter",`Process exited (code=${l})`),clearTimeout(I),this.alive=!1,this.transport.disconnect(),this.stopComposing(),this.stopIdleTimer(),this.stopTextFlush(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`Process exited (code=${l})`),this.clearRun()),p?this.stopped||this.emit("exit",l??1):(p=!0,n(new Error(`opencode serve exited with code ${l}`)))})})}async ensureOcSession(e){const s=this.sessions.get(e),t=this.getSessionCwd(e);if(await this.transport.useDirectory(t),s?.ocSessionId)try{return await this.transport.getSession(s.ocSessionId,t),s.ocSessionId}catch{r.warn("opencode-adapter",`OC session ${s.ocSessionId} gone, creating new`),s.ocSessionId=""}const i=this.options.bindingStore?.getAcpSessionId(e);if(i)try{return await this.transport.getSession(i,t),this.sessions.set(e,{ocSessionId:i,cwd:t}),r.info("opencode-adapter",`Resumed OC session ${i} for aibot=${e}`),await this.applySessionPermission(e,i,t),i}catch{r.warn("opencode-adapter",`Persisted OC session ${i} gone, creating new`)}const n=await this.transport.createSession({title:`grix-${e.slice(-8)}`},t);return this.sessions.set(e,{ocSessionId:n.id,cwd:t}),this.options.bindingStore?.setAcpSessionId(e,n.id),r.info("opencode-adapter",`Created OC session ${n.id} for aibot=${e}`),await this.applySessionPermission(e,n.id,t),n.id}async sendOcPrompt(e,s){const t=this.getSessionCwd(e),i=await this.ensureOcSession(e);this.activeRun&&(this.activeRun.ocSessionId=i,this.activeRun.cwd=t);const n=this.resolveModelId(e),o=n.indexOf("/"),a=o>0&&o<n.length-1?{providerID:n.slice(0,o),modelID:n.slice(o+1)}:void 0;await this.transport.sendPromptAsync(i,{parts:[{type:"text",text:s}],...a?{model:a}:{}},t)}handleSseEvent(e){if(!this.stopped){if(this.updateToolInFlight(e),e.type!=="server.heartbeat"&&(this.lastSseAt=Date.now(),this.resetIdleTimer()),this.activeRun){const s=this.auditCaptures.get(this.activeRun.eventId);s&&s.push({sequence:s.length,observedAt:new Date().toISOString(),event:structuredClone(e)})}switch(e.type){case"message.part.updated":{if(!this.activeRun)break;const s=e.part,t=e.delta;if(s.type==="text"){const i=t||s.text;i&&this.acceptAssistantPartText(s.messageID,"text",i)}else s.type==="reasoning"?t&&this.acceptAssistantPartText(s.messageID,"reasoning",t):s.type==="tool"&&this.handleToolPartUpdate(s,t);break}case"message.updated":{if(!this.activeRun)break;const s=e.info;if(this.rememberMessageRole(s),s.role==="assistant"){const t=s;typeof t.tokens?.input=="number"&&this.contextTokensBySession.set(this.activeRun.sessionId,t.tokens.input);const i=this.buildContextWindowMeta(this.activeRun.sessionId,t.providerID,t.modelID,t.tokens?.input);this.callbacks.sendUpdateBindingCard(this.activeRun.sessionId,"composing",this.activeRun.cwd,{...this.buildToolbarMeta(this.activeRun.sessionId),model_provider:t.providerID,model_id:t.modelID,...i??{}}),t.error&&r.warn("opencode-adapter",`Message error: ${JSON.stringify(t.error)}`);const n=this.activeRun.ocSessionId;n&&t.sessionID===n&&(t.error?(this.flushTextBuffer(),this.finishRun("failed",k(t.error,t.error.type||"unknown error"))):t.time?.completed&&t.finish!=="tool-calls"&&(this.flushTextBuffer(),this.finishRun("responded")))}break}case"session.idle":{if(!this.activeRun)break;e.sessionID===this.activeRun.ocSessionId&&(this.flushTextBuffer(),this.finishRun("responded"));break}case"session.status":{if(!this.activeRun)break;e.sessionID===this.activeRun.ocSessionId&&e.status.type==="idle"&&(this.flushTextBuffer(),this.finishRun("responded"));break}case"session.error":{if(!this.activeRun)break;const s=k(e.error);r.error("opencode-adapter",`Session error: ${s}`),this.flushTextBuffer(),this.finishRun("failed",s);break}case"permission.updated":{this.handlePermission(e.permission);break}case"permission.asked":{this.handlePermissionAsked(e);break}case"question.asked":{this.handleQuestionAsked(e);break}case"permission.replied":case"question.replied":case"question.rejected":r.debug("opencode-adapter",`Interaction settled: ${e.type}`);break;case"session.created":case"session.updated":case"session.deleted":case"session.compacted":case"session.diff":case"file.edited":case"server.connected":case"server.heartbeat":break;case"server.instance.disposed":{r.warn("opencode-adapter",`Server instance disposed: ${e.directory}`),this.alive=!1,this.transport.disconnect(),this.activeRun&&(this.flushTextBuffer(),this.callbacks.sendEventResult(this.activeRun.eventId,"failed","server instance disposed"),this.clearRun()),this.stopped||this.emit("exit",-1);break}default:r.debug("opencode-adapter",`Unhandled SSE event type: ${e.type}`);break}}}updateToolInFlight(e){if(e.type!=="message.part.updated")return;const s=e.part;if(s?.type!=="tool"||!s.callID)return;const t=s.state?.status;t==="pending"||t==="running"?this.toolCallsInFlight.add(s.callID):(t==="completed"||t==="error")&&this.toolCallsInFlight.delete(s.callID)}rememberMessageRole(e){const s=typeof e.id=="string"?e.id.trim():"";s&&(e.role!=="user"&&e.role!=="assistant"||(this.messageRoles.set(s,e.role),this.flushOrDropPendingParts(s,e.role)))}acceptAssistantPartText(e,s,t){if(!this.activeRun||!t)return;const i=typeof e=="string"?e.trim():"";if(!i)return;const n=this.messageRoles.get(i);if(n==="user")return;if(n==="assistant"){this.emitAssistantPartChunk(s,t);return}const o=this.pendingPartChunks.get(i)??[];o.push({kind:s,value:t}),this.pendingPartChunks.set(i,o)}flushOrDropPendingParts(e,s){const t=this.pendingPartChunks.get(e);if(this.pendingPartChunks.delete(e),!(!t||t.length===0)&&s==="assistant")for(const i of t)this.emitAssistantPartChunk(i.kind,i.value)}emitAssistantPartChunk(e,s){if(!(!this.activeRun||!s)){if(e==="reasoning"){this.callbacks.sendThinking(this.activeRun.eventId,this.activeRun.sessionId,s);return}this.appendText(s)}}clearMessageRoleState(){this.messageRoles.clear(),this.pendingPartChunks.clear()}handleToolPartUpdate(e,s){if(!this.activeRun)return;const t=e.state;switch(t.status){case"pending":case"running":{this.sendToolUseOnce(e,t.input);break}case"completed":{this.sendToolUseOnce(e,t.input);break}case"error":{this.sendToolUseOnce(e,t.input),this.callbacks.sendToolResult(this.activeRun.eventId,this.activeRun.sessionId,e.tool,"(failed)");break}}}sendToolUseOnce(e,s){!this.activeRun||this.toolCardsSent.has(e.callID)||(this.flushTextBuffer(),this.toolCardsSent.add(e.callID),this.callbacks.sendToolUse(this.activeRun.eventId,this.activeRun.sessionId,e.tool,X(s??{})))}onPermissionTimeout(e){const s=this.pendingPermissions.get(e);s&&(this.pendingPermissions.delete(e),r.error("opencode-adapter",`Permission approval timeout: ${e}`),this.transport.respondPermission(s.ocSessionId,e,"reject",s.cwd).catch(()=>{}),this.activeRun&&this.activeRun.eventId===s.eventId&&(this.flushTextBuffer(),this.finishRun("failed","permission approval timeout")))}trackPendingPermission(e){if(!this.activeRun)return;this.stopIdleTimer();const s=setTimeout(()=>this.onPermissionTimeout(e),R);this.pendingPermissions.set(e,{permissionId:e,eventId:this.activeRun.eventId,ocSessionId:this.activeRun.ocSessionId,cwd:this.activeRun.cwd,timer:s})}handlePermissionAsked(e){if(!this.activeRun){this.transport.respondPermission(e.sessionID,e.id,"reject").catch(o=>{r.warn("opencode-adapter",`Orphan permission reject failed: ${o}`)});return}const{eventId:s,sessionId:t,ocSessionId:i}=this.activeRun;if(this.resolveModeId(t)===m.fullAuto){this.transport.respondPermission(i,e.id,"always",this.activeRun.cwd).catch(o=>{r.warn("opencode-adapter",`Auto-approve failed: ${o}`)});return}this.trackPendingPermission(e.id);const n=e.patterns.length>0?`${e.permission}: ${e.patterns.join(", ")}`:e.permission;this.callbacks.sendPermissionCard?this.callbacks.sendPermissionCard({eventId:s,sessionId:t,approvalId:e.id,toolName:e.permission,toolTitle:n,toolInput:JSON.stringify(e.metadata??{})}):this.callbacks.sendToolUse(s,t,e.permission,JSON.stringify(e.metadata??{}))}handlePermission(e){if(!this.activeRun)return;const{eventId:s,sessionId:t,ocSessionId:i}=this.activeRun;if(this.resolveModeId(t)===m.fullAuto){this.transport.respondPermission(i,e.id,"always",this.activeRun.cwd).catch(n=>{r.warn("opencode-adapter",`Auto-approve failed: ${n}`)});return}if(this.trackPendingPermission(e.id),this.callbacks.sendPermissionCard)this.callbacks.sendPermissionCard({eventId:s,sessionId:t,approvalId:e.id,toolName:e.type,toolTitle:e.title||e.type,toolInput:JSON.stringify(e.metadata??{})});else{const n=JSON.stringify(e.metadata??{});this.callbacks.sendToolUse(s,t,e.type,n)}}handlePermissionAction(e){if(!this.activeRun)return{handled:!1,kind:""};const s=e.params??{},t=String(s.approval_id??s.approval_command_id??s.approvalId??s.tool_call_id??"");let i=t?this.pendingPermissions.get(t):void 0;if(!i){for(const a of this.pendingPermissions.values())if(a.eventId===this.activeRun.eventId){i=a;break}}if(!i)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:"permission"};const n=e.action_type==="exec_approve"||e.action_type==="permission_approve",o=n?"once":"reject";return clearTimeout(i.timer),this.pendingPermissions.delete(i.permissionId),this.transport.respondPermission(i.ocSessionId,i.permissionId,o,i.cwd).then(()=>{r.info("opencode-adapter",`Permission ${o}: ${i.permissionId}`),this.resetIdleTimer()}).catch(a=>{r.warn("opencode-adapter",`Permission response failed: ${a}`),this.resetIdleTimer()}),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.permissionId,decision:n?"approve":"reject"}),{handled:!0,kind:"permission"}}async handleExecApprovalEvent(e){if(!this.activeRun)return{delivered:!1,errorCode:"approval_not_found",errorMsg:"no active run"};const s=String(e.approval_id??e.approval_command_id??e.tool_call_id??"");let t=s?this.pendingPermissions.get(s):void 0;if(!t){for(const n of this.pendingPermissions.values())if(n.eventId===this.activeRun.eventId){t=n;break}}if(!t)return{delivered:!1,errorCode:"approval_not_found",errorMsg:"That approval request is no longer pending."};const i=e.decision==="deny"?"reject":e.decision==="allow-always"?"always":"once";return clearTimeout(t.timer),this.pendingPermissions.delete(t.permissionId),this.transport.respondPermission(t.ocSessionId,t.permissionId,i,t.cwd).then(()=>{r.info("opencode-adapter",`Permission ${i} (text event): ${t.permissionId}`),this.resetIdleTimer()}).catch(n=>{r.warn("opencode-adapter",`Permission response failed: ${n}`),this.resetIdleTimer()}),{delivered:!0}}onQuestionTimeout(e){const s=this.pendingQuestions.get(e);s&&(this.pendingQuestions.delete(e),r.error("opencode-adapter",`Question answer timeout: ${e}`),this.transport.rejectQuestion(e,s.cwd).catch(()=>{}),this.activeRun&&this.activeRun.eventId===s.eventId&&(this.flushTextBuffer(),this.finishRun("failed","question answer timeout")))}handleQuestionAsked(e){if(!this.activeRun){this.transport.rejectQuestion(e.id).catch(n=>{r.warn("opencode-adapter",`Orphan question reject failed: ${n}`)});return}const{eventId:s,sessionId:t}=this.activeRun;this.stopIdleTimer();const i=setTimeout(()=>this.onQuestionTimeout(e.id),R);if(this.pendingQuestions.set(e.id,{requestId:e.id,eventId:s,cwd:this.activeRun.cwd,questions:e.questions,timer:i}),this.callbacks.sendAgentQuestionCard)this.callbacks.sendAgentQuestionCard(s,t,{request_id:e.id,mode:"form",questions:e.questions.map(n=>({header:n.header,prompt:n.question,...n.options.length>0?{options:n.options.map(o=>o.label)}:{},...n.multiple!==void 0?{multi_select:n.multiple}:{}})),expires_at:Date.now()+R});else{const n=e.questions.map(o=>o.question).join(`
4
- `);this.callbacks.sendRunError(s,t,`Agent asks: ${n}`)}}handleQuestionReplyAction(e){const s=e.params??{},t=this.deliverQuestionReply(s);return t.delivered?this.callbacks.sendLocalActionResult(e.action_id,"ok",t.result):this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,t.errorCode,t.errorMsg),{handled:!0,kind:"question_reply"}}deliverQuestionReply(e){const s=String(e.request_id??""),t=s?this.pendingQuestions.get(s):void 0;if(!t)return{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The question is no longer pending; the reply was not delivered."};const i=e.resolution??{},n=String(i.type??""),o=(d,h)=>(clearTimeout(t.timer),this.pendingQuestions.delete(t.requestId),d().then(()=>this.resetIdleTimer()).catch(c=>{r.warn("opencode-adapter",`Question response failed: ${c}`),this.resetIdleTimer()}),{delivered:!0,result:h});if(n==="action"){const d=String(i.value??"");if(d==="cancel"||d==="decline")return o(()=>this.transport.rejectQuestion(t.requestId,t.cwd),{request_id:s,resolution:"cancel"})}let a=null;if(Array.isArray(e.answers))a=e.answers.map(d=>Array.isArray(d)?d.map(String):[String(d)]);else if(n==="text"){const d=String(i.value??"");d&&(a=t.questions.map((h,c)=>c===0?[d]:[]))}else if(n==="map"){const d=Array.isArray(i.entries)?i.entries:[];a=t.questions.map((h,c)=>{const u=d.find(p=>p.key===h.header||p.key===String(c+1));return u&&u.value?[u.value]:[]}),a.every(h=>h.length===0)&&d.length>0&&(a=t.questions.map((h,c)=>{const u=d[c]?.value;return u?[String(u)]:[]}))}if(!a||a.every(d=>d.length===0))return o(()=>this.transport.rejectQuestion(t.requestId,t.cwd),{request_id:s,resolution:"cancel"});const f=a;return o(()=>this.transport.replyQuestion(t.requestId,f,t.cwd),{request_id:s,resolution:"answer"})}rejectAllPendingInteractions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),this.transport.respondPermission(e.ocSessionId,e.permissionId,"reject",e.cwd).catch(()=>{});this.pendingPermissions.clear();for(const e of this.pendingQuestions.values())clearTimeout(e.timer),this.transport.rejectQuestion(e.requestId,e.cwd).catch(()=>{});this.pendingQuestions.clear()}hasPendingInteractionForRun(e){for(const s of this.pendingPermissions.values())if(s.eventId===e)return!0;for(const s of this.pendingQuestions.values())if(s.eventId===e)return!0;return!1}startRun(e,s,t=!1){this.activeRun={eventId:e,sessionId:s,ocSessionId:"",cwd:this.getSessionCwd(s),chunkSeq:0,clientMsgId:`oc_${++this.clientMsgSeq}_${Date.now()}`,textBuffer:"",flushTimer:null},this.toolCardsSent.clear(),t&&this.auditCaptures.set(e,[]),this.lastSseAt=Date.now(),this.livenessExtendStartAt=void 0}finishRun(e,s){const t=this.activeRun;if(!t)return;if(this.completedEvents.add(t.eventId),this.completedEvents.size>le){const a=[...this.completedEvents].slice(-500);this.completedEvents=new Set(a)}this.snapshotAuditBoundary(t),this.activeRun=null,this.rejectAllPendingInteractions(),this.toolCallsInFlight.clear(),this.toolCardsSent.clear(),this.livenessExtendStartAt=void 0,this.clearMessageRoleState(),this.stopComposing(),this.stopIdleTimer();const i=++t.chunkSeq,n=t.clientMsgId;e==="failed"&&s&&this.callbacks.sendRunError(t.eventId,t.sessionId,s);const o=()=>{this.callbacks.sendFinalStreamChunkReliable?this.callbacks.sendFinalStreamChunkReliable(t.eventId,t.sessionId,n).then(()=>{this.callbacks.sendEventResult(t.eventId,e,s)}).catch(a=>{const f=e==="responded"?"failed":e,d=e==="responded"?`final output delivery failed: ${a instanceof Error?a.message:String(a)}`:s;this.callbacks.sendEventResult(t.eventId,f,d)}):(this.callbacks.sendStreamChunk(t.eventId,t.sessionId,"",i,!0,n),this.callbacks.sendEventResult(t.eventId,e,s))};if(t.textBuffer){this.stopTextFlush();for(const a of A(t.textBuffer))t.chunkSeq++,this.callbacks.sendStreamChunk(t.eventId,t.sessionId,a,t.chunkSeq,!1,t.clientMsgId);t.textBuffer=""}o(),this.emit("eventDone",t.eventId)}clearRun(){this.activeRun?.flushTimer&&clearTimeout(this.activeRun.flushTimer);const e=this.activeRun?.eventId;this.activeRun&&this.snapshotAuditBoundary(this.activeRun),this.activeRun=null,this.rejectAllPendingInteractions(),this.toolCallsInFlight.clear(),this.toolCardsSent.clear(),this.livenessExtendStartAt=void 0,this.clearMessageRoleState(),this.stopIdleTimer(),e&&this.emit("eventDone",e)}snapshotAuditBoundary(e){const s=this.auditCaptures.get(e.eventId);s&&(this.completedAuditBoundaries.set(e.eventId,{adapterType:"opencode",providerSessionId:e.ocSessionId||void 0,openCodeEvidence:{events:s}}),this.auditCaptures.delete(e.eventId))}appendText(e){if(this.activeRun){if(this.activeRun.textBuffer+=e,this.activeRun.textBuffer.length>=se){this.flushTextBuffer();return}this.scheduleTextFlush()}}scheduleTextFlush(){!this.activeRun||this.activeRun.flushTimer||(this.activeRun.flushTimer=setTimeout(()=>{this.activeRun&&(this.activeRun.flushTimer=null),this.flushTextBuffer()},te))}flushTextBuffer(){if(this.stopTextFlush(),!(!this.activeRun||!this.activeRun.textBuffer)){for(const e of A(this.activeRun.textBuffer))this.activeRun.chunkSeq++,this.callbacks.sendStreamChunk(this.activeRun.eventId,this.activeRun.sessionId,e,this.activeRun.chunkSeq,!1,this.activeRun.clientMsgId);this.activeRun.textBuffer=""}}stopTextFlush(){this.activeRun?.flushTimer&&(clearTimeout(this.activeRun.flushTimer),this.activeRun.flushTimer=null)}startComposing(e){}stopComposing(){}shouldExtendByLiveness(){if(!this.activeRun)return!1;const e=this.process?.pid;if(!this.alive||!e||!C(e))return!1;const s=Date.now(),t=this.lastSseAt>0?s-this.lastSseAt:Number.POSITIVE_INFINITY;if(t<ne)return this.livenessExtendStartAt=s,r.info("opencode-adapter",`Liveness check: fresh SSE for ${this.activeRun.eventId} (sseAge=${t}ms, toolsInFlight=${this.toolCallsInFlight.size}), extending`),!0;const n=this.livenessExtendStartAt??s;return this.livenessExtendStartAt===void 0&&(this.livenessExtendStartAt=n),s-n>x?(r.warn("opencode-adapter",`Liveness extension budget exhausted for ${this.activeRun.eventId} (no progress for ${Math.round((s-n)/6e4)}min), allowing idle fail`),!1):(r.info("opencode-adapter",`Liveness check: turn in progress for ${this.activeRun.eventId} (toolsInFlight=${this.toolCallsInFlight.size}, sseAge=${Number.isFinite(t)?`${t}ms`:"n/a"}), extending`),!0)}resetIdleTimer(){this.stopIdleTimer(),!(this.stopped||!this.activeRun)&&(this.idleTimer=setTimeout(()=>{if(this.stopped||!this.activeRun)return;if(this.hasPendingInteractionForRun(this.activeRun.eventId)&&this.shouldExtendByLiveness()){r.info("opencode-adapter",`Idle timeout skipped: pending interaction for ${this.activeRun.eventId}, resetting timer`),this.resetIdleTimer();return}if(this.shouldExtendByLiveness()){this.resetIdleTimer();return}const e=this.process?.pid,t=!!(this.alive&&e&&C(e))?`liveness budget exhausted after ${x/6e4}min`:"process not alive";r.error("opencode-adapter",`Idle timeout (${t}, toolsInFlight=${this.toolCallsInFlight.size}) \u2014 emitting exit for respawn`),this.flushTextBuffer(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`idle timeout: ${t}`),this.clearRun()),this.emit("exit",-1)},ie))}stopIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}resolveCwd(){const e=this.options.aibotSessionId?this.options.bindingStore?.get(this.options.aibotSessionId)?.cwd:void 0;if(e)return e;const s=(this.config.options??{}).cwd;return typeof s=="string"&&s?s:process.cwd()}getSessionCwd(e){return this.sessions.get(e)?.cwd??this.options.bindingStore?.get(e)?.cwd??this.resolveCwd()}buildPromptText(e){let s=e.text;if(e.contextMessages&&e.contextMessages.length>0){const t=e.contextMessages.map(i=>`[context] ${i.senderId}: ${i.content}`).join(`
1
+ import{EventEmitter as T}from"node:events";import{stat as M}from"node:fs/promises";import{existsSync as $,mkdirSync as O,readFileSync as F,writeFileSync as D}from"node:fs";import{join as S,resolve as B,dirname as L}from"node:path";import{homedir as N}from"node:os";import{fileURLToPath as j}from"node:url";import{resolveCommandPath as Q,spawnCommand as U,killProcessGroup as y,hasChildProcesses as q}from"../../core/runtime/spawn.js";import{InternalApiServer as H}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as J,pruneLegacyMcpServerEntries as V}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as W}from"../shared/inbound-message-id-injector.js";import{IdentityInjector as z}from"../shared/identity-injector.js";import{syncDefaultSkillsToDir as G}from"../../default-skills/index.js";import{buildSimpleProbeReport as X}from"../shared/probe-util.js";import{compactToolInputForWire as Y}from"../shared/tool-wire-payload.js";import{normalizeOCProviderModels as K}from"./opencode-types.js";import{buildOpencodeConfigContent as Z}from"./opencode-config.js";import{agentIdOf as A}from"../shared/native-provider-config.js";import{formatOpenCodeErrorMessage as k}from"./format-error.js";import{OpenCodeTransport as ee}from"./opencode-transport.js";import{log as r}from"../../core/log/index.js";import{splitTextForAibotProtocol as x}from"../../core/protocol/index.js";class te extends T{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitError(e){if(this.listenerCount("error")===0){r.warn("opencode-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}const se=200,ie=2e3,ne=12e4,oe=90*1e3,b=1800*1e3,P=3e4,R=600*1e3,re="claude_interaction_reply",ae="set_mode",de="set_model",ce="127.0.0.1",le=0,he=1e3,m={fullAuto:"full_auto",approval:"approval"},C=[{id:m.fullAuto,displayName:"Full Auto"},{id:m.approval,displayName:"Approval"}],pe=[{permission:"*",pattern:"*",action:"allow"}],ue=[{permission:"doom_loop",pattern:"*",action:"ask"},{permission:"external_directory",pattern:"*",action:"ask"},{permission:"question",pattern:"*",action:"deny"},{permission:"plan_enter",pattern:"*",action:"deny"},{permission:"plan_exit",pattern:"*",action:"deny"},{permission:"repo_clone",pattern:"*",action:"deny"},{permission:"repo_overview",pattern:"*",action:"deny"},{permission:"read",pattern:"*.env",action:"ask"},{permission:"read",pattern:"*.env.*",action:"ask"},{permission:"read",pattern:"*.env.example",action:"allow"}];function w(g){const e=String(g??"").trim().toLowerCase();if(e==="full_auto"||e==="fullauto")return m.fullAuto;if(e==="approval"||e==="ask"||e==="autoedit"||e==="auto_edit")return m.approval}function E(g){try{return process.kill(g,0),!0}catch(e){return e.code==="EPERM"}}class Fe extends T{type="opencode";config;callbacks;options;identity;inboundMessageIds=new W;process=null;transport=new ee;alive=!1;stopped=!1;internalApi=null;sessions=new Map;sessionModes=new Map;sessionModels=new Map;availableModels=[];modelContextLimits=new Map;contextTokensBySession=new Map;activeRun=null;completedEvents=new Set;clientMsgSeq=0;auditCaptures=new Map;completedAuditBoundaries=new Map;idleTimer=null;lastSseAt=0;livenessExtendStartAt;toolCallsInFlight=new Set;toolCardsSent=new Set;messageRoles=new Map;pendingPartChunks=new Map;pendingPermissions=new Map;pendingQuestions=new Map;permissionHandler=null;constructor(e,s,t){super(),this.config=e,this.callbacks=s,this.options=t??{},this.identity=new z("opencode-adapter",s.getAgentProfile)}onAgentProfileChanged(){this.identity.onProfileChanged()}async start(){await this.startInternalApiAndInjectMcp();const e=this.options.hostname??ce,s=this.options.port??le,t=await this.spawnAndWait(e,s),i=this.resolveCwd();await this.transport.connect(t,i),this.transport.on("event",n=>this.handleSseEvent(n));try{await this.refreshModels()}catch(n){r.warn("opencode-adapter",`Failed to fetch providers for toolbar models: ${n instanceof Error?n.message:String(n)}`)}r.info("opencode-adapter",`Ready (pid=${this.process?.pid}, url=${t})`)}async refreshModels(e){const s=await this.transport.listProviders(e),t=[],i=new Map;for(const n of s)for(const o of K(n.models)){t.push({id:`${n.id}/${o.id}`,displayName:o.name||o.id});const a=o.limit?.context;typeof a=="number"&&a>0&&i.set(`${n.id}/${o.id}`,a)}t.sort((n,o)=>{const a=n.displayName.toLowerCase().localeCompare(o.displayName.toLowerCase());return a!==0?a:n.id.localeCompare(o.id)}),this.availableModels=t,this.modelContextLimits=i,r.info("opencode-adapter",`Fetched ${t.length} models from ${s.length} providers (directory=${e??"current"})`)}resolveContextLimit(e,s){const t=this.modelContextLimits.get(`${e}/${s}`);if(t)return t;let i;for(const[n,o]of this.modelContextLimits)n.startsWith(`${e}/`)&&(i=i===void 0?o:Math.max(i,o));return i}buildContextWindowMeta(e,s,t,i){if(!i||i<=0)return;const n=this.resolveContextLimit(s,t);if(!n)return;const o=Math.min(100,i/n*100);return{context_window:{used:i,size:n,usedPercentage:o,remainingPercentage:100-o}}}async stop(){if(this.stopped=!0,this.alive=!1,this.stopComposing(),this.stopIdleTimer(),this.stopTextFlush(),this.transport.disconnect(),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null),this.process){const e=this.process;try{y(e,"SIGTERM")}catch{}const s=setTimeout(()=>{try{y(e,"SIGKILL")}catch{}},5e3);e.on("exit",()=>clearTimeout(s)),this.process=null}}isAlive(){return this.alive}async createSession(e){const s=e.cwd??this.resolveCwd();await this.transport.useDirectory(s);const t=await this.transport.createSession({title:`grix-${Date.now()}`},s);return this.sessions.set(t.id,{ocSessionId:t.id,cwd:s}),r.info("opencode-adapter",`Created OC session ${t.id} for cwd=${s}`),await this.applySessionPermission(t.id,t.id,s),t.id}async resumeSession(e,s){const t=this.sessions.get(e);if(t?.ocSessionId)try{await this.transport.useDirectory(t.cwd),await this.transport.getSession(t.ocSessionId,t.cwd),await this.applySessionPermission(e,t.ocSessionId,t.cwd)}catch{r.warn("opencode-adapter",`OC session ${t.ocSessionId} gone, will create new on next prompt`),t.ocSessionId=""}}async destroySession(e){const s=this.sessions.get(e),t=s?s.ocSessionId:e;if(t)try{await this.transport.deleteSession(t,s?.cwd)}catch{}this.sessions.delete(e),this.contextTokensBySession.delete(e),this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e)}sendPrompt(e){const s=new te(e.adapterSessionId);return this.sendOcPrompt(e.adapterSessionId,this.buildPromptText(e)).catch(t=>{s.emitError(t instanceof Error?t:new Error(String(t)))}),s}async cancel(e){if(this.activeRun)try{await this.transport.abortSession(this.activeRun.ocSessionId,this.activeRun.cwd)}catch{}}deliverInboundEvent(e){const{event_id:s,session_id:t,content:i}=e;if(this.completedEvents.has(s)){r.info("opencode-adapter",`Dropping duplicate event ${s}`),this.callbacks.sendEventAck(s,t),this.callbacks.sendEventResult(s,"responded");return}if(!this.alive){r.warn("opencode-adapter",`Dropping event ${s}: process not alive`),this.callbacks.sendEventAck(s,t),this.callbacks.sendEventResult(s,"failed","Agent process not running");return}this.activeRun&&this.activeRun.eventId!==s&&(r.info("opencode-adapter",`steer: ${this.activeRun.eventId} -> ${s}`),this.flushTextBuffer(),this.callbacks.sendEventResult(this.activeRun.eventId,"canceled","steered to new event"),this.clearRun()),r.info("opencode-adapter",`prompt: event=${s} session=${t}`),this.callbacks.sendEventAck(s,t),this.startRun(s,t,e.audit?.enabled===!0),this.startComposing(t),this.resetIdleTimer();const n=this.buildPromptTextFromEvent(e);this.sendOcPrompt(t,n).catch(o=>{r.error("opencode-adapter",`prompt_async failed: ${o}`),this.finishRun("failed",String(o))})}deliverStopEvent(e,s){this.activeRun&&this.activeRun.eventId===e&&(r.info("opencode-adapter",`stop: event=${e}`),this.rejectAllPendingInteractions(),this.transport.abortSession(this.activeRun.ocSessionId,this.activeRun.cwd).catch(()=>{}),this.flushTextBuffer(),this.finishRun("canceled","stopped by user"))}setPermissionHandler(e){this.permissionHandler=e}async ping(e){return this.transport.healthCheck()}getStatus(){return{alive:this.alive,busy:this.activeRun!==null,sessions:this.sessions.size}}getActiveEventIds(){return this.activeRun?[this.activeRun.eventId]:[]}takeAuditBoundary(e){const s=this.completedAuditBoundaries.get(e);return s&&this.completedAuditBoundaries.delete(e),s}clearActiveEventForShutdown(){this.stopIdleTimer(),this.stopTextFlush(),this.rejectAllPendingInteractions(),this.activeRun&&this.snapshotAuditBoundary(this.activeRun),this.activeRun=null}getMcpConfig(){if(!this.internalApi)return null;const e=B(j(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:J(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?q(e,[e]):!1}async probe(e){const s=this.getStatus();return X(this.config.command||"opencode",{alive:s.alive,busy:s.busy,started:!!this.process},e)}async startInternalApiAndInjectMcp(){try{this.internalApi=new H,this.internalApi.setInvokeHandler(async(d,l,h,u)=>this.callbacks.agentInvoke(d,l,u)),await this.internalApi.start(0),r.info("opencode-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),s=A(this.config.command||"opencode")||"opencode",t=process.env.XDG_CONFIG_HOME||S(N(),".config"),i=S(t,s,`${s}.json`);O(L(i),{recursive:!0});let n={};try{$(i)&&(n=JSON.parse(F(i,"utf8")))}catch{}const o=n.mcp&&typeof n.mcp=="object"?n.mcp:{};V(o,this.internalApi.url),o[e.name]={type:"local",command:[e.command,...e.args??[]],enabled:!0},n.mcp=o,D(i,`${JSON.stringify(n,null,2)}
2
+ `,"utf8"),r.info("opencode-adapter",`MCP config injected into ${i}`);const a=S(t,s,"skills"),c=G(a);c.length>0&&r.info("opencode-adapter",`Synced connector skills to ${a}: [${c.join(", ")}]`)}catch(e){r.warn("opencode-adapter",`Failed to inject MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}async handleLocalAction(e){const{action_type:s}=e;if(s==="exec_approve"||s==="exec_reject"||s==="permission_approve"||s==="permission_reject")return this.handlePermissionAction(e);if(s===ae)return this.handleSetModeAction(e);if(s===de)return this.handleSetModelAction(e);if(s===re){const t=e.params??{};if(String(t.kind??"")==="permission"){const i=t.resolution??{},n=String(i.value??"");return this.handlePermissionAction({...e,action_type:n==="allow"?"exec_approve":"exec_reject",params:{...t,approval_command_id:t.request_id}})}return this.handleQuestionReplyAction(e)}return{handled:!1,kind:""}}handleQuestionReplyEvent(e){let s;if(e.action)s={type:"action",value:e.action};else if(e.response?.type==="single")s={type:"text",value:e.response.value};else if(e.response?.type==="map")s={type:"map",entries:e.response.entries};else return{delivered:!1,errorCode:"resolution_invalid",errorMsg:"Question reply response is invalid."};return this.deliverQuestionReply({request_id:e.request_id,resolution:s})}async bindSession(e,s){if(r.info("opencode-adapter",`bindSession: ${e} \u2192 ${s}`),!this.sessions.has(e))this.sessions.set(e,{ocSessionId:"",cwd:s});else{const t=this.sessions.get(e);t.cwd=s}try{await this.refreshModels(s)}catch(t){r.warn("opencode-adapter",`Failed to refresh models on bind: ${t instanceof Error?t.message:String(t)}`)}this.callbacks.sendUpdateBindingCard(e,"ready",s,this.buildToolbarMeta(e))}resolveModeId(e){if(e){const t=this.sessionModes.get(e);if(t)return t}const s=w(this.options.permissionPolicy);if(s)return s;if(e){const t=w(this.options.bindingStore?.get(e)?.modeId);if(t)return t}return m.fullAuto}buildModeToolbarMeta(e){const s=this.resolveModeId(e);return{mode_id:s,currentModeId:s,available_modes:C.map(t=>({...t}))}}async applySessionPermission(e,s,t){const i=this.resolveModeId(e),n=i===m.fullAuto?pe:ue;try{await this.transport.updateSessionPermission(s,n,t),r.info("opencode-adapter",`Applied session permission ruleset (${i}) to ${s}`)}catch(o){r.warn("opencode-adapter",`Failed to apply session permission ruleset: ${o instanceof Error?o.message:String(o)}`)}}async handleSetModeAction(e){const s=e.params??{},t=String(s.session_id??this.options.aibotSessionId??"").trim(),i=w(s.mode_id);if(!i||!t)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","mode_id must be full_auto or approval and session_id is required"),{handled:!0,kind:"set_mode"};this.sessionModes.set(t,i);const n=this.sessions.get(t);n?.ocSessionId&&await this.applySessionPermission(t,n.ocSessionId,n.cwd);const o=n?.cwd??this.getSessionCwd(t);return this.callbacks.sendUpdateBindingCard(t,"ready",o,this.buildToolbarMeta(t)),this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"mode_set",session_context:{mode_id:i,modeId:i},mode_id:i,available_modes:C.map(a=>({...a}))}),{handled:!0,kind:"set_mode"}}resolveModelId(e){if(e){const t=this.sessionModels.get(e);if(t)return t}const s=String(this.options.model??"").trim();if(s)return s;if(e){const t=String(this.options.bindingStore?.get(e)?.modelId??"").trim();if(t)return t}return""}buildModelToolbarMeta(e){const s=this.resolveModelId(e);return{model_id:s,currentModelId:s,available_models:this.availableModels.map(t=>({...t}))}}buildToolbarMeta(e){return{...this.buildModelToolbarMeta(e),...this.buildModeToolbarMeta(e)}}handleSetModelAction(e){const s=e.params??{},t=String(s.session_id??this.options.aibotSessionId??"").trim(),i=String(s.model_id??"").trim();if(!i||!t)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","model_id and session_id are required"),{handled:!0,kind:"set_model"};this.sessionModels.set(t,i);const n=this.sessions.get(t)?.cwd??this.getSessionCwd(t);return this.callbacks.sendUpdateBindingCard(t,"ready",n,this.buildToolbarMeta(t)),this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"model_set",session_context:{model_id:i,modelId:i},model_id:i,available_models:this.availableModels.map(o=>({...o}))}),{handled:!0,kind:"set_model"}}async spawnAndWait(e,s){const t=this.resolveCwd();try{if(!(await M(t)).isDirectory())throw new Error(`Bound path is not a directory: ${t}`)}catch(i){throw String(i?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${t}. Please rebind with /grix open <valid-directory>.`):i}return new Promise((i,n)=>{const o=this.config.command||"opencode",c=[...this.config.args??["serve"],`--hostname=${e}`,`--port=${s}`],d={...process.env,...this.config.env},l=Z({model:this.options.model,permissionPolicy:this.options.permissionPolicy,provider:this.options.provider});if(l){const v=(A(o)||"opencode").toUpperCase().replace(/[^A-Z0-9_]/g,"_")||"OPENCODE";d[`${v}_CONFIG_CONTENT`]=JSON.stringify(l)}const h=Q(o,typeof d.PATH=="string"?d.PATH:void 0);r.info("opencode-adapter",`Spawning: ${h} ${c.join(" ")} (cwd=${t})`),this.process=U(h,c,{env:d,cwd:t}).process;let u="",f=!1;const I=setTimeout(()=>{f||(f=!0,n(new Error(`opencode serve did not start after ${P/1e3}s`)))},P);this.process.stdout?.on("data",p=>{if(u+=p.toString(),!f)for(const v of u.split(`
3
+ `)){const _=v.match(/\bserver listening on (https?:\/\/\S+)/);if(_){clearTimeout(I),f=!0,this.alive=!0,i(_[1]);return}}}),this.process.stderr?.on("data",p=>{const v=p.toString().trim();v&&r.info("opencode-adapter",`[stderr] ${v}`)}),this.process.on("error",p=>{r.error("opencode-adapter",`Spawn error: ${p.message}`),clearTimeout(I),this.alive=!1,this.transport.disconnect(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`Spawn error: ${p.message}`),this.clearRun()),f?this.stopped||this.emit("exit",1):(f=!0,n(p))}),this.process.on("exit",p=>{r.info("opencode-adapter",`Process exited (code=${p})`),clearTimeout(I),this.alive=!1,this.transport.disconnect(),this.stopComposing(),this.stopIdleTimer(),this.stopTextFlush(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`Process exited (code=${p})`),this.clearRun()),f?this.stopped||this.emit("exit",p??1):(f=!0,n(new Error(`opencode serve exited with code ${p}`)))})})}async ensureOcSession(e){const s=this.sessions.get(e),t=this.getSessionCwd(e);if(await this.transport.useDirectory(t),s?.ocSessionId)try{return await this.transport.getSession(s.ocSessionId,t),s.ocSessionId}catch{r.warn("opencode-adapter",`OC session ${s.ocSessionId} gone, creating new`),s.ocSessionId=""}const i=this.options.bindingStore?.getAcpSessionId(e);if(i)try{return await this.transport.getSession(i,t),this.sessions.set(e,{ocSessionId:i,cwd:t}),r.info("opencode-adapter",`Resumed OC session ${i} for aibot=${e}`),await this.applySessionPermission(e,i,t),i}catch{r.warn("opencode-adapter",`Persisted OC session ${i} gone, creating new`)}const n=await this.transport.createSession({title:`grix-${e.slice(-8)}`},t);return this.sessions.set(e,{ocSessionId:n.id,cwd:t}),this.options.bindingStore?.setAcpSessionId(e,n.id),r.info("opencode-adapter",`Created OC session ${n.id} for aibot=${e}`),await this.applySessionPermission(e,n.id,t),n.id}async sendOcPrompt(e,s){const t=this.getSessionCwd(e),i=await this.ensureOcSession(e);this.activeRun&&(this.activeRun.ocSessionId=i,this.activeRun.cwd=t);const n=this.resolveModelId(e),o=n.indexOf("/"),a=o>0&&o<n.length-1?{providerID:n.slice(0,o),modelID:n.slice(o+1)}:void 0;await this.transport.sendPromptAsync(i,{parts:[{type:"text",text:s}],...a?{model:a}:{}},t)}handleSseEvent(e){if(!this.stopped){if(this.updateToolInFlight(e),e.type!=="server.heartbeat"&&(this.lastSseAt=Date.now(),this.resetIdleTimer()),this.activeRun){const s=this.auditCaptures.get(this.activeRun.eventId);s&&s.push({sequence:s.length,observedAt:new Date().toISOString(),event:structuredClone(e)})}switch(e.type){case"message.part.updated":{if(!this.activeRun)break;const s=e.part,t=e.delta;if(s.type==="text"){const i=t||s.text;i&&this.acceptAssistantPartText(s.messageID,"text",i)}else s.type==="reasoning"?t&&this.acceptAssistantPartText(s.messageID,"reasoning",t):s.type==="tool"&&this.handleToolPartUpdate(s,t);break}case"message.updated":{if(!this.activeRun)break;const s=e.info;if(this.rememberMessageRole(s),s.role==="assistant"){const t=s;typeof t.tokens?.input=="number"&&this.contextTokensBySession.set(this.activeRun.sessionId,t.tokens.input);const i=this.buildContextWindowMeta(this.activeRun.sessionId,t.providerID,t.modelID,t.tokens?.input);this.callbacks.sendUpdateBindingCard(this.activeRun.sessionId,"composing",this.activeRun.cwd,{...this.buildToolbarMeta(this.activeRun.sessionId),model_provider:t.providerID,model_id:t.modelID,...i??{}}),t.error&&r.warn("opencode-adapter",`Message error: ${JSON.stringify(t.error)}`);const n=this.activeRun.ocSessionId;n&&t.sessionID===n&&(t.error?(this.flushTextBuffer(),this.finishRun("failed",k(t.error,t.error.type||"unknown error"))):t.time?.completed&&t.finish!=="tool-calls"&&(this.flushTextBuffer(),this.finishRun("responded")))}break}case"session.idle":{if(!this.activeRun)break;e.sessionID===this.activeRun.ocSessionId&&(this.flushTextBuffer(),this.finishRun("responded"));break}case"session.status":{if(!this.activeRun)break;e.sessionID===this.activeRun.ocSessionId&&e.status.type==="idle"&&(this.flushTextBuffer(),this.finishRun("responded"));break}case"session.error":{if(!this.activeRun)break;const s=k(e.error);r.error("opencode-adapter",`Session error: ${s}`),this.flushTextBuffer(),this.finishRun("failed",s);break}case"permission.updated":{this.handlePermission(e.permission);break}case"permission.asked":{this.handlePermissionAsked(e);break}case"question.asked":{this.handleQuestionAsked(e);break}case"permission.replied":case"question.replied":case"question.rejected":r.debug("opencode-adapter",`Interaction settled: ${e.type}`);break;case"session.created":case"session.updated":case"session.deleted":case"session.compacted":case"session.diff":case"file.edited":case"server.connected":case"server.heartbeat":break;case"server.instance.disposed":{r.warn("opencode-adapter",`Server instance disposed: ${e.directory}`),this.alive=!1,this.transport.disconnect(),this.activeRun&&(this.flushTextBuffer(),this.callbacks.sendEventResult(this.activeRun.eventId,"failed","server instance disposed"),this.clearRun()),this.stopped||this.emit("exit",-1);break}default:r.debug("opencode-adapter",`Unhandled SSE event type: ${e.type}`);break}}}updateToolInFlight(e){if(e.type!=="message.part.updated")return;const s=e.part;if(s?.type!=="tool"||!s.callID)return;const t=s.state?.status;t==="pending"||t==="running"?this.toolCallsInFlight.add(s.callID):(t==="completed"||t==="error")&&this.toolCallsInFlight.delete(s.callID)}rememberMessageRole(e){const s=typeof e.id=="string"?e.id.trim():"";s&&(e.role!=="user"&&e.role!=="assistant"||(this.messageRoles.set(s,e.role),this.flushOrDropPendingParts(s,e.role)))}acceptAssistantPartText(e,s,t){if(!this.activeRun||!t)return;const i=typeof e=="string"?e.trim():"";if(!i)return;const n=this.messageRoles.get(i);if(n==="user")return;if(n==="assistant"){this.emitAssistantPartChunk(s,t);return}const o=this.pendingPartChunks.get(i)??[];o.push({kind:s,value:t}),this.pendingPartChunks.set(i,o)}flushOrDropPendingParts(e,s){const t=this.pendingPartChunks.get(e);if(this.pendingPartChunks.delete(e),!(!t||t.length===0)&&s==="assistant")for(const i of t)this.emitAssistantPartChunk(i.kind,i.value)}emitAssistantPartChunk(e,s){if(!(!this.activeRun||!s)){if(e==="reasoning"){this.callbacks.sendThinking(this.activeRun.eventId,this.activeRun.sessionId,s);return}this.appendText(s)}}clearMessageRoleState(){this.messageRoles.clear(),this.pendingPartChunks.clear()}handleToolPartUpdate(e,s){if(!this.activeRun)return;const t=e.state;switch(t.status){case"pending":case"running":{this.sendToolUseOnce(e,t.input);break}case"completed":{this.sendToolUseOnce(e,t.input);break}case"error":{this.sendToolUseOnce(e,t.input),this.callbacks.sendToolResult(this.activeRun.eventId,this.activeRun.sessionId,e.tool,"(failed)");break}}}sendToolUseOnce(e,s){!this.activeRun||this.toolCardsSent.has(e.callID)||(this.flushTextBuffer(),this.toolCardsSent.add(e.callID),this.callbacks.sendToolUse(this.activeRun.eventId,this.activeRun.sessionId,e.tool,Y(s??{})))}onPermissionTimeout(e){const s=this.pendingPermissions.get(e);s&&(this.pendingPermissions.delete(e),r.error("opencode-adapter",`Permission approval timeout: ${e}`),this.transport.respondPermission(s.ocSessionId,e,"reject",s.cwd).catch(()=>{}),this.activeRun&&this.activeRun.eventId===s.eventId&&(this.flushTextBuffer(),this.finishRun("failed","permission approval timeout")))}trackPendingPermission(e){if(!this.activeRun)return;this.stopIdleTimer();const s=setTimeout(()=>this.onPermissionTimeout(e),R);this.pendingPermissions.set(e,{permissionId:e,eventId:this.activeRun.eventId,ocSessionId:this.activeRun.ocSessionId,cwd:this.activeRun.cwd,timer:s})}handlePermissionAsked(e){if(!this.activeRun){this.transport.respondPermission(e.sessionID,e.id,"reject").catch(o=>{r.warn("opencode-adapter",`Orphan permission reject failed: ${o}`)});return}const{eventId:s,sessionId:t,ocSessionId:i}=this.activeRun;if(this.resolveModeId(t)===m.fullAuto){this.transport.respondPermission(i,e.id,"always",this.activeRun.cwd).catch(o=>{r.warn("opencode-adapter",`Auto-approve failed: ${o}`)});return}this.trackPendingPermission(e.id);const n=e.patterns.length>0?`${e.permission}: ${e.patterns.join(", ")}`:e.permission;this.callbacks.sendPermissionCard?this.callbacks.sendPermissionCard({eventId:s,sessionId:t,approvalId:e.id,toolName:e.permission,toolTitle:n,toolInput:JSON.stringify(e.metadata??{})}):this.callbacks.sendToolUse(s,t,e.permission,JSON.stringify(e.metadata??{}))}handlePermission(e){if(!this.activeRun)return;const{eventId:s,sessionId:t,ocSessionId:i}=this.activeRun;if(this.resolveModeId(t)===m.fullAuto){this.transport.respondPermission(i,e.id,"always",this.activeRun.cwd).catch(n=>{r.warn("opencode-adapter",`Auto-approve failed: ${n}`)});return}if(this.trackPendingPermission(e.id),this.callbacks.sendPermissionCard)this.callbacks.sendPermissionCard({eventId:s,sessionId:t,approvalId:e.id,toolName:e.type,toolTitle:e.title||e.type,toolInput:JSON.stringify(e.metadata??{})});else{const n=JSON.stringify(e.metadata??{});this.callbacks.sendToolUse(s,t,e.type,n)}}handlePermissionAction(e){if(!this.activeRun)return{handled:!1,kind:""};const s=e.params??{},t=String(s.approval_id??s.approval_command_id??s.approvalId??s.tool_call_id??"");let i=t?this.pendingPermissions.get(t):void 0;if(!i){for(const a of this.pendingPermissions.values())if(a.eventId===this.activeRun.eventId){i=a;break}}if(!i)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:"permission"};const n=e.action_type==="exec_approve"||e.action_type==="permission_approve",o=n?"once":"reject";return clearTimeout(i.timer),this.pendingPermissions.delete(i.permissionId),this.transport.respondPermission(i.ocSessionId,i.permissionId,o,i.cwd).then(()=>{r.info("opencode-adapter",`Permission ${o}: ${i.permissionId}`),this.resetIdleTimer()}).catch(a=>{r.warn("opencode-adapter",`Permission response failed: ${a}`),this.resetIdleTimer()}),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.permissionId,decision:n?"approve":"reject"}),{handled:!0,kind:"permission"}}async handleExecApprovalEvent(e){if(!this.activeRun)return{delivered:!1,errorCode:"approval_not_found",errorMsg:"no active run"};const s=String(e.approval_id??e.approval_command_id??e.tool_call_id??"");let t=s?this.pendingPermissions.get(s):void 0;if(!t){for(const n of this.pendingPermissions.values())if(n.eventId===this.activeRun.eventId){t=n;break}}if(!t)return{delivered:!1,errorCode:"approval_not_found",errorMsg:"That approval request is no longer pending."};const i=e.decision==="deny"?"reject":e.decision==="allow-always"?"always":"once";return clearTimeout(t.timer),this.pendingPermissions.delete(t.permissionId),this.transport.respondPermission(t.ocSessionId,t.permissionId,i,t.cwd).then(()=>{r.info("opencode-adapter",`Permission ${i} (text event): ${t.permissionId}`),this.resetIdleTimer()}).catch(n=>{r.warn("opencode-adapter",`Permission response failed: ${n}`),this.resetIdleTimer()}),{delivered:!0}}onQuestionTimeout(e){const s=this.pendingQuestions.get(e);s&&(this.pendingQuestions.delete(e),r.error("opencode-adapter",`Question answer timeout: ${e}`),this.transport.rejectQuestion(e,s.cwd).catch(()=>{}),this.activeRun&&this.activeRun.eventId===s.eventId&&(this.flushTextBuffer(),this.finishRun("failed","question answer timeout")))}handleQuestionAsked(e){if(!this.activeRun){this.transport.rejectQuestion(e.id).catch(n=>{r.warn("opencode-adapter",`Orphan question reject failed: ${n}`)});return}const{eventId:s,sessionId:t}=this.activeRun;this.stopIdleTimer();const i=setTimeout(()=>this.onQuestionTimeout(e.id),R);if(this.pendingQuestions.set(e.id,{requestId:e.id,eventId:s,cwd:this.activeRun.cwd,questions:e.questions,timer:i}),this.callbacks.sendAgentQuestionCard)this.callbacks.sendAgentQuestionCard(s,t,{request_id:e.id,mode:"form",questions:e.questions.map(n=>({header:n.header,prompt:n.question,...n.options.length>0?{options:n.options.map(o=>o.label)}:{},...n.multiple!==void 0?{multi_select:n.multiple}:{}})),expires_at:Date.now()+R});else{const n=e.questions.map(o=>o.question).join(`
4
+ `);this.callbacks.sendRunError(s,t,`Agent asks: ${n}`)}}handleQuestionReplyAction(e){const s=e.params??{},t=this.deliverQuestionReply(s);return t.delivered?this.callbacks.sendLocalActionResult(e.action_id,"ok",t.result):this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,t.errorCode,t.errorMsg),{handled:!0,kind:"question_reply"}}deliverQuestionReply(e){const s=String(e.request_id??""),t=s?this.pendingQuestions.get(s):void 0;if(!t)return{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The question is no longer pending; the reply was not delivered."};const i=e.resolution??{},n=String(i.type??""),o=(d,l)=>(clearTimeout(t.timer),this.pendingQuestions.delete(t.requestId),d().then(()=>this.resetIdleTimer()).catch(h=>{r.warn("opencode-adapter",`Question response failed: ${h}`),this.resetIdleTimer()}),{delivered:!0,result:l});if(n==="action"){const d=String(i.value??"");if(d==="cancel"||d==="decline")return o(()=>this.transport.rejectQuestion(t.requestId,t.cwd),{request_id:s,resolution:"cancel"})}let a=null;if(Array.isArray(e.answers))a=e.answers.map(d=>Array.isArray(d)?d.map(String):[String(d)]);else if(n==="text"){const d=String(i.value??"");d&&(a=t.questions.map((l,h)=>h===0?[d]:[]))}else if(n==="map"){const d=Array.isArray(i.entries)?i.entries:[];a=t.questions.map((l,h)=>{const u=d.find(f=>f.key===l.header||f.key===String(h+1));return u&&u.value?[u.value]:[]}),a.every(l=>l.length===0)&&d.length>0&&(a=t.questions.map((l,h)=>{const u=d[h]?.value;return u?[String(u)]:[]}))}if(!a||a.every(d=>d.length===0))return o(()=>this.transport.rejectQuestion(t.requestId,t.cwd),{request_id:s,resolution:"cancel"});const c=a;return o(()=>this.transport.replyQuestion(t.requestId,c,t.cwd),{request_id:s,resolution:"answer"})}rejectAllPendingInteractions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),this.transport.respondPermission(e.ocSessionId,e.permissionId,"reject",e.cwd).catch(()=>{});this.pendingPermissions.clear();for(const e of this.pendingQuestions.values())clearTimeout(e.timer),this.transport.rejectQuestion(e.requestId,e.cwd).catch(()=>{});this.pendingQuestions.clear()}hasPendingInteractionForRun(e){for(const s of this.pendingPermissions.values())if(s.eventId===e)return!0;for(const s of this.pendingQuestions.values())if(s.eventId===e)return!0;return!1}startRun(e,s,t=!1){this.activeRun={eventId:e,sessionId:s,ocSessionId:"",cwd:this.getSessionCwd(s),chunkSeq:0,clientMsgId:`oc_${++this.clientMsgSeq}_${Date.now()}`,textBuffer:"",flushTimer:null},this.toolCardsSent.clear(),t&&this.auditCaptures.set(e,[]),this.lastSseAt=Date.now(),this.livenessExtendStartAt=void 0}finishRun(e,s){const t=this.activeRun;if(!t)return;if(this.completedEvents.add(t.eventId),this.completedEvents.size>he){const c=[...this.completedEvents].slice(-500);this.completedEvents=new Set(c)}this.snapshotAuditBoundary(t),this.activeRun=null,this.rejectAllPendingInteractions(),this.toolCallsInFlight.clear(),this.toolCardsSent.clear(),this.livenessExtendStartAt=void 0,this.clearMessageRoleState(),this.stopComposing(),this.stopIdleTimer();const i=++t.chunkSeq,n=t.clientMsgId,o=e==="failed"&&!!s;o&&this.callbacks.sendRunError(t.eventId,t.sessionId,s);const a=()=>{this.callbacks.sendFinalStreamChunkReliable?this.callbacks.sendFinalStreamChunkReliable(t.eventId,t.sessionId,n).then(()=>{this.callbacks.sendEventResult(t.eventId,e,s,void 0,o)}).catch(c=>{const d=e==="responded"?"failed":e,l=e==="responded"?`final output delivery failed: ${c instanceof Error?c.message:String(c)}`:s,h=e==="responded"?!1:o;this.callbacks.sendEventResult(t.eventId,d,l,void 0,h)}):(this.callbacks.sendStreamChunk(t.eventId,t.sessionId,"",i,!0,n),this.callbacks.sendEventResult(t.eventId,e,s,void 0,o))};if(t.textBuffer){this.stopTextFlush();for(const c of x(t.textBuffer))t.chunkSeq++,this.callbacks.sendStreamChunk(t.eventId,t.sessionId,c,t.chunkSeq,!1,t.clientMsgId);t.textBuffer=""}a(),this.emit("eventDone",t.eventId)}clearRun(){this.activeRun?.flushTimer&&clearTimeout(this.activeRun.flushTimer);const e=this.activeRun?.eventId;this.activeRun&&this.snapshotAuditBoundary(this.activeRun),this.activeRun=null,this.rejectAllPendingInteractions(),this.toolCallsInFlight.clear(),this.toolCardsSent.clear(),this.livenessExtendStartAt=void 0,this.clearMessageRoleState(),this.stopIdleTimer(),e&&this.emit("eventDone",e)}snapshotAuditBoundary(e){const s=this.auditCaptures.get(e.eventId);s&&(this.completedAuditBoundaries.set(e.eventId,{adapterType:"opencode",providerSessionId:e.ocSessionId||void 0,openCodeEvidence:{events:s}}),this.auditCaptures.delete(e.eventId))}appendText(e){if(this.activeRun){if(this.activeRun.textBuffer+=e,this.activeRun.textBuffer.length>=ie){this.flushTextBuffer();return}this.scheduleTextFlush()}}scheduleTextFlush(){!this.activeRun||this.activeRun.flushTimer||(this.activeRun.flushTimer=setTimeout(()=>{this.activeRun&&(this.activeRun.flushTimer=null),this.flushTextBuffer()},se))}flushTextBuffer(){if(this.stopTextFlush(),!(!this.activeRun||!this.activeRun.textBuffer)){for(const e of x(this.activeRun.textBuffer))this.activeRun.chunkSeq++,this.callbacks.sendStreamChunk(this.activeRun.eventId,this.activeRun.sessionId,e,this.activeRun.chunkSeq,!1,this.activeRun.clientMsgId);this.activeRun.textBuffer=""}}stopTextFlush(){this.activeRun?.flushTimer&&(clearTimeout(this.activeRun.flushTimer),this.activeRun.flushTimer=null)}startComposing(e){}stopComposing(){}shouldExtendByLiveness(){if(!this.activeRun)return!1;const e=this.process?.pid;if(!this.alive||!e||!E(e))return!1;const s=Date.now(),t=this.lastSseAt>0?s-this.lastSseAt:Number.POSITIVE_INFINITY;if(t<oe)return this.livenessExtendStartAt=s,r.info("opencode-adapter",`Liveness check: fresh SSE for ${this.activeRun.eventId} (sseAge=${t}ms, toolsInFlight=${this.toolCallsInFlight.size}), extending`),!0;const n=this.livenessExtendStartAt??s;return this.livenessExtendStartAt===void 0&&(this.livenessExtendStartAt=n),s-n>b?(r.warn("opencode-adapter",`Liveness extension budget exhausted for ${this.activeRun.eventId} (no progress for ${Math.round((s-n)/6e4)}min), allowing idle fail`),!1):(r.info("opencode-adapter",`Liveness check: turn in progress for ${this.activeRun.eventId} (toolsInFlight=${this.toolCallsInFlight.size}, sseAge=${Number.isFinite(t)?`${t}ms`:"n/a"}), extending`),!0)}resetIdleTimer(){this.stopIdleTimer(),!(this.stopped||!this.activeRun)&&(this.idleTimer=setTimeout(()=>{if(this.stopped||!this.activeRun)return;if(this.hasPendingInteractionForRun(this.activeRun.eventId)&&this.shouldExtendByLiveness()){r.info("opencode-adapter",`Idle timeout skipped: pending interaction for ${this.activeRun.eventId}, resetting timer`),this.resetIdleTimer();return}if(this.shouldExtendByLiveness()){this.resetIdleTimer();return}const e=this.process?.pid,t=!!(this.alive&&e&&E(e))?`liveness budget exhausted after ${b/6e4}min`:"process not alive";r.error("opencode-adapter",`Idle timeout (${t}, toolsInFlight=${this.toolCallsInFlight.size}) \u2014 emitting exit for respawn`),this.flushTextBuffer(),this.activeRun&&(this.callbacks.sendEventResult(this.activeRun.eventId,"failed",`idle timeout: ${t}`),this.clearRun()),this.emit("exit",-1)},ne))}stopIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}resolveCwd(){const e=this.options.aibotSessionId?this.options.bindingStore?.get(this.options.aibotSessionId)?.cwd:void 0;if(e)return e;const s=(this.config.options??{}).cwd;return typeof s=="string"&&s?s:process.cwd()}getSessionCwd(e){return this.sessions.get(e)?.cwd??this.options.bindingStore?.get(e)?.cwd??this.resolveCwd()}buildPromptText(e){let s=e.text;if(e.contextMessages&&e.contextMessages.length>0){const t=e.contextMessages.map(i=>`[context] ${i.senderId}: ${i.content}`).join(`
5
5
  `);s=`${s}
6
6
 
7
7
  [Conversation context]
@@ -9,4 +9,4 @@ ${t}`}return this.identity.injectOnce(e.adapterSessionId,s)}buildPromptTextFromE
9
9
  `);s=`${s}
10
10
 
11
11
  [Conversation context]
12
- ${n}`}}catch{}const t=this.identity.injectOnce(e.session_id,s);return this.inboundMessageIds.inject(e.session_id,t,e.msg_id)}}export{$e as OpenCodeAdapter};
12
+ ${n}`}}catch{}const t=this.identity.injectOnce(e.session_id,s);return this.inboundMessageIds.inject(e.session_id,t,e.msg_id)}}export{Fe as OpenCodeAdapter};
@@ -1,8 +1,8 @@
1
- import{log as O}from"../../core/log/index.js";import{openReadOnlyDatabase as R}from"../../core/util/sqlite-reader.js";import{SESSION_HISTORY_ERROR_CODES as p,SessionHistoryError as f,decodeOpaqueCursor as E,encodeOpaqueCursor as x,normalizeHistoryLimit as I,registerSessionHistoryReader as b}from"../shared/session-history.js";import{resolveOpenCodeDbPath as T}from"./session-scanner.js";const w="opencode-session-history",A=/^[A-Za-z0-9][A-Za-z0-9_-]*$/;function y(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function N(t){const s=E(t);if(s.v!==2||typeof s.t!="number"||!Number.isFinite(s.t)||s.t<0||typeof s.id!="string")throw new f(p.invalidCursor,`invalid opencode sync_history cursor: ${t}`);return{t:s.t,id:s.id}}function g(t){return x({v:2,t:t.t,id:t.id})}function $(t){return t==="user"||t==="assistant"||t==="system"||t==="tool"?t:"system"}const m=new Set(["pending","running"]);function S(t){try{const s=JSON.parse(t.data);return y(s)?s:null}catch{return null}}function D(t){const s=S(t);if(!s||s.type!=="tool")return!1;const e=y(s.state)?s.state:void 0,r=typeof e?.status=="string"?e.status:"";return m.has(r)}function P(t,s){const e=S(t);if(!e)return[];const r=typeof e.type=="string"?e.type:"",d=t.id||s,c=t.message_id||null,h=new Date(t.time_created).toISOString(),o=[];if(r==="text"){if(typeof e.text!="string"||!e.text)return[];o.push({role:$(t.role),content:e.text,msg_type:"text"})}else if(r==="reasoning"){if(typeof e.text!="string"||!e.text)return[];o.push({role:"assistant",content:e.text,msg_type:"thinking"})}else if(r==="tool"){const a=typeof e.tool=="string"?e.tool:"",i=typeof e.callID=="string"?e.callID:"",n=y(e.state)?e.state:void 0;if(!a||!i)return O.warn(w,`skipped unidentifiable tool part: ${d}`),[];const _=typeof n?.status=="string"?n.status:"";if(m.has(_))return[];let u="{}";try{u=JSON.stringify(n?.input??{})}catch{}o.push({role:"assistant",content:u,msg_type:"tool_use",extra:{tool_name:a,tool_use_id:i}}),_==="error"?o.push({role:"tool",content:typeof n?.error=="string"?n.error:"",msg_type:"tool_result",extra:{tool_use_id:i,is_error:!0}}):o.push({role:"tool",content:typeof n?.output=="string"?n.output:"",msg_type:"tool_result",extra:{tool_use_id:i}})}else return[];return o.map((a,i)=>({native_message_id:i===0?d:`${d}#${i}`,native_parent_id:c,created_at:h,...a}))}async function C(t,s){if(!A.test(t.agent_session_id))throw new f(p.invalidAgentSession,`invalid agent_session_id: ${t.agent_session_id}`);const e=t.cursor?N(t.cursor):{t:0,id:""},r=I(t.limit),d=s?.dbPath??T(),c=R(d);if(!c)throw new f(p.sourceUnreadable,`failed to open opencode database: ${d}`);try{if(c.all("SELECT id FROM session WHERE id = ?",t.agent_session_id).length===0)throw new f(p.sessionNotFound,`opencode session not found: ${t.agent_session_id}`);let o;try{o=c.all(`SELECT p.id, p.message_id, p.time_created, p.data,
1
+ import{log as b}from"../../core/log/index.js";import{openReadOnlyDatabase as x}from"../../core/util/sqlite-reader.js";import{SESSION_HISTORY_ERROR_CODES as p,SessionHistoryError as f,decodeOpaqueCursor as I,encodeOpaqueCursor as T,normalizeHistoryLimit as w,registerSessionHistoryReader as m}from"../shared/session-history.js";import{resolveOpenCodeDbPath as S}from"./session-scanner.js";const A="opencode-session-history",N=/^[A-Za-z0-9][A-Za-z0-9_-]*$/;function y(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function $(t){const s=I(t);if(s.v!==2||typeof s.t!="number"||!Number.isFinite(s.t)||s.t<0||typeof s.id!="string")throw new f(p.invalidCursor,`invalid opencode sync_history cursor: ${t}`);return{t:s.t,id:s.id}}function g(t){return T({v:2,t:t.t,id:t.id})}function P(t){return t==="user"||t==="assistant"||t==="system"||t==="tool"?t:"system"}const O=new Set(["pending","running"]);function R(t){try{const s=JSON.parse(t.data);return y(s)?s:null}catch{return null}}function D(t){const s=R(t);if(!s||s.type!=="tool")return!1;const e=y(s.state)?s.state:void 0,r=typeof e?.status=="string"?e.status:"";return O.has(r)}function C(t,s){const e=R(t);if(!e)return[];const r=typeof e.type=="string"?e.type:"",d=t.id||s,c=t.message_id||null,h=new Date(t.time_created).toISOString(),o=[];if(r==="text"){if(typeof e.text!="string"||!e.text)return[];o.push({role:P(t.role),content:e.text,msg_type:"text"})}else if(r==="reasoning"){if(typeof e.text!="string"||!e.text)return[];o.push({role:"assistant",content:e.text,msg_type:"thinking"})}else if(r==="tool"){const a=typeof e.tool=="string"?e.tool:"",i=typeof e.callID=="string"?e.callID:"",n=y(e.state)?e.state:void 0;if(!a||!i)return b.warn(A,`skipped unidentifiable tool part: ${d}`),[];const _=typeof n?.status=="string"?n.status:"";if(O.has(_))return[];let u="{}";try{u=JSON.stringify(n?.input??{})}catch{}o.push({role:"assistant",content:u,msg_type:"tool_use",extra:{tool_name:a,tool_use_id:i}}),_==="error"?o.push({role:"tool",content:typeof n?.error=="string"?n.error:"",msg_type:"tool_result",extra:{tool_use_id:i,is_error:!0}}):o.push({role:"tool",content:typeof n?.output=="string"?n.output:"",msg_type:"tool_result",extra:{tool_use_id:i}})}else return[];return o.map((a,i)=>({native_message_id:i===0?d:`${d}#${i}`,native_parent_id:c,created_at:h,...a}))}async function E(t,s){if(!N.test(t.agent_session_id))throw new f(p.invalidAgentSession,`invalid agent_session_id: ${t.agent_session_id}`);const e=t.cursor?$(t.cursor):{t:0,id:""},r=w(t.limit),d=s?.dbPath??S(),c=x(d);if(!c)throw new f(p.sourceUnreadable,`failed to open opencode database: ${d}`);try{if(c.all("SELECT id FROM session WHERE id = ?",t.agent_session_id).length===0)throw new f(p.sessionNotFound,`opencode session not found: ${t.agent_session_id}`);let o;try{o=c.all(`SELECT p.id, p.message_id, p.time_created, p.data,
2
2
  json_extract(m.data, '$.role') AS role
3
3
  FROM part p
4
4
  LEFT JOIN message m ON m.id = p.message_id
5
5
  WHERE p.session_id = ?
6
6
  AND (p.time_created > ? OR (p.time_created = ? AND p.id > ?))
7
7
  ORDER BY p.time_created, p.id
8
- LIMIT ?`,t.agent_session_id,e.t,e.t,e.id,r+1)}catch(l){throw new f(p.sourceUnreadable,`failed to query opencode parts for ${t.agent_session_id}: ${l}`)}if(o.length===0)return{messages:[],has_more:!1,next_cursor:t.cursor??g(e),...t.sync_run_id?{sync_run_id:t.sync_run_id}:{}};let a=o.length>r;const i=o.slice(0,r),n=[],_=[];for(const l of i){if(D(l)){a=!1;break}n.push(l),_.push(...P(l,`part-${l.time_created}-${n.length-1}`))}const u=n[n.length-1];return{messages:_,has_more:a,next_cursor:u?g({t:u.time_created,id:u.id}):t.cursor??g(e),...t.sync_run_id?{sync_run_id:t.sync_run_id}:{}}}finally{c.close()}}b("opencode",C);export{C as readOpenCodeSessionHistory};
8
+ LIMIT ?`,t.agent_session_id,e.t,e.t,e.id,r+1)}catch(l){throw new f(p.sourceUnreadable,`failed to query opencode parts for ${t.agent_session_id}: ${l}`)}if(o.length===0)return{messages:[],has_more:!1,next_cursor:t.cursor??g(e),...t.sync_run_id?{sync_run_id:t.sync_run_id}:{}};let a=o.length>r;const i=o.slice(0,r),n=[],_=[];for(const l of i){if(D(l)){a=!1;break}n.push(l),_.push(...C(l,`part-${l.time_created}-${n.length-1}`))}const u=n[n.length-1];return{messages:_,has_more:a,next_cursor:u?g({t:u.time_created,id:u.id}):t.cursor??g(e),...t.sync_run_id?{sync_run_id:t.sync_run_id}:{}}}finally{c.close()}}m("opencode",E),m("deveco",t=>E(t,{dbPath:S(void 0,"deveco")}));export{E as readOpenCodeSessionHistory};
@@ -1,6 +1,6 @@
1
- import i from"node:path";import{homedir as s}from"node:os";import{log as d}from"../../core/log/index.js";import{makeTitle as c,stripInjectedPreamble as p}from"../../core/util/session-title.js";import{openReadOnlyDatabase as m}from"../../core/util/sqlite-reader.js";function l(t=s()){const o=process.env.XDG_DATA_HOME;return i.join(o||i.join(t,".local","share"),"opencode")}function f(t=s()){return i.join(l(t),"opencode.db")}function u(t,o){const r=t.all(`SELECT p.data AS data FROM part p
1
+ import a from"node:path";import{homedir as d}from"node:os";import{log as c}from"../../core/log/index.js";import{makeTitle as p,stripInjectedPreamble as m}from"../../core/util/session-title.js";import{openReadOnlyDatabase as l}from"../../core/util/sqlite-reader.js";function f(t=d(),e="opencode"){const o=process.env.XDG_DATA_HOME;return a.join(o||a.join(t,".local","share"),e)}function u(t=d(),e="opencode"){return a.join(f(t,e),`${e}.db`)}function O(t,e){const o=t.all(`SELECT p.data AS data FROM part p
2
2
  JOIN message m ON m.id = p.message_id
3
3
  WHERE p.session_id = ? AND json_extract(m.data, '$.role') = 'user'
4
4
  ORDER BY p.time_created, p.id
5
- LIMIT 20`,o);for(const a of r)try{const n=JSON.parse(a.data);if(n.type!=="text"||typeof n.text!="string")continue;const e=c(p(n.text));if(e)return e}catch{}}function x(t=s()){const o=f(t),r=m(o);if(!r)return[];try{const n=r.all(`SELECT id, directory, time_created, time_updated, time_archived
6
- FROM session ORDER BY time_updated DESC`).map(e=>({sessionId:e.id,cwd:e.directory??"",title:u(r,e.id),createdAt:e.time_created,updatedAt:e.time_updated,archived:e.time_archived!=null}));return d.info("opencode-session-scanner",`Scanned ${n.length} OpenCode sessions from ${o}`),n}catch{return[]}finally{r.close()}}export{l as resolveOpenCodeDataDir,f as resolveOpenCodeDbPath,x as scanOpenCodeSessions};
5
+ LIMIT 20`,e);for(const n of o)try{const s=JSON.parse(n.data);if(s.type!=="text"||typeof s.text!="string")continue;const i=p(m(s.text));if(i)return i}catch{}}function y(t=d(),e="opencode"){const o=u(t,e),n=l(o);if(!n)return[];try{const i=n.all(`SELECT id, directory, time_created, time_updated, time_archived
6
+ FROM session ORDER BY time_updated DESC`).map(r=>({sessionId:r.id,cwd:r.directory??"",title:O(n,r.id),createdAt:r.time_created,updatedAt:r.time_updated,archived:r.time_archived!=null}));return c.info("opencode-session-scanner",`Scanned ${i.length} OpenCode sessions from ${o}`),i}catch{return[]}finally{n.close()}}export{f as resolveOpenCodeDataDir,u as resolveOpenCodeDbPath,y as scanOpenCodeSessions};
@@ -0,0 +1,3 @@
1
+ import{existsSync as h,readFileSync as A,writeFileSync as g,unlinkSync as a,mkdirSync as S}from"node:fs";import{randomBytes as k}from"node:crypto";import{dirname as P,join as O}from"node:path";import{serializeOnFile as u}from"../shared/serialize-on-file.js";import{log as w}from"../../core/log/index.js";const b=".grix-mcp-state.json",$=15e3;function f(t){return O(t,".omp","mcp.json")}function y(t){return O(t,".omp",b)}function x(t){if(!t||t<=0)return!1;try{return process.kill(t,0),!0}catch(e){return e?.code==="EPERM"}}function v(t){try{if(!h(t))return{};const e=JSON.parse(A(t,"utf8"));return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}catch{return{}}}function p(t){const r=v(t).mcpServers;return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}function d(t){return v(t)}function l(t,e){S(P(t),{recursive:!0}),g(t,`${JSON.stringify({mcpServers:e},null,2)}
2
+ `,{encoding:"utf8",mode:384})}function m(t,e){S(P(t),{recursive:!0}),g(t,`${JSON.stringify(e,null,2)}
3
+ `,{encoding:"utf8",mode:384})}function M(t,e){return t.pid===0?e-t.createdAt>$:!x(t.pid)}function j(t,e){const r=Date.now(),o=[];for(const n of Object.keys(e))M(e[n],r)&&(delete t[n],delete e[n],o.push(n));return o}async function C(t,e){const r=f(t),o=y(t);return u(r,async()=>{const n=p(r),c=d(o),i=j(n,c),s=`${e.name}-${k(4).toString("hex")}`;return n[s]={type:"stdio",command:e.command,args:e.args},c[s]={pid:0,createdAt:Date.now()},l(r,n),m(o,c),w.info("pi-adapter",`omp MCP \u914D\u7F6E\u5DF2\u5199\u5165 ${r}\uFF08key=${s}${i.length>0?`\uFF0C\u6E05\u7406\u9648\u65E7\u6761\u76EE [${i.join(", ")}]`:""}\uFF09`),s})}async function L(t,e,r){const o=f(t),n=y(t);await u(o,async()=>{const c=d(n);c[e]&&(c[e]={...c[e],pid:r},m(n,c))})}async function N(t,e){const r=f(t),o=y(t);await u(r,async()=>{const n=p(r),c=d(o);if(delete n[e],delete c[e],Object.keys(n).length===0)try{a(r)}catch{}else l(r,n);if(Object.keys(c).length===0)try{a(o)}catch{}else m(o,c)})}async function I(t){const e=[];for(const r of t){const o=f(r),n=y(r);h(n)&&await u(o,async()=>{const c=p(o),i=d(n),s=j(c,i);if(s.length!==0){if(Object.keys(c).length===0)try{a(o)}catch{}else l(o,c);if(Object.keys(i).length===0)try{a(n)}catch{}else m(n,i);for(const E of s)e.push({cwd:r,key:E})}})}return e}export{L as recordOmpMcpEntryPid,N as removeOmpMcpEntry,I as sweepOmpMcpResidue,C as writeOmpMcpEntry};