shennian 0.4.65 → 0.4.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/publish-build-manifest.json +39 -34
  2. package/dist/src/agents/acp/manifests.d.ts +2 -2
  3. package/dist/src/agents/adapter.d.ts +1 -1
  4. package/dist/src/agents/codex.js +5 -5
  5. package/dist/src/index.js +3 -3
  6. package/dist/src/manager/registry.d.ts +10 -0
  7. package/dist/src/manager/registry.js +1 -1
  8. package/dist/src/manager/runtime.d.ts +4 -2
  9. package/dist/src/manager/runtime.js +6 -6
  10. package/dist/src/manager/worker-ipc.d.ts +5 -3
  11. package/dist/src/manager/worker-ipc.js +1 -1
  12. package/dist/src/room/activation-service.d.ts +8 -2
  13. package/dist/src/room/activation-service.js +10 -5
  14. package/dist/src/room/managed-context.d.ts +3 -1
  15. package/dist/src/room/managed-context.js +1 -1
  16. package/dist/src/room/managed-room-ipc.d.ts +2 -0
  17. package/dist/src/room/managed-room-ipc.js +2 -2
  18. package/dist/src/session/handlers/chat-recovery.js +1 -1
  19. package/dist/src/session/handlers/chat.js +2 -2
  20. package/dist/src/session/manager-event-authority.d.ts +3 -0
  21. package/dist/src/session/manager-event-authority.js +1 -0
  22. package/dist/src/session/manager.d.ts +2 -2
  23. package/dist/src/session/manager.js +2 -2
  24. package/dist/src/session/queue-helpers.d.ts +5 -0
  25. package/dist/src/session/queue-helpers.js +8 -8
  26. package/dist/src/session/queue-message.d.ts +4 -1
  27. package/dist/src/session/queue-message.js +1 -1
  28. package/dist/src/session/queue-storage.d.ts +1 -0
  29. package/dist/src/session/queue-storage.js +2 -2
  30. package/dist/src/session/queue-types.d.ts +8 -0
  31. package/dist/src/session/queue.d.ts +3 -3
  32. package/dist/src/session/queue.js +1 -1
  33. package/dist/src/session/queued-chat-dispatch.js +1 -1
  34. package/dist/src/session/turn-trigger.d.ts +5 -0
  35. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import{SESSION_SYNC_PROTOCOL_VERSION as g,SESSION_SYNC_DATA_EPOCH as f}from"@shennian/wire";import h from"node:crypto";import{getRegisteredAgents as k,unregisterAgent as I}from"../agents/adapter.js";import{resetCommandSpecCache as A}from"../agents/command-spec.js";import{loadConfig as T}from"../config/index.js";import{handleUpgradeStart as P,handleUpgradeStatus as C}from"../commands/upgrade.js";import{handleAgentsRefresh as M,handleModelsRefresh as D,refreshMachineAgents as x}from"./handlers/agents.js";import{AcpDiscoveryWatcher as E}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as F}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as _,handleAgentConfigGet as O,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as B,handleChatSend as U}from"./handlers/chat.js";import{recoverJournaledRun as z}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as $}from"./handlers/tool-detail.js";import{handleSessionTitleSet as H}from"./handlers/title.js";import{handleSessionMessageStatus as J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as N}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as V}from"./handlers/voice-window.js";import{handleRemoteAccessPause as L}from"./handlers/remote-access.js";import{cleanupPendingTransfers as G,handleFsLs as Y,handleFsRead as K,handleFsRename as X,handleFsWrite as Z,handleFsTransferAbort as q,handleFsTransferChunk as ee,handleFsTransferFinish as se,handleFsTransferStart as te,handleFsExportMarkdownPdf as ae,handleFsExportMarkdownPdfSetup as re,handleFsArchiveZip as ne}from"./handlers/fs.js";import{handleRegionProbe as ie,handleRegionSwitch as oe,handleUpgradeSetPolicy as ce}from"./handlers/control.js";import{ManagerRuntimeService as le,setManagerRuntimeService as v}from"../manager/runtime.js";import{ChatQueueManager as de}from"./queue.js";import{createAuthorizedFsRoot as he,createAuthorizedFsRootAsync as ue,resolveAuthorizedPath as pe,resolveAuthorizedPathAsync as me,resolveSessionWorkDir as ge}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as fe}from"../agents/custom.js";import{handleManagedRoomBind as ve,handleManagedRoomRestart as ye,discardPreBindingSession as Re}from"./handlers/room-managed.js";import{getDaemonInstallationId as u,listSessionRecords as p,purgeCanonicalSession as be,purgeSessionRecord as Se,recordSession as we,upsertMessage as ke}from"./store.js";import{requestSessionIndexPublish as Ie}from"./index-publisher.js";import{reportUpgradeAggregateMetric as Ae}from"../log-reporter.js";import{PersonalHistorySubscriptions as Te}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Pe}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Ce}from"../native-fusion/native-source-deletions.js";import{purgeToolDetails as Me}from"./tool-detail-store.js";import{readDeletionSyncRevision as De,writeDeletionSyncRevision as y}from"./deletion-sync-state.js";import{assertDeletionSyncRunnable as xe,clearDeletionSyncFailure as Ee,DeletionSyncRetryWaitError as Fe,DeletionSyncTerminalError as _e,recordDeletionSyncFailure as m}from"./deletion-sync-state.js";import{NativeSessionCleanupOutbox as Oe}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Qe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as je}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Be}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ue}from"./project-fs-store.js";import{handleProjectFsRequest as ze}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as We,handleAcpAgentRequest as $e}from"./handlers/agent-control.js";import{validateDeletionSyncResponse as He}from"./deletion-sync-validation.js";import{dispatchManagedChat as Je,dispatchQueuedChat as Ne,interruptQueuedChat as Ve}from"./queued-chat-dispatch.js";const Le=50;import{resolveSessionWorkDir as Xs}from"../fs/boundary.js";class Gs{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new je;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ue;constructor(e,t=null,s,n=null,r=null,d=null,o=null,R=null,b=null,S=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=n,this.managedRoomBinder=r,this.remoteAccessPauseController=d,this.managedRoomContextRevoker=o,this.managedRoomExecutor=R,this.trustedProjectFsRequestResolver=S,this.runJournal=b??new Qe(u());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Be({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>z(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=p().find(w=>w.sessionId===a.sessionId),l=`terminal:${h.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>Ae({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new le({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new de({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Je(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ne(this.getRuntime(),a,i),interruptQueuedSession:a=>Ve(this.getRuntime(),a)}),this.historySubscriptions=new Te(this.client),this.nativeCleanupOutbox=new Oe({logger:console.info}),this.acpDiscoveryWatcher=new E(async()=>{A(),await x(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeCleanupOutbox.start(),v(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...p().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Pe(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params)}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const n=t.result==="interrupted_by_upgrade"?`\u4EFB\u52A1\u56E0\u795E\u5FF5\u5347\u7EA7\u800C\u4E2D\u65AD\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
1
+ import{SESSION_SYNC_PROTOCOL_VERSION as g,SESSION_SYNC_DATA_EPOCH as f}from"@shennian/wire";import h from"node:crypto";import{getRegisteredAgents as k,unregisterAgent as I}from"../agents/adapter.js";import{resetCommandSpecCache as A}from"../agents/command-spec.js";import{loadConfig as T}from"../config/index.js";import{handleUpgradeStart as P,handleUpgradeStatus as C}from"../commands/upgrade.js";import{handleAgentsRefresh as M,handleModelsRefresh as D,refreshMachineAgents as x}from"./handlers/agents.js";import{AcpDiscoveryWatcher as E}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as F}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as O,handleAgentConfigGet as _,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as B,handleChatSend as U}from"./handlers/chat.js";import{recoverJournaledRun as z}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as $}from"./handlers/tool-detail.js";import{handleSessionTitleSet as H}from"./handlers/title.js";import{handleSessionMessageStatus as J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as N}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as V}from"./handlers/voice-window.js";import{handleRemoteAccessPause as L}from"./handlers/remote-access.js";import{cleanupPendingTransfers as G,handleFsLs as Y,handleFsRead as K,handleFsRename as X,handleFsWrite as Z,handleFsTransferAbort as q,handleFsTransferChunk as ee,handleFsTransferFinish as se,handleFsTransferStart as te,handleFsExportMarkdownPdf as ae,handleFsExportMarkdownPdfSetup as re,handleFsArchiveZip as ne}from"./handlers/fs.js";import{handleRegionProbe as ie,handleRegionSwitch as oe,handleUpgradeSetPolicy as ce}from"./handlers/control.js";import{ManagerRuntimeService as le,setManagerRuntimeService as v}from"../manager/runtime.js";import{ChatQueueManager as de}from"./queue.js";import{createAuthorizedFsRoot as he,createAuthorizedFsRootAsync as ue,resolveAuthorizedPath as pe,resolveAuthorizedPathAsync as me,resolveSessionWorkDir as ge}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as fe}from"../agents/custom.js";import{handleManagedRoomBind as ve,handleManagedRoomRestart as ye,discardPreBindingSession as Re}from"./handlers/room-managed.js";import{getDaemonInstallationId as u,listSessionRecords as p,purgeCanonicalSession as be,purgeSessionRecord as Se,recordSession as we,upsertMessage as ke}from"./store.js";import{requestSessionIndexPublish as Ie}from"./index-publisher.js";import{reportUpgradeAggregateMetric as Ae}from"../log-reporter.js";import{PersonalHistorySubscriptions as Te}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Pe}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Ce}from"../native-fusion/native-source-deletions.js";import{purgeToolDetails as Me}from"./tool-detail-store.js";import{readDeletionSyncRevision as De,writeDeletionSyncRevision as y}from"./deletion-sync-state.js";import{assertDeletionSyncRunnable as xe,clearDeletionSyncFailure as Ee,DeletionSyncRetryWaitError as Fe,DeletionSyncTerminalError as Oe,recordDeletionSyncFailure as m}from"./deletion-sync-state.js";import{NativeSessionCleanupOutbox as _e}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Qe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as je}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Be}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ue}from"./project-fs-store.js";import{handleProjectFsRequest as ze}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as We,handleAcpAgentRequest as $e}from"./handlers/agent-control.js";import{validateDeletionSyncResponse as He}from"./deletion-sync-validation.js";import{dispatchManagedChat as Je,dispatchQueuedChat as Ne,interruptQueuedChat as Ve}from"./queued-chat-dispatch.js";const Le=50;import{resolveSessionWorkDir as Xs}from"../fs/boundary.js";class Gs{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new je;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ue;constructor(e,t=null,s,n=null,r=null,d=null,o=null,R=null,b=null,S=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=n,this.managedRoomBinder=r,this.remoteAccessPauseController=d,this.managedRoomContextRevoker=o,this.managedRoomExecutor=R,this.trustedProjectFsRequestResolver=S,this.runJournal=b??new Qe(u());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Be({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>z(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=p().find(w=>w.sessionId===a.sessionId),l=`terminal:${h.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>Ae({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new le({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new de({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Je(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ne(this.getRuntime(),a,i),interruptQueuedSession:a=>Ve(this.getRuntime(),a)}),this.historySubscriptions=new Te(this.client),this.nativeCleanupOutbox=new _e({logger:console.info}),this.acpDiscoveryWatcher=new E(async()=>{A(),await x(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeCleanupOutbox.start(),v(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...p().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Pe(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const n=t.result==="interrupted_by_upgrade"?`\u4EFB\u52A1\u56E0\u795E\u5FF5\u5347\u7EA7\u800C\u4E2D\u65AD\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
2
2
  Task interrupted by the Shennian upgrade (${t.reason}). The session is preserved and ready for a new message.`:`\u795E\u5FF5\u5347\u7EA7\u540E\u672A\u80FD\u6062\u590D\u4EFB\u52A1\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u91CD\u8BD5\u6216\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
3
- The task could not be recovered after the Shennian upgrade (${t.reason}). The session is preserved; retry or send a new message.`;ke(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:n,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),we({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:n}),Ie(this.client);const r=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason,...t.message?{message:t.message}:{}},seq:r,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const n=p().find(r=>r.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:n?.modelId??s.params.modelId,sessionMode:n?.sessionMode??s.params.sessionMode,managerConfig:n?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:n?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await Re(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){xe();try{await this.synchronizeSessionDeletionsOnce(),Ee()}catch(e){if(e instanceof Fe||e instanceof _e)throw e;const t=e instanceof Error?e.message:String(e),s=/offline|not connected|disconnect|timed out|timeout|temporar|unavailable|ECONN|ENOTFOUND|EIO|EBUSY/i.test(t)?"transport_unavailable":/invalid (?:deletion sync|session deletion)|deletion revision gap/i.test(t)?"invalid_deletion_sync_response":"deletion_sync_failed";throw console.warn("[session.deletions] retrying failed synchronization",{code:s}),m({code:s,retryable:!0}),e}}async synchronizeSessionDeletionsOnce(){const e=u(),t=De(),s=await this.client.sendReq({type:"req",id:`session-deletions-sync-${h.randomUUID()}`,method:"session.deletions.sync",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,afterRevision:t}});if(!s.ok){const o=s.rejection;throw o?(m({code:o.code,retryable:o.retryable&&o.requiredAction==="retry"}),new Error(o.code)):(m({code:"unstructured_rejection",retryable:!0}),new Error(s.error??"unstructured_rejection"))}const n=s.payload;c(n),He(n,t);let r=n.baselineRevision;r>t&&y(r);for(const o of n.deletions)o.deletionRevision<=r||(await this.applySessionDeletion(o),r=o.deletionRevision,y(r));if(r!==n.latestRevision)throw new Error(`deletion revision gap: applied ${r}, latest ${n.latestRevision}`);if(r===0)return;const d=await this.client.sendReq({type:"req",id:`session-deletions-ack-${h.randomUUID()}`,method:"session.deletions.ack",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,deletionRevision:r}});if(!d.ok)throw new Error(d.error??"session deletion acknowledgement failed")}async applySessionDeletion(e){const t=new Ce({daemonInstallationId:u()});t.recordSession(e);for(const n of e.sources){const r=t.find(n.agentType,n.sourceSessionKey);r&&r.sessionId!==e.sessionId||t.record({...e,...n})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const s=this.sessions.get(e.sessionId);if(s){this.revokeManagedRoomToken(s);try{await s.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Me(e.sessionId),be(e.sessionId),Se(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const n=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:n,canStop:s.canStop??!0});const r=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:r,runPhase:s.runPhase,canStop:s.canStop??!0},seq:r,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of k())t.startsWith("custom:")&&I(t);const e=T();for(const[t,s]of Object.entries(e.customAgents??{}))fe(t,s)}async handleReq(e,t={}){const s=this.getRuntime();let n;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?n={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await U(s,e);break;case"chat.enqueue":c(e.params),n={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await B(s,e);break;case"session.refresh":c(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":J(s,e);break;case"session.tool.detail":await $(s,e);break;case"voice.session.body.window":V(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ve(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await ye(s,this.managedRoomBinder,e);break;case"fs.ls":await Y(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await ze(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await K(s,e);break;case"fs.write":await Z(s,e);break;case"fs.export.markdown-pdf":await ae(s,e);break;case"fs.export.markdown-pdf.setup":await re(s,e);break;case"fs.archive.zip":await ne(s,e);break;case"fs.rename":await X(s,e);break;case"fs.transfer.start":await te(s,e);break;case"fs.transfer.chunk":await ee(s,e);break;case"fs.transfer.finish":await se(s,e);break;case"fs.transfer.abort":await q(s,e);break;case"region.probe":await ie(s,e);break;case"region.switch":await oe(s,e);break;case"upgrade.start":await P(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:r=>this.prepareForUpgrade(r),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await C(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ce(s,e);break;case"machine.remote-access.pause":await L(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await M(s,e);break;case"agent.permission.respond":await We(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await $e(s,e);break;case"models.refresh":await D(s,e);break;case"agent.config.get":await O(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await _(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await N(s,e);break;case"agent.capabilities.list":await F(s,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(r){if(t.propagateErrors)throw r;this.client.sendRes({type:"res",id:e.id,ok:!1,error:r instanceof Error?r.message:String(r)})}finally{this.activeRequests--}return n}evictIdleSessions(){if(this.sessions.size<Le)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return ge(e)}resolveAuthorizedPath(e,t){return pe(e,he(t))}async resolveAuthorizedPathAsync(e,t){return me(e,await ue(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),G(this.getRuntime()),await this.managerRuntime.stop(),v(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Gs as SessionManager,Xs as resolveSessionWorkDir};
3
+ The task could not be recovered after the Shennian upgrade (${t.reason}). The session is preserved; retry or send a new message.`;ke(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:n,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),we({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:n}),Ie(this.client);const r=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason,...t.message?{message:t.message}:{}},seq:r,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const n=p().find(r=>r.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:n?.modelId??s.params.modelId,sessionMode:n?.sessionMode??s.params.sessionMode,managerConfig:n?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:n?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await Re(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){xe();try{await this.synchronizeSessionDeletionsOnce(),Ee()}catch(e){if(e instanceof Fe||e instanceof Oe)throw e;const t=e instanceof Error?e.message:String(e),s=/offline|not connected|disconnect|timed out|timeout|temporar|unavailable|ECONN|ENOTFOUND|EIO|EBUSY/i.test(t)?"transport_unavailable":/invalid (?:deletion sync|session deletion)|deletion revision gap/i.test(t)?"invalid_deletion_sync_response":"deletion_sync_failed";throw console.warn("[session.deletions] retrying failed synchronization",{code:s}),m({code:s,retryable:!0}),e}}async synchronizeSessionDeletionsOnce(){const e=u(),t=De(),s=await this.client.sendReq({type:"req",id:`session-deletions-sync-${h.randomUUID()}`,method:"session.deletions.sync",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,afterRevision:t}});if(!s.ok){const o=s.rejection;throw o?(m({code:o.code,retryable:o.retryable&&o.requiredAction==="retry"}),new Error(o.code)):(m({code:"unstructured_rejection",retryable:!0}),new Error(s.error??"unstructured_rejection"))}const n=s.payload;c(n),He(n,t);let r=n.baselineRevision;r>t&&y(r);for(const o of n.deletions)o.deletionRevision<=r||(await this.applySessionDeletion(o),r=o.deletionRevision,y(r));if(r!==n.latestRevision)throw new Error(`deletion revision gap: applied ${r}, latest ${n.latestRevision}`);if(r===0)return;const d=await this.client.sendReq({type:"req",id:`session-deletions-ack-${h.randomUUID()}`,method:"session.deletions.ack",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,deletionRevision:r}});if(!d.ok)throw new Error(d.error??"session deletion acknowledgement failed")}async applySessionDeletion(e){const t=new Ce({daemonInstallationId:u()});t.recordSession(e);for(const n of e.sources){const r=t.find(n.agentType,n.sourceSessionKey);r&&r.sessionId!==e.sessionId||t.record({...e,...n})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const s=this.sessions.get(e.sessionId);if(s){this.revokeManagedRoomToken(s);try{await s.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Me(e.sessionId),be(e.sessionId),Se(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const n=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:n,canStop:s.canStop??!0});const r=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:r,runPhase:s.runPhase,canStop:s.canStop??!0},seq:r,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of k())t.startsWith("custom:")&&I(t);const e=T();for(const[t,s]of Object.entries(e.customAgents??{}))fe(t,s)}async handleReq(e,t={}){const s=this.getRuntime();let n;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?n={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await U(s,e);break;case"chat.enqueue":c(e.params),n={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await B(s,e);break;case"session.refresh":c(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":J(s,e);break;case"session.tool.detail":await $(s,e);break;case"voice.session.body.window":V(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ve(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await ye(s,this.managedRoomBinder,e);break;case"fs.ls":await Y(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await ze(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await K(s,e);break;case"fs.write":await Z(s,e);break;case"fs.export.markdown-pdf":await ae(s,e);break;case"fs.export.markdown-pdf.setup":await re(s,e);break;case"fs.archive.zip":await ne(s,e);break;case"fs.rename":await X(s,e);break;case"fs.transfer.start":await te(s,e);break;case"fs.transfer.chunk":await ee(s,e);break;case"fs.transfer.finish":await se(s,e);break;case"fs.transfer.abort":await q(s,e);break;case"region.probe":await ie(s,e);break;case"region.switch":await oe(s,e);break;case"upgrade.start":await P(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:r=>this.prepareForUpgrade(r),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await C(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ce(s,e);break;case"machine.remote-access.pause":await L(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await M(s,e);break;case"agent.permission.respond":await We(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await $e(s,e);break;case"models.refresh":await D(s,e);break;case"agent.config.get":await _(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await O(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await N(s,e);break;case"agent.capabilities.list":await F(s,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(r){if(t.propagateErrors)throw r;this.client.sendRes({type:"res",id:e.id,ok:!1,error:r instanceof Error?r.message:String(r)})}finally{this.activeRequests--}return n}evictIdleSessions(){if(this.sessions.size<Le)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return ge(e)}resolveAuthorizedPath(e,t){return pe(e,he(t))}async resolveAuthorizedPathAsync(e,t){return me(e,await ue(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),G(this.getRuntime()),await this.managerRuntime.stop(),v(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Gs as SessionManager,Xs as resolveSessionWorkDir};
@@ -1,6 +1,11 @@
1
1
  import type { QueuedChatMessage } from '@shennian/wire';
2
2
  import type { LocalQueuedChatMessage } from './queue.js';
3
3
  import type { SessionManagerRuntime } from './types.js';
4
+ import type { ManagedAgentDirectTurnOptions } from './queue-types.js';
5
+ import type { ManagedWorkerRoomOrigin } from '../manager/registry.js';
6
+ export declare function managedDirectTurnOptions(managerEvent: {
7
+ roomOrigin?: ManagedWorkerRoomOrigin;
8
+ } | null | undefined, ownerManagedDirect: boolean): ManagedAgentDirectTurnOptions | undefined;
4
9
  export declare function findDuplicateQueuedMessage<T extends QueuedChatMessage & {
5
10
  origin?: 'app' | 'external' | 'room';
6
11
  }>(pending: T[], message: T): T | null;
@@ -1,11 +1,11 @@
1
- import{listSessionRecords as p}from"./store.js";function I(n,e){const r=u(e);if(r)return n.find(i=>u(i)===r)??null;if(e.origin!=="external")return null;const t=f(e);return n.find(i=>f(i)===t)??null}function x(n){const{origin:e,managedRoom:r,managedAgentDirect:t,trigger:i,...a}=n;return a}function b(n){const e=n.reduce((o,g)=>{const l=s(g);return o===null||l<o?l:o},null);if(e===null)return[];const r=n.filter(o=>s(o)===e),t=r[0];if(!t)return[];if(d(t))return[t];if(t.trigger?.kind==="manager_worker"||t.trigger?.kind==="scheduled")return[t];const i=m(t),a=[];for(const o of r){if(m(o)!==i)break;a.push(o)}return a}function d(n){if(n.origin==="external"||n.origin==="room"||n.managedRoom)return!1;const e=n.trigger?.kind;return e==null||e==="personal"||e==="managed_direct"}function _(n){return n?.trim()||void 0}function M(n,e){const r=n.find(t=>t.id===e&&d(t));return r?[r]:[]}function s(n){const e=c(n).kind;return e==="personal"||e==="managed_direct"?0:e==="manager_event"||e==="manager_worker"?1:2}function c(n){const e=n.trigger;return e?e.kind==="room_activation"?{kind:e.kind,registryKey:e.registryKey}:e.kind==="manager_worker"?{kind:e.kind,parentSessionId:e.parentSessionId}:{kind:e.kind}:n.managedRoom?{kind:"room_activation",registryKey:n.managedRoom.registryKey}:n.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"}}function m(n){return JSON.stringify({agentType:n.agentType,sessionMode:n.sessionMode??null,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:_(n.modelId)??null,systemPrompt:n.systemPrompt??null,reasoningEffort:n.reasoningEffort??null,managerConfig:n.managerConfig??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId??null,externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,roomRegistryKey:n.managedRoom?.registryKey??null,trigger:c(n)})}function D(n){return n.every(e=>e.managedRoom)?`[\u7FA4\u6D88\u606F]
2
- ${n.map(e=>y(e.text)).filter(Boolean).join(`
1
+ import{listSessionRecords as p}from"./store.js";function x(n,r){return n?{roomOrigin:n.roomOrigin,allowedRoomActions:n.roomOrigin?["send"]:[],managerEvent:!0}:r?{allowedRoomActions:[]}:void 0}function I(n,r){const e=u(r);if(e)return n.find(i=>u(i)===e)??null;if(r.origin!=="external")return null;const t=f(r);return n.find(i=>f(i)===t)??null}function b(n){const{origin:r,managedRoom:e,managedAgentDirect:t,trigger:i,...a}=n;return a}function M(n){const r=n.reduce((o,g)=>{const l=s(g);return o===null||l<o?l:o},null);if(r===null)return[];const e=n.filter(o=>s(o)===r),t=e[0];if(!t)return[];if(d(t))return[t];if(t.trigger?.kind==="manager_worker"||t.trigger?.kind==="scheduled")return[t];const i=m(t),a=[];for(const o of e){if(m(o)!==i)break;a.push(o)}return a}function d(n){if(n.origin==="external"||n.origin==="room"||n.managedRoom)return!1;const r=n.trigger?.kind;return r==null||r==="personal"||r==="managed_direct"}function _(n){return n?.trim()||void 0}function D(n,r){const e=n.find(t=>t.id===r&&d(t));return e?[e]:[]}function s(n){const r=c(n).kind;return r==="personal"||r==="managed_direct"?0:r==="manager_event"||r==="manager_worker"?1:2}function c(n){const r=n.trigger;return r?r.kind==="room_activation"?{kind:r.kind,registryKey:r.registryKey}:r.kind==="manager_worker"?{kind:r.kind,parentSessionId:r.parentSessionId,roomOrigin:r.roomOrigin??null}:r.kind==="manager_event"?{kind:r.kind,roomOrigin:r.roomOrigin??null}:{kind:r.kind}:n.managedRoom?{kind:"room_activation",registryKey:n.managedRoom.registryKey}:n.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"}}function m(n){return JSON.stringify({agentType:n.agentType,sessionMode:n.sessionMode??null,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:_(n.modelId)??null,systemPrompt:n.systemPrompt??null,reasoningEffort:n.reasoningEffort??null,managerConfig:n.managerConfig??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId??null,externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,roomRegistryKey:n.managedRoom?.registryKey??null,trigger:c(n)})}function R(n){return n.every(r=>r.managedRoom)?`[\u7FA4\u6D88\u606F]
2
+ ${n.map(r=>y(r.text)).filter(Boolean).join(`
3
3
 
4
4
  `)}`:`[\u8FDE\u7EED\u7528\u6237\u6D88\u606F]
5
- ${n.map((e,r)=>`<\u6D88\u606F ${r+1}>
6
- ${e.text.trim()}`).join(`
5
+ ${n.map((r,e)=>`<\u6D88\u606F ${e+1}>
6
+ ${r.text.trim()}`).join(`
7
7
 
8
- `)}`}function y(n){const e=n.trim(),r=e.match(/^\[群消息\][ \t]+<([^>\n]+)>\n([\s\S]*)$/);return r?`<${r[1]}>
9
- ${r[2]}`:e.startsWith(`[\u7FA4\u6D88\u606F]
10
- `)?e.slice(6):e}function f(n){const e=u(n);return e?`id:${e}`:["body",k(n.text),...(n.attachments??[]).map(r=>r.path||`${r.name}:${r.mimeType}`)].join(`
11
- `)}function u(n){const e=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(e)return e;const r=typeof n.id=="string"?n.id.trim():"";return r&&!r.startsWith("queue-")?r:""}function S(n){const e=new Set,r=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;e.has(i)||(e.add(i),r.push(t))}return r.length?r:void 0}function k(n){return String(n||"").replace(/\s+/g," ").trim()}function $(n,e){const r=n.toLowerCase();if(r.includes("managed claim session conflicts with source binding"))return"managed_claim_source_binding_conflict";const t=r.match(/\b(?:managed_(?:agent|room)|agent_validation|acp|native)_[a-z0-9_]+\b/)?.[0];return t||(r.includes("no rollout found")?"missing_rollout":r.includes("managed_room_permission_snapshot_mismatch")?"managed_room_permission_snapshot_mismatch":r.includes("managed_room_prompt_snapshot_mismatch")?"managed_room_prompt_snapshot_mismatch":r.includes("managed_room_turn_preparer_unavailable")?"managed_room_turn_preparer_unavailable":r.includes("timeout")?"timeout":r.includes("connection")?"connection_error":e)}function v(n,e){if(n.sessions.has(e.sessionId))return null;const r=p().find(t=>t.sessionId===e.sessionId)?.agentSessionId?.trim();return!r||r.startsWith("managed:")?null:r}export{$ as classifyQueueError,S as dedupeQueuedAttachments,I as findDuplicateQueuedMessage,D as formatQueuedBatch,d as isControllableQueueMessage,_ as normalizeQueuedModelId,v as resolveManagedRoomNativeSessionId,x as stripLocalQueueFields,b as takeCompatibleBatch,M as takeControllableMessage};
8
+ `)}`}function y(n){const r=n.trim(),e=r.match(/^\[群消息\][ \t]+<([^>\n]+)>\n([\s\S]*)$/);return e?`<${e[1]}>
9
+ ${e[2]}`:r.startsWith(`[\u7FA4\u6D88\u606F]
10
+ `)?r.slice(6):r}function f(n){const r=u(n);return r?`id:${r}`:["body",k(n.text),...(n.attachments??[]).map(e=>e.path||`${e.name}:${e.mimeType}`)].join(`
11
+ `)}function u(n){const r=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(r)return r;const e=typeof n.id=="string"?n.id.trim():"";return e&&!e.startsWith("queue-")?e:""}function S(n){const r=new Set,e=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;r.has(i)||(r.add(i),e.push(t))}return e.length?e:void 0}function k(n){return String(n||"").replace(/\s+/g," ").trim()}function $(n,r){const e=n.toLowerCase();if(e.includes("managed claim session conflicts with source binding"))return"managed_claim_source_binding_conflict";const t=e.match(/\b(?:managed_(?:agent|room)|agent_validation|acp|native)_[a-z0-9_]+\b/)?.[0];return t||(e.includes("no rollout found")?"missing_rollout":e.includes("managed_room_permission_snapshot_mismatch")?"managed_room_permission_snapshot_mismatch":e.includes("managed_room_prompt_snapshot_mismatch")?"managed_room_prompt_snapshot_mismatch":e.includes("managed_room_turn_preparer_unavailable")?"managed_room_turn_preparer_unavailable":e.includes("timeout")?"timeout":e.includes("connection")?"connection_error":r)}function v(n,r){if(n.sessions.has(r.sessionId))return null;const e=p().find(t=>t.sessionId===r.sessionId)?.agentSessionId?.trim();return!e||e.startsWith("managed:")?null:e}export{$ as classifyQueueError,S as dedupeQueuedAttachments,I as findDuplicateQueuedMessage,R as formatQueuedBatch,d as isControllableQueueMessage,x as managedDirectTurnOptions,_ as normalizeQueuedModelId,v as resolveManagedRoomNativeSessionId,b as stripLocalQueueFields,M as takeCompatibleBatch,D as takeControllableMessage};
@@ -1,5 +1,6 @@
1
1
  import { type ChatEnqueueParams, type QueuedChatMessage } from '@shennian/wire';
2
2
  import type { ManagedRoomTriggerContext, TurnTrigger } from './turn-trigger.js';
3
+ import type { ManagedWorkerRoomOrigin } from '../manager/registry.js';
3
4
  export type LocalQueuedChatMessage = QueuedChatMessage & {
4
5
  origin?: 'app' | 'external' | 'room';
5
6
  trigger?: TurnTrigger;
@@ -15,6 +16,8 @@ export type InternalEnqueueParams = ChatEnqueueParams & {
15
16
  roomId?: string;
16
17
  };
17
18
  managerEventId?: string;
19
+ managerEventRoomOrigin?: ManagedWorkerRoomOrigin;
20
+ managerWorkerRoomOrigin?: ManagedWorkerRoomOrigin;
18
21
  };
19
22
  export declare class TerminalQueuedChatDispatchError extends Error {
20
23
  constructor(message: string);
@@ -24,7 +27,7 @@ export declare function queueMessageFromParams(params: InternalEnqueueParams): L
24
27
  export declare function queueEnvelope(message: LocalQueuedChatMessage): {
25
28
  id: string;
26
29
  sessionId: string;
27
- role: "agent" | "user";
30
+ role: "user" | "agent";
28
31
  ts: number;
29
32
  payload: string;
30
33
  };
@@ -1 +1 @@
1
- import{randomUUID as o}from"node:crypto";import{buildUserMessagePayload as r}from"@shennian/wire";import{parsePersonalAttachmentReferences as d}from"./attachment-reference.js";import{normalizeQueuedModelId as i}from"./queue-helpers.js";import{getPersonalSyncIdentity as l}from"../personal-sync/epoch.js";import{getDaemonInstallationId as s}from"../personal-sync/identity.js";class h extends Error{constructor(n){super(n),this.name="TerminalQueuedChatDispatchError"}}function u(){return new Date().toISOString()}function m(e){const n=u(),t=e.scheduledTask?{kind:"scheduled",taskId:e.scheduledTask.id,bindingId:e.scheduledTask.bindingId,roomId:e.scheduledTask.roomId}:e.managedWorkerParentSessionId?{kind:"manager_worker",parentSessionId:e.managedWorkerParentSessionId}:e.managerEventId?{kind:"manager_event",eventId:e.managerEventId}:e.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"};return{...l(s()),id:e.queueMessageId||e.clientMessageId||`queue-${o()}`,sessionId:e.sessionId,text:e.text,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:i(e.modelId)??null,systemPrompt:e.systemPrompt??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId??null,reasoningEffort:e.reasoningEffort??null,clientMessageId:e.clientMessageId??null,attachments:d(e.attachments),externalChannel:e.externalChannel??null,replyTarget:e.replyTarget??null,origin:e.origin,createdAt:n,updatedAt:n,trigger:t}}function D(e){return{id:e.clientMessageId??e.id,sessionId:e.sessionId,role:e.trigger?.kind==="manager_event"||e.trigger?.kind==="scheduled"?"agent":"user",ts:Date.parse(e.createdAt),payload:r(e.text,e.attachments)}}export{h as TerminalQueuedChatDispatchError,u as nowIso,D as queueEnvelope,m as queueMessageFromParams};
1
+ import{randomUUID as o}from"node:crypto";import{buildUserMessagePayload as r}from"@shennian/wire";import{parsePersonalAttachmentReferences as d}from"./attachment-reference.js";import{normalizeQueuedModelId as i}from"./queue-helpers.js";import{getPersonalSyncIdentity as l}from"../personal-sync/epoch.js";import{getDaemonInstallationId as g}from"../personal-sync/identity.js";class m extends Error{constructor(n){super(n),this.name="TerminalQueuedChatDispatchError"}}function u(){return new Date().toISOString()}function h(e){const n=u(),t=e.scheduledTask?{kind:"scheduled",taskId:e.scheduledTask.id,bindingId:e.scheduledTask.bindingId,roomId:e.scheduledTask.roomId}:e.managedWorkerParentSessionId?{kind:"manager_worker",parentSessionId:e.managedWorkerParentSessionId,roomOrigin:e.managerWorkerRoomOrigin}:e.managerEventId?{kind:"manager_event",eventId:e.managerEventId,...e.managerEventRoomOrigin?{roomOrigin:e.managerEventRoomOrigin}:{}}:e.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"};return{...l(g()),id:e.queueMessageId||e.clientMessageId||`queue-${o()}`,sessionId:e.sessionId,text:e.text,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:i(e.modelId)??null,systemPrompt:e.systemPrompt??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId??null,reasoningEffort:e.reasoningEffort??null,clientMessageId:e.clientMessageId??null,attachments:d(e.attachments),externalChannel:e.externalChannel??null,replyTarget:e.replyTarget??null,origin:e.origin,createdAt:n,updatedAt:n,trigger:t}}function D(e){return{id:e.clientMessageId??e.id,sessionId:e.sessionId,role:e.trigger?.kind==="manager_event"||e.trigger?.kind==="scheduled"?"agent":"user",ts:Date.parse(e.createdAt),payload:r(e.text,e.attachments)}}export{m as TerminalQueuedChatDispatchError,u as nowIso,D as queueEnvelope,h as queueMessageFromParams};
@@ -5,3 +5,4 @@ export type QueueFile = {
5
5
  export declare function readQueue(): QueueFile;
6
6
  export declare function writeQueue(queue: QueueFile): void;
7
7
  export declare function purgeQueuedSessionData(sessionId: string): void;
8
+ export declare function clearPersistedManagerRoomOrigins(): void;
@@ -1,2 +1,2 @@
1
- import n from"node:fs";import{randomUUID as c}from"node:crypto";import{resolvePersonalSyncV1Path as t}from"../personal-sync/paths.js";function u(){try{const e=JSON.parse(n.readFileSync(t("outbound-queue.json"),"utf-8"));return{sessions:e.sessions&&typeof e.sessions=="object"?e.sessions:{}}}catch(e){if(e.code==="ENOENT"||e instanceof Error&&e.message.startsWith("ENOENT:"))return{sessions:{}};throw e}}function f(e){const o=t();n.mkdirSync(o,{recursive:!0,mode:448});const i=t("outbound-queue.json"),s=`${i}.tmp-${process.pid}-${c()}`;try{n.writeFileSync(s,`${JSON.stringify(e,null,2)}
2
- `,{encoding:"utf8",mode:384,flag:"wx"});const r=n.openSync(s,"r");if(typeof r=="number")try{n.fsyncSync(r)}finally{n.closeSync(r)}n.renameSync(s,i)}finally{try{n.unlinkSync(s)}catch{}}}function d(e){const o=u();o.sessions[e]&&(delete o.sessions[e],f(o))}export{d as purgeQueuedSessionData,u as readQueue,f as writeQueue};
1
+ import r from"node:fs";import{randomUUID as a}from"node:crypto";import{resolvePersonalSyncV1Path as i}from"../personal-sync/paths.js";function c(){try{const e=JSON.parse(r.readFileSync(i("outbound-queue.json"),"utf-8"));return{sessions:e.sessions&&typeof e.sessions=="object"?e.sessions:{}}}catch(e){if(e.code==="ENOENT"||e instanceof Error&&e.message.startsWith("ENOENT:"))return{sessions:{}};throw e}}function u(e){const o=i();r.mkdirSync(o,{recursive:!0,mode:448});const t=i("outbound-queue.json"),s=`${t}.tmp-${process.pid}-${a()}`;try{r.writeFileSync(s,`${JSON.stringify(e,null,2)}
2
+ `,{encoding:"utf8",mode:384,flag:"wx"});const n=r.openSync(s,"r");if(typeof n=="number")try{r.fsyncSync(n)}finally{r.closeSync(n)}r.renameSync(s,t)}finally{try{r.unlinkSync(s)}catch{}}}function y(e){const o=c();o.sessions[e]&&(delete o.sessions[e],u(o))}function g(){const e=c();let o=!1;for(const t of Object.values(e.sessions))for(const s of t){const n=s.trigger;!n||n.kind!=="manager_event"&&n.kind!=="manager_worker"||!n.roomOrigin||(delete n.roomOrigin,o=!0)}o&&u(e)}export{g as clearPersistedManagerRoomOrigins,y as purgeQueuedSessionData,c as readQueue,u as writeQueue};
@@ -1,6 +1,8 @@
1
1
  import type { AgentType, ChatEnqueueParams, SessionMode, ManagerConfig } from '@shennian/wire';
2
2
  import type { CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
3
3
  import type { ManagedRoomPromptSnapshot } from '../room/managed-prompt-composer.js';
4
+ import type { ManagedRoomAction } from '../room/managed-context.js';
5
+ import type { ManagedWorkerRoomOrigin } from '../manager/registry.js';
4
6
  export type PreparedManagedTurnContext = {
5
7
  agentType: AgentType;
6
8
  workDir: string;
@@ -17,4 +19,10 @@ export type PreparedManagedTurnContext = {
17
19
  };
18
20
  /** @deprecated Compatibility name for callers migrated incrementally. */
19
21
  export type PreparedManagedRoomTurn = PreparedManagedTurnContext;
22
+ export type ManagedAgentDirectTurnOptions = {
23
+ roomOrigin?: ManagedWorkerRoomOrigin;
24
+ allowedRoomActions?: ManagedRoomAction[];
25
+ managerEvent?: boolean;
26
+ };
27
+ export type ManagedAgentDirectTurnPreparer = (sessionId: string, options?: ManagedAgentDirectTurnOptions) => Promise<PreparedManagedRoomTurn | null>;
20
28
  export type ManagedRoomEnqueueParams = Omit<ChatEnqueueParams, 'protocolVersion' | 'dataEpoch' | 'daemonInstallationId'>;
@@ -4,8 +4,8 @@ import type { SessionManagerRuntime } from './types.js';
4
4
  import type { ManagedRoomTriggerContext } from './turn-trigger.js';
5
5
  export { purgeQueuedSessionData } from './queue-storage.js';
6
6
  export type ManagedRoomQueueContext = ManagedRoomTriggerContext;
7
- export type { PreparedManagedTurnContext, PreparedManagedRoomTurn, ManagedRoomEnqueueParams } from './queue-types.js';
8
- import type { PreparedManagedRoomTurn, ManagedRoomEnqueueParams } from './queue-types.js';
7
+ export type { PreparedManagedTurnContext, PreparedManagedRoomTurn, ManagedRoomEnqueueParams, ManagedAgentDirectTurnPreparer } from './queue-types.js';
8
+ import type { PreparedManagedRoomTurn, ManagedRoomEnqueueParams, ManagedAgentDirectTurnPreparer } from './queue-types.js';
9
9
  export { TerminalQueuedChatDispatchError } from './queue-message.js';
10
10
  export type { LocalQueuedChatMessage } from './queue-message.js';
11
11
  export declare class ChatQueueManager {
@@ -35,7 +35,7 @@ export declare class ChatQueueManager {
35
35
  stop(): void;
36
36
  getSnapshot(sessionId: string): ChatQueueSnapshot;
37
37
  setManagedRoomTurnPreparer(prepare: (contexts: ManagedRoomQueueContext[]) => Promise<PreparedManagedRoomTurn>): void;
38
- setManagedAgentDirectTurnPreparer(prepare: (sessionId: string) => Promise<PreparedManagedRoomTurn | null>): void;
38
+ setManagedAgentDirectTurnPreparer(prepare: ManagedAgentDirectTurnPreparer): void;
39
39
  enqueueManagedRoomBatch(inputs: Array<{
40
40
  params: ManagedRoomEnqueueParams;
41
41
  context: ManagedRoomQueueContext;
@@ -1 +1 @@
1
- import{NativeSourceDeletionStore as G}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as H}from"./queue-retry.js";import{findDuplicateQueuedMessage as E,stripLocalQueueFields as D,takeCompatibleBatch as U,formatQueuedBatch as P,dedupeQueuedAttachments as B,classifyQueueError as Q,isControllableQueueMessage as T,takeControllableMessage as V,normalizeQueuedModelId as F,resolveManagedRoomNativeSessionId as q}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as X}from"@shennian/wire";import{isCodexThreadTailInterrupted as Y}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as Z}from"./projection.js";import{assertFinishedAttachmentReferences as b,markAttachmentReferences as L}from"./attachment-transfer-store.js";import{appendMessage as W,getMessageDeliveryStatus as _,listSessionRecords as j,recordSession as N,tombstoneMessage as z,upsertMessage as C}from"./store.js";import{requestSessionIndexPublish as w}from"./index-publisher.js";import{purgeQueuedSessionData as ee,readQueue as c,writeQueue as S}from"./queue-storage.js";import{getNativeSourceAgentType as te}from"./handlers/chat-events.js";import{parsePersonalAttachmentReferences as $}from"./attachment-reference.js";import{getPersonalSyncIdentity as x}from"../personal-sync/epoch.js";import{getDaemonInstallationId as A}from"../personal-sync/identity.js";import{TerminalQueuedChatDispatchError as v,nowIso as O,queueEnvelope as R,queueMessageFromParams as K}from"./queue-message.js";import{purgeQueuedSessionData as Se}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as Re}from"./queue-message.js";class ye{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new H(e=>{this.wakeSession(e)});deletions=new G;inFlightMessageIds=new Map;deferredLogState=new Map;prepareManagedRoomTurn=null;prepareManagedAgentDirectTurn=null;constructor(e){this.opts=e,setTimeout(()=>this.drainIdleQueues(),0).unref?.()}stop(){this.disposed=!0,this.retries.stop()}getSnapshot(e){const s=c().sessions[e]??[],t=this.inFlightMessageIds.get(e);return{...x(A()),sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:s.map(D),controllablePending:s.filter(r=>T(r)&&!t?.has(r.id)).map(D)}}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const s=this.opts.getRuntime(),t=c(),r=new Set,i=new Map;let a=!1;for(const n of e){const d=n.params;if(this.deletions.hasSession(d.sessionId)){delete t.sessions[d.sessionId],a=!0;continue}if(!d.sessionId||!d.text||!d.agentType||!d.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=K({...x(A()),...d});u.origin="room",u.managedRoom=n.context,u.trigger={kind:"room_activation",...n.context};const l=t.sessions[d.sessionId]??[],m=E(l,u),I=u.clientMessageId??u.id,f=_(d.sessionId,I);if(!m&&f.state==="not_found")l.push(u),t.sessions[d.sessionId]=l,i.set(`${u.sessionId}\0${I}`,u),r.add(d.sessionId),a=!0;else if(m&&f.state==="not_found")i.set(`${m.sessionId}\0${I}`,m),r.add(d.sessionId);else if(m&&f.state==="queued")r.add(d.sessionId);else if(m){const y=l.filter(h=>h.id!==m.id);y.length?t.sessions[d.sessionId]=y:delete t.sessions[d.sessionId],a=!0}}a&&S(t);let o;for(const n of r)try{for(const d of i.values())d.sessionId===n&&(W(n,R(d),"queued"),N({sessionId:n,agentType:d.agentType,sessionMode:d.sessionMode,managerConfig:d.managerConfig,workDir:d.workDir,agentSessionId:q(s,d),modelId:d.modelId}));this.logLifecycle("enqueue.persisted",n,{origin:"room",pendingCount:c().sessions[n]?.length??0}),this.broadcast(n),this.wakeSession(n)}catch(d){o=d,this.logLifecycle("enqueue.commit-failed",n,{failureClass:Q(d instanceof Error?d.message:"","canonical_commit_failed")},"error"),this.retries.schedule(n,!0)}if(r.size&&w(s.client),o)throw o}async handleEnqueue(e,s=!1){const t=this.opts.getRuntime(),r=e.params;if(r.scheduledTask&&!s)throw new Error("schedule_source_untrusted");const i=!!(s&&r.scheduledTask?.bindingId);if(Z(r.sessionListProjection),!r.sessionId||!r.text||!r.agentType||!r.workDir)return t.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const a=r.managedAgentDirect||i?await this.prepareManagedAgentDirectTurn?.(r.sessionId):null;if((r.managedAgentDirect||i)&&!a)throw new Error("managed_agent_context_unavailable");const o=a?j().find(J=>J.sessionId===r.sessionId):null,n=a?{...r,...a,agentType:a.agentType,sessionMode:a.sessionMode,managerConfig:a.managerConfig,workDir:a.workDir,agentSessionId:a.agentSessionId?.startsWith("managed:")?o?.agentSessionId&&!o.agentSessionId.startsWith("managed:")?o.agentSessionId:null:a.agentSessionId,modelId:o?.modelId??void 0,systemPrompt:a.systemPrompt,managerDefaultWorkerAgentType:a.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:a.managerDefaultWorkerModelId}:r,d=t.resolvePath(n.workDir),u=$(n.attachments);u?.length&&b(d,u);const l={text:n.text,attachments:u,localized:!1},m=t.sessions.get(n.sessionId);if(n.agentType==="codex"&&n.agentSessionId&&m?.currentRunId?.startsWith("dispatch:")&&Y(n.agentSessionId))return t.client.sendRes({type:"res",id:e.id,ok:!1,error:X}),!1;a?.managedRoomContextToken&&t.revokeManagedRoomContextToken?.(a.managedRoomContextToken);const I=await this.isSessionBusy(n.sessionId),f=c(),y=f.sessions[n.sessionId]??[],h=K({...n,text:l.text,attachments:l.attachments,systemPrompt:a?null:n.systemPrompt});a&&(h.managedAgentDirect=!0,h.trigger?.kind!=="manager_event"&&h.trigger?.kind!=="scheduled"&&(h.trigger={kind:"managed_direct"}));const g=h.clientMessageId??h.id,k=_(n.sessionId,g);if(k.state!=="not_found")return t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:k.state==="queued",queueMessageId:h.id,...k,queue:this.getSnapshot(n.sessionId)}}),!0;const M=E(y,h);M||(f.sessions[n.sessionId]=[...y,h],S(f));const p=M??h;return N({sessionId:p.sessionId,agentType:p.agentType,sessionMode:p.sessionMode,managerConfig:p.managerConfig,workDir:p.workDir,agentSessionId:p.agentSessionId,modelId:p.modelId}),W(p.sessionId,R(p),"queued"),L(t.resolvePath(p.workDir),p.attachments??[]),w(t.client),this.logLifecycle("enqueue.persisted",n.sessionId,{origin:n.origin??"app",queueMessageId:p.id,pendingCount:(c().sessions[n.sessionId]??[]).length}),this.broadcast(n.sessionId),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:M?.id??h.id,..._(n.sessionId,M?.clientMessageId??M?.id??h.clientMessageId??h.id),queue:this.getSnapshot(n.sessionId),...l.localized?{localizedAttachments:!0}:{}}}),I?this.retries.schedule(n.sessionId):this.wakeSession(n.sessionId),!0}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const r=c(),i=r.sessions[t.sessionId]??[],a=i.findIndex(d=>d.id===t.queueMessageId);if(a<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}if(!T(i[a])||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId)){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const o=$(t.attachments),n=s.resolvePath(i[a].workDir);o?.length&&b(n,o),i[a]={...i[a],text:t.text,attachments:o,updatedAt:O()},r.sessions[t.sessionId]=i,S(r),C(t.sessionId,R(i[a]),"queued"),i[a].attachments?.length&&L(n,i[a].attachments??[]),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const r=c(),i=r.sessions[t.sessionId]??[],a=i.find(n=>n.id===t.queueMessageId);if(a&&(!T(a)||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId))){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const o=i.filter(n=>n.id!==t.queueMessageId);if(o.length===i.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}o.length?r.sessions[t.sessionId]=o:delete r.sessions[t.sessionId],S(r),z(t.sessionId,a?.clientMessageId??a?.id??t.queueMessageId),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handlePromote(e){const s=this.opts.getRuntime(),t=e.params,r=a=>s.client.sendRes({type:"res",id:e.id,ok:!1,error:a});if(!t.sessionId||!t.queueMessageId){r("sessionId and queueMessageId are required");return}if(this.promoting.has(t.sessionId)){r("queue_promotion_in_progress");return}this.promoting.add(t.sessionId);let i=[];try{for(;this.draining.has(t.sessionId);)await new Promise(n=>setTimeout(n,5));if(i=V(c().sessions[t.sessionId]??[],t.queueMessageId),!i.length){r("Queued message not found");return}this.inFlightMessageIds.set(t.sessionId,new Set(i.map(n=>n.id)));const a=s.sessions.get(t.sessionId);let o="idle";if(a?.currentRunId)if(this.canInjectActiveBatch(a,i)){const n=i.length===1?i[0].text:P(i),d=i[0].clientMessageId??i[0].id;s.nativeFusion?.registerManagedSend({sessionId:t.sessionId,agentType:i[0].agentType,sourceAgentType:te(i[0].agentType,i[0].modelId),canonicalMessageId:d,sourceSessionKey:a.agentSessionId,text:n,managedEchoPolicy:"suppress_following"});const u=Date.now();try{await a.adapter.injectActiveInput({text:n,attachments:B(i.flatMap(l=>l.attachments??[])),clientMessageId:d})}catch(l){throw s.nativeFusion?.cancelManagedSend(d),l}for(const l of i)C(t.sessionId,{...R(l),ts:u},"executing");this.removeBatch(t.sessionId,i),o="injected"}else{if(!this.opts.interruptQueuedSession)throw new Error("queue_interrupt_unavailable");await this.opts.interruptQueuedSession(t.sessionId),await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i),o="restarted"}else await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i);w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId),promotedMessageIds:i.map(n=>n.id),mode:o}})}catch(a){r(a instanceof Error?a.message:"queue_promotion_failed"),this.broadcast(t.sessionId)}finally{this.inFlightMessageIds.delete(t.sessionId),this.promoting.delete(t.sessionId),c().sessions[t.sessionId]?.length&&this.wakeSession(t.sessionId)}}noteTerminal(e){this.wakeSession(e)}purgeSession(e){ee(e),this.retries.cancel(e)}discardPendingManagedRoomMessages(e){if(this.deletions.hasSession(e)){const o=c().sessions[e]?.length??0;return this.purgeSession(e),o}const s=c(),t=s.sessions[e]??[],r=this.inFlightMessageIds.get(e)??new Set,i=t.filter(o=>o.managedRoom&&!r.has(o.id));if(i.length===0)return 0;const a=t.filter(o=>!i.includes(o));a.length?s.sessions[e]=a:delete s.sessions[e],S(s);for(const o of i)z(e,o.clientMessageId??o.id);return w(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:i.length,pendingCount:a.length}),this.broadcast(e),i.length}wakeSession(e){this.drainNext(e).catch(()=>{this.logLifecycle("drain.retry-required",e,{},"error"),this.retries.schedule(e,!0)})}drainIdleQueues(){if(this.disposed)return;const e=c();for(const s of Object.keys(e.sessions))this.wakeSession(s)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let s=!1,t=!1,r=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const u=c().sessions[e]?.length??0,l=this.deferredLogState.get(e),m=Date.now();(!l||l.pendingCount!==u||m-l.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:u}),this.deferredLogState.set(e,{at:m,pendingCount:u}));return}this.deferredLogState.delete(e);const i=c(),a=i.sessions[e]??[],o=a.filter(u=>{const l=u.clientMessageId??u.id,m=_(e,l).state;return m==="queued"||m==="not_found"});o.length!==a.length&&(o.length?i.sessions[e]=o:delete i.sessions[e],S(i),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:a.length-o.length,pendingCount:o.length}));const n=U(o);if(n.length===0){this.broadcast(e);return}r=n,this.inFlightMessageIds.set(e,new Set(n.map(u=>u.id))),this.logLifecycle("dispatch.start",e,{batchCount:n.length,queueMessageId:n[0].id,origin:n[0].origin??"app"});for(const u of n)C(e,R(u),"queued");await this.dispatchQueuedMessages(n);const d=this.removeBatch(e,n);this.logLifecycle("dispatch.accepted",e,{batchCount:n.length,queueMessageId:n[0].id,pendingCount:d}),this.deferredLogState.delete(e),s=d>0,this.broadcast(e)}catch(i){const a=Q(i instanceof Error?i.message:String(i),i instanceof v?"terminal_dispatch_failed":"transient_dispatch_failed"),o=r[0],n=!!(o&&!o.trigger&&!o.clientMessageId&&Date.now()-Date.parse(o.createdAt)>=10*6e4&&this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e));if(i instanceof v||a==="managed_claim_source_binding_conflict"||n){const u=this.removeBatch(e,r);this.logLifecycle("dispatch.terminal-failure",e,{batchCount:r.length,queueMessageId:r[0]?.id,pendingCount:u,failureClass:n?"stale_legacy_managed_worker_dispatch_failure":a},"error"),s=u>0}else t=!0,this.logLifecycle("dispatch.transient-failure",e,{failureClass:a},"error");this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e),c().sessions[e]?.length?s?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,t):this.retries.cancel(e)}}canInjectActiveBatch(e,s){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const t=this.opts.getRuntime().runJournal?.get(s[0].sessionId,e.journalRunId),r=s[0].trigger?.kind==="managed_direct"||s[0].managedAgentDirect?null:"personal";return!!(r&&s[0].systemPrompt==null&&t&&t.source===r&&t.deliveryMode==="direct"&&t.agentType===s[0].agentType&&t.workDir===e.workDir&&t.agentSessionId===e.agentSessionId&&t.modelId===(s[0].modelId??null)&&t.reasoningEffort===(s[0].reasoningEffort??null))}removeBatch(e,s){if(s.length===0)return c().sessions[e]?.length??0;const t=c(),r=new Set(s.map(a=>a.id)),i=(t.sessions[e]??[]).filter(a=>!r.has(a.id));return i.length?t.sessions[e]=i:delete t.sessions[e],S(t),i.length}logLifecycle(e,s,t,r="info"){const i=`[chat.queue] ${JSON.stringify({at:O(),event:e,sessionId:s,...t})}`;r==="error"?console.error(i):console.info(i)}async dispatchQueuedMessages(e){const s=e[0],t=s.trigger?.kind==="scheduled"?s.trigger:null;if(t&&await this.validateScheduledTarget?.({sessionId:s.sessionId,...t})!=="ready")throw new v("schedule_target_unavailable");const r=e.flatMap(g=>{if(g.trigger?.kind==="room_activation"){const{kind:k,...M}=g.trigger;return[M]}return!g.trigger&&g.managedRoom?[g.managedRoom]:[]}),i=e.find(g=>g.trigger?.kind==="manager_event")?.trigger,a=e.some(g=>g.trigger?.kind==="managed_direct"||!!g.managedAgentDirect||g.trigger?.kind==="scheduled"&&!!g.trigger.bindingId),o=e.find(g=>g.trigger?.kind==="manager_worker")?.trigger,n=r.length>0?await this.prepareManagedRoomTurn?.(r):a||i?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(s.sessionId):void 0;if(r.length>0&&!n)throw new Error("managed_room_turn_preparer_unavailable");if(a&&!n)throw new Error("managed_agent_context_unavailable");if(i?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(s.sessionId)&&!n)throw new Error("managed_agent_context_unavailable");const d=new Set((c().sessions[s.sessionId]??[]).map(g=>g.id));if(this.disposed||this.deletions.hasSession(s.sessionId)||e.some(g=>!d.has(g.id)))throw n?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(n.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new v("queued_dispatch_cancelled");i?.kind==="manager_event"&&n?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(n.managedRoomContextToken);const u=n??null,l=u?.sessionMode==="manager"?u.managerConfig:null,m=e.length===1?s.text:P(e),I=B(e.flatMap(g=>g.attachments??[])),f=a||i?.kind==="manager_event"&&!!n,y=f?n.agentSessionId?.startsWith("managed:")?q(this.opts.getRuntime(),s):n.agentSessionId:r.length>0?q(this.opts.getRuntime(),s):s.agentSessionId??null,h=n?j().find(g=>g.sessionId===s.sessionId):null;await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${s.id}-${Date.now()}`,method:"chat.send",params:{...x(A()),sessionId:s.sessionId,text:m,agentType:f?n.agentType:s.agentType,sessionMode:u?.sessionMode??s.sessionMode,managerConfig:u?l:s.managerConfig,workDir:f?n.workDir:s.workDir,agentSessionId:y,modelId:F(h?.modelId)??F(s.modelId),systemPrompt:i?.kind==="manager_event"?null:n?.systemPrompt??s.systemPrompt??null,managerDefaultWorkerAgentType:u?u.managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:u?u.managerDefaultWorkerModelId:s.managerDefaultWorkerModelId,reasoningEffort:s.reasoningEffort??void 0,clientMessageId:s.clientMessageId??s.id,attachments:I,externalChannel:i?.kind==="manager_event"?void 0:s.externalChannel,replyTarget:i?.kind==="manager_event"?void 0:s.replyTarget,roomContextRegistryKey:i?.kind==="manager_event"?void 0:n?.roomContextRegistryKey,activationCauseMessageId:i?.kind==="manager_event"?void 0:r.at(-1)?.causeMessageId,rootCauseMessageId:i?.kind==="manager_event"?void 0:r.at(-1)?.rootCauseMessageId,activationSequence:i?.kind==="manager_event"?void 0:r.at(-1)?.sequence,activationHopCount:i?.kind==="manager_event"?void 0:r.at(-1)?.hopCount,managedRecoverySource:i?.kind==="manager_event"?"manager_event":a?"managed_direct":r.length>0?"managed_room":void 0,managerEventId:i?.kind==="manager_event"?i.eventId:void 0,managedWorkerParentSessionId:o?.kind==="manager_worker"?o.parentSessionId:void 0,managerWorkerNativeFull:o?.kind==="manager_worker"&&this.opts.getRuntime().managerRuntime?.isNativeSkillManager(o.parentSessionId,s.workDir)||void 0,managedRoomContextToken:i?.kind==="manager_event"?void 0:n?.managedRoomContextToken,scheduledDelivery:!!t,suppressExternalOwnerEcho:r.length>0||!!t||void 0,queuedBatchItems:e.map(g=>{const k=D(g);return i?.kind==="manager_event"?{...k,systemPrompt:null,externalChannel:null,replyTarget:null}:k}),waitForDispatch:!0}},n??void 0)}async isSessionBusy(e){const s=this.opts.getRuntime().recoveryBarrier;if(s?.isDispatchFrozen()||s?.isRecovering(e))return!0;const t=this.opts.getRuntime().sessions.get(e);if(!t)return!1;if(t.currentRunId){if(!(t.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!t.journalRunId)||(t.adapter.getStatus?await t.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:t.currentRunId}),t.currentRunId=null,t.currentRunPhase=null}if(!t.adapter.getStatus)return!1;const r=await t.adapter.getStatus().catch(()=>null);return r?.active?(r.runId&&(t.currentRunId=r.runId,t.currentRunPhase=r.runPhase??t.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{ye as ChatQueueManager,Re as TerminalQueuedChatDispatchError,Se as purgeQueuedSessionData};
1
+ import{NativeSourceDeletionStore as U}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as V}from"./queue-retry.js";import{findDuplicateQueuedMessage as P,stripLocalQueueFields as T,takeCompatibleBatch as X,formatQueuedBatch as B,dedupeQueuedAttachments as Q,classifyQueueError as F,isControllableQueueMessage as C,takeControllableMessage as Y,normalizeQueuedModelId as W,resolveManagedRoomNativeSessionId as q,managedDirectTurnOptions as b}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as Z}from"@shennian/wire";import{isCodexThreadTailInterrupted as ee}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as te}from"./projection.js";import{assertFinishedAttachmentReferences as L,markAttachmentReferences as O}from"./attachment-transfer-store.js";import{appendMessage as j,getMessageDeliveryStatus as _,listSessionRecords as N,recordSession as z,tombstoneMessage as $,upsertMessage as x}from"./store.js";import{requestSessionIndexPublish as w}from"./index-publisher.js";import{clearPersistedManagerRoomOrigins as se,purgeQueuedSessionData as ne,readQueue as m,writeQueue as S}from"./queue-storage.js";import{getNativeSourceAgentType as ie}from"./handlers/chat-events.js";import{parsePersonalAttachmentReferences as K}from"./attachment-reference.js";import{getPersonalSyncIdentity as A}from"../personal-sync/epoch.js";import{getDaemonInstallationId as E}from"../personal-sync/identity.js";import{isTrustedManagerEvent as ae}from"./manager-event-authority.js";import{TerminalQueuedChatDispatchError as v,nowIso as J,queueEnvelope as R,queueMessageFromParams as G}from"./queue-message.js";import{purgeQueuedSessionData as De}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as Ce}from"./queue-message.js";class Re{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new V(e=>{this.wakeSession(e)});deletions=new U;inFlightMessageIds=new Map;deferredLogState=new Map;prepareManagedRoomTurn=null;prepareManagedAgentDirectTurn=null;constructor(e){this.opts=e,se(),setTimeout(()=>this.drainIdleQueues(),0).unref?.()}stop(){this.disposed=!0,this.retries.stop()}getSnapshot(e){const s=m().sessions[e]??[],t=this.inFlightMessageIds.get(e);return{...A(E()),sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:s.map(T),controllablePending:s.filter(n=>C(n)&&!t?.has(n.id)).map(T)}}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const s=this.opts.getRuntime(),t=m(),n=new Set,i=new Map;let d=!1;for(const o of e){const a=o.params;if(this.deletions.hasSession(a.sessionId)){delete t.sessions[a.sessionId],d=!0;continue}if(!a.sessionId||!a.text||!a.agentType||!a.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=G({...A(E()),...a});u.origin="room",u.managedRoom=o.context,u.trigger={kind:"room_activation",...o.context};const c=t.sessions[a.sessionId]??[],g=P(c,u),M=u.clientMessageId??u.id,k=_(a.sessionId,M);if(!g&&k.state==="not_found")c.push(u),t.sessions[a.sessionId]=c,i.set(`${u.sessionId}\0${M}`,u),n.add(a.sessionId),d=!0;else if(g&&k.state==="not_found")i.set(`${g.sessionId}\0${M}`,g),n.add(a.sessionId);else if(g&&k.state==="queued")n.add(a.sessionId);else if(g){const I=c.filter(y=>y.id!==g.id);I.length?t.sessions[a.sessionId]=I:delete t.sessions[a.sessionId],d=!0}}d&&S(t);let r;for(const o of n)try{for(const a of i.values())a.sessionId===o&&(j(o,R(a),"queued"),z({sessionId:o,agentType:a.agentType,sessionMode:a.sessionMode,managerConfig:a.managerConfig,workDir:a.workDir,agentSessionId:q(s,a),modelId:a.modelId}));this.logLifecycle("enqueue.persisted",o,{origin:"room",pendingCount:m().sessions[o]?.length??0}),this.broadcast(o),this.wakeSession(o)}catch(a){r=a,this.logLifecycle("enqueue.commit-failed",o,{failureClass:F(a instanceof Error?a.message:"","canonical_commit_failed")},"error"),this.retries.schedule(o,!0)}if(n.size&&w(s.client),r)throw r}async handleEnqueue(e,s=!1){const t=this.opts.getRuntime(),n=e.params;if(n.scheduledTask&&!s)throw new Error("schedule_source_untrusted");if((n.managerEventId||n.managerEventRoomOrigin||n.managedWorkerParentSessionId||n.managerWorkerRoomOrigin||e.params.managerWorkerNativeFull||e.params.managedRecoverySource)&&!ae(e))throw new Error("manager_event_source_untrusted");const i=!!(s&&n.scheduledTask?.bindingId);if(te(n.sessionListProjection),!n.sessionId||!n.text||!n.agentType||!n.workDir)return t.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const d=b(n.managerEventId?{roomOrigin:n.managerEventRoomOrigin}:null,!!n.managedAgentDirect),r=n.managedAgentDirect||i?await this.prepareManagedAgentDirectTurn?.(n.sessionId,d):null;if((n.managedAgentDirect||i)&&!r)throw new Error("managed_agent_context_unavailable");const o=r?N().find(H=>H.sessionId===n.sessionId):null,a=r?{...n,...r,agentType:r.agentType,sessionMode:r.sessionMode,managerConfig:r.managerConfig,workDir:r.workDir,agentSessionId:r.agentSessionId?.startsWith("managed:")?o?.agentSessionId&&!o.agentSessionId.startsWith("managed:")?o.agentSessionId:null:r.agentSessionId,modelId:o?.modelId??void 0,systemPrompt:r.systemPrompt,externalChannel:n.managedAgentDirect?null:n.externalChannel,replyTarget:n.managedAgentDirect?null:n.replyTarget,managerDefaultWorkerAgentType:r.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r.managerDefaultWorkerModelId}:n,u=t.resolvePath(a.workDir),c=K(a.attachments);c?.length&&L(u,c);const g={text:a.text,attachments:c,localized:!1},M=t.sessions.get(a.sessionId);if(a.agentType==="codex"&&a.agentSessionId&&M?.currentRunId?.startsWith("dispatch:")&&ee(a.agentSessionId))return t.client.sendRes({type:"res",id:e.id,ok:!1,error:Z}),!1;r?.managedRoomContextToken&&t.revokeManagedRoomContextToken?.(r.managedRoomContextToken);const k=await this.isSessionBusy(a.sessionId),I=m(),y=I.sessions[a.sessionId]??[],h=G({...a,text:g.text,attachments:g.attachments,systemPrompt:r?null:a.systemPrompt});r&&(n.managedAgentDirect&&(h.managedAgentDirect=!0),h.trigger?.kind!=="manager_event"&&h.trigger?.kind!=="scheduled"&&(h.trigger={kind:"managed_direct"}));const D=h.clientMessageId??h.id,l=_(a.sessionId,D);if(l.state!=="not_found")return t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:l.state==="queued",queueMessageId:h.id,...l,queue:this.getSnapshot(a.sessionId)}}),!0;const f=P(y,h);f||(I.sessions[a.sessionId]=[...y,h],S(I));const p=f??h;return z({sessionId:p.sessionId,agentType:p.agentType,sessionMode:p.sessionMode,managerConfig:p.managerConfig,workDir:p.workDir,agentSessionId:p.agentSessionId,modelId:p.modelId}),j(p.sessionId,R(p),"queued"),O(t.resolvePath(p.workDir),p.attachments??[]),w(t.client),this.logLifecycle("enqueue.persisted",a.sessionId,{origin:a.origin??"app",queueMessageId:p.id,pendingCount:(m().sessions[a.sessionId]??[]).length}),this.broadcast(a.sessionId),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:f?.id??h.id,..._(a.sessionId,f?.clientMessageId??f?.id??h.clientMessageId??h.id),queue:this.getSnapshot(a.sessionId),...g.localized?{localizedAttachments:!0}:{}}}),k?this.retries.schedule(a.sessionId):this.wakeSession(a.sessionId),!0}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const n=m(),i=n.sessions[t.sessionId]??[],d=i.findIndex(a=>a.id===t.queueMessageId);if(d<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}if(!C(i[d])||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId)){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const r=K(t.attachments),o=s.resolvePath(i[d].workDir);r?.length&&L(o,r),i[d]={...i[d],text:t.text,attachments:r,updatedAt:J()},n.sessions[t.sessionId]=i,S(n),x(t.sessionId,R(i[d]),"queued"),i[d].attachments?.length&&O(o,i[d].attachments??[]),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const n=m(),i=n.sessions[t.sessionId]??[],d=i.find(o=>o.id===t.queueMessageId);if(d&&(!C(d)||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId))){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const r=i.filter(o=>o.id!==t.queueMessageId);if(r.length===i.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}r.length?n.sessions[t.sessionId]=r:delete n.sessions[t.sessionId],S(n),$(t.sessionId,d?.clientMessageId??d?.id??t.queueMessageId),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handlePromote(e){const s=this.opts.getRuntime(),t=e.params,n=d=>s.client.sendRes({type:"res",id:e.id,ok:!1,error:d});if(!t.sessionId||!t.queueMessageId){n("sessionId and queueMessageId are required");return}if(this.promoting.has(t.sessionId)){n("queue_promotion_in_progress");return}this.promoting.add(t.sessionId);let i=[];try{for(;this.draining.has(t.sessionId);)await new Promise(o=>setTimeout(o,5));if(i=Y(m().sessions[t.sessionId]??[],t.queueMessageId),!i.length){n("Queued message not found");return}this.inFlightMessageIds.set(t.sessionId,new Set(i.map(o=>o.id)));const d=s.sessions.get(t.sessionId);let r="idle";if(d?.currentRunId)if(this.canInjectActiveBatch(d,i)){const o=i.length===1?i[0].text:B(i),a=i[0].clientMessageId??i[0].id;s.nativeFusion?.registerManagedSend({sessionId:t.sessionId,agentType:i[0].agentType,sourceAgentType:ie(i[0].agentType,i[0].modelId),canonicalMessageId:a,sourceSessionKey:d.agentSessionId,text:o,managedEchoPolicy:"suppress_following"});const u=Date.now();try{await d.adapter.injectActiveInput({text:o,attachments:Q(i.flatMap(c=>c.attachments??[])),clientMessageId:a})}catch(c){throw s.nativeFusion?.cancelManagedSend(a),c}for(const c of i)x(t.sessionId,{...R(c),ts:u},"executing");this.removeBatch(t.sessionId,i),r="injected"}else{if(!this.opts.interruptQueuedSession)throw new Error("queue_interrupt_unavailable");await this.opts.interruptQueuedSession(t.sessionId),await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i),r="restarted"}else await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i);w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId),promotedMessageIds:i.map(o=>o.id),mode:r}})}catch(d){n(d instanceof Error?d.message:"queue_promotion_failed"),this.broadcast(t.sessionId)}finally{this.inFlightMessageIds.delete(t.sessionId),this.promoting.delete(t.sessionId),m().sessions[t.sessionId]?.length&&this.wakeSession(t.sessionId)}}noteTerminal(e){this.wakeSession(e)}purgeSession(e){ne(e),this.retries.cancel(e)}discardPendingManagedRoomMessages(e){if(this.deletions.hasSession(e)){const r=m().sessions[e]?.length??0;return this.purgeSession(e),r}const s=m(),t=s.sessions[e]??[],n=this.inFlightMessageIds.get(e)??new Set,i=t.filter(r=>r.managedRoom&&!n.has(r.id));if(i.length===0)return 0;const d=t.filter(r=>!i.includes(r));d.length?s.sessions[e]=d:delete s.sessions[e],S(s);for(const r of i)$(e,r.clientMessageId??r.id);return w(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:i.length,pendingCount:d.length}),this.broadcast(e),i.length}wakeSession(e){this.drainNext(e).catch(()=>{this.logLifecycle("drain.retry-required",e,{},"error"),this.retries.schedule(e,!0)})}drainIdleQueues(){if(this.disposed)return;const e=m();for(const s of Object.keys(e.sessions))this.wakeSession(s)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let s=!1,t=!1,n=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const u=m().sessions[e]?.length??0,c=this.deferredLogState.get(e),g=Date.now();(!c||c.pendingCount!==u||g-c.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:u}),this.deferredLogState.set(e,{at:g,pendingCount:u}));return}this.deferredLogState.delete(e);const i=m(),d=i.sessions[e]??[],r=d.filter(u=>{const c=u.clientMessageId??u.id,g=_(e,c).state;return g==="queued"||g==="not_found"});r.length!==d.length&&(r.length?i.sessions[e]=r:delete i.sessions[e],S(i),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:d.length-r.length,pendingCount:r.length}));const o=X(r);if(o.length===0){this.broadcast(e);return}n=o,this.inFlightMessageIds.set(e,new Set(o.map(u=>u.id))),this.logLifecycle("dispatch.start",e,{batchCount:o.length,queueMessageId:o[0].id,origin:o[0].origin??"app"});for(const u of o)x(e,R(u),"queued");await this.dispatchQueuedMessages(o);const a=this.removeBatch(e,o);this.logLifecycle("dispatch.accepted",e,{batchCount:o.length,queueMessageId:o[0].id,pendingCount:a}),this.deferredLogState.delete(e),s=a>0,this.broadcast(e)}catch(i){const d=F(i instanceof Error?i.message:String(i),i instanceof v?"terminal_dispatch_failed":"transient_dispatch_failed"),r=n[0],o=!!(r&&!r.trigger&&!r.clientMessageId&&Date.now()-Date.parse(r.createdAt)>=10*6e4&&this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e));if(i instanceof v||d==="managed_claim_source_binding_conflict"||o){const u=this.removeBatch(e,n);this.logLifecycle("dispatch.terminal-failure",e,{batchCount:n.length,queueMessageId:n[0]?.id,pendingCount:u,failureClass:o?"stale_legacy_managed_worker_dispatch_failure":d},"error"),s=u>0}else t=!0,this.logLifecycle("dispatch.transient-failure",e,{failureClass:d},"error");this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e),m().sessions[e]?.length?s?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,t):this.retries.cancel(e)}}canInjectActiveBatch(e,s){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const t=this.opts.getRuntime().runJournal?.get(s[0].sessionId,e.journalRunId),n=s[0].trigger?.kind==="managed_direct"||s[0].managedAgentDirect?null:"personal";return!!(n&&s[0].systemPrompt==null&&t&&t.source===n&&t.deliveryMode==="direct"&&t.agentType===s[0].agentType&&t.workDir===e.workDir&&t.agentSessionId===e.agentSessionId&&t.modelId===(s[0].modelId??null)&&t.reasoningEffort===(s[0].reasoningEffort??null))}removeBatch(e,s){if(s.length===0)return m().sessions[e]?.length??0;const t=m(),n=new Set(s.map(d=>d.id)),i=(t.sessions[e]??[]).filter(d=>!n.has(d.id));return i.length?t.sessions[e]=i:delete t.sessions[e],S(t),i.length}logLifecycle(e,s,t,n="info"){const i=`[chat.queue] ${JSON.stringify({at:J(),event:e,sessionId:s,...t})}`;n==="error"?console.error(i):console.info(i)}async dispatchQueuedMessages(e){const s=e[0],t=s.trigger?.kind==="scheduled"?s.trigger:null;if(t&&await this.validateScheduledTarget?.({sessionId:s.sessionId,...t})!=="ready")throw new v("schedule_target_unavailable");const n=e.flatMap(l=>{if(l.trigger?.kind==="room_activation"){const{kind:f,...p}=l.trigger;return[p]}return!l.trigger&&l.managedRoom?[l.managedRoom]:[]}),i=e.find(l=>l.trigger?.kind==="manager_event")?.trigger,d=e.some(l=>l.trigger?.kind==="managed_direct"||!!l.managedAgentDirect),r=d||!!t?.bindingId,o=e.find(l=>l.trigger?.kind==="manager_worker")?.trigger,a=i?.kind==="manager_event"||d,u=n.length>0?await this.prepareManagedRoomTurn?.(n):r||i?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(s.sessionId,b(i?.kind==="manager_event"?i:null,d)):void 0;if(n.length>0&&!u)throw new Error("managed_room_turn_preparer_unavailable");if(r&&!u)throw new Error("managed_agent_context_unavailable");if(i?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(s.sessionId)&&!u)throw new Error("managed_agent_context_unavailable");const c=new Set((m().sessions[s.sessionId]??[]).map(l=>l.id));if(this.disposed||this.deletions.hasSession(s.sessionId)||e.some(l=>!c.has(l.id)))throw u?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(u.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new v("queued_dispatch_cancelled");const g=u??null,M=g?.sessionMode==="manager"?g.managerConfig:null,k=e.length===1?s.text:B(e),I=Q(e.flatMap(l=>l.attachments??[])),y=r||i?.kind==="manager_event"&&!!u,h=y?u.agentSessionId?.startsWith("managed:")?q(this.opts.getRuntime(),s):u.agentSessionId:n.length>0?q(this.opts.getRuntime(),s):s.agentSessionId??null,D=u?N().find(l=>l.sessionId===s.sessionId):null;await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${s.id}-${Date.now()}`,method:"chat.send",params:{...A(E()),sessionId:s.sessionId,text:k,agentType:y?u.agentType:s.agentType,sessionMode:g?.sessionMode??s.sessionMode,managerConfig:g?M:s.managerConfig,workDir:y?u.workDir:s.workDir,agentSessionId:h,modelId:W(D?.modelId)??W(s.modelId),systemPrompt:u?.systemPrompt??s.systemPrompt??null,managerDefaultWorkerAgentType:g?g.managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:g?g.managerDefaultWorkerModelId:s.managerDefaultWorkerModelId,reasoningEffort:s.reasoningEffort??void 0,clientMessageId:s.clientMessageId??s.id,attachments:I,externalChannel:a?void 0:s.externalChannel,replyTarget:a?void 0:s.replyTarget,roomContextRegistryKey:a?void 0:u?.roomContextRegistryKey,activationCauseMessageId:a?void 0:n.at(-1)?.causeMessageId,rootCauseMessageId:a?void 0:n.at(-1)?.rootCauseMessageId,activationSequence:a?void 0:n.at(-1)?.sequence,activationHopCount:a?void 0:n.at(-1)?.hopCount,managedRecoverySource:i?.kind==="manager_event"?"manager_event":r?"managed_direct":n.length>0?"managed_room":void 0,managerEventId:i?.kind==="manager_event"?i.eventId:void 0,managedWorkerParentSessionId:o?.kind==="manager_worker"?o.parentSessionId:void 0,managerWorkerRoomOrigin:o?.kind==="manager_worker"?o.roomOrigin:void 0,managerWorkerNativeFull:o?.kind==="manager_worker"&&this.opts.getRuntime().managerRuntime?.isNativeSkillManager(o.parentSessionId,s.workDir)||void 0,managedRoomContextToken:u?.managedRoomContextToken,scheduledDelivery:!!t,suppressExternalOwnerEcho:n.length>0||!!t||void 0,queuedBatchItems:e.map(l=>{const f=T(l);return a?{...f,systemPrompt:u?.systemPrompt??null,externalChannel:null,replyTarget:null}:f}),waitForDispatch:!0}},u??void 0)}async isSessionBusy(e){const s=this.opts.getRuntime().recoveryBarrier;if(s?.isDispatchFrozen()||s?.isRecovering(e))return!0;const t=this.opts.getRuntime().sessions.get(e);if(!t)return!1;if(t.currentRunId){if(!(t.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!t.journalRunId)||(t.adapter.getStatus?await t.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:t.currentRunId}),t.currentRunId=null,t.currentRunPhase=null}if(!t.adapter.getStatus)return!1;const n=await t.adapter.getStatus().catch(()=>null);return n?.active?(n.runId&&(t.currentRunId=n.runId,t.currentRunPhase=n.runPhase??t.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{Re as ChatQueueManager,Ce as TerminalQueuedChatDispatchError,De as purgeQueuedSessionData};
@@ -1 +1 @@
1
- import{handleChatAbort as m,handleChatSend as u}from"./handlers/chat.js";import{TerminalQueuedChatDispatchError as s}from"./queue.js";function d(e){return{source:"room_activation",managedAgentPolicy:e.managedAgentPolicy,managedRoomPromptSnapshot:e.managedRoomPromptSnapshot}}function h(e){return{source:"manager_event",managedAgentPolicy:e.managedAgentPolicy,managedRoomPolicyVersion:e.managedRoomPromptSnapshot.managedRoomPolicyVersion,managedRuntimePolicyHash:e.managedRoomPromptSnapshot.runtimePermissionPolicyHash}}async function v(e,i,a){await u(e,i,d(a))}async function y(e,i,a){const o={value:null},n=new Proxy(e.client,{get:(t,l)=>{if(l==="sendRes")return r=>{o.value=r};const c=Reflect.get(t,l,t);return typeof c=="function"?c.bind(t):c}});if(await u({...e,client:n},i,a?i.params.managedRecoverySource==="manager_event"?h(a):d(a):void 0),o.value?.payload?.deliveryState==="failed")throw new s(o.value.payload.failureMessage??o.value.error??"queued_chat_dispatch_failed");if(!o.value?.ok)throw new Error(o.value?.error??"queued_chat_dispatch_failed")}async function P(e,i){const a={value:null},o=new Proxy(e.client,{get:(n,t)=>t==="sendRes"?l=>{a.value=l}:typeof Reflect.get(n,t,n)=="function"?Reflect.get(n,t,n).bind(n):Reflect.get(n,t,n)});if(await m({...e,client:o},{type:"req",id:`queue-promote-abort-${Date.now()}`,method:"chat.abort",params:{sessionId:i,discardPending:!1}}),!a.value?.ok)throw new Error(a.value?.error??"agent_stop_failed")}export{v as dispatchManagedChat,y as dispatchQueuedChat,P as interruptQueuedChat,d as managedChatContext,h as managedManagerEventContext};
1
+ import{handleChatAbort as s,handleChatSend as r}from"./handlers/chat.js";import{TerminalQueuedChatDispatchError as h}from"./queue.js";import{markTrustedManagerEvent as u}from"./manager-event-authority.js";function d(e){return{source:"room_activation",managedAgentPolicy:e.managedAgentPolicy,managedRoomPromptSnapshot:e.managedRoomPromptSnapshot}}function f(e){return{source:"manager_event",managedAgentPolicy:e.managedAgentPolicy,managedRoomPolicyVersion:e.managedRoomPromptSnapshot.managedRoomPolicyVersion,managedRuntimePolicyHash:e.managedRoomPromptSnapshot.runtimePermissionPolicyHash}}async function p(e,i,a){await r(e,u(i),d(a))}async function P(e,i,a){const o={value:null},n=new Proxy(e.client,{get:(t,l)=>{if(l==="sendRes")return m=>{o.value=m};const c=Reflect.get(t,l,t);return typeof c=="function"?c.bind(t):c}});if(await r({...e,client:n},u(i),a?i.params.managedRecoverySource==="managed_room"||i.params.scheduledDelivery===!0?d(a):f(a):void 0),o.value?.payload?.deliveryState==="failed")throw new h(o.value.payload.failureMessage??o.value.error??"queued_chat_dispatch_failed");if(!o.value?.ok)throw new Error(o.value?.error??"queued_chat_dispatch_failed")}async function R(e,i){const a={value:null},o=new Proxy(e.client,{get:(n,t)=>t==="sendRes"?l=>{a.value=l}:typeof Reflect.get(n,t,n)=="function"?Reflect.get(n,t,n).bind(n):Reflect.get(n,t,n)});if(await s({...e,client:o},{type:"req",id:`queue-promote-abort-${Date.now()}`,method:"chat.abort",params:{sessionId:i,discardPending:!1}}),!a.value?.ok)throw new Error(a.value?.error??"agent_stop_failed")}export{p as dispatchManagedChat,P as dispatchQueuedChat,R as interruptQueuedChat,d as managedChatContext,f as managedManagerEventContext};
@@ -1,3 +1,4 @@
1
+ import type { ManagedWorkerRoomOrigin } from '../manager/registry.js';
1
2
  export type ManagedRoomTriggerContext = {
2
3
  registryKey: string;
3
4
  causeMessageId: string;
@@ -19,9 +20,11 @@ export type TurnTrigger = {
19
20
  } & ManagedRoomTriggerContext) | {
20
21
  kind: 'manager_event';
21
22
  eventId: string;
23
+ roomOrigin?: ManagedWorkerRoomOrigin;
22
24
  } | {
23
25
  kind: 'manager_worker';
24
26
  parentSessionId: string;
27
+ roomOrigin?: ManagedWorkerRoomOrigin;
25
28
  };
26
29
  export type RecoveryAuthority = {
27
30
  kind: 'personal';
@@ -32,7 +35,9 @@ export type RecoveryAuthority = {
32
35
  } & ManagedRoomTriggerContext) | {
33
36
  kind: 'manager_event';
34
37
  eventId: string;
38
+ roomOrigin?: ManagedWorkerRoomOrigin;
35
39
  } | {
36
40
  kind: 'manager_worker';
37
41
  parentSessionId: string;
42
+ roomOrigin?: ManagedWorkerRoomOrigin;
38
43
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.65",
3
+ "version": "0.4.67",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {