beeos-claw 0.5.65-staging.4 → 0.5.65-staging.6

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.
@@ -1 +1 @@
1
- import{RUNTIME_ERROR_DESCRIPTORS,RUNTIME_HASH_DOMAINS,RUNTIME_INVOCATION_PARITY_ENTRIES,RUNTIME_INVOCATION_RECOVERY_CLASSES,SERVICE_CANONICAL_COMMAND_NAMES,mapCanonicalResultToService}from"@beeos-ai/beeos-types/runtime";import{reduceRuntimeRecoveryPolicy}from"@beeos-ai/beeos-types/runtime/internal";import{verifyAndCreateMessageServiceCoreExecutionAttempt}from"./core-execution-attempt-context.js";import{awaitRuntimeProjection,hasEffectReceiptHandoff,RuntimeCommandError}from"./runtime-command-dispatcher.js";import{RUNTIME_MESSAGE_TYPES,runtimeMessageBase,runtimeMessageHash,semanticEqual,validateRuntimeCancelEnvelope,validateRuntimeRequestEnvelope}from"./runtime-message-channel-contract.js";import{RuntimeResourceResolutionError}from"./runtime-operation-resource-resolver.js";export class MsRuntimeMessageChannelAdapter{dispatcher;channel;verifier;ports;journal;getLease;options;controller;running;workers=new Map;poisonJournal;receiptHistory=this;constructor(e,t,a,o,n,r,i){if(this.dispatcher=e,this.channel=t,this.verifier=a,this.ports=o,this.journal=n,this.getLease=r,this.options=i,!i.poisonJournal)throw new Error("durable poison journal is required");if(this.poisonJournal=i.poisonJournal,!Number.isSafeInteger(i.poisonDeliveryLimit??3)||(i.poisonDeliveryLimit??3)<=0)throw new Error("poison delivery limit must be a positive integer")}start(){if(this.running)return;this.controller=new AbortController;const e=this.loop(this.controller.signal).finally(()=>{this.running===e&&(this.running=void 0)});this.running=e}async stop(e){this.controller?.abort();for(const e of this.workers.values())e.cancel?.();this.running&&await abortable(this.running,e)}async readOperationHistory(e){const t=this.getLease();if(!t)return{status:"unavailable"};try{return await this.channel.history({operationId:e.operationId,lease:t})}catch{return{status:"unavailable"}}}async loop(e){let t;(()=>{t||(t=setInterval(()=>{this.renewActive().catch(()=>{})},this.options.renewIntervalMs??2e4),t.unref?.())})();try{for(;!e.aborted;){const t=this.getLease();if(!t){await delay(this.options.idleDelayMs??500,e);continue}let a;try{a=await this.channel.read({maxCount:this.options.readCount??32,blockMs:this.options.blockMs??5e3,lease:t,signal:e})}catch{if(e.aborted)return;await delay(this.options.idleDelayMs??500,e);continue}for(const o of a){if(e.aborted)break;if(o.message.type===RUNTIME_MESSAGE_TYPES.cancel){await this.handleCancel(o,t).catch(e=>this.observeDeliveryError(e));continue}const a=o.message.channel_id;if(this.workers.has(a))continue;const n={deliveryId:o.deliveryId,claimedLease:t,completion:Promise.resolve()};n.completion=this.handleRequest(o,t,e,e=>{n.cancel=e}).catch(e=>this.observeDeliveryError(e)).finally(()=>{this.workers.delete(a)}),this.workers.set(a,n)}}}finally{t&&clearInterval(t),await Promise.allSettled([...this.workers.values()].map(e=>e.completion))}}observeDeliveryError(e){try{this.options.onDeliveryError?.(e)}catch{}}async renewActive(){const e=this.getLease();if(!e)return;const t=[];for(const a of this.workers.values())sameLeaseBinding(a.claimedLease,e)?t.push(a.deliveryId):a.cancel?.();if(!t.length)return;const a=await this.channel.renew({deliveryIds:t,lease:e});if(a.notPending.length){const e=new Set(a.notPending);for(const t of this.workers.values())e.has(t.deliveryId)&&t.cancel?.()}}async handleCancel(e,t){const a=validateRuntimeCancelEnvelope(e.message);if(!a.ok)return void await this.handlePoison(e,`invalid_cancel:${a.reason}`,t);const o=a.envelope.payload,n=await this.channel.history({operationId:o.operationId,lease:t});if("found"===n.status&&n.snapshot.terminal&&"final_message"===n.snapshot.terminalSource)return void await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t});if("not_found"===n.status||"expired"===n.status)return void await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t});const r=n.snapshot.request.payload;r.operationId===o.operationId&&r.requestMessageId===o.requestMessageId&&r.requestHash===o.requestHash&&r.dispatchEpoch===o.dispatchEpoch&&r.method===o.method?(await this.journal.observeCancellation({operationId:o.operationId,requestMessageId:o.requestMessageId,requestHash:o.requestHash,eventId:o.eventId}),this.workers.get(o.operationId)?.cancel?.(),await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t})):await this.handlePoison(e,"cancel_history_mismatch",t)}async handleRequest(e,t,a,o){const n=validateRuntimeRequestEnvelope(e.message);if(!n.ok)return void await this.handlePoison(e,`invalid_request:${n.reason}`,t);const r=n.envelope.payload,i=e.executionGrant,s=new AbortController;o(()=>s.abort());const d=async()=>await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:this.currentLease(t)}),c=await this.channel.history({operationId:r.operationId,lease:t});if("not_found"===c.status||"expired"===c.status)return void await d();if(c.snapshot.terminal&&"final_message"===c.snapshot.terminalSource)return void await d();if(this.options.allowedMethods&&!this.options.allowedMethods.has(r.method))return await this.reject(r,"unsupported_method",t),void await d();if("deadline"===c.snapshot.terminalSource||Date.parse(r.executionDeadlineAt)<=Date.now()||!c.snapshot.started&&Date.parse(r.claimDeadlineAt)<=Date.now())return await this.reject(r,"execution_deadline_exceeded",t),void await d();const l=await this.journal.getCancellation(r.operationId),u=c.snapshot.cancelRequested||null!==l;if(u&&"queued"===c.snapshot.status)return await this.reject(r,"cancelled_before_dispatch",t),void await d();if(r.instanceId!==t.instanceId||r.runtimeHandlerIdentity!==t.handlerIdentity||r.dispatchEpoch!==t.runtimeEpoch)return await this.reject(r,"authority_mismatch",t),void await d();const p=c.snapshot.request.payload;if(c.snapshot.operationId!==r.operationId||c.snapshot.requestMessageId!==r.requestMessageId||c.snapshot.requestHash!==r.requestHash||!semanticEqual(p,r))return void await this.handlePoison(e,"request_history_mismatch",t);const m=c.snapshot.started?.payload,h=void 0!==m&&m.operationId===r.operationId&&m.requestMessageId===r.requestMessageId&&m.requestHash===r.requestHash&&m.executionGrantHash===r.executionGrantHash&&m.handlerIdentity===t.handlerIdentity&&m.dispatchEpoch===t.runtimeEpoch&&m.method===r.method,I=await this.journal.get(r.operationId),E=await this.journal.acceptMessageRequest({operationId:r.operationId,command:r.command.name,paramsHash:r.paramsHash,runtimeEpoch:r.dispatchEpoch,requestMessageId:r.requestMessageId,requestHash:r.requestHash}),f=h?I:E,_=decideMessageServiceRecovery(c.snapshot,r,f,h);if("already_terminal"===_)return void await d();if(!CORE_RECOVERY_DECISIONS.has(_))return await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN",`Types recovery policy requires ${_}; this runtime cannot safely replay Core`),(new Date).toISOString())}),void await d();if(await this.verifier.refresh(),!i)return h?await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","retained started proof has no live execution grant"),(new Date).toISOString())}):await this.reject(r,"invalid_execution_grant",t),void await d();this.verifier.verifyAndDecodeGrant(i)||await this.verifier.refresh(!0);const R=()=>s.abort();let v;a.addEventListener("abort",R,{once:!0});try{v=await verifyAndCreateMessageServiceCoreExecutionAttempt({request:r,executionGrant:i,runtimeEpoch:t.runtimeEpoch,lease:t,verifier:this.verifier,allowExpiredGrant:h,abortSignal:s.signal,resolvePorts:async()=>await this.ports.resolve({request:r,executionGrant:i,command:r.command,getLease:()=>this.currentLease(t),journalRecord:E,abortSignal:s.signal})})}catch(e){if(a.removeEventListener("abort",R),s.abort(),!(e instanceof RuntimeResourceResolutionError))throw e;if("transient"===e.kind)return;return h?(await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","eager resources cannot be reconstructed after retained started proof"),(new Date).toISOString())})):await this.reject(r,"integrity_mismatch"===e.kind?"resource_integrity_mismatch":"resource_resolution_rejected",t),void await d()}if(!v.ok)return a.removeEventListener("abort",R),s.abort(),h?(await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","execution grant cannot be revalidated after retained started proof"),(new Date).toISOString())})):await this.reject(r,"invalid_execution_grant",t),void await d();if(!u||"prepared"!==E.phase&&"started"!==E.phase||s.abort(),s.signal.aborted&&!h)return a.removeEventListener("abort",R),await this.reject(r,"cancelled_before_dispatch",t),void await d();h||await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),executionGrant:i,type:RUNTIME_MESSAGE_TYPES.started,payload:{...runtimeMessageBase(r),executionMode:"start",executionGrantHash:r.executionGrantHash,handlerIdentity:t.handlerIdentity,claimedAt:E.messageBinding?.acceptedAt??E.updatedAt}});const M=this.dispatcher.dispatch(r.command,v.context);M.completion.catch(()=>{}),o(()=>{s.abort(),M.cancel()}),s.signal.aborted&&M.cancel();const g=this.forwardProgress(r,M.progress,t).catch(()=>{});let w,y=!1;try{if(("mcp/set"===r.method||"mcp/unset"===r.method)&&hasEffectReceiptHandoff(M)){const e=await M.effectCommitted;if(e){if(e.operationId!==r.operationId||e.method!==r.command.name)throw new RuntimeCommandError("OUTCOME_UNKNOWN","Core MCP receipt correlation mismatch");const a=runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:r.method,result:e.result}),o={schemaVersion:1,operationId:r.operationId,method:r.method,coreResultRef:`sha256:${a}`,coreResultHash:a};w=runtimeMessageHash(RUNTIME_HASH_DOMAINS.effectRecord,o),y=!0,await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.effectCommitted,payload:{...runtimeMessageBase(r),effectRecord:o,effectRecordHash:w,committedAt:e.committedAt}}),await M.acknowledgeEffectReceipt({operationId:r.operationId,method:r.command.name,effectRecordHash:w})}}const a=await M.completion;await g;const o=await this.journal.get(r.operationId);if(!o||!isCommittedCorePhase(o.phase))throw new RuntimeCommandError("OUTCOME_UNKNOWN","Core completed without a committed local journal record");const n=o.updatedAt;let i,s;if("query"!==RUNTIME_INVOCATION_RECOVERY_CLASSES[r.method]){const e=isAgentProjectionMethod(r.method),s=M.getSnapshot().projection,c=o.agentProjectionIntent??o.agentProjectionPreparationFailure;if(e&&!c)throw new RuntimeCommandError("OUTCOME_UNKNOWN","agent effect committed without an atomic projection preparation record");if(!w){const e=c?.coreResultHash??runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:r.method,result:a}),i={schemaVersion:1,operationId:r.operationId,method:r.method,coreResultRef:`sha256:${e}`,coreResultHash:e,...o.agentProjectionIntent?{projectionRevision:o.agentProjectionIntent.projectionRevision}:{}};w=runtimeMessageHash(RUNTIME_HASH_DOMAINS.effectRecord,i),y=!0,await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.effectCommitted,payload:{...runtimeMessageBase(r),effectRecord:i,effectRecordHash:w,committedAt:n}})}const l=e?await awaitRuntimeProjection(M):s;if(e&&o.agentProjectionIntent&&(!l||l.revision!==o.agentProjectionIntent.projectionRevision))throw new RuntimeCommandError("OUTCOME_UNKNOWN","agent projection receipt revision mismatch");if("pending"===l?.state)return void await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionPending,payload:{...runtimeMessageBase(r),revision:l.revision}});if("synced"===l?.state&&await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionSynced,payload:{...runtimeMessageBase(r),revision:l.revision,...l.platformAgentId?{platformAgentId:l.platformAgentId}:{}}}),"blocked"===l?.state){await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionBlocked,payload:{...runtimeMessageBase(r),revision:l.revision,errorCode:"PROJECTION_BLOCKED"}});const e=RUNTIME_ERROR_DESCRIPTORS.PROJECTION_BLOCKED;return await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:{...runtimeMessageBase(r),outcome:"projection_blocked",response:{jsonrpc:"2.0",id:r.request.id,error:{code:e.jsonRpcCode,message:"PROJECTION_BLOCKED",data:{code:"PROJECTION_BLOCKED",operationId:r.operationId,effectState:"committed",retryMode:e.retryMode}}},effectRecordHash:w,completedAt:n}}),void await d()}i=e?l?.platformAgentId:void 0}try{s=sanitizeRuntimeServiceResult(r.method,a,v.context,i)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed Core result cannot be mapped safely",void 0,{cause:e})}const c=runtimeMessageHash(RUNTIME_HASH_DOMAINS.serviceResult,{method:r.method,result:s});y=!0;const l=await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:{...runtimeMessageBase(r),outcome:"succeeded",response:{jsonrpc:"2.0",id:r.request.id,result:s},serviceResultHash:c,...w?{effectRecordHash:w}:{},completedAt:n}});if(this.observeRequestTerminalAccepted(e.deliveryId,l.message),("mcp/set"===r.method||"mcp/unset"===r.method)&&hasEffectReceiptHandoff(M)&&"function"==typeof M.acknowledgeTerminalReceipt){if(!w)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP terminal response lacks its committed effect hash");await M.acknowledgeTerminalReceipt({operationId:r.operationId,method:r.command.name,effectRecordHash:w,terminalMessageId:l.message.message_id})}await d(),this.observeRequestAcknowledged(e.deliveryId,l.message)}catch(e){const a=await this.journal.get(r.operationId);if(a&&isCommittedCorePhase(a.phase)&&y)throw e;const o=!a||!isCommittedCorePhase(a.phase)||e instanceof RuntimeCommandError&&"OUTCOME_UNKNOWN"===e.code?e:new RuntimeCommandError("OUTCOME_UNKNOWN","Core effect committed before terminal mapping",void 0,{cause:e}),n=failurePayload(r,o,a?.updatedAt??(new Date).toISOString());await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:n}),await d()}finally{s.abort(),a.removeEventListener("abort",R)}}async handlePoison(e,t,a){this.currentLease(a);(await this.poisonJournal.record({delivery:e,reason:durablePoisonReason(t),limit:this.options.poisonDeliveryLimit??3})).terminal&&await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:this.currentLease(a)})}observeRequestTerminalAccepted(e,t){try{this.options.onRequestTerminalAccepted?.({deliveryId:e,message:t})}catch{}}observeRequestAcknowledged(e,t){try{this.options.onRequestAcknowledged?.({deliveryId:e,message:t})}catch{}}async forwardProgress(e,t,a){for await(const o of t)await this.channel.append({operationId:e.operationId,lease:this.currentLease(a),type:RUNTIME_MESSAGE_TYPES.progress,payload:{...runtimeMessageBase(e),phase:o.phase,progress:o}})}async reject(e,t,a){await this.channel.append({operationId:e.operationId,lease:this.currentLease(a),type:RUNTIME_MESSAGE_TYPES.final,payload:prestartFailurePayload(e,t)})}async markOutcomeUnknownIfMutable(e){"prepared"!==e.phase&&"started"!==e.phase||await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"outcome_unknown",errorCode:"OUTCOME_UNKNOWN"})}currentLease(e){const t=this.getLease();if(!t||t.instanceId!==e.instanceId||t.leaseId!==e.leaseId||t.runtimeEpoch!==e.runtimeEpoch||t.handlerIdentity!==e.handlerIdentity||!Number.isFinite(Date.parse(t.leaseExpiresAt))||Date.parse(t.leaseExpiresAt)<=Date.now())throw new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","runtime message lease changed");return t}}function durablePoisonReason(e){const t=e.replace(/[^a-z0-9_:.-]+/gi,"_").replace(/^_+|_+$/g,"").slice(0,256);if(!t)throw new Error("poison reason is empty");return t}function isCommittedCorePhase(e){return"effect_committed"===e||"projection_committed"===e}const CORE_RECOVERY_DECISIONS=new Set(["execute","resume","replay_effect_committed","resume_projection","publish_committed_result","publish_projected_result","publish_terminal_result"]);function decideMessageServiceRecovery(e,t,a,o){const n=RUNTIME_INVOCATION_PARITY_ENTRIES.find(e=>e.acpMethod===t.method),r=e.terminal?"terminal":"blocked"===e.projectionState?"projection_blocked":"synced"===e.projectionState?"projection_synced":"pending"===e.projectionState?"projection_pending":e.effectCommitted?"runtime_committed":o?"running":"queued",i="failed"===a?.phase||"outcome_unknown"===a?.phase?"terminal":a?.phase,s=a&&a.runtimeEpoch===t.dispatchEpoch&&(void 0===a.messageBinding||a.messageBinding.requestMessageId===t.requestMessageId&&a.messageBinding.requestHash===t.requestHash)?"continuous":"discontinuous";return reduceRuntimeRecoveryPolicy({recoveryClass:n?.recoveryClass??RUNTIME_INVOCATION_RECOVERY_CLASSES[t.method],projectionRequired:"mcp/set"===t.method||"mcp/unset"===t.method||(n?.projectionRequired??!1),messageServicePhase:r,executionBoundaryCrossed:o,lineageContinuity:s,journalState:a?"available":"unavailable",...i?{journalPhase:i}:{}})}export function sanitizeRuntimeServiceResult(e,t,a,o){if("session/clear"===e)return serviceClearResult(t,a?.historyBoundary);if("session/set_model"===e)return serviceSetModelResult(t,a);if(!(e in SERVICE_CANONICAL_COMMAND_NAMES))return t;const n="cron/status"===e&&record(t)?{enabled:t.enabled,jobCount:t.jobCount,..."number"==typeof t.nextWakeAtMs?{nextWakeAtMs:t.nextWakeAtMs}:{}}:t;return mapCanonicalResultToService(e,n,{...o?{platformAgentId:o}:{},classifySkillOrigin:e=>e.bundled?{origin:"bundled",slug:e.slug}:{origin:"legacy_runtime",slug:e.slug},resolveMcpView:e=>({name:e.name,transport:e.transport,origin:"legacy_runtime",...void 0===e.connected?{}:{connected:e.connected},...void 0===e.connectionTimeoutMs?{}:{connectionTimeoutMs:e.connectionTimeoutMs}}),sanitizeDiagnostic:e=>/^[A-Z][A-Z0-9_]{0,63}$/.test(e)?e:"RUNTIME_EXECUTION_FAILED"})}function serviceClearResult(e,t){if(!record(e)||!0!==e.cleared||"string"!=typeof e.historyGeneration||!t||"message-service"!==t.kind)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed clear result lacks its Message Service receipt");const a=t;if(!a.committedIntentId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","Message Service clear receipt is unavailable");return{...e,clearIntentId:a.committedIntentId()}}function serviceSetModelResult(e,t){if(!record(e)||"string"!=typeof e.effectiveModelId||!t)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed set_model result is invalid");const a=t.verifiedMessageGrant?.claims.command;if(!a||"session.setModel"!==a.name||"conversation"!==a.context.scope)throw new RuntimeCommandError("OUTCOME_UNKNOWN","set_model Service target receipt is unavailable");const o=a.params.modelOverrideId;return{conversationId:a.context.conversation.runtimeConversationUid,...null===o?{defaultModelId:e.effectiveModelId}:{},modelOverrideId:o,effectiveModelId:e.effectiveModelId,effectState:"committed",projectionState:"synced",operationId:t.operationId}}function isAgentProjectionMethod(e){return"agent/create"===e||"agent/update"===e||"agent/delete"===e||"agent/applyTemplate"===e}function record(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function sameLeaseBinding(e,t){return e.instanceId===t.instanceId&&e.leaseId===t.leaseId&&e.handlerIdentity===t.handlerIdentity&&e.runtimeEpoch===t.runtimeEpoch}function failurePayload(e,t,a){const o=t instanceof RuntimeCommandError?t.code:"RUNTIME_EXECUTION_FAILED",n=o in RUNTIME_ERROR_DESCRIPTORS?o:"RUNTIME_EXECUTION_FAILED",r="OUTCOME_UNKNOWN"===n||"INSTANCE_EPOCH_MISMATCH"===n?"outcome_unknown":"COMMAND_EXPIRED"===n?"expired":"OPERATION_CANCELLED"===n?"cancelled":"failed",i="outcome_unknown"===r?"OUTCOME_UNKNOWN":n,s=RUNTIME_ERROR_DESCRIPTORS[i],d="outcome_unknown"===r?"outcome_unknown":r;return{...runtimeMessageBase(e),outcome:r,response:{jsonrpc:"2.0",id:e.request.id,error:{code:s.jsonRpcCode,message:i,data:{code:i,operationId:e.operationId,effectState:d,retryMode:s.retryMode}}},completedAt:a}}function prestartFailurePayload(e,t){const a="invalid_execution_grant"===t?"INVALID_EXECUTION_GRANT":"unsupported_method"===t?"METHOD_NOT_SUPPORTED":"authority_mismatch"===t?"INSTANCE_EPOCH_MISMATCH":"execution_deadline_exceeded"===t?"COMMAND_EXPIRED":"cancelled_before_dispatch"===t?"OPERATION_CANCELLED":"resource_resolution_rejected"===t?"INVALID_INVOCATION":"RUNTIME_EXECUTION_FAILED",o=RUNTIME_ERROR_DESCRIPTORS[a in RUNTIME_ERROR_DESCRIPTORS?a:"RUNTIME_EXECUTION_FAILED"],n="COMMAND_EXPIRED"===a?"expired":"OPERATION_CANCELLED"===a?"cancelled":"failed";return{...runtimeMessageBase(e),outcome:n,response:{jsonrpc:"2.0",id:e.request.id,error:{code:o.jsonRpcCode,message:a,data:{code:a,operationId:e.operationId,effectState:n,retryMode:o.retryMode}}},completedAt:(new Date).toISOString()}}function abortable(e,t){return t?t.aborted?Promise.resolve():new Promise((a,o)=>{const n=()=>a();t.addEventListener("abort",n,{once:!0}),e.then(()=>{t.removeEventListener("abort",n),a()},e=>{t.removeEventListener("abort",n),o(e)})}):e}function delay(e,t){return new Promise(a=>{if(t?.aborted)return a();const o=()=>{clearTimeout(n),a()},n=setTimeout(()=>{t?.removeEventListener("abort",o),a()},e);t?.addEventListener("abort",o,{once:!0})})}
1
+ import{RUNTIME_ERROR_DESCRIPTORS,RUNTIME_HASH_DOMAINS,RUNTIME_INVOCATION_PARITY_ENTRIES,RUNTIME_INVOCATION_RECOVERY_CLASSES,SERVICE_CANONICAL_COMMAND_NAMES,mapCanonicalResultToService}from"@beeos-ai/beeos-types/runtime";import{reduceRuntimeRecoveryPolicy}from"@beeos-ai/beeos-types/runtime/internal";import{verifyAndCreateMessageServiceCoreExecutionAttempt}from"./core-execution-attempt-context.js";import{awaitRuntimeProjection,hasEffectReceiptHandoff,RuntimeCommandError}from"./runtime-command-dispatcher.js";import{RUNTIME_MESSAGE_TYPES,runtimeMessageBase,runtimeMessageHash,semanticEqual,validateRuntimeCancelEnvelope,validateRuntimeRequestEnvelope}from"./runtime-message-channel-contract.js";import{RuntimeResourceResolutionError}from"./runtime-operation-resource-resolver.js";export class MsRuntimeMessageChannelAdapter{dispatcher;channel;verifier;ports;journal;getLease;options;controller;running;workers=new Map;poisonJournal;receiptHistory=this;constructor(e,t,a,o,n,r,i){if(this.dispatcher=e,this.channel=t,this.verifier=a,this.ports=o,this.journal=n,this.getLease=r,this.options=i,!i.poisonJournal)throw new Error("durable poison journal is required");if(this.poisonJournal=i.poisonJournal,!Number.isSafeInteger(i.poisonDeliveryLimit??3)||(i.poisonDeliveryLimit??3)<=0)throw new Error("poison delivery limit must be a positive integer")}start(){if(this.running)return;const e=new AbortController;this.controller=e;const t=this.loop(e.signal).catch(t=>{e.signal.aborted||this.observeDeliveryError(t)}).finally(()=>{this.running===t&&(this.running=void 0)});this.running=t}async stop(e){this.controller?.abort();for(const e of this.workers.values())e.cancel?.();this.running&&await abortable(this.running,e)}async readOperationHistory(e){const t=this.getLease();if(!t)return{status:"unavailable"};try{return await this.channel.history({operationId:e.operationId,lease:t})}catch{return{status:"unavailable"}}}async loop(e){let t;(()=>{t||(t=setInterval(()=>{this.renewActive().catch(()=>{})},this.options.renewIntervalMs??2e4),t.unref?.())})();try{for(;!e.aborted;){const t=this.getLease();if(!t){await delay(this.options.idleDelayMs??500,e);continue}let a;try{a=await this.channel.read({maxCount:this.options.readCount??32,blockMs:this.options.blockMs??5e3,lease:t,signal:e})}catch{if(e.aborted)return;await delay(this.options.idleDelayMs??500,e);continue}for(const o of a){if(e.aborted)break;if(o.message.type===RUNTIME_MESSAGE_TYPES.cancel){await this.handleCancel(o,t).catch(e=>this.observeDeliveryError(e));continue}const a=o.message.channel_id;if(this.workers.has(a))continue;const n={deliveryId:o.deliveryId,claimedLease:t,completion:Promise.resolve()};n.completion=this.handleRequest(o,t,e,e=>{n.cancel=e}).catch(e=>this.observeDeliveryError(e)).finally(()=>{this.workers.delete(a)}),this.workers.set(a,n)}}}finally{t&&clearInterval(t),await Promise.allSettled([...this.workers.values()].map(e=>e.completion))}}observeDeliveryError(e){try{this.options.onDeliveryError?.(e)}catch{}}async renewActive(){const e=this.getLease();if(!e)return;const t=[];for(const a of this.workers.values())sameLeaseBinding(a.claimedLease,e)?t.push(a.deliveryId):a.cancel?.();if(!t.length)return;const a=await this.channel.renew({deliveryIds:t,lease:e});if(a.notPending.length){const e=new Set(a.notPending);for(const t of this.workers.values())e.has(t.deliveryId)&&t.cancel?.()}}async handleCancel(e,t){const a=validateRuntimeCancelEnvelope(e.message);if(!a.ok)return void await this.handlePoison(e,`invalid_cancel:${a.reason}`,t);const o=a.envelope.payload,n=await this.channel.history({operationId:o.operationId,lease:t});if("found"===n.status&&n.snapshot.terminal&&"final_message"===n.snapshot.terminalSource)return void await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t});if("not_found"===n.status||"expired"===n.status)return void await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t});const r=n.snapshot.request.payload;r.operationId===o.operationId&&r.requestMessageId===o.requestMessageId&&r.requestHash===o.requestHash&&r.dispatchEpoch===o.dispatchEpoch&&r.method===o.method?(await this.journal.observeCancellation({operationId:o.operationId,requestMessageId:o.requestMessageId,requestHash:o.requestHash,eventId:o.eventId}),this.workers.get(o.operationId)?.cancel?.(),await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:t})):await this.handlePoison(e,"cancel_history_mismatch",t)}async handleRequest(e,t,a,o){const n=validateRuntimeRequestEnvelope(e.message);if(!n.ok)return void await this.handlePoison(e,`invalid_request:${n.reason}`,t);const r=n.envelope.payload,i=e.executionGrant,s=new AbortController;o(()=>s.abort());const d=async()=>await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:this.currentLease(t)}),c=await this.channel.history({operationId:r.operationId,lease:t});if("not_found"===c.status||"expired"===c.status)return void await d();if(c.snapshot.terminal&&"final_message"===c.snapshot.terminalSource)return void await d();if(this.options.allowedMethods&&!this.options.allowedMethods.has(r.method))return await this.reject(r,"unsupported_method",t),void await d();if("deadline"===c.snapshot.terminalSource||Date.parse(r.executionDeadlineAt)<=Date.now()||!c.snapshot.started&&Date.parse(r.claimDeadlineAt)<=Date.now())return await this.reject(r,"execution_deadline_exceeded",t),void await d();const l=await this.journal.getCancellation(r.operationId),u=c.snapshot.cancelRequested||null!==l;if(u&&"queued"===c.snapshot.status)return await this.reject(r,"cancelled_before_dispatch",t),void await d();if(r.instanceId!==t.instanceId||r.runtimeHandlerIdentity!==t.handlerIdentity||r.dispatchEpoch!==t.runtimeEpoch)return await this.reject(r,"authority_mismatch",t),void await d();const p=c.snapshot.request.payload;if(c.snapshot.operationId!==r.operationId||c.snapshot.requestMessageId!==r.requestMessageId||c.snapshot.requestHash!==r.requestHash||!semanticEqual(p,r))return void await this.handlePoison(e,"request_history_mismatch",t);const m=c.snapshot.started?.payload,h=void 0!==m&&m.operationId===r.operationId&&m.requestMessageId===r.requestMessageId&&m.requestHash===r.requestHash&&m.executionGrantHash===r.executionGrantHash&&m.handlerIdentity===t.handlerIdentity&&m.dispatchEpoch===t.runtimeEpoch&&m.method===r.method,I=await this.journal.get(r.operationId),E=await this.journal.acceptMessageRequest({operationId:r.operationId,command:r.command.name,paramsHash:r.paramsHash,runtimeEpoch:r.dispatchEpoch,requestMessageId:r.requestMessageId,requestHash:r.requestHash}),f=h?I:E,_=decideMessageServiceRecovery(c.snapshot,r,f,h);if("already_terminal"===_)return void await d();if(!CORE_RECOVERY_DECISIONS.has(_))return await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN",`Types recovery policy requires ${_}; this runtime cannot safely replay Core`),(new Date).toISOString())}),void await d();if(await this.verifier.refresh(),!i)return h?await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","retained started proof has no live execution grant"),(new Date).toISOString())}):await this.reject(r,"invalid_execution_grant",t),void await d();this.verifier.verifyAndDecodeGrant(i)||await this.verifier.refresh(!0);const R=()=>s.abort();let v;a.addEventListener("abort",R,{once:!0});try{v=await verifyAndCreateMessageServiceCoreExecutionAttempt({request:r,executionGrant:i,runtimeEpoch:t.runtimeEpoch,lease:t,verifier:this.verifier,allowExpiredGrant:h,abortSignal:s.signal,resolvePorts:async()=>await this.ports.resolve({request:r,executionGrant:i,command:r.command,getLease:()=>this.currentLease(t),journalRecord:E,abortSignal:s.signal})})}catch(e){if(a.removeEventListener("abort",R),s.abort(),!(e instanceof RuntimeResourceResolutionError))throw e;if("transient"===e.kind)return;return h?(await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","eager resources cannot be reconstructed after retained started proof"),(new Date).toISOString())})):await this.reject(r,"integrity_mismatch"===e.kind?"resource_integrity_mismatch":"resource_resolution_rejected",t),void await d()}if(!v.ok)return a.removeEventListener("abort",R),s.abort(),h?(await this.markOutcomeUnknownIfMutable(E),await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:failurePayload(r,new RuntimeCommandError("OUTCOME_UNKNOWN","execution grant cannot be revalidated after retained started proof"),(new Date).toISOString())})):await this.reject(r,"invalid_execution_grant",t),void await d();if(!u||"prepared"!==E.phase&&"started"!==E.phase||s.abort(),s.signal.aborted&&!h)return a.removeEventListener("abort",R),await this.reject(r,"cancelled_before_dispatch",t),void await d();h||await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),executionGrant:i,type:RUNTIME_MESSAGE_TYPES.started,payload:{...runtimeMessageBase(r),executionMode:"start",executionGrantHash:r.executionGrantHash,handlerIdentity:t.handlerIdentity,claimedAt:E.messageBinding?.acceptedAt??E.updatedAt}});const M=this.dispatcher.dispatch(r.command,v.context);M.completion.catch(()=>{}),o(()=>{s.abort(),M.cancel()}),s.signal.aborted&&M.cancel();const g=this.forwardProgress(r,M.progress,t).catch(()=>{});let w,y=!1;try{if(("mcp/set"===r.method||"mcp/unset"===r.method)&&hasEffectReceiptHandoff(M)){const e=await M.effectCommitted;if(e){if(e.operationId!==r.operationId||e.method!==r.command.name)throw new RuntimeCommandError("OUTCOME_UNKNOWN","Core MCP receipt correlation mismatch");const a=runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:r.method,result:e.result}),o={schemaVersion:1,operationId:r.operationId,method:r.method,coreResultRef:`sha256:${a}`,coreResultHash:a};w=runtimeMessageHash(RUNTIME_HASH_DOMAINS.effectRecord,o),y=!0,await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.effectCommitted,payload:{...runtimeMessageBase(r),effectRecord:o,effectRecordHash:w,committedAt:e.committedAt}}),await M.acknowledgeEffectReceipt({operationId:r.operationId,method:r.command.name,effectRecordHash:w})}}const a=await M.completion;await g;const o=await this.journal.get(r.operationId);if(!o||!isCommittedCorePhase(o.phase))throw new RuntimeCommandError("OUTCOME_UNKNOWN","Core completed without a committed local journal record");const n=o.updatedAt;let i,s;if("query"!==RUNTIME_INVOCATION_RECOVERY_CLASSES[r.method]){const e=isAgentProjectionMethod(r.method),s=M.getSnapshot().projection,c=o.agentProjectionIntent??o.agentProjectionPreparationFailure;if(e&&!c)throw new RuntimeCommandError("OUTCOME_UNKNOWN","agent effect committed without an atomic projection preparation record");if(!w){const e=c?.coreResultHash??runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:r.method,result:a}),i={schemaVersion:1,operationId:r.operationId,method:r.method,coreResultRef:`sha256:${e}`,coreResultHash:e,...o.agentProjectionIntent?{projectionRevision:o.agentProjectionIntent.projectionRevision}:{}};w=runtimeMessageHash(RUNTIME_HASH_DOMAINS.effectRecord,i),y=!0,await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.effectCommitted,payload:{...runtimeMessageBase(r),effectRecord:i,effectRecordHash:w,committedAt:n}})}const l=e?await awaitRuntimeProjection(M):s;if(e&&o.agentProjectionIntent&&(!l||l.revision!==o.agentProjectionIntent.projectionRevision))throw new RuntimeCommandError("OUTCOME_UNKNOWN","agent projection receipt revision mismatch");if("pending"===l?.state)return void await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionPending,payload:{...runtimeMessageBase(r),revision:l.revision}});if("synced"===l?.state&&await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionSynced,payload:{...runtimeMessageBase(r),revision:l.revision,...l.platformAgentId?{platformAgentId:l.platformAgentId}:{}}}),"blocked"===l?.state){await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.projectionBlocked,payload:{...runtimeMessageBase(r),revision:l.revision,errorCode:"PROJECTION_BLOCKED"}});const e=RUNTIME_ERROR_DESCRIPTORS.PROJECTION_BLOCKED;return await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:{...runtimeMessageBase(r),outcome:"projection_blocked",response:{jsonrpc:"2.0",id:r.request.id,error:{code:e.jsonRpcCode,message:"PROJECTION_BLOCKED",data:{code:"PROJECTION_BLOCKED",operationId:r.operationId,effectState:"committed",retryMode:e.retryMode}}},effectRecordHash:w,completedAt:n}}),void await d()}i=e?l?.platformAgentId:void 0}try{s=sanitizeRuntimeServiceResult(r.method,a,v.context,i)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed Core result cannot be mapped safely",void 0,{cause:e})}const c=runtimeMessageHash(RUNTIME_HASH_DOMAINS.serviceResult,{method:r.method,result:s});y=!0;const l=await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:{...runtimeMessageBase(r),outcome:"succeeded",response:{jsonrpc:"2.0",id:r.request.id,result:s},serviceResultHash:c,...w?{effectRecordHash:w}:{},completedAt:n}});if(this.observeRequestTerminalAccepted(e.deliveryId,l.message),("mcp/set"===r.method||"mcp/unset"===r.method)&&hasEffectReceiptHandoff(M)&&"function"==typeof M.acknowledgeTerminalReceipt){if(!w)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP terminal response lacks its committed effect hash");await M.acknowledgeTerminalReceipt({operationId:r.operationId,method:r.command.name,effectRecordHash:w,terminalMessageId:l.message.message_id})}await d(),this.observeRequestAcknowledged(e.deliveryId,l.message)}catch(e){const a=await this.journal.get(r.operationId);if(a&&isCommittedCorePhase(a.phase)&&y)throw e;const o=!a||!isCommittedCorePhase(a.phase)||e instanceof RuntimeCommandError&&"OUTCOME_UNKNOWN"===e.code?e:new RuntimeCommandError("OUTCOME_UNKNOWN","Core effect committed before terminal mapping",void 0,{cause:e}),n=failurePayload(r,o,a?.updatedAt??(new Date).toISOString());await this.channel.append({operationId:r.operationId,lease:this.currentLease(t),type:RUNTIME_MESSAGE_TYPES.final,payload:n}),await d()}finally{s.abort(),a.removeEventListener("abort",R)}}async handlePoison(e,t,a){this.currentLease(a);(await this.poisonJournal.record({delivery:e,reason:durablePoisonReason(t),limit:this.options.poisonDeliveryLimit??3})).terminal&&await this.channel.acknowledge({deliveryIds:[e.deliveryId],lease:this.currentLease(a)})}observeRequestTerminalAccepted(e,t){try{this.options.onRequestTerminalAccepted?.({deliveryId:e,message:t})}catch{}}observeRequestAcknowledged(e,t){try{this.options.onRequestAcknowledged?.({deliveryId:e,message:t})}catch{}}async forwardProgress(e,t,a){for await(const o of t)await this.channel.append({operationId:e.operationId,lease:this.currentLease(a),type:RUNTIME_MESSAGE_TYPES.progress,payload:{...runtimeMessageBase(e),phase:o.phase,progress:o}})}async reject(e,t,a){await this.channel.append({operationId:e.operationId,lease:this.currentLease(a),type:RUNTIME_MESSAGE_TYPES.final,payload:prestartFailurePayload(e,t)})}async markOutcomeUnknownIfMutable(e){"prepared"!==e.phase&&"started"!==e.phase||await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"outcome_unknown",errorCode:"OUTCOME_UNKNOWN"})}currentLease(e){const t=this.getLease();if(!t||t.instanceId!==e.instanceId||t.leaseId!==e.leaseId||t.runtimeEpoch!==e.runtimeEpoch||t.handlerIdentity!==e.handlerIdentity||!Number.isFinite(Date.parse(t.leaseExpiresAt))||Date.parse(t.leaseExpiresAt)<=Date.now())throw new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","runtime message lease changed");return t}}function durablePoisonReason(e){const t=e.replace(/[^a-z0-9_:.-]+/gi,"_").replace(/^_+|_+$/g,"").slice(0,256);if(!t)throw new Error("poison reason is empty");return t}function isCommittedCorePhase(e){return"effect_committed"===e||"projection_committed"===e}const CORE_RECOVERY_DECISIONS=new Set(["execute","resume","replay_effect_committed","resume_projection","publish_committed_result","publish_projected_result","publish_terminal_result"]);function decideMessageServiceRecovery(e,t,a,o){const n=RUNTIME_INVOCATION_PARITY_ENTRIES.find(e=>e.acpMethod===t.method),r=e.terminal?"terminal":"blocked"===e.projectionState?"projection_blocked":"synced"===e.projectionState?"projection_synced":"pending"===e.projectionState?"projection_pending":e.effectCommitted?"runtime_committed":o?"running":"queued",i="failed"===a?.phase||"outcome_unknown"===a?.phase?"terminal":a?.phase,s=a&&a.runtimeEpoch===t.dispatchEpoch&&(void 0===a.messageBinding||a.messageBinding.requestMessageId===t.requestMessageId&&a.messageBinding.requestHash===t.requestHash)?"continuous":"discontinuous";return reduceRuntimeRecoveryPolicy({recoveryClass:n?.recoveryClass??RUNTIME_INVOCATION_RECOVERY_CLASSES[t.method],projectionRequired:"mcp/set"===t.method||"mcp/unset"===t.method||(n?.projectionRequired??!1),messageServicePhase:r,executionBoundaryCrossed:o,lineageContinuity:s,journalState:a?"available":"unavailable",...i?{journalPhase:i}:{}})}export function sanitizeRuntimeServiceResult(e,t,a,o){if("session/clear"===e)return serviceClearResult(t,a?.historyBoundary);if("session/set_model"===e)return serviceSetModelResult(t,a);if(!(e in SERVICE_CANONICAL_COMMAND_NAMES))return t;const n="cron/status"===e&&record(t)?{enabled:t.enabled,jobCount:t.jobCount,..."number"==typeof t.nextWakeAtMs?{nextWakeAtMs:t.nextWakeAtMs}:{}}:t;return mapCanonicalResultToService(e,n,{...o?{platformAgentId:o}:{},classifySkillOrigin:e=>e.bundled?{origin:"bundled",slug:e.slug}:{origin:"legacy_runtime",slug:e.slug},resolveMcpView:e=>({name:e.name,transport:e.transport,origin:"legacy_runtime",...void 0===e.connected?{}:{connected:e.connected},...void 0===e.connectionTimeoutMs?{}:{connectionTimeoutMs:e.connectionTimeoutMs}}),sanitizeDiagnostic:e=>/^[A-Z][A-Z0-9_]{0,63}$/.test(e)?e:"RUNTIME_EXECUTION_FAILED"})}function serviceClearResult(e,t){if(!record(e)||!0!==e.cleared||"string"!=typeof e.historyGeneration||!t||"message-service"!==t.kind)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed clear result lacks its Message Service receipt");const a=t;if(!a.committedIntentId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","Message Service clear receipt is unavailable");return{...e,clearIntentId:a.committedIntentId()}}function serviceSetModelResult(e,t){if(!record(e)||"string"!=typeof e.effectiveModelId||!t)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed set_model result is invalid");const a=t.verifiedMessageGrant?.claims.command;if(!a||"session.setModel"!==a.name||"conversation"!==a.context.scope)throw new RuntimeCommandError("OUTCOME_UNKNOWN","set_model Service target receipt is unavailable");const o=a.params.modelOverrideId;return{conversationId:a.context.conversation.runtimeConversationUid,...null===o?{defaultModelId:e.effectiveModelId}:{},modelOverrideId:o,effectiveModelId:e.effectiveModelId,effectState:"committed",projectionState:"synced",operationId:t.operationId}}function isAgentProjectionMethod(e){return"agent/create"===e||"agent/update"===e||"agent/delete"===e||"agent/applyTemplate"===e}function record(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function sameLeaseBinding(e,t){return e.instanceId===t.instanceId&&e.leaseId===t.leaseId&&e.handlerIdentity===t.handlerIdentity&&e.runtimeEpoch===t.runtimeEpoch}function failurePayload(e,t,a){const o=t instanceof RuntimeCommandError?t.code:"RUNTIME_EXECUTION_FAILED",n=o in RUNTIME_ERROR_DESCRIPTORS?o:"RUNTIME_EXECUTION_FAILED",r="OUTCOME_UNKNOWN"===n||"INSTANCE_EPOCH_MISMATCH"===n?"outcome_unknown":"COMMAND_EXPIRED"===n?"expired":"OPERATION_CANCELLED"===n?"cancelled":"failed",i="outcome_unknown"===r?"OUTCOME_UNKNOWN":n,s=RUNTIME_ERROR_DESCRIPTORS[i],d="outcome_unknown"===r?"outcome_unknown":r;return{...runtimeMessageBase(e),outcome:r,response:{jsonrpc:"2.0",id:e.request.id,error:{code:s.jsonRpcCode,message:i,data:{code:i,operationId:e.operationId,effectState:d,retryMode:s.retryMode}}},completedAt:a}}function prestartFailurePayload(e,t){const a="invalid_execution_grant"===t?"INVALID_EXECUTION_GRANT":"unsupported_method"===t?"METHOD_NOT_SUPPORTED":"authority_mismatch"===t?"INSTANCE_EPOCH_MISMATCH":"execution_deadline_exceeded"===t?"COMMAND_EXPIRED":"cancelled_before_dispatch"===t?"OPERATION_CANCELLED":"resource_resolution_rejected"===t?"INVALID_INVOCATION":"RUNTIME_EXECUTION_FAILED",o=RUNTIME_ERROR_DESCRIPTORS[a in RUNTIME_ERROR_DESCRIPTORS?a:"RUNTIME_EXECUTION_FAILED"],n="COMMAND_EXPIRED"===a?"expired":"OPERATION_CANCELLED"===a?"cancelled":"failed";return{...runtimeMessageBase(e),outcome:n,response:{jsonrpc:"2.0",id:e.request.id,error:{code:o.jsonRpcCode,message:a,data:{code:a,operationId:e.operationId,effectState:n,retryMode:o.retryMode}}},completedAt:(new Date).toISOString()}}function abortable(e,t){return t?t.aborted?Promise.resolve():new Promise((a,o)=>{const n=()=>a();t.addEventListener("abort",n,{once:!0}),e.then(()=>{t.removeEventListener("abort",n),a()},e=>{t.removeEventListener("abort",n),o(e)})}):e}function delay(e,t){return new Promise(a=>{if(t?.aborted)return a();const o=()=>{clearTimeout(n),a()},n=setTimeout(()=>{t?.removeEventListener("abort",o),a()},e);t?.addEventListener("abort",o,{once:!0})})}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.5.65-staging.4",
3
+ "version": "0.5.65-staging.6",
4
4
  "description": "OpenClaw plugin that bridges the BeeOS platform with the local OpenClaw Gateway, providing file transfer, ACP bridge, and observability.",
5
5
  "license": "MIT",
6
6
  "author": "BeeOS <dev@beeos.ai>",
@@ -38,10 +38,10 @@ export async function withinDeadline(run, deadline) {
38
38
  * invoking start() again would create competing reconnect loops.
39
39
  */
40
40
  export async function startGatewayWithinDeadline(gateway, deadline) {
41
- await withinDeadline((signal) => startAndObserveGateway(gateway, signal), deadline);
41
+ return await withinDeadline((signal) => startAndObserveGateway(gateway, signal), deadline);
42
42
  }
43
43
 
44
- export async function closeRuntimeResources({ consumer, gateway }, cleanupTimeoutMs = 5_000) {
44
+ export async function closeRuntimeResources({ consumer, gateway, releaseGatewayTransportObserver }, cleanupTimeoutMs = 5_000) {
45
45
  let cleanupError;
46
46
  try {
47
47
  if (consumer) {
@@ -56,6 +56,11 @@ export async function closeRuntimeResources({ consumer, gateway }, cleanupTimeou
56
56
  }
57
57
  } catch (error) {
58
58
  cleanupError ??= new Error(WORKER_CLEANUP_MESSAGE, { cause: error });
59
+ } finally {
60
+ // The retained observer is only needed while GatewayClient can still
61
+ // emit a transport error. Release it after the bounded stop completes,
62
+ // including the consumer-stop failure path.
63
+ releaseGatewayTransportObserver?.();
59
64
  }
60
65
  }
61
66
  return cleanupError;
@@ -113,20 +118,25 @@ function startAndObserveGateway(gateway, signal) {
113
118
  return new Promise((resolve, reject) => {
114
119
  let settled = false;
115
120
  let observedTransportFailure = false;
116
- const cleanup = () => {
121
+ const cleanup = (retainTransportObserver = false) => {
117
122
  gateway.off("connected", onConnected);
118
123
  gateway.off("auth-failed", onAuthFailed);
119
- gateway.off("error", onError);
124
+ if (!retainTransportObserver) gateway.off("error", onError);
120
125
  gateway.off("disconnected", onDisconnected);
121
126
  signal.removeEventListener("abort", onAbort);
122
127
  };
123
- const settle = (callback, value) => {
128
+ const releaseTransportObserver = () => gateway.off("error", onError);
129
+ const settle = (callback, value, retainTransportObserver = false) => {
124
130
  if (settled) return;
125
131
  settled = true;
126
- cleanup();
132
+ cleanup(retainTransportObserver);
127
133
  callback(value);
128
134
  };
129
- const onConnected = () => settle(resolve);
135
+ // `error` has special EventEmitter semantics: after the initial handshake
136
+ // succeeds, a later WebSocket transport error must stay observed until the
137
+ // worker shuts the Gateway down. GatewayClient owns reconnects; this
138
+ // observer only prevents that owned transient from becoming process-fatal.
139
+ const onConnected = () => settle(resolve, releaseTransportObserver, true);
130
140
  const onAuthFailed = (failure) => {
131
141
  const reason = failure && typeof failure.reason === "string"
132
142
  ? failure.reason
@@ -154,7 +164,7 @@ function startAndObserveGateway(gateway, signal) {
154
164
  Promise.resolve()
155
165
  .then(() => gateway.start())
156
166
  .then(
157
- () => settle(resolve),
167
+ () => settle(resolve, releaseTransportObserver, true),
158
168
  (error) => {
159
169
  // Typed handshake UNAVAILABLE and a pre-auth transport failure both
160
170
  // leave GatewayClient's single bounded reconnect loop authoritative.
@@ -114,13 +114,14 @@ export async function main() {
114
114
  retry: { baseMs: 100, maxMs: 500, maxAttempts: 60 } });
115
115
  let consumer;
116
116
  let primaryError;
117
+ let releaseGatewayTransportObserver;
117
118
  const runtimeLease = () => ({ instanceId, leaseId: nonempty(authority.leaseId, "authority.leaseId"),
118
119
  handlerIdentity: nonempty(authority.handlerIdentity, "authority.handlerIdentity"),
119
120
  runtimeEpoch: decimal(authority.runtimeEpoch, "authority.runtimeEpoch"),
120
121
  runtimeLeaseCredential: nonempty(authority.runtimeLeaseCredential, "authority.runtimeLeaseCredential"),
121
122
  leaseExpiresAt: new Date(Number(leaseClaims.exp) * 1_000).toISOString() });
122
123
  try {
123
- await startGatewayWithinDeadline(gateway, deadline);
124
+ releaseGatewayTransportObserver = await startGatewayWithinDeadline(gateway, deadline);
124
125
  const identities = new FileRuntimeAgentIdentityRegistry(`${statePrefix}-identities.json`);
125
126
  const dispatcher = new OpenClawRuntimeCommandDispatcher({ getGateway: () => gateway,
126
127
  resources: rejectingResources(), identities,
@@ -150,7 +151,7 @@ export async function main() {
150
151
  primaryError = error;
151
152
  } finally {
152
153
  primaryError = selectRuntimeError(primaryError,
153
- await closeRuntimeResources({ consumer, gateway }));
154
+ await closeRuntimeResources({ consumer, gateway, releaseGatewayTransportObserver }));
154
155
  try { completionGate.assertNoFailure(); }
155
156
  catch (error) { primaryError ??= error; }
156
157
  }