grix-connector 4.11.10 → 4.11.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/deepseek-harness/jsonrpc-adapter.js +1 -1
- package/dist/adapter/deepseek-harness/profile-bridge-protocol.js +1 -1
- package/dist/adapter/deepseek-harness/turn-correlator.js +1 -1
- package/dist/assets/dsh-bridge/grix-dsh-bridge-4.11.11.tgz +0 -0
- package/dist/assets/dsh-bridge/manifest.json +6 -6
- package/dist/core/observability/sentry.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/grix.js +6 -6
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/service/process-control.js +1 -1
- package/package.json +1 -1
- package/scripts/upgrade-guardian.mjs +3 -10
- package/dist/assets/dsh-bridge/grix-dsh-bridge-4.11.10.tgz +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
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+=`
|
|
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=180*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
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 +1 @@
|
|
|
1
|
-
import{EventEmitter as c}from"node:events";const l=1,u=1,a=16*1024*1024;class p extends c{stream;options;pending=new Map;abandoned=new Set;nextId=1;buffer=Buffer.alloc(0);closed=!1;writeChain=Promise.resolve();requestHandler=null;constructor(t,e={}){super(),this.stream=t,this.options=e,t.on("data",r=>this.onData(Buffer.isBuffer(r)?r:Buffer.from(r))),t.on("end",()=>this.close(new Error("DSH Bridge IPC ended"))),t.on("close",()=>this.close(new Error("DSH Bridge IPC closed"))),t.on("error",r=>this.protocolError(r))}get isOpen(){return!this.closed&&!this.stream.destroyed}setRequestHandler(t){this.requestHandler=t}call(t,e,r){if(!this.isOpen)return Promise.reject(new Error("DSH Bridge JSON-RPC peer closed"));const o=`${process.pid}-${this.nextId++}`;return new Promise((
|
|
1
|
+
import{EventEmitter as c}from"node:events";const l=1,u=1,a=16*1024*1024;class p extends c{stream;options;pending=new Map;abandoned=new Set;nextId=1;buffer=Buffer.alloc(0);closed=!1;writeChain=Promise.resolve();requestHandler=null;constructor(t,e={}){super(),this.stream=t,this.options=e,t.on("data",r=>this.onData(Buffer.isBuffer(r)?r:Buffer.from(r))),t.on("end",()=>this.close(new Error("DSH Bridge IPC ended"))),t.on("close",()=>this.close(new Error("DSH Bridge IPC closed"))),t.on("error",r=>this.protocolError(r))}get isOpen(){return!this.closed&&!this.stream.destroyed}setRequestHandler(t){this.requestHandler=t}call(t,e,r){if(!this.isOpen)return Promise.reject(new Error("DSH Bridge JSON-RPC peer closed"));const o=`${process.pid}-${this.nextId++}`;return new Promise((s,n)=>{const d={resolve:s,reject:n};if(r){const i=()=>{this.pending.delete(o),this.abandoned.add(o),this.abandoned.size>4096&&this.abandoned.delete(this.abandoned.values().next().value),n(Object.assign(new Error("DSH Bridge call aborted"),{code:"aborted"}))};if(d.cleanup=()=>r.removeEventListener("abort",i),r.aborted){i();return}r.addEventListener("abort",i,{once:!0})}this.pending.set(o,d),this.write({jsonrpc:"2.0",id:o,method:t,params:e??null}).catch(i=>{this.pending.delete(o),d.cleanup?.(),n(i)})})}notify(t,e){return this.write({jsonrpc:"2.0",method:t,params:e??null})}close(t=new Error("DSH Bridge JSON-RPC peer closed")){if(!this.closed){this.closed=!0;for(const e of this.pending.values())e.cleanup?.(),e.reject(t);this.pending.clear(),this.abandoned.clear(),this.stream.destroyed||this.stream.destroy(),this.emit("close",t)}}onData(t){if(this.closed)return;this.buffer=this.buffer.length===0?t:Buffer.concat([this.buffer,t]);const e=this.options.maxFrameBytes??a;for(;this.buffer.length>=4;){const r=this.buffer.readUInt32BE(0);if(r===0||r>e){this.protocolError(Object.assign(new Error(`DSH Bridge frame length ${r} is invalid`),{code:"frame_too_large"}));return}if(this.buffer.length<4+r)return;const o=this.buffer.subarray(4,4+r);if(this.buffer=this.buffer.subarray(4+r),this.dispatch(o),this.closed)return}this.buffer.length>e+4&&this.protocolError(new Error("DSH Bridge receive buffer exceeds limit"))}dispatch(t){let e;try{e=JSON.parse(t.toString("utf8"))}catch{this.protocolError(Object.assign(new Error("DSH Bridge frame contains invalid JSON"),{code:"invalid_json"}));return}if(this.options.capture?.append("in",e),e.jsonrpc!=="2.0"){this.protocolError(new Error("Unsupported JSON-RPC version"));return}if(e.id!==void 0&&typeof e.method!="string"){const r=String(e.id),o=this.pending.get(r);if(!o){if(this.abandoned.delete(r))return;this.protocolError(new Error(`Unexpected DSH Bridge response id=${r}`));return}if(this.pending.delete(r),o.cleanup?.(),e.error&&typeof e.error=="object"){const s=e.error,n=s.data&&typeof s.data=="object"?s.data:void 0;o.reject(Object.assign(new Error(String(s.message??"DSH Bridge request failed")),{code:n?.code??s.code,data:s.data}))}else o.resolve(e.result);return}if(typeof e.method=="string"&&e.id===void 0){const r=e.method,o=e.params;setImmediate(()=>{this.closed||this.emit("notification",r,o)});return}if(typeof e.method=="string"&&e.id!==void 0){this.handleRequest(String(e.id),e.method,e.params);return}this.protocolError(new Error("Unsupported DSH Bridge JSON-RPC envelope"))}async handleRequest(t,e,r){if(!this.requestHandler){await this.write({jsonrpc:"2.0",id:t,error:{code:-32601,message:`Method not found: ${e}`}}).catch(()=>{});return}try{const o=await this.requestHandler(e,r);await this.write({jsonrpc:"2.0",id:t,result:o??null})}catch(o){const s=o;await this.write({jsonrpc:"2.0",id:t,error:{code:typeof s.code=="number"?s.code:-32e3,message:s.message||"Request failed",data:{code:typeof s.code=="string"?s.code:"bridge_request_failed"}}}).catch(()=>{})}}write(t){if(!this.isOpen)return Promise.reject(new Error("DSH Bridge JSON-RPC peer closed"));const e=Buffer.from(JSON.stringify(t),"utf8"),r=this.options.maxFrameBytes??a;if(e.length===0||e.length>r)return Promise.reject(Object.assign(new Error("Outbound DSH Bridge frame exceeds limit"),{code:"frame_too_large"}));const o=Buffer.allocUnsafe(4+e.length);o.writeUInt32BE(e.length,0),e.copy(o,4),this.options.capture?.append("out",t);const s=this.writeChain.then(()=>new Promise((n,d)=>{this.stream.write(o,i=>i?d(i):n())}));return this.writeChain=s.catch(()=>{}),s}protocolError(t){this.emit("protocolError",t),this.close(t)}}export{a as DEFAULT_DSH_BRIDGE_FRAME_BYTES,p as DshBridgeJsonRpcPeer,u as GRIX_DSH_PROTOCOL_MAX,l as GRIX_DSH_PROTOCOL_MIN};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{finishReasonDetail as
|
|
1
|
+
import{finishReasonDetail as a,finishReasonKind as d}from"./event-mapper.js";class c{active;observedAdmissionIds=new Set;observedClaimTurns=new Map;constructor(t){this.active=t}setPromptMessageId(t){if(this.active.messageId=t,this.observedAdmissionIds.has(t)&&(this.active.admitted=!0),this.observedClaimTurns.has(t)){this.active.claimed=!0;const e=this.observedClaimTurns.get(t);e!==void 0&&(this.active.turn=e)}}accept(t){const e=t.data??{};if(t.type==="agent/inbox/spliced"){const i=Array.isArray(e.inserted)?e.inserted:[];for(const r of i){if(!r||typeof r!="object")continue;const s=String(r.id??"");s&&(this.observedAdmissionIds.size<1024&&this.observedAdmissionIds.add(s),s===this.active.messageId&&(this.active.admitted=!0))}return!1}if(t.type==="user/message"){const i=String(e.id??""),r=Number(t.turn??e.turn),s=Number.isSafeInteger(r)?r:void 0;return i&&this.observedClaimTurns.size<1024&&this.observedClaimTurns.set(i,s),i===this.active.messageId&&(this.active.claimed=!0,s!==void 0&&(this.active.turn=s)),!1}if(!this.active.claimed)return!1;const n=Number(t.turn??e.turn);if(this.active.turn!==void 0&&Number.isSafeInteger(n)&&n!==this.active.turn)return!1;if(t.type==="turn/end"){this.active.turnEnded=!0;const i=e.reason??t.reason;this.active.outcome=d(i),this.active.outcomeDetail=a(i)}return!0}markRootStatus(t){t==="idle"&&(this.active.rootIdle=!0)}get complete(){return this.active.admitted&&this.active.claimed&&this.active.turnEnded&&this.active.rootIdle}}export{c as TurnCorrelator};
|
|
Binary file
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bridgeVersion": "4.11.
|
|
4
|
-
"tarball": "grix-dsh-bridge-4.11.
|
|
5
|
-
"size":
|
|
6
|
-
"unpackedSize":
|
|
7
|
-
"shasum": "
|
|
8
|
-
"integrity": "sha512-
|
|
3
|
+
"bridgeVersion": "4.11.11",
|
|
4
|
+
"tarball": "grix-dsh-bridge-4.11.11.tgz",
|
|
5
|
+
"size": 23418,
|
|
6
|
+
"unpackedSize": 94155,
|
|
7
|
+
"shasum": "da6a672951ae15db5f4d21f0219a9f0626147c44",
|
|
8
|
+
"integrity": "sha512-T7j/74iQ+d3tU3HEkLNyK2+qwN/klP6eSMjtWkhKFteW0t44kNAW9AoCU8JOwuSbfJJDCNnWWgt/7zfFH9ai2Q=="
|
|
9
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{log as i}from"../log/logger.js";import{resolveClientVersion as f}from"../util/client-version.js";import{PersistentSentryDeduplicator as
|
|
1
|
+
import{log as i}from"../log/logger.js";import{resolveClientVersion as f}from"../util/client-version.js";import{PersistentSentryDeduplicator as u}from"./sentry-event-dedup.js";let o=null,a=!1;const c=new u,l="https://e8e202d7625372b1314b3ff4e85a7ff9@o119262.ingest.us.sentry.io/4511410543329280";function E(){if(!process.env.GRIX_SENTRY_DISABLE)return process.env.SENTRY_DSN||process.env.GRIX_SENTRY_DSN||l}async function R(){const e=E();if(e){try{o=await import("@sentry/node")}catch(n){i.warn("sentry",`Sentry \u6A21\u5757\u52A0\u8F7D\u5931\u8D25\uFF08\u5E73\u53F0\u4E0D\u517C\u5BB9\uFF09\uFF0C\u9519\u8BEF\u4E0A\u62A5\u5DF2\u7981\u7528: ${n instanceof Error?n.message:String(n)}`);return}try{o.init({dsn:e,release:`grix-connector@${f()}`,environment:process.env.SENTRY_ENVIRONMENT||process.env.NODE_ENV||"production",sendDefaultPii:!1,initialScope:{tags:{component:"grix-connector"}},defaultIntegrations:!1,tracesSampleRate:0,beforeSend:S}),o.getClient()?.on("afterSendEvent",(n,t)=>{const r=t.statusCode;c.recordSendResult(n,r!==void 0&&r>=200&&r<300)}),a=!0}catch(n){i.error("sentry",`Sentry \u521D\u59CB\u5316\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}}function g(e){if(typeof e.message=="string"&&e.message)return e.message;const n=e.exception?.values;if(!n?.length)return"";const t=n[0],r=typeof t?.value=="string"?t.value:"",s=typeof t?.type=="string"?t.type:"";return r||s}function _(){return a}function S(e,n,t=c){const r=g(e);return r&&p(r)?null:t.shouldSend(e)?e:null}const y=new Set(["INSTALL_FAILED","INSTALL_TIMEOUT","FALLBACK_EXHAUSTED","PREREQ_INSTALL_FAILED","VERIFICATION_FAILED","ENVIRONMENT_UNSUPPORTED","INTERNAL"]);function N(e){if(e.ok)return!1;const n=e.error?.code;return!!n&&y.has(n)}function h(e){if(!a||!o||!N(e))return;const n=e.error?.code??"INTERNAL",t=e.error?.message??"unknown install failure",r=e.environment;try{o.withScope(s=>{s.setLevel("error"),s.setTags({agent_type:e.agentType,error_code:n,phase:e.phase}),s.setContext("install",{agentType:e.agentType,code:n,phase:e.phase,durationMs:e.durationMs,os:r?.platform,osVersion:r?.osVersion,arch:r?.arch,nodeVersion:r?.nodeVersion,npmVersion:r?.npmVersion,isDocker:r?.isDocker,isCI:r?.isCI,outputTail:(e.output??"").slice(-2e3)}),s.setFingerprint(["agent-install-failure",e.agentType,n]),o.captureException(new Error(`Agent install failed [${e.agentType}/${n}]: ${t}`))}),i.info("sentry",`\u5DF2\u63D0\u4EA4\u5B89\u88C5\u5931\u8D25\u7ED9 Sentry SDK: ${e.agentType}/${n}`)}catch(s){i.error("sentry",`\u4E0A\u62A5\u5B89\u88C5\u5931\u8D25\u65F6\u51FA\u9519: ${s instanceof Error?s.message:String(s)}`)}}const d=[/No config files found/,/spawn wmic ENOENT/i];function p(e){const n=e instanceof Error?e.message:String(e);return d.some(t=>t.test(n))}function D(e){const n=e instanceof Error?e.message:String(e);return/spawn wmic ENOENT/i.test(n)}function L(e,n){if(!(!a||!o)&&!p(e))try{o.withScope(t=>{t.setLevel("fatal"),t.setTag("crash_type",n);const r=e instanceof Error?e:new Error(String(e));o.captureException(r)}),i.info("sentry",`\u5DF2\u63D0\u4EA4\u5D29\u6E83\u7ED9 Sentry SDK: ${n}`)}catch(t){i.error("sentry",`\u4E0A\u62A5\u5D29\u6E83\u65F6\u51FA\u9519: ${t instanceof Error?t.message:String(t)}`)}}async function x(e=2e3){if(!(!a||!o))try{await o.close(e)}catch{}}export{x as closeSentry,g as extractEventMessage,S as filterSentryEvent,R as initSentry,p as isNonReportable,_ as isSentryEnabled,D as isWindowsWmicProbeError,L as reportFatal,h as reportInstallFailure,N as shouldReportInstallFailure};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{accessSync as
|
|
2
|
-
`).forEach(s=>{const
|
|
1
|
+
import{accessSync as l,constants as w}from"node:fs";import{spawn as d,execSync as h}from"node:child_process";import{isAbsolute as P,join as m}from"node:path";const S=process.platform==="win32"?";":":";function $(t){try{return l(t,w.X_OK),!0}catch{return!1}}function H(t,e){const n=String(t??"").trim();if(!n||P(n))return n;const o=process.platform==="win32",i=String(e??process.env.PATH??""),s=[],r=new Set;for(const c of i.split(S)){const a=c.trim();if(!a)continue;if(o){const u=m(a,n+".cmd");r.has(u)||(r.add(u),s.push(u))}const p=m(a,n);r.has(p)||(r.add(p),s.push(p))}for(const c of s)if($(c))return c;return console.warn(`[spawn:resolve] command="${n}" not found in PATH. candidates tried: [${s.join(", ")}] PATH=${i.substring(0,500)}${i.length>500?"...(truncated)":""}`),n}function x(t,e=process.platform){return e==="win32"&&/\.(cmd|bat)$/i.test(t)}function C(t){return t.length>0&&!/[\s"^&|<>()%!]/.test(t)?t:`"${t.replace(/(\\*)"/g,'$1$1\\"').replace(/(\\*)$/,"$1$1")}"`}function f(t,e){const n=e.map(C).join(" ");return n?`""${t}" ${n}"`:`""${t}""`}function v(t,e,n=process.platform){return x(t,n)?{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",f(t,e)],windowsVerbatimArguments:!0}:{command:t,args:e,windowsVerbatimArguments:!1}}function V(t,e,n=process.platform){return n!=="win32"?{command:t,args:e,windowsVerbatimArguments:!1}:{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",f(t,e)],windowsVerbatimArguments:!0}}function k(t,e,n={}){const{cwd:o,env:i,...s}=n,r={stdio:s.stdio??["pipe","pipe","pipe"],env:i??{...process.env},cwd:o,windowsHide:!0,...s},c=v(t,e);return c.windowsVerbatimArguments?{process:d(c.command,c.args,{...r,windowsVerbatimArguments:!0}),isCmdSpawn:!0}:{process:d(t,e,{...r,detached:r.detached??process.platform!=="win32"}),isCmdSpawn:!1}}async function b(t){return!t||t<=0?[]:process.platform==="win32"?A(t):new Promise(e=>{const n=d("pgrep",["-g",String(t)],{stdio:"pipe",timeout:3e3}),o=[];n.stdout?.on("data",i=>{i.toString().split(`
|
|
2
|
+
`).forEach(s=>{const r=parseInt(s.trim(),10);!isNaN(r)&&r>0&&o.push(r)})}),n.on("close",()=>e(o)),n.on("error",()=>e([]))})}function A(t){return W(t)}function W(t){return new Promise(e=>{const n=`${process.env.SystemRoot||"C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,o=d(n,["-NoProfile","-NonInteractive","-WindowStyle","Hidden","-Command",`(Get-CimInstance Win32_Process -Filter 'ParentProcessId=${t}').ProcessId`],{stdio:"pipe",windowsHide:!0});let i="";o.stdout?.on("data",s=>{i+=s.toString()}),o.on("close",()=>{e(i.split(/\r?\n/).map(s=>parseInt(s.trim(),10)).filter(s=>!isNaN(s)&&s>0))}),o.on("error",()=>e([]))})}async function N(t,e=[]){return(await b(t)).some(o=>!e.includes(o))}function T(t,e="SIGTERM"){if(t.pid){if(process.platform==="win32"){try{h(`taskkill /pid ${t.pid} /T /F`,{stdio:"pipe",timeout:5e3,windowsHide:!0})}catch{t.kill(e)}return}try{process.kill(-t.pid,e)}catch{t.kill(e)}}}export{f as buildWindowsCmdLine,N as hasChildProcesses,x as isWindowsShimPath,T as killProcessGroup,b as listGroupPids,C as quoteWindowsCmdArg,H as resolveCommandPath,v as resolveShimInvocation,V as resolveWindowsExecInvocation,k as spawnCommand};
|
package/dist/grix.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import b from"node:path";import{writeFileSync as ae}from"node:fs";import{Manager as Ce}from"./manager.js";import{ensureGrixDirs as Te,initLogger as $e,getLoggerStatus as Le,log as i,installProcessLogRotation as Ue,setConsoleOutput as ie}from"./core/log/index.js";import{HealthServer as He,bindPortOrFail as se}from"./core/runtime/index.js";import{writePidFile as Oe,removePidFile as T,readDaemonPid as ce}from"./core/runtime/index.js";import{killOrphanedClaudeProcesses as Fe}from"./core/runtime/index.js";import{resolveRuntimePaths as V}from"./core/config/index.js";import{supportsNonMitmRelayConfig as Me}from"./core/config/provider-env.js";import{ServiceManager as le}from"./service/service-manager.js";import{RESTART_EXIT_CODE as Ne,UNHEALTHY_EXIT_CODE as Ge,markManagedStop as de,resolveLauncherStore as Y,writeCrashNote as Be}from"./core/upgrade/version-store.js";import{migrateWindowsWrapper as q}from"./service/windows-wrapper-migration.js";const je=300*1e3;import{killProcessesByCommandLine as We,isWindowsElevated as Ke,shouldSweepWindowsWrappers as Xe,getProcessCommandLine as Ve}from"./service/process-control.js";import{buildServiceID as Ye}from"./service/service-paths.js";import{isInsideManagedDaemonTree as qe}from"./service/platform-adapter.js";import{acquireDaemonLock as Je,createHealthzHolderProbe as ze,DaemonAlreadyServingError as Qe,findLiveLockHolder as Ze,isLockHolderSameProcess as et,readDaemonLock as J,releaseDaemonLock as F}from"./runtime/daemon-lock.js";import{writeDaemonStatus as G,removeDaemonStatus as tt}from"./runtime/service-state.js";import{readDuplicateDaemonRecord as rt,recordDuplicateDaemon as nt}from"./runtime/duplicate-daemon.js";import{RemoteAdminSettingsStore as ot}from"./core/config/remote-admin-settings.js";import{AdminServer as at,generateToken as it,writeTokenFile as st}from"./core/admin/index.js";import{initSentry as ct,closeSentry as B,reportFatal as z}from"./core/observability/sentry.js";import{initProxyManager as
|
|
3
|
-
Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),D.version&&(console.log(
|
|
2
|
+
import b from"node:path";import{writeFileSync as ae}from"node:fs";import{Manager as Ce}from"./manager.js";import{ensureGrixDirs as Te,initLogger as $e,getLoggerStatus as Le,log as i,installProcessLogRotation as Ue,setConsoleOutput as ie}from"./core/log/index.js";import{HealthServer as He,bindPortOrFail as se}from"./core/runtime/index.js";import{writePidFile as Oe,removePidFile as T,readDaemonPid as ce}from"./core/runtime/index.js";import{killOrphanedClaudeProcesses as Fe}from"./core/runtime/index.js";import{resolveRuntimePaths as V}from"./core/config/index.js";import{supportsNonMitmRelayConfig as Me}from"./core/config/provider-env.js";import{ServiceManager as le}from"./service/service-manager.js";import{RESTART_EXIT_CODE as Ne,UNHEALTHY_EXIT_CODE as Ge,markManagedStop as de,resolveLauncherStore as Y,writeCrashNote as Be}from"./core/upgrade/version-store.js";import{migrateWindowsWrapper as q}from"./service/windows-wrapper-migration.js";const je=300*1e3;import{killProcessesByCommandLine as We,isWindowsElevated as Ke,shouldSweepWindowsWrappers as Xe,getProcessCommandLine as Ve}from"./service/process-control.js";import{buildServiceID as Ye}from"./service/service-paths.js";import{isInsideManagedDaemonTree as qe}from"./service/platform-adapter.js";import{acquireDaemonLock as Je,createHealthzHolderProbe as ze,DaemonAlreadyServingError as Qe,findLiveLockHolder as Ze,isLockHolderSameProcess as et,readDaemonLock as J,releaseDaemonLock as F}from"./runtime/daemon-lock.js";import{writeDaemonStatus as G,removeDaemonStatus as tt}from"./runtime/service-state.js";import{readDuplicateDaemonRecord as rt,recordDuplicateDaemon as nt}from"./runtime/duplicate-daemon.js";import{RemoteAdminSettingsStore as ot}from"./core/config/remote-admin-settings.js";import{AdminServer as at,generateToken as it,writeTokenFile as st}from"./core/admin/index.js";import{initSentry as ct,closeSentry as B,reportFatal as z,isWindowsWmicProbeError as lt}from"./core/observability/sentry.js";import{initProxyManager as dt,getProxyManager as f,relayHostsForClientType as pe,RelayStateStore as pt,SecretStore as gt}from"./core/proxy/index.js";import{stopProxyIfNobodyNeedsIt as ge,switchAgentRelayMode as Q,reconcileRelayStates as me}from"./core/proxy/relay-orchestration.js";import{setAgentRelayCredential as ue,RelayCredentialError as fe}from"./core/proxy/relay-credential.js";import{RelayFetchError as he,RelayToggleCoordinator as mt}from"./core/proxy/relay-credential-fetch.js";import{applyHermesProfileRelay as ut,clearHermesProfileRelay as ft,discoverHermesProfiles as ht}from"./core/proxy/hermes-profile-relay.js";import{disableRelayCredential as yt,enableRelayCredential as wt,RelayRouteError as ye}from"./core/proxy/relay-credential-router.js";import{upgradeStatusSnapshot as St}from"./core/upgrade/npm-upgrader.js";import{resolveClientVersion as Rt}from"./core/util/client-version.js";import{parseCliArgs as Et}from"./core/util/cli-args.js";const{command:I,flags:D,unknownFlags:Z}=Et(process.argv.slice(2));if(Z.length>0&&(console.error(`Unknown option${Z.length>1?"s":""}: ${Z.map(t=>`--${t}`).join(", ")}
|
|
3
|
+
Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),D.version&&(console.log(Rt()),process.exit(0)),D.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
|
|
4
4
|
|
|
5
5
|
Usage: grix-connector <command> [options]
|
|
6
6
|
|
|
@@ -37,7 +37,7 @@ Examples:
|
|
|
37
37
|
`),process.exit(0)),I==="reload"){const t=ce();t||(console.error("reload failed: daemon is not running (no pid file)"),process.exit(1));try{process.kill(t,0)}catch{console.error(`reload failed: daemon process ${t} is not running (stale pid file)`),process.exit(1)}{const s=J(V().daemonLockFile);s&&s.pid===t&&!et(s)&&(console.error(`reload failed: pid ${t} has been reused by another process (stale pid file)`),process.exit(1))}try{process.kill(t,"SIGHUP"),console.log(JSON.stringify({ok:!0,signaled:t},null,2)),process.exit(0)}catch(s){console.error(`reload failed: ${s instanceof Error?s.message:s}`),process.exit(1)}}const we="detected connector-managed session; restart delegated to launchd, this process may be terminated by the restart",Se=["start","stop","restart","status"];if(I&&Se.includes(I)){process.platform==="win32"&&["start","stop","restart"].includes(I)&&!Ke()&&console.warn(`Warning: Not running as administrator. Task Scheduler registration is skipped;
|
|
38
38
|
using Startup folder auto-start instead. For full Task Scheduler integration,
|
|
39
39
|
right-click the terminal and select "Run as administrator".`);const t=V(),s=D["config-dir"]??(D.profile?b.join(t.configDir,D.profile):void 0),g=b.resolve(process.argv[1]||`${t.rootDir}/dist/grix.js`),u=new le({cliPath:g,nodePath:process.execPath});try{let l;switch(I){case"start":{const h=await u.healLegacyState({rootDir:t.rootDir});(await u.status({rootDir:t.rootDir})).installed?l=await u.start({rootDir:t.rootDir}):l=await u.install({rootDir:t.rootDir,configDir:s??h.configDir}),h.healed&&(l={...l,legacy_heal:h.reasons})}break;case"stop":l=await u.stop({rootDir:t.rootDir});break;case"restart":if(!(await u.status({rootDir:t.rootDir})).installed)l=await u.install({rootDir:t.rootDir,configDir:s});else{const S=process.platform==="darwin"&&qe();S&&console.warn(we),l=await u.restart({rootDir:t.rootDir}),S&&(l={...l,mode:"kickstart",note:we})}break;case"status":l=await u.status({rootDir:t.rootDir});{const h=rt(t.dataDir);h&&(l={...l,duplicate_daemon:h})}break}console.log(JSON.stringify(l,null,2)),process.exit(0)}catch(l){console.error(`${I} failed: ${l instanceof Error?l.message:l}`),process.exit(1)}}else I&&(console.error(`Unknown command: ${I}
|
|
40
|
-
Valid commands: ${Se.join(", ")}`),process.exit(1));const c=V(),
|
|
41
|
-
`),i.warn("main",s);const g=Y();g&&de(g)}function
|
|
42
|
-
`),i.error("main",t.message.replace(/\n/g," \u2014 ")),W("port_bind",t.message);const s=J(c.daemonLockFile);s?.pid===process.pid&&s.instance_id===$&&await G(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:$,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await B(),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)}async function _(t){if(j)return;j=!0,i.info("main",`Received ${t}, shutting down...`),M.markShuttingDown();const s=Y();s&&de(s);const g=t==="upgrade-switch"?Ne:t==="launcher-unhealthy"?Ge:null,u=g??2,l=t==="uncaughtException"||t==="unhandledRejection",h=setTimeout(()=>{i.error("main","Shutdown timed out, forcing exit"),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)},1e4);try{await o.stop(),await f()?.stop().catch(()=>{}),await x.stop(),await M.stop(),await B(),await F(c.daemonLockFile),await tt(c.daemonStatusFile).catch(()=>{}),clearTimeout(h),T(),i.info("main","Shutdown complete"),process.exit(g??(l?2:0))}catch(S){i.error("main",`Shutdown error: ${S}`),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)}}async function vt(){Te(),$e(),Ue(c.stdoutLogFile,c.stderrLogFile),ie(!1);try{$=(await Je(c.daemonLockFile,c.rootDir,2,{isHolderServing:ze(c.dataDir)})).instance_id}catch(e){e instanceof Qe&&Dt(e.holder),console.error(e instanceof Error?e.message:e),process.exit(1)}if(Xe()){const e=Ye(c.rootDir,"win32");await We(e,{platform:"win32"})}await ct(),Oe(),i.info("main",`grix-connector starting (PID ${process.pid})`);try{Fe({info:e=>i.info("main",e),warn:e=>i.warn("main",e)})}catch(e){i.warn("main",`orphan Claude cleanup failed: ${e instanceof Error?e.message:String(e)}`)}if(await G(c.daemonStatusFile,{state:"starting",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.env.GRIX_LAUNCHER_MANAGED!=="1"&&await new le({cliPath:b.resolve(process.argv[1]??""),nodePath:process.execPath}).adoptLauncher(c.rootDir).then(e=>{e&&i.info("main","Service definition now points at the version-store launcher")}).catch(e=>{i.warn("main",`Launcher adoption failed: ${e instanceof Error?e.message:e}`)}),(await q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).catch(e=>(i.warn("main",`Windows wrapper migration failed: ${e instanceof Error?e.message:e}`),null)))?.handoffStarted)return;process.platform==="win32"&&process.env.GRIX_LAUNCHER_MANAGED!=="1"&&setInterval(()=>{j||q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).then(n=>{n.handoffStarted&&i.info("main","Wrapper handoff started by the periodic migration retry")}).catch(n=>{i.warn("main",`Periodic wrapper migration failed: ${n instanceof Error?n.message:n}`)})},je).unref();const s=parseInt(D["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await se({label:"health",port:s,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:n=>M.start(n)});e&&await De(e)}const g=b.join(c.dataDir,"health-port");ae(g,String(s),"utf-8"),process.on("SIGINT",()=>_("SIGINT")),process.on("SIGTERM",()=>_("SIGTERM")),process.on("SIGHUP",()=>{j||(i.info("main","Received SIGHUP, reloading config..."),o.reload().then(e=>i.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>i.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let u="",l=0,h;process.on("uncaughtException",e=>{const n=e instanceof Error?e.stack??e.message:String(e);n===u?(l++,(l<=3||l%100===0)&&i.error("main",`Uncaught exception (x${l}): ${n}`)):(l>3&&i.error("main",`Previous exception repeated ${l} times total`),u=n,l=1,i.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),h||(h=setTimeout(()=>{l>3&&i.error("main",`Previous exception repeated ${l} times total`),u="",l=0,h=void 0},1e4).unref())),!Ae(e)&&(z(e,"uncaughtException"),W("uncaughtException",e),_("uncaughtException"))}),process.on("unhandledRejection",e=>{i.error("main",`Unhandled rejection: ${e}`),!Ae(e)&&(z(e,"unhandledRejection"),W("unhandledRejection",e),_("unhandledRejection"))});const S=lt(c.dataDir);await S.clearRuntimeState();const k=new dt(b.join(c.dataDir,"proxy","relay-state.json"),{warn:e=>i.warn("main",e)}),N=new pt(b.join(c.dataDir,"secrets"));o.setRelaySecretResolver(e=>N.get(e));const L={hasDirectConfig:e=>o.hasDirectRelayConfig(e),clearDirectConfig:(e,n)=>o.setAgentProvider(e,void 0,{deferRestart:n?.deferRestart===!0})},K=()=>({pm:f(),agents:o,direct:L,store:k,secrets:N}),U=S.getRelayAgents();if(U.length>0)try{await S.startIfAnyRelayAgent(),i.info("main",`mitm proxy started for relay agents: ${U.join(", ")} (per-agent; others stay direct)`)}catch(e){i.error("main",`mitm proxy FAILED to start (relay agents: ${U.join(", ")}): ${e}. These agents will REFUSE to start (they must not silently fall back to your own account). Fix the proxy or turn relay off for them. Other agents are unaffected.`)}else i.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');let H=null;if(f()){const e=async()=>{const r=f();r&&await ge(r,o)&&i.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};o.setRelayEnvSettledHandler(()=>{const r=f();r&&me(r,L,k),e().catch(a=>{i.warn("main",`failed to stop idle mitm proxy: ${a}`)})});const n=()=>{const r=f(),a=r.getRelayAgents(),p=r.getDegradedRelayAgents();return{enabled:a.length>0,relayAgents:a,staleRelayAgents:o.getAgentsWithStaleRelayEnv(),degradedRelayAgents:p,relayState:k.list(),runtime:r.getRuntimeInfo(),config:r.getConfigSnapshot()}},d=new gt,A={status:()=>n(),setAgentRelay:async(r,a,p)=>{const m=f(),E={info:w=>i.info("main",w),warn:w=>i.warn("main",w)},R=w=>o.getAgentsStatus().find(v=>v.name===w),y=R(r);if(!a){d.cancel(r);const w=await d.runExclusive(r,async()=>{const v=await Q(K(),E,{agentName:r,target:"off"});return{...n(),restarted:v.restarted,busy:v.busy,...v.pending?{pending:v.pending}:{}}});return o.reportRelayStateLocalChange(r),w}if(!y)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});if(!Me(y.clientType)&&pe(y.clientType).length===0)throw Object.assign(new Error(`client type "${y.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"});const O=await d.runExclusive(r,async()=>{const w=d.epoch(r),v=R(r);if(!v)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});const re=String(v.agentId??"").trim();if(!re)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const ne=d.waitCancelled(r,w);let C;try{C=await Promise.race([o.fetchRelayCredential(r,{model:p}),ne.promise.then(()=>{throw new he("relay enable cancelled by a later disable","CANCELLED")})])}finally{ne.dispose()}d.assertCurrent(r,w);const{restarted:xe,busy:Pe,pending:oe}=await ue(m,o,R,E,{localName:r,agentId:re,virtualKey:C.apiKey,anthropicBaseUrl:C.anthropicBaseUrl,openaiBaseUrl:C.openaiBaseUrl,model:p,...C.directRelay!==void 0?{directRelay:C.directRelay}:{}},(Ie,_e,ke)=>o.setAgentProvider(Ie,_e,{deferRestart:ke?.deferRestart===!0}),{store:k,secrets:N,direct:L});if(d.epoch(r)!==w)throw await Q(K(),E,{agentName:r,target:"off"}),new he("relay enable cancelled by a later disable","CANCELLED");return{...n(),restarted:xe,busy:Pe,...oe?{pending:oe}:{}}});return o.reportRelayStateLocalChange(r),O},setAgentRelayCredential:async(r,a)=>{const p=f(),m=o.getAgentsStatus(),{restarted:E,busy:R,pending:y}=await ue(p,o,P=>m.find(O=>O.name===P),{info:P=>i.info("main",P),warn:P=>i.warn("main",P)},{localName:r,agentId:a.agentId,virtualKey:a.virtualKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}},(P,O,w)=>o.setAgentProvider(P,O,{deferRestart:w?.deferRestart===!0}),{store:k,secrets:N,direct:L});return o.reportRelayStateLocalChange(r),{...n(),restarted:E,busy:R,...y?{pending:y}:{}}},disableAll:async()=>{const r=f(),a={info:m=>i.info("main",m),warn:m=>i.warn("main",m)},p=new Set([...r.getRelayAgents(),...o.getDirectRelayConfigAgentNames(),...Object.keys(k.list())]);for(const m of p)d.cancel(m);for(const m of p)await d.runExclusive(m,()=>Q(K(),a,{agentName:m,target:"off"})),o.reportRelayStateLocalChange(m);return await ge(r,o),n()},setRoute:async(r,a)=>{const p=a,m=f();return m.setRoute({routeKey:r,targetBaseUrl:p.targetBaseUrl,...p.headers?{headers:p.headers}:{},...p.model?{model:p.model}:{},...p.modelMap?{modelMap:p.modelMap}:{},...p.passthrough?{passthrough:!0}:{},...p.relayOnly?{relayOnly:!0}:{},...p.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await m.persistConfig(),n()},deleteRoute:async r=>{const a=f();a.deleteRoute(r),await a.persistConfig()},setDefaultRoute:async r=>{const a=f();return a.setDefaultRouteKey(r),await a.persistConfig(),n()},setInterceptHosts:async r=>{const a=f();return a.setInterceptHosts(r),await a.persistConfig(),n()}};H=A,x.setProxyHandler(A),o.setRelayStateApplier({getLocalState:r=>{const a=f();if(a.getRelayAgents().includes(r)){const m=o.getAgentsStatus().find(y=>y.name===r),E=`grix-gateway-${String(m?.clientType??"").trim().toLowerCase()}`;return{enabled:!0,model:a.getConfigSnapshot().routes?.find(y=>y.routeKey===E)?.model?.trim()||void 0}}const p=o.getAgentProvider(r);return p?.api_key?.trim()?{enabled:!0,model:p.model?.trim()||void 0}:{enabled:!1}},applyEnable:async(r,a,p)=>{const m=o.getAgentsStatus().find(y=>y.name===r),E=String(m?.agentId??"").trim();if(!E)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const R=await A.setAgentRelayCredential(r,{agentId:E,virtualKey:a.apiKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:p??a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}});return{restarted:R.restarted===!0,busy:R.busy===!0,...R.pending?{pending:R.pending}:{}}},applyDisable:async r=>{const a=await A.setAgentRelay(r,!1);return{restarted:a.restarted===!0,busy:a.busy===!0,...a.pending?{pending:a.pending}:{}}}})}M.setStatusProvider(()=>o.getAgentsStatus()),M.setMetaProvider(()=>{const e=o.getAgentsStatus(),n=Le();return{ws:{connected:e.filter(d=>d.wsConnected===!0).length,total:e.length},upgrade:wt(),log:{dir:n.logDir,file:n.logFile,primary_dir:n.primaryLogDir,degraded:n.degraded,using_fallback:n.usingFallback,...n.degradeReason?{degrade_reason:n.degradeReason}:{}}}});const X=new ot(b.join(c.dataDir,"remote-admin.json"));if(o.setRemoteAdminGate(()=>X.isEnabled()),await o.start(Et),U.length>0){const e=o.getAgentsStatus();for(const n of U){const d=e.find(r=>r.name===n);if(!d)continue;const A=pe(d.clientType);A.length!==0&&await S.setAgentRelayEnabled(n,!0,{relayHosts:A}).catch(r=>{i.warn("main",`failed to reconcile relay hosts for "${n}": ${r}`)})}}me(S,L,k);const ee=parseInt(D["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);x.setAgentHandler({list:()=>o.getAgentsStatus(),add:e=>o.addAgent(e),remove:e=>o.removeAgent(e),restart:e=>o.restartAgent(e),reload:()=>o.reload()}),x.setUpgradeHandler({check:()=>o.checkUpgrade(),trigger:()=>o.triggerUpgrade()}),x.setProbeHandler({probeAll:e=>o.probeAll(e),probeOne:(e,n)=>o.probeOne(e,n)}),x.setRemoteAdminHandler({isEnabled:()=>X.isEnabled(),setEnabled:e=>{const n=X.setEnabled(e);return i.info("main",`remote admin ${n?"enabled":"disabled"} via admin API`),n}}),x.setInstallHandler({listInstallable:()=>o.listInstallable(),installAgent:e=>o.installAgent(e),getInstallProgress:e=>o.getInstallProgress(e)});const te={listAgents:()=>o.getAgentsStatus(),enableManaged:(e,n,d)=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelayCredential(e,{agentId:n,virtualKey:d.virtualKey,anthropicBaseUrl:d.anthropicBaseUrl,openaiBaseUrl:d.openaiBaseUrl,model:d.model,...d.directRelay!==void 0?{directRelay:d.directRelay}:{}})},disableManaged:e=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelay(e,!1)},enableHermesProfile:(e,n)=>mt({agentId:e,baseUrl:n.openaiBaseUrl??"",virtualKey:n.virtualKey,model:n.model??""}),disableHermesProfile:e=>ut(e)};x.setRelayCredentialHandler({listHermesProfiles:()=>ft(),enable:async(e,n)=>{const{target:d,result:A}=await yt(te,e,n);return{target:d,...A}},disable:async e=>{const{target:n,result:d}=await ht(te,e);return{target:n,...d}}});{const e=await se({label:"admin",port:ee,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:n=>x.start(n)});e&&await De(e)}const ve=b.join(c.dataDir,"admin-token"),be=b.join(c.dataDir,"admin-port");st(ve,Re),ae(be,String(ee),"utf-8"),await G(c.daemonStatusFile,{state:"running",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.send&&process.send("ready"),i.info("main","grix-connector ready")}vt().catch(async t=>{const s=`Fatal: ${t instanceof Error?t.stack??t.message:String(t)}`;try{process.stderr.write(`${s}
|
|
43
|
-
`)}catch{}ie(!1),i.error("main",s),z(t,"startup"),W("startup",t);const g=J(c.daemonLockFile);g?.pid===process.pid&&g.instance_id===$&&await G(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:g.instance_id,updated_at:Date.now(),reason:"startup_error"}).catch(()=>{}),await B(),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)});const
|
|
40
|
+
Valid commands: ${Se.join(", ")}`),process.exit(1));const c=V(),Dt=D["config-dir"]??(D.profile?`${c.configDir}/${D.profile}`:void 0),o=new Ce({requestGracefulShutdown:t=>{_(t)},onTransactionSettled:()=>{q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).then(t=>{t.handoffStarted&&i.info("main","Wrapper handoff started after the upgrade transaction settled")}).catch(t=>{i.warn("main",`Post-upgrade wrapper migration failed: ${t instanceof Error?t.message:t}`)})}}),M=new He,Re=it(),x=new at(Re);let j=!1,$;function W(t,s){const g=Y(),u=process.env.GRIX_LAUNCHER_VERSION;if(!g||!u)return;const l=s instanceof Error?s.stack??s.message:String(s);Be(g,u,`${t}: ${l}`)}function Ee(t,s){nt(c.dataDir,{holder_pid:t.pid,holder_command_line:t.command_line,yielded_pid:process.pid,yielded_command_line:Ve(process.pid)}),process.stderr.write(`${s}
|
|
41
|
+
`),i.warn("main",s);const g=Y();g&&de(g)}function At(t){const s=`another grix-connector daemon (pid ${t.pid}) is already serving ${c.rootDir} and answering /healthz; this process yields instead of taking over. A second supervisor is starting duplicate daemons \u2014 check for a leftover wrapper, a duplicate logon task, or a desktop app launching its own copy.`;Ee(t,s),process.exit(0)}function vt(t,s){const g=`${s.label} \u7AEF\u53E3 ${s.port} \u5DF2\u88AB\u5360\u7528\uFF0C\u4E14 daemon \u9501\u4ECD\u7531\u53E6\u4E00\u4E2A\u5B58\u6D3B\u5B9E\u4F8B (pid ${t.pid}) \u6301\u6709\uFF1A\u672C\u8FDB\u7A0B\u6309\u7BA1\u7406\u6027\u9000\u51FA\u8BA9\u4F4D\uFF0C\u4E0D\u8BA1\u4E3A\u5D29\u6E83\u3002 \u8FD9\u53F0\u673A\u5668\u4E0A\u6709\u7B2C\u4E8C\u4E2A supervisor \u5728\u91CD\u590D\u62C9\u8D77 daemon\u2014\u2014\u68C0\u67E5\u6B8B\u7559\u7684 wrapper\u3001\u91CD\u590D\u7684\u767B\u5F55\u4EFB\u52A1\uFF0C\u6216\u684C\u9762\u7AEF\u53E6\u8D77\u7684\u526F\u672C\u3002`;Ee(t,g),ce()===process.pid&&T(),process.exit(0)}async function De(t){if(t.kind==="in_use"){const g=Ze(c.daemonLockFile);g&&(await B(),vt(g,t))}process.stderr.write(t.message+`
|
|
42
|
+
`),i.error("main",t.message.replace(/\n/g," \u2014 ")),W("port_bind",t.message);const s=J(c.daemonLockFile);s?.pid===process.pid&&s.instance_id===$&&await G(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:$,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await B(),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)}async function _(t){if(j)return;j=!0,i.info("main",`Received ${t}, shutting down...`),M.markShuttingDown();const s=Y();s&&de(s);const g=t==="upgrade-switch"?Ne:t==="launcher-unhealthy"?Ge:null,u=g??2,l=t==="uncaughtException"||t==="unhandledRejection",h=setTimeout(()=>{i.error("main","Shutdown timed out, forcing exit"),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)},1e4);try{await o.stop(),await f()?.stop().catch(()=>{}),await x.stop(),await M.stop(),await B(),await F(c.daemonLockFile),await tt(c.daemonStatusFile).catch(()=>{}),clearTimeout(h),T(),i.info("main","Shutdown complete"),process.exit(g??(l?2:0))}catch(S){i.error("main",`Shutdown error: ${S}`),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)}}async function bt(){Te(),$e(),Ue(c.stdoutLogFile,c.stderrLogFile),ie(!1);try{$=(await Je(c.daemonLockFile,c.rootDir,2,{isHolderServing:ze(c.dataDir)})).instance_id}catch(e){e instanceof Qe&&At(e.holder),console.error(e instanceof Error?e.message:e),process.exit(1)}if(Xe()){const e=Ye(c.rootDir,"win32");await We(e,{platform:"win32"})}await ct(),Oe(),i.info("main",`grix-connector starting (PID ${process.pid})`);try{Fe({info:e=>i.info("main",e),warn:e=>i.warn("main",e)})}catch(e){i.warn("main",`orphan Claude cleanup failed: ${e instanceof Error?e.message:String(e)}`)}if(await G(c.daemonStatusFile,{state:"starting",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.env.GRIX_LAUNCHER_MANAGED!=="1"&&await new le({cliPath:b.resolve(process.argv[1]??""),nodePath:process.execPath}).adoptLauncher(c.rootDir).then(e=>{e&&i.info("main","Service definition now points at the version-store launcher")}).catch(e=>{i.warn("main",`Launcher adoption failed: ${e instanceof Error?e.message:e}`)}),(await q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).catch(e=>(i.warn("main",`Windows wrapper migration failed: ${e instanceof Error?e.message:e}`),null)))?.handoffStarted)return;process.platform==="win32"&&process.env.GRIX_LAUNCHER_MANAGED!=="1"&&setInterval(()=>{j||q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).then(n=>{n.handoffStarted&&i.info("main","Wrapper handoff started by the periodic migration retry")}).catch(n=>{i.warn("main",`Periodic wrapper migration failed: ${n instanceof Error?n.message:n}`)})},je).unref();const s=parseInt(D["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await se({label:"health",port:s,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:n=>M.start(n)});e&&await De(e)}const g=b.join(c.dataDir,"health-port");ae(g,String(s),"utf-8"),process.on("SIGINT",()=>_("SIGINT")),process.on("SIGTERM",()=>_("SIGTERM")),process.on("SIGHUP",()=>{j||(i.info("main","Received SIGHUP, reloading config..."),o.reload().then(e=>i.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>i.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let u="",l=0,h;process.on("uncaughtException",e=>{const n=e instanceof Error?e.stack??e.message:String(e);n===u?(l++,(l<=3||l%100===0)&&i.error("main",`Uncaught exception (x${l}): ${n}`)):(l>3&&i.error("main",`Previous exception repeated ${l} times total`),u=n,l=1,i.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),h||(h=setTimeout(()=>{l>3&&i.error("main",`Previous exception repeated ${l} times total`),u="",l=0,h=void 0},1e4).unref())),!Ae(e)&&(z(e,"uncaughtException"),W("uncaughtException",e),_("uncaughtException"))}),process.on("unhandledRejection",e=>{i.error("main",`Unhandled rejection: ${e}`),!Ae(e)&&(z(e,"unhandledRejection"),W("unhandledRejection",e),_("unhandledRejection"))});const S=dt(c.dataDir);await S.clearRuntimeState();const k=new pt(b.join(c.dataDir,"proxy","relay-state.json"),{warn:e=>i.warn("main",e)}),N=new gt(b.join(c.dataDir,"secrets"));o.setRelaySecretResolver(e=>N.get(e));const L={hasDirectConfig:e=>o.hasDirectRelayConfig(e),clearDirectConfig:(e,n)=>o.setAgentProvider(e,void 0,{deferRestart:n?.deferRestart===!0})},K=()=>({pm:f(),agents:o,direct:L,store:k,secrets:N}),U=S.getRelayAgents();if(U.length>0)try{await S.startIfAnyRelayAgent(),i.info("main",`mitm proxy started for relay agents: ${U.join(", ")} (per-agent; others stay direct)`)}catch(e){i.error("main",`mitm proxy FAILED to start (relay agents: ${U.join(", ")}): ${e}. These agents will REFUSE to start (they must not silently fall back to your own account). Fix the proxy or turn relay off for them. Other agents are unaffected.`)}else i.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');let H=null;if(f()){const e=async()=>{const r=f();r&&await ge(r,o)&&i.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};o.setRelayEnvSettledHandler(()=>{const r=f();r&&me(r,L,k),e().catch(a=>{i.warn("main",`failed to stop idle mitm proxy: ${a}`)})});const n=()=>{const r=f(),a=r.getRelayAgents(),p=r.getDegradedRelayAgents();return{enabled:a.length>0,relayAgents:a,staleRelayAgents:o.getAgentsWithStaleRelayEnv(),degradedRelayAgents:p,relayState:k.list(),runtime:r.getRuntimeInfo(),config:r.getConfigSnapshot()}},d=new mt,A={status:()=>n(),setAgentRelay:async(r,a,p)=>{const m=f(),E={info:w=>i.info("main",w),warn:w=>i.warn("main",w)},R=w=>o.getAgentsStatus().find(v=>v.name===w),y=R(r);if(!a){d.cancel(r);const w=await d.runExclusive(r,async()=>{const v=await Q(K(),E,{agentName:r,target:"off"});return{...n(),restarted:v.restarted,busy:v.busy,...v.pending?{pending:v.pending}:{}}});return o.reportRelayStateLocalChange(r),w}if(!y)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});if(!Me(y.clientType)&&pe(y.clientType).length===0)throw Object.assign(new Error(`client type "${y.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"});const O=await d.runExclusive(r,async()=>{const w=d.epoch(r),v=R(r);if(!v)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});const re=String(v.agentId??"").trim();if(!re)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const ne=d.waitCancelled(r,w);let C;try{C=await Promise.race([o.fetchRelayCredential(r,{model:p}),ne.promise.then(()=>{throw new he("relay enable cancelled by a later disable","CANCELLED")})])}finally{ne.dispose()}d.assertCurrent(r,w);const{restarted:xe,busy:Pe,pending:oe}=await ue(m,o,R,E,{localName:r,agentId:re,virtualKey:C.apiKey,anthropicBaseUrl:C.anthropicBaseUrl,openaiBaseUrl:C.openaiBaseUrl,model:p,...C.directRelay!==void 0?{directRelay:C.directRelay}:{}},(Ie,_e,ke)=>o.setAgentProvider(Ie,_e,{deferRestart:ke?.deferRestart===!0}),{store:k,secrets:N,direct:L});if(d.epoch(r)!==w)throw await Q(K(),E,{agentName:r,target:"off"}),new he("relay enable cancelled by a later disable","CANCELLED");return{...n(),restarted:xe,busy:Pe,...oe?{pending:oe}:{}}});return o.reportRelayStateLocalChange(r),O},setAgentRelayCredential:async(r,a)=>{const p=f(),m=o.getAgentsStatus(),{restarted:E,busy:R,pending:y}=await ue(p,o,P=>m.find(O=>O.name===P),{info:P=>i.info("main",P),warn:P=>i.warn("main",P)},{localName:r,agentId:a.agentId,virtualKey:a.virtualKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}},(P,O,w)=>o.setAgentProvider(P,O,{deferRestart:w?.deferRestart===!0}),{store:k,secrets:N,direct:L});return o.reportRelayStateLocalChange(r),{...n(),restarted:E,busy:R,...y?{pending:y}:{}}},disableAll:async()=>{const r=f(),a={info:m=>i.info("main",m),warn:m=>i.warn("main",m)},p=new Set([...r.getRelayAgents(),...o.getDirectRelayConfigAgentNames(),...Object.keys(k.list())]);for(const m of p)d.cancel(m);for(const m of p)await d.runExclusive(m,()=>Q(K(),a,{agentName:m,target:"off"})),o.reportRelayStateLocalChange(m);return await ge(r,o),n()},setRoute:async(r,a)=>{const p=a,m=f();return m.setRoute({routeKey:r,targetBaseUrl:p.targetBaseUrl,...p.headers?{headers:p.headers}:{},...p.model?{model:p.model}:{},...p.modelMap?{modelMap:p.modelMap}:{},...p.passthrough?{passthrough:!0}:{},...p.relayOnly?{relayOnly:!0}:{},...p.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await m.persistConfig(),n()},deleteRoute:async r=>{const a=f();a.deleteRoute(r),await a.persistConfig()},setDefaultRoute:async r=>{const a=f();return a.setDefaultRouteKey(r),await a.persistConfig(),n()},setInterceptHosts:async r=>{const a=f();return a.setInterceptHosts(r),await a.persistConfig(),n()}};H=A,x.setProxyHandler(A),o.setRelayStateApplier({getLocalState:r=>{const a=f();if(a.getRelayAgents().includes(r)){const m=o.getAgentsStatus().find(y=>y.name===r),E=`grix-gateway-${String(m?.clientType??"").trim().toLowerCase()}`;return{enabled:!0,model:a.getConfigSnapshot().routes?.find(y=>y.routeKey===E)?.model?.trim()||void 0}}const p=o.getAgentProvider(r);return p?.api_key?.trim()?{enabled:!0,model:p.model?.trim()||void 0}:{enabled:!1}},applyEnable:async(r,a,p)=>{const m=o.getAgentsStatus().find(y=>y.name===r),E=String(m?.agentId??"").trim();if(!E)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const R=await A.setAgentRelayCredential(r,{agentId:E,virtualKey:a.apiKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:p??a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}});return{restarted:R.restarted===!0,busy:R.busy===!0,...R.pending?{pending:R.pending}:{}}},applyDisable:async r=>{const a=await A.setAgentRelay(r,!1);return{restarted:a.restarted===!0,busy:a.busy===!0,...a.pending?{pending:a.pending}:{}}}})}M.setStatusProvider(()=>o.getAgentsStatus()),M.setMetaProvider(()=>{const e=o.getAgentsStatus(),n=Le();return{ws:{connected:e.filter(d=>d.wsConnected===!0).length,total:e.length},upgrade:St(),log:{dir:n.logDir,file:n.logFile,primary_dir:n.primaryLogDir,degraded:n.degraded,using_fallback:n.usingFallback,...n.degradeReason?{degrade_reason:n.degradeReason}:{}}}});const X=new ot(b.join(c.dataDir,"remote-admin.json"));if(o.setRemoteAdminGate(()=>X.isEnabled()),await o.start(Dt),U.length>0){const e=o.getAgentsStatus();for(const n of U){const d=e.find(r=>r.name===n);if(!d)continue;const A=pe(d.clientType);A.length!==0&&await S.setAgentRelayEnabled(n,!0,{relayHosts:A}).catch(r=>{i.warn("main",`failed to reconcile relay hosts for "${n}": ${r}`)})}}me(S,L,k);const ee=parseInt(D["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);x.setAgentHandler({list:()=>o.getAgentsStatus(),add:e=>o.addAgent(e),remove:e=>o.removeAgent(e),restart:e=>o.restartAgent(e),reload:()=>o.reload()}),x.setUpgradeHandler({check:()=>o.checkUpgrade(),trigger:()=>o.triggerUpgrade()}),x.setProbeHandler({probeAll:e=>o.probeAll(e),probeOne:(e,n)=>o.probeOne(e,n)}),x.setRemoteAdminHandler({isEnabled:()=>X.isEnabled(),setEnabled:e=>{const n=X.setEnabled(e);return i.info("main",`remote admin ${n?"enabled":"disabled"} via admin API`),n}}),x.setInstallHandler({listInstallable:()=>o.listInstallable(),installAgent:e=>o.installAgent(e),getInstallProgress:e=>o.getInstallProgress(e)});const te={listAgents:()=>o.getAgentsStatus(),enableManaged:(e,n,d)=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelayCredential(e,{agentId:n,virtualKey:d.virtualKey,anthropicBaseUrl:d.anthropicBaseUrl,openaiBaseUrl:d.openaiBaseUrl,model:d.model,...d.directRelay!==void 0?{directRelay:d.directRelay}:{}})},disableManaged:e=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelay(e,!1)},enableHermesProfile:(e,n)=>ut({agentId:e,baseUrl:n.openaiBaseUrl??"",virtualKey:n.virtualKey,model:n.model??""}),disableHermesProfile:e=>ft(e)};x.setRelayCredentialHandler({listHermesProfiles:()=>ht(),enable:async(e,n)=>{const{target:d,result:A}=await wt(te,e,n);return{target:d,...A}},disable:async e=>{const{target:n,result:d}=await yt(te,e);return{target:n,...d}}});{const e=await se({label:"admin",port:ee,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:n=>x.start(n)});e&&await De(e)}const ve=b.join(c.dataDir,"admin-token"),be=b.join(c.dataDir,"admin-port");st(ve,Re),ae(be,String(ee),"utf-8"),await G(c.daemonStatusFile,{state:"running",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.send&&process.send("ready"),i.info("main","grix-connector ready")}bt().catch(async t=>{const s=`Fatal: ${t instanceof Error?t.stack??t.message:String(t)}`;try{process.stderr.write(`${s}
|
|
43
|
+
`)}catch{}ie(!1),i.error("main",s),z(t,"startup"),W("startup",t);const g=J(c.daemonLockFile);g?.pid===process.pid&&g.instance_id===$&&await G(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:g.instance_id,updated_at:Date.now(),reason:"startup_error"}).catch(()=>{}),await B(),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)});const xt=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH","EIO"]);function Ae(t){return lt(t)?!0:t instanceof Error&&"code"in t?xt.has(t.code):!1}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as
|
|
1
|
+
import{execFileSync as R,execSync as g,spawn as x}from"node:child_process";import r from"node:process";import{setTimeout as S}from"node:timers/promises";let d;function F(e=r.platform,t=r.env){return e==="win32"&&t.GRIX_WRAPPER_SUPERVISED!=="1"}function T(){if(r.platform!=="win32")return!1;if(d!==void 0)return d;try{g("net session",{stdio:"ignore",windowsHide:!0}),d=!0}catch{d=!1}return d}function G(e,t,n={}){x(e,t,{detached:!0,stdio:"ignore",windowsHide:!0,env:n.env??r.env}).unref()}function m(e,t,n={}){const{cwd:o,env:c=r.env,allowFailure:a=!1}=n;return new Promise((u,i)=>{const l=x(e,t,{cwd:o||void 0,env:c,stdio:["ignore","pipe","pipe"],windowsHide:!0}),w=[],h=[];l.stdout&&l.stdout.on("data",s=>w.push(s)),l.stderr&&l.stderr.on("data",s=>h.push(s)),l.on("error",s=>{if(a){u({exitCode:-1,stdout:"",stderr:s instanceof Error?s.message:String(s)});return}i(s)}),l.on("close",s=>{const f=s??0,P=Buffer.concat(w).toString("utf8"),C=Buffer.concat(h).toString("utf8");if(f!==0&&!a){const v=C.trim()||P.trim()||`${e} exited with code ${f}`;i(new Error(v));return}u({exitCode:f,stdout:P,stderr:C})})})}function p(e){if(e<=0)return!1;try{return r.kill(e,0),!0}catch(t){if(t instanceof Error&&"code"in t){if(t.code==="ESRCH")return!1;if(t.code==="EPERM")return!0}return!1}}const y=3e3;function W(e){try{const n=R(I(),["-NoProfile","-NonInteractive","-WindowStyle","Hidden","-Command",`(Get-CimInstance Win32_Process -Filter 'ProcessId=${e}').CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:y,windowsHide:!0}).trim();return n||null}catch{return null}}function H(e){if(e<=0||!Number.isInteger(e))return null;if(r.platform==="win32")return W(e);try{const n=g(`ps -ww -o command= -p ${e}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:y}).trim();return n||null}catch{return null}}async function k(e,t={}){const{platform:n=r.platform,runCommandImpl:o=m}=t;if(e<=0)return!1;if(n==="win32")return await o("taskkill",["/PID",String(e),"/T","/F"],{allowFailure:!0}),!0;try{return r.kill(-e,"SIGTERM"),!0}catch{}try{return r.kill(e,"SIGTERM"),!0}catch{return!1}}async function $(e,t={}){const{timeoutMs:n=5e3,intervalMs:o=100}=t;if(e<=0)return!0;const c=Date.now()+n;for(;Date.now()<=c;){if(!p(e))return!0;await S(o)}return!p(e)}function I(){return`${r.env.SystemRoot||"C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`}function E(e){return e.split(/\r?\n/).map(t=>parseInt(t.trim(),10)).filter(t=>t>0&&!Number.isNaN(t))}async function L(e,t={}){const n=t.runCommandImpl??m;if((t.platform??r.platform)==="win32"){const c=e.replace(/'/g,"''"),a=await n(I(),["-NoProfile","-NonInteractive","-WindowStyle","Hidden","-Command",`Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*${c}*' } | Select-Object -ExpandProperty ProcessId`],{allowFailure:!0});return a.exitCode!==0?[]:E(a.stdout)}const o=await n("pgrep",["-f",e],{allowFailure:!0});return o.exitCode!==0?[]:E(o.stdout)}async function D(e,t={}){const{exceptPid:n=0,platform:o=r.platform}=t,c=await L(e),a=new Set([r.pid,r.ppid,n]),u=c.filter(i=>!a.has(i));if(u.length===0)return 0;if(o==="win32")for(const i of u)await k(i,{platform:"win32",runCommandImpl:m});else{for(const i of u)try{r.kill(i,"SIGTERM")}catch{}await S(500);for(const i of u)if(p(i))try{r.kill(i,"SIGKILL")}catch{}}return u.length}export{L as findProcessesByCommandLine,H as getProcessCommandLine,p as isProcessRunning,T as isWindowsElevated,D as killProcessesByCommandLine,m as runCommand,F as shouldSweepWindowsWrappers,G as spawnDetached,k as terminateProcessTree,$ as waitForProcessExit};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.11",
|
|
4
4
|
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -1246,10 +1246,10 @@ export async function monitorWindowsUpgrade(rootDir, injected = {}) {
|
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
1248
|
/**
|
|
1249
|
-
* 找出命令行含 wrapper 文件名的 wscript
|
|
1249
|
+
* 找出命令行含 wrapper 文件名的 wscript 进程(PowerShell CIM;Win11 已移除 wmic)。
|
|
1250
1250
|
*
|
|
1251
1251
|
* 返回值区分两种"空":`[]` 表示查询工具正常工作且确实没有匹配进程;
|
|
1252
|
-
* `null` 表示
|
|
1252
|
+
* `null` 表示 CIM 查询失败、根本查不了。调用方(adopt-wrapper)靠这个
|
|
1253
1253
|
* 区别决定敢不敢拉起新 wrapper——查不了就不能当作"没有旧 wrapper"。
|
|
1254
1254
|
*/
|
|
1255
1255
|
function findWrapperPids(wrapperFileName) {
|
|
@@ -1257,13 +1257,6 @@ function findWrapperPids(wrapperFileName) {
|
|
|
1257
1257
|
.split(/\r?\n/)
|
|
1258
1258
|
.map((line) => Number.parseInt(line.trim(), 10))
|
|
1259
1259
|
.filter((pid) => Number.isFinite(pid) && pid > 0);
|
|
1260
|
-
try {
|
|
1261
|
-
return parse(execFileSync(
|
|
1262
|
-
'wmic',
|
|
1263
|
-
['process', 'where', `CommandLine like '%${wrapperFileName}%'`, 'get', 'ProcessId'],
|
|
1264
|
-
{ encoding: 'utf8', timeout: 15_000, windowsHide: true },
|
|
1265
|
-
));
|
|
1266
|
-
} catch { /* fall through to CIM */ }
|
|
1267
1260
|
try {
|
|
1268
1261
|
const script = `Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*${wrapperFileName}*' } | ForEach-Object { $_.ProcessId }`;
|
|
1269
1262
|
return parse(execFileSync(
|
|
@@ -1336,7 +1329,7 @@ export async function adoptWindowsWrapper(rootDir, options, injected = {}) {
|
|
|
1336
1329
|
const wrapperFileName = `${serviceId}-wrapper.vbs`;
|
|
1337
1330
|
const found = deps.findWrapperPids(wrapperFileName);
|
|
1338
1331
|
if (found === null) {
|
|
1339
|
-
appendLog(paths.log, 'adopt-wrapper: cannot enumerate wrapper processes (
|
|
1332
|
+
appendLog(paths.log, 'adopt-wrapper: cannot enumerate wrapper processes (CIM query failed); NOT starting a wrapper that might duplicate a live one');
|
|
1340
1333
|
return;
|
|
1341
1334
|
}
|
|
1342
1335
|
const stalePids = found.filter((pid) => pid !== process.pid);
|
|
Binary file
|