beeos-claw 0.6.71 → 0.6.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -13
- package/dist/a2a/tools.js +1 -1
- package/dist/acp-gateway/beeos-file-resolver.js +1 -1
- package/dist/acp-gateway/bridge-core.js +1 -1
- package/dist/acp-gateway/gateway-events.js +1 -1
- package/dist/acp-gateway/local-session-history.js +1 -1
- package/dist/acp-gateway/mcp-desired-state-controller.js +1 -1
- package/dist/acp-gateway/mcp-desired-state-store.js +1 -1
- package/dist/acp-gateway/mcp-service.js +1 -1
- package/dist/acp-server.js +1 -1
- package/dist/agent-sync.js +1 -1
- package/dist/approval/bridge.js +1 -0
- package/dist/approval/presentation.js +1 -0
- package/dist/approval/protocol.generated.js +1 -0
- package/dist/auto-reply-tokens.js +1 -1
- package/dist/automation/tools.js +1 -1
- package/dist/canvas/relay-client.js +1 -1
- package/dist/canvas/static-html.js +1 -1
- package/dist/canvas/tools.js +1 -1
- package/dist/canvas/ws-provider.js +1 -1
- package/dist/canvas-orchestrator.js +1 -1
- package/dist/chat-envelope.js +1 -0
- package/dist/connectors/harness-connector-mcp.js +1 -0
- package/dist/files/fetch-tool.js +1 -1
- package/dist/files/list-tool.js +1 -1
- package/dist/gateway-client.js +1 -1
- package/dist/im-inbound-handler.js +1 -1
- package/dist/im-runtime-dispatch.js +1 -1
- package/dist/index.js +1 -1
- package/dist/media/arouter-config.js +1 -1
- package/dist/media/image-provider.js +1 -1
- package/dist/media/video-provider.js +1 -1
- package/dist/message-client-composition.js +1 -1
- package/dist/message-projection-inbound-consumer.js +1 -1
- package/dist/plugin-registration-plan.js +1 -1
- package/dist/question/bridge.js +1 -0
- package/dist/runtime/agent-projection-production.js +1 -1
- package/dist/runtime/assistant-message-commit-router.js +1 -1
- package/dist/runtime/callback-queue.js +1 -1
- package/dist/runtime/chat-handler-port.js +1 -0
- package/dist/runtime/conversation-title.js +1 -1
- package/dist/runtime/core-execution-attempt-context.js +1 -1
- package/dist/runtime/deepseek-reasoning-stream.js +1 -1
- package/dist/runtime/im-reply-sink.js +1 -1
- package/dist/runtime/message-service-conversation-clear-http-authority.js +1 -1
- package/dist/runtime/message-service-conversation-run-boundary.js +1 -1
- package/dist/runtime/message-service-cron-delivery-http-authority.js +1 -1
- package/dist/runtime/message-service-runtime-authenticated-fetch.js +1 -1
- package/dist/runtime/message-service-runtime-claim-authority.js +1 -1
- package/dist/runtime/message-service-runtime-message-channel.js +1 -1
- package/dist/runtime/message-service-session-model-http-authority.js +1 -1
- package/dist/runtime/ms-runtime-message-channel-adapter.js +1 -1
- package/dist/runtime/ms-runtime-message-channel-consumer-factory.js +1 -1
- package/dist/runtime/ms-runtime-rpc-adapter.js +1 -1
- package/dist/runtime/native-cloud-chat-composition.js +1 -0
- package/dist/runtime/native-cloud-prompt-bridge.js +1 -0
- package/dist/runtime/native-input-files-http.js +1 -0
- package/dist/runtime/native-input-files.js +1 -0
- package/dist/runtime/native-output-file-attempt.js +1 -0
- package/dist/runtime/native-prompt-authority.js +1 -0
- package/dist/runtime/native-prompt-preflight.js +1 -0
- package/dist/runtime/native-session-new-bridge.js +1 -0
- package/dist/runtime/openclaw-runtime-capabilities.js +1 -1
- package/dist/runtime/openclaw-session-model.js +1 -0
- package/dist/runtime/openclaw-session-write-quiescence.js +1 -1
- package/dist/runtime/reply-router.js +1 -1
- package/dist/runtime/runtime-command-dispatcher.js +1 -1
- package/dist/runtime/runtime-command-journal.js +1 -1
- package/dist/runtime/runtime-error-part.js +1 -0
- package/dist/runtime/runtime-local-parity-matrix.js +1 -1
- package/dist/runtime/runtime-message-channel-contract.js +1 -1
- package/dist/runtime/runtime-operation-resource-resolver.js +1 -1
- package/dist/runtime/runtime-parity-manifest-digest.js +1 -1
- package/dist/runtime/runtime-parity-manifest.js +1 -1
- package/dist/runtime/runtime-production-authority.js +1 -1
- package/dist/runtime/runtime-service-contract-compatibility.js +1 -1
- package/dist/runtime/runtime-service-production-candidate.js +1 -1
- package/dist/runtime/runtime-session-control-service.js +1 -1
- package/dist/runtime/runtime-skills-service.js +1 -1
- package/dist/runtime/session-mutation-coordinator.js +1 -1
- package/dist/runtime/session-new-runtime-delivery-bridge.js +1 -1
- package/dist/runtime/session-set-model-mapping.js +1 -1
- package/dist/runtime/write-runtime-failure.js +1 -1
- package/dist/terminal/runtime-terminal-outbound-registration.js +1 -1
- package/dist/terminal/runtime-terminal-service.js +1 -1
- package/dist/terminal/terminal-authority-admission.js +1 -1
- package/dist/terminal/terminal-authority-contract.js +1 -1
- package/dist/terminal/terminal-lease-bound-bridge-client.js +1 -1
- package/dist/upload/desktop-screenshot-tool.js +1 -1
- package/dist/upload/finalize-hook.js +1 -1
- package/dist/upload/native-output-tool-hook.js +1 -0
- package/dist/upload/tool-artifact-enrichment.js +1 -1
- package/dist/upload/tool.js +1 -1
- package/dist/upload/upload-file.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +12 -11
- package/runtime-service-wire-identity.v1.json +12 -12
- package/scripts/runtime-blackbox-worker-main.mjs +5 -2
- package/dist/agent-auth.js +0 -1
- package/dist/bridge-discovery.js +0 -1
- package/dist/mcp-connector-proxy.js +0 -1
- package/dist/runtime/agent-gateway-runtime-attempt-authorization.js +0 -1
- package/dist/runtime/message-service-runtime-invocation-authority.js +0 -1
- package/dist/runtime/message-service-session-reasoning-http-authority.js +0 -1
- package/dist/runtime/openclaw-native-sessions.js +0 -1
- package/dist/runtime/openclaw-question-adapter.js +0 -1
- package/dist/runtime/question-wire.js +0 -1
- package/dist/runtime/runtime-jwks-verifier.js +0 -1
- package/dist/runtime/runtime-reasoning.js +0 -1
- package/dist/runtime/runtime-registration.js +0 -1
- package/dist/runtime/runtime-transport-failure-policy.js +0 -1
- package/dist/runtime/split-runtime-authorization-verifier.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash,randomUUID}from"node:crypto";import{mkdir,writeFile}from"node:fs/promises";import{homedir}from"node:os";import path,{join,relative,resolve}from"node:path";import{RUNTIME_HASH_DOMAINS,RUNTIME_METHOD_PARITY_MANIFEST,runtimeHashPreimage}from"@beeos-ai/beeos-types/runtime";import{reduceRuntimeRecoveryPolicy}from"@beeos-ai/beeos-types/runtime/internal";import{assertTrustedCoreExecutionAttempt}from"./core-execution-attempt-context.js";import{InMemoryRuntimeCommandJournal,RuntimeCommandJournalConflictError,runtimeCommandIsReplayableQuery,runtimeCommandResultHash}from"./runtime-command-journal.js";import{RuntimeProjectionTransportError}from"./agent-projection-worker.js";import{ImHotPathAbortedError}from"./im-hot-path-deferral.js";import{prepareOpenClawToolCatalog}from"./prepare-openclaw-tool-catalog.js";const DEFAULT_AGENT_ID="main",AGENT_VALID_ID_RE=/^[a-z0-9][a-z0-9_-]{0,63}$/i,AGENT_INVALID_CHARS_RE=/[^a-z0-9_-]+/g;export function normalizeRuntimeAgentLocalKey(e){const t=(e??"").trim();return t?AGENT_VALID_ID_RE.test(t)?t.toLowerCase():t.toLowerCase().replace(AGENT_INVALID_CHARS_RE,"-").replace(/^-+/,"").replace(/-+$/,"").slice(0,64)||"main":"main"}export async function awaitRuntimeProjection(e){const t=e;return await(t.awaitProjection?.()??Promise.resolve(e.getSnapshot().projection))}export function hasEffectReceiptHandoff(e){const t=e;return t.effectCommitted instanceof Promise&&"function"==typeof t.acknowledgeEffectReceipt}export class RuntimeCommandError extends Error{code;param;constructor(e,t,r,i){super(t,i),this.code=e,this.param=r,this.name="RuntimeCommandError"}}const emptyProgress=async function*(){};function deferred(){let e;return{promise:new Promise(t=>{e=t}),resolve:e}}async function waitForEffectReceipt(e,t){if(!t)return await e;if(t.aborted)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt was not durably published before the Service attempt ended");await new Promise((r,i)=>{const a=()=>i(new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt was not durably published before the Service attempt ended"));t.addEventListener("abort",a,{once:!0}),e.then(()=>{t.removeEventListener("abort",a),r()},e=>{t.removeEventListener("abort",a),i(e)})})}export class OpenClawRuntimeCommandDispatcher{deps;logger;getOpenclawHome;createAgentId;journal;capabilities;constructor(e){this.deps=e,this.logger=e.logger??{},this.getOpenclawHome=e.getOpenclawHome??(()=>process.env.OPENCLAW_HOME||join(homedir(),".openclaw")),this.createAgentId=e.createAgentId??(()=>`agent-${randomUUID().replace(/-/g,"").slice(0,12)}`),this.journal=e.journal??new InMemoryRuntimeCommandJournal,this.capabilities=e.capabilities}setCapabilities(e){this.capabilities=e}dispatch(e,t){const r=e;assertTrustedCoreExecutionAttempt(t,{operationId:r.context.operationId,runtimeEpoch:r.context.dispatchEpoch});let i,a,n,o="running";const s=deferred(),c=deferred();let m;const d="service"===t.origin&&("mcp.set"===r.name||"mcp.unset"===r.name),p=this.executeWithLease(r,t,(e,t)=>{o="committed",m={operationId:r.context.operationId,method:r.name,record:t},s.resolve({...m,result:e,committedAt:t.updatedAt})},async()=>{d?await waitForEffectReceipt(c.promise,t.abortSignal):"acp"!==t.origin||"mcp.set"!==r.name&&"mcp.unset"!==r.name||!m?.record.mcpDesiredStateCommit||(await this.journal.releaseMcpLiveEffect({operationId:r.context.operationId,source:"acp_local"}),await this.journal.promoteMcpDesiredStateActive({operationId:r.context.operationId,source:"acp_local"}))},d,e=>{i=e},e=>{a=e}).then(e=>(o="committed",e),e=>{throw o=e instanceof RuntimeCommandError&&("OUTCOME_UNKNOWN"===e.code||"INSTANCE_EPOCH_MISMATCH"===e.code)?"outcome_unknown":"failed",s.resolve(void 0),e});return{operationId:r.context.operationId,getSnapshot:()=>({effectState:o,...i?{projection:i}:{}}),completion:p,progress:emptyProgress(),effectCommitted:s.promise,acknowledgeEffectReceipt:async e=>{if(!m||e.operationId!==m.operationId||e.method!==m.method)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt does not match this operation");if(!/^[a-f0-9]{64}$/.test(e.effectRecordHash))throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt hash is invalid");await this.journal.releaseMcpLiveEffect({operationId:e.operationId,source:"service",effectRecordHash:e.effectRecordHash}),c.resolve()},acknowledgeTerminalReceipt:async e=>{if(!(d&&m&&e.operationId===m.operationId&&e.method===m.method&&/^[a-f0-9]{64}$/.test(e.effectRecordHash)&&e.terminalMessageId))throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP terminal receipt does not match this operation");await this.journal.promoteMcpDesiredStateActive({operationId:e.operationId,source:"service",effectRecordHash:e.effectRecordHash,terminalMessageId:e.terminalMessageId});const n=await this.requireReleasedRecord(e.operationId);if(void 0===n.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","active MCP desired state lost its committed result");await this.afterCommittedEffect(r,n.result,n,t,e=>{i=e},e=>{a=e})},cancel:async()=>"running"===o?{status:"cancel_requested"===await(this.capabilities?.cancel?.(r.context.operationId))?"cancel_requested":"not_cancellable"}:{status:"already_terminal"},awaitProjection:async()=>a?(n??=a(),await n):i}}async executeWithLease(e,t,r,i,a,n,o){return await this.withExclusiveLifecycle(e,t.abortSignal,()=>this.executeClaimedLifecycle(e,t,r,i,a,n,o))}async executeClaimedLifecycle(e,t,r,i,a,n,o){const s=await this.deps.leases.claim(e.context.operationId,e.context.dispatchEpoch);if(s.runtimeEpoch!==e.context.dispatchEpoch)throw await this.deps.leases.release(s),new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","runtime operation lease epoch mismatch");const c=this.deps.leases.startHeartbeat(s);try{if(runtimeCommandIsReplayableQuery(e.name))return await this.executeReplayableQuery(e,s,t,r,i);let c;await this.recoverInterruptedCreates(e.context.operationId);try{c=await this.journal.prepare({operationId:e.context.operationId,command:e.name,paramsHash:e.context.paramsHash,runtimeEpoch:s.runtimeEpoch})}catch(e){if(e instanceof RuntimeCommandJournalConflictError)throw new RuntimeCommandError("OUTCOME_UNKNOWN",e.message,void 0,{cause:e});throw e}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&void 0!==c.result){if(r(c.result,c),await i(),c=await this.requireReleasedRecord(c.operationId),void 0===c.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed result disappeared from command journal");return a||await this.afterCommittedEffect(e,c.result,c,t,n,o),c.result}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&"hash_only"===c.resultReceipt?.policy&&runtimeCommandIsReplayableQuery(e.name)){const a=await this.execute(e,s,t);if(runtimeCommandResultHash(a)!==c.resultReceipt.resultHash)throw new RuntimeCommandError("OUTCOME_UNKNOWN","redacted committed query result changed");return r(a,c),await i(),a}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&"hash_only"===c.resultReceipt?.policy){if(r(void 0,c),await i(),c=await this.requireReleasedRecord(c.operationId),!a){if(isRuntimeAgentMutation(e)&&(c.agentProjectionIntent||c.agentProjectionPreparationFailure)){const r=agentProjectionRecoveryResult(c.agentProjectionIntent??c.agentProjectionPreparationFailure);return await this.afterCommittedEffect(e,r,c,t,n,o),r}await this.runAfterEffect(e,void 0,c,t,n)}throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed mutation result is redacted")}if("effect_committed"===c.phase||"projection_committed"===c.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed result receipt is unavailable");if("outcome_unknown"===c.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","previous execution outcome is unknown");if("started"===c.phase&&isRuntimeAgentMutation(e)){let a;try{a=await this.recoverStartedAgentMutation(e,s,t)}catch(e){throw await this.markJournalUnknown(c),e instanceof RuntimeCommandError?e:new RuntimeCommandError("OUTCOME_UNKNOWN",`agent desired-state recovery could not prove its effect: ${errorText(e)}`,void 0,{cause:e})}const m=this.deps.projection?await this.prepareAgentProjectionCommit(e,a,t):void 0,d=await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:"effect_committed",result:a,...m?{agentProjection:m}:{}});return r(a,d),await i(),await this.afterCommittedEffect(e,a,d,t,n,o),this.scheduleJournalCompaction(),a}if("started"===c.phase&&"outcome_unknown"===this.recoveryDecision(e.name,c.phase))throw await this.markJournalUnknown(c),new RuntimeCommandError("OUTCOME_UNKNOWN","imperative action crossed its execution boundary");if("failed"===c.phase)throw new RuntimeCommandError("EXECUTION_FAILED","previous execution failed");"prepared"===c.phase&&(c=await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:"started"}));let m=!1;try{const d=await this.execute(e,s,t);m=!0;const p=isRuntimeAgentMutation(e)&&this.deps.projection?await this.prepareAgentProjectionCommit(e,d,t):void 0;let u;try{const e=await this.requireReleasedRecord(c.operationId);u=await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"effect_committed",result:d,...p?{agentProjection:p}:{}})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`effect completed before its journal commit: ${errorText(e)}`,void 0,{cause:e})}return r(d,u),await i(),u=await this.requireReleasedRecord(u.operationId),a||await this.afterCommittedEffect(e,d,u,t,n,o),this.scheduleJournalCompaction(),d}catch(t){if(m)throw t;const r=t instanceof RuntimeCommandError&&("OUTCOME_UNKNOWN"===t.code||"INSTANCE_EPOCH_MISMATCH"===t.code);if(r&&"clear-saga"===recoveryMetadata(e.name).recoveryClass)throw t;try{await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:r?"outcome_unknown":"failed",errorCode:r?"OUTCOME_UNKNOWN":"EXECUTION_FAILED"})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`command and journal outcome unknown: ${errorText(e)}`,void 0,{cause:t})}throw t}}finally{try{await c.stop(),await this.deps.leases.release(s)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`runtime operation lease finalization unknown: ${errorText(e)}`,void 0,{cause:e})}}}async executeReplayableQuery(e,t,r,i,a){const n=await this.execute(e,t,r);return i(n,{operationId:e.context.operationId,command:e.name,paramsHash:e.context.paramsHash,runtimeEpoch:t.runtimeEpoch,phase:"effect_committed",revision:1,updatedAt:(new Date).toISOString(),resultReceipt:{policy:"hash_only",resultHash:runtimeCommandResultHash(n),redacted:{kind:"query_result",command:e.name}}}),await a(),await this.runPostCommit(e,n),n}scheduleJournalCompaction(){this.journal.compact().catch(e=>this.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=effect_committed error=${errorText(e)}`))}async execute(e,t,r){switch(e.name){case"agent.create":return await this.createAgent(e,t,r);case"agent.update":return await this.updateAgent(e);case"agent.delete":return await this.deleteAgent(e,t);case"agent.applyTemplate":return await this.applyTemplate(e,t,r)}if(!this.capabilities)throw new RuntimeCommandError("INVALID_PARAMS",`Unsupported runtime command: ${e.name}`);return await this.capabilities.execute(e,t,r)}async recoverStartedAgentMutation(e,t,r){if("agent.create"===e.name||"agent.applyTemplate"===e.name){let i=await this.bindCreateOperation(e,t,!1);if(i||(i=await this.findCreateRecoveryIdentity(e,!1),"allocated"===i.state&&void 0===i.createOperation?.paramsHash&&await this.bindCreateOperation(e,t,!1),i=await this.findCreateRecoveryIdentity(e)),"active"===i.state)return await this.recoverActiveCreateEffect(i);if(await this.runtimeAgentExists(i.observedRuntimeLocalKey??i.runtimeLocalKey)){const a={runtimeLocalKey:i.observedRuntimeLocalKey??i.runtimeLocalKey,workspacePath:join(this.getOpenclawHome(),`workspace-${i.runtimeLocalKey}`)};return"agent.create"===e.name?await this.completeCreatedAgent(e,t,r,a):await this.completeTemplateAgent(e,t,r,a)}return await this.execute(e,t,r)}const i=e.context.agent,a=await this.runtimeAgentExists(i.runtimeLocalKey);if("agent.delete"===e.name&&!a)return await this.deps.identities.commitDeleteTombstone(i.runtimeAgentUid,i.runtimeLocalKey,t),{runtimeAgentUid:i.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey};if("agent.update"===e.name&&!a)throw new RuntimeCommandError("OUTCOME_UNKNOWN","update recovery target is absent");return await this.execute(e,t,r)}async runtimeAgentExists(e){const t=await this.requireGateway().request("agents.list",{});if(!Array.isArray(t?.agents))throw new RuntimeCommandError("OUTCOME_UNKNOWN","runtime agent directory query is incomplete");return t.agents.some(t=>null!==t&&"object"==typeof t&&(t.id===e||t.name===e))}async findCreateRecoveryIdentity(e,t=!0){const r={operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash,runtimeAgentUid:e.params.runtimeAgentUid},i=void 0!==this.deps.identities.findCreateOperation,a=i?await this.deps.identities.findCreateOperation(r):(await this.deps.identities.pendingAllocations()).filter(e=>e.operationId===r.operationId&&e.command===r.command&&e.runtimeEpoch===r.runtimeEpoch&&e.runtimeAgentUid===r.runtimeAgentUid);if(1!==a.length)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity binding is missing or ambiguous");const n=a[0];if(i&&(!n.createOperation||t&&n.createOperation.paramsHash!==r.paramsHash||n.createOperation.operationId!==r.operationId||n.createOperation.command!==r.command||n.createOperation.runtimeEpoch!==r.runtimeEpoch))throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity hash binding conflicts");return n}async bindCreateOperation(e,t,r=!0){if(!this.deps.identities.findCreateOperation||!this.deps.identities.bindCreateOperation)return;const i={operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash,runtimeAgentUid:e.params.runtimeAgentUid};try{let a=await this.deps.identities.findCreateOperation(i);if(0===a.length){if(!r)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity binding is missing");if((await this.deps.identities.allocateCreate(t,e.name,e.params.runtimeAgentUid)).runtimeAgentUid!==e.params.runtimeAgentUid)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create allocation UID does not match the canonical command");a=await this.deps.identities.findCreateOperation(i)}if(1!==a.length)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create identity binding is missing or ambiguous");const n=a[0],o=await this.deps.identities.bindCreateOperation(n.runtimeAgentUid,n.runtimeLocalKey,{operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash});if(!o.createOperation||o.runtimeAgentUid!==e.params.runtimeAgentUid||o.createOperation.operationId!==i.operationId||o.createOperation.command!==i.command||o.createOperation.runtimeEpoch!==i.runtimeEpoch||o.createOperation.paramsHash!==i.paramsHash)throw new Error("create operation identity binding changed during compare-and-set");if("tombstoned"===o.state)throw new Error("create operation identity is tombstoned");return o}catch(e){if(e instanceof RuntimeCommandError)throw e;throw new RuntimeCommandError("OUTCOME_UNKNOWN",`create operation identity binding is corrupt: ${errorText(e)}`,void 0,{cause:e})}}async recoverActiveCreateEffect(e){const t=e.observedRuntimeLocalKey??e.runtimeLocalKey;if(!await this.runtimeAgentExists(t))throw new RuntimeCommandError("OUTCOME_UNKNOWN","active create identity is absent from the runtime directory");return{runtimeAgentUid:e.runtimeAgentUid,runtimeLocalKey:t,workspacePath:join(this.getOpenclawHome(),`workspace-${e.runtimeLocalKey}`)}}async markJournalUnknown(e){try{await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"outcome_unknown",errorCode:"OUTCOME_UNKNOWN"})}catch{}}async requireReleasedRecord(e){const t=await this.journal.get(e);if(!t)throw new RuntimeCommandError("OUTCOME_UNKNOWN","command journal record disappeared");return t}async afterCommittedEffect(e,t,r,i,a,n){if(!isRuntimeAgentMutation(e))return void await this.runAfterEffect(e,t,r,i,a);const o=await this.prepareAgentProjection(e,t,r,i,a);o&&(n(o),"acp"===i.origin&&o().catch(e=>this.logger.warn?.(`[runtime-core] deferred ACP agent projection failed: ${errorText(e)}`)))}async prepareAgentProjectionCommit(e,t,r){const i=agentProjectionRecoverySummary(e,t,r);try{const r=await this.deps.projection.prepareCommittedMutation({command:e,result:t,...i.expectedPlatformAgentId?{expectedPlatformAgentId:i.expectedPlatformAgentId}:{}});return Object.freeze({...r,...i})}catch(e){const t=!(e instanceof RuntimeProjectionTransportError)||e.retryable;return this.logger.warn?.(`[runtime-core] agent projection preparation ${t?"deferred":"blocked"}: ${errorText(e)}`),Object.freeze({...i,state:t?"pending":"blocked",errorKind:t?"snapshot_retryable":"snapshot_nonretryable"})}}async prepareAgentProjection(e,t,r,i,a){if("projection_committed"===r.phase)return a(r.projectionReceipt?.snapshot??Object.freeze({state:"synced",revision:`${Math.max(0,r.revision-1)}`})),r.agentProjectionIntent&&await this.compactAgentProjectionReference(r.agentProjectionIntent),void await this.runPostCommit(e,t);if("effect_committed"!==r.phase||!this.deps.projection)return;let n=r,o=n.agentProjectionIntent;const s=n.agentProjectionPreparationFailure;if(o&&"blocked"===n.agentProjectionTerminal?.state)return a(Object.freeze({state:"blocked",revision:n.agentProjectionTerminal.revision})),await this.compactAgentProjectionReference(o),void await this.runPostCommit(e,t);let c;return o&&a(Object.freeze({state:"pending",revision:o.projectionRevision})),async()=>(c??=(async()=>{if(!o){if(!s||"blocked"===s.state)return Object.freeze({state:"blocked",revision:`${Math.max(0,n.revision)}`});const t=await this.prepareAgentProjectionCommit(e,agentProjectionRecoveryResult(s),i);if(!isProjectionIntent(t))return"blocked"===t.state?Object.freeze({state:"blocked",revision:`${Math.max(0,n.revision)}`}):Object.freeze({state:"pending",revision:`${Math.max(0,n.revision)}`});o=t;try{n=await this.journal.recordAgentProjectionIntent({operationId:n.operationId,expectedRevision:n.revision,intent:o})}catch(e){return void this.logger.warn?.(`[runtime-core] agent projection reservation recovery deferred: ${errorText(e)}`)}a(Object.freeze({state:"pending",revision:o.projectionRevision}))}const r=Object.freeze({state:"pending",revision:o.projectionRevision});let c;try{c=await this.deps.projection.applyCommittedMutation(o)}catch(e){this.logger.warn?.(`[runtime-core] agent projection receipt deferred: ${errorText(e)}`),c=r}if(c.revision!==o.projectionRevision&&(c=Object.freeze({state:"blocked",revision:o.projectionRevision})),"synced"===c.state)try{n=await this.journal.transition({operationId:n.operationId,expectedRevision:n.revision,phase:"projection_committed",projectionSnapshot:c}),await this.compactAgentProjectionReference(o)}catch(e){this.logger.warn?.(`[runtime-core] projection phase commit deferred: ${errorText(e)}`),c=Object.freeze({state:"pending",revision:o.projectionRevision})}if("blocked"===c.state)try{n=await this.journal.recordAgentProjectionBlocked({operationId:n.operationId,expectedRevision:n.revision,revision:o.projectionRevision}),await this.compactAgentProjectionReference(o)}catch(e){this.logger.warn?.(`[runtime-core] blocked projection terminal commit deferred: ${errorText(e)}`),c=r}return"synced"===c.state&&c.platformAgentId&&"projection_committed"===n.phase&&this.reportTemplateOriginBestEffort(e,c.platformAgentId),a(c),await this.runPostCommit(e,t),c})(),await c)}async compactAgentProjectionReference(e){if(this.deps.projection)try{await this.deps.projection.compactCommittedMutation(e)}catch(e){this.logger.warn?.(`[runtime-core] projection reference compaction deferred: ${errorText(e)}`)}}reportTemplateOriginBestEffort(e,t){if("agent.applyTemplate"!==e.name||!this.deps.templateOriginReporter)return;const r=e.params.templateId;r&&this.deps.templateOriginReporter.report({platformAgentId:t,templateId:r}).catch(e=>{this.logger.warn?.(`[runtime-core] active template origin report failed, client fallback remains: ${errorText(e)}`)})}async runAfterEffect(e,t,r,i,a){if("projection_committed"===r.phase)return a(r.projectionReceipt?.snapshot??Object.freeze({state:"synced",revision:`${Math.max(0,r.revision-1)}`})),void await this.runPostCommit(e,t);const n="effect_committed"===r.phase&&await this.runProjection(e,t,i),o=!0===n?Object.freeze({state:"synced",revision:`${r.revision}`}):n&&"object"==typeof n?Object.freeze({...n,revision:`${r.revision}`}):"session.setModel"===e.name||"session.setReasoning"===e.name?Object.freeze({state:"pending",revision:`${r.revision}`}):void 0;if("synced"===o?.state)try{const e=o;await this.journal.transition({operationId:r.operationId,expectedRevision:r.revision,phase:"projection_committed",projectionSnapshot:e}),a(o)}catch(e){return this.logger.warn?.(`[runtime-core] projection phase commit deferred: ${errorText(e)}`),void a(Object.freeze({revision:o.revision,state:"pending"}))}else o&&a(o);await this.runPostCommit(e,t)}async runPostCommit(e,t){if(this.capabilities?.afterCommit)try{await this.capabilities.afterCommit(e,t)}catch(e){this.logger.warn?.(`[runtime-core] post-commit action failed: ${errorText(e)}`)}}async runProjection(e,t,r){if(!recoveryMetadata(e.name).projectionRequired)return!1;try{return!isRuntimeAgentMutation(e)&&(await(this.capabilities?.projectCommitted?.(e,t,r))??!1)}catch(e){return this.logger.warn?.(`[runtime-core] agent projection deferred: ${errorText(e)}`),!1}}recoveryDecision(e,t){const r=recoveryMetadata(e);return reduceRuntimeRecoveryPolicy({...r,messageServicePhase:"queued",executionBoundaryCrossed:"prepared"!==t,lineageContinuity:"continuous",journalState:"available",journalPhase:t})}requireGateway(){const e=this.deps.getGateway();if(!e?.isConnected)throw new RuntimeCommandError("GATEWAY_NOT_CONNECTED","Gateway not connected");return e}exclusiveLifecycleReason(e){switch(e.name){case"agent.applyTemplate":return"applyTemplate";case"agent.create":return"createAgent";case"agent.delete":return"deleteAgent";case"agent.update":return"updateAgent";default:return}}async withExclusiveLifecycle(e,t,r){const i=this.exclusiveLifecycleReason(e);if(!i)return await r();if(this.deps.runExclusive)try{return await this.deps.runExclusive(i,r,t)}catch(e){if(e instanceof ImHotPathAbortedError)throw new RuntimeCommandError("INVALID_PARAMS",`${i} aborted while waiting for in-flight chat`);throw e}return await(this.deps.waitForChatIdle?.(i,t)),await r()}async createAgentShell(e,t,r,i,a,n){const o=this.requireGateway(),s=(await this.deps.identities.pendingAllocations()).find(t=>t.runtimeAgentUid===e),c=n??s?.runtimeLocalKey??this.createAgentId(),m=join(this.getOpenclawHome(),`workspace-${c}`);let d;try{d=await o.request("agents.create",{name:c,workspace:m,...a?{model:a}:{},...i?.emoji?{emoji:i.emoji}:{},...i?.avatar?{avatar:i.avatar}:{}})}catch(r){if(isDeterministicAgentsCreateParamsRejection(r)&&(void 0!==n||void 0!==s))try{await this.deps.identities.tombstone(e,c,t)}catch(e){this.logger.warn?.(`[runtime-core] rejected-create allocation cleanup deferred: ${errorText(e)}`)}throw r}const p=d?.agentId??c,u=d?.workspace??m;if(await this.deps.identities.observeEffectKey(e,c,p,t),p!==c)throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Create agent outcome unknown: gateway changed reserved local key to ${p}`);try{await o.request("agents.update",{agentId:p,name:r})}catch(e){this.logger.warn?.(`[runtime-core] display-name update failed agent=${p}: ${errorText(e)}`)}return{runtimeLocalKey:p,workspacePath:u}}async createAgent(e,t,r){const i=e.params.name.trim();if(!i)throw new RuntimeCommandError("INVALID_PARAMS","Missing agent name");try{const a=await this.bindCreateOperation(e,t);if("active"===a?.state)return await this.recoverActiveCreateEffect(a);const n=await this.createAgentShell(e.params.runtimeAgentUid,t,i,e.params.identity,e.params.defaultModelId,a?.runtimeLocalKey);return await this.completeCreatedAgent(e,t,r,n)}catch(e){throw this.executionError("Create agent",e)}}async updateAgent(e){const{runtimeAgentUid:t,runtimeLocalKey:r}=e.context.agent;if(!r.trim())throw new RuntimeCommandError("MISSING_PARAM","Missing agentId","agentId");const i=e.params,a=i.name?.trim(),n=i.defaultModelId?.trim(),o=i.identity?.emoji?.trim(),s=i.identity?.avatar?.trim();if(!(a||n||o||s||void 0!==i.description||void 0!==i.version||void 0!==i.capabilities||void 0!==i.skills||void 0!==i.avatarUrl||void 0!==i.homepage||void 0!==i.status||void 0!==i.identity?.vibe))throw new RuntimeCommandError("INVALID_PARAMS","No updatable fields provided (name/model/identity)");try{return await this.deps.identities.requireActive(t,r),await this.requireGateway().request("agents.update",{agentId:r,...a?{name:a}:{},...n?{model:n}:{},...o?{emoji:o}:{},...s?{avatar:s}:{},...i.identity?.vibe?{vibe:i.identity.vibe}:{},...void 0!==i.description?{description:i.description}:{},...void 0!==i.version?{version:i.version}:{},...void 0!==i.capabilities?{capabilities:i.capabilities}:{},...void 0!==i.skills?{skills:i.skills}:{},...void 0!==i.avatarUrl?{avatarUrl:i.avatarUrl}:{},...void 0!==i.homepage?{homepage:i.homepage}:{},...void 0!==i.status?{status:i.status}:{}}),{runtimeAgentUid:t,runtimeLocalKey:r}}catch(e){throw this.executionError("Update agent",e)}}async deleteAgent(e,t){const{runtimeAgentUid:r,runtimeLocalKey:i}=e.context.agent;if(!i.trim())throw new RuntimeCommandError("MISSING_PARAM","Missing agentId","agentId");if("main"===normalizeRuntimeAgentLocalKey(i))throw new RuntimeCommandError("INVALID_PARAMS",'"main" cannot be deleted; delete the instance instead');try{if("tombstoned"===await this.deps.identities.requireDeleteTarget(r,i))return{runtimeAgentUid:r,runtimeLocalKey:i};if(!await this.runtimeAgentExists(i))return await this.deps.identities.commitDeleteTombstone(r,i,t),{runtimeAgentUid:r,runtimeLocalKey:i};const a=requireCommittedOpenClawDeleteAck(await this.requireGateway().request("agents.delete",{agentId:i,deleteFiles:e.params.deleteFiles??!0}),i);try{await this.deps.identities.commitDeleteTombstone(r,i,t)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Delete agent outcome unknown: identity tombstone failed: ${errorText(e)}`,void 0,{cause:e})}return{runtimeAgentUid:r,runtimeLocalKey:i,...void 0===a.removedBindings?{}:{removedBindings:a.removedBindings}}}catch(e){throw this.executionError("Delete agent",e)}}async applyTemplate(e,t,r){const i=e.params.name.trim();if(!i)throw new RuntimeCommandError("INVALID_PARAMS","Missing agent name");this.requireGateway();try{const a=await this.bindCreateOperation(e,t);if("active"===a?.state)return await this.recoverActiveCreateEffect(a);const n=await r.resources.readVerifiedArtifact(e.params.artifact),o=await this.createAgentShell(e.params.runtimeAgentUid,t,i,e.params.identity,e.params.defaultModelId,a?.runtimeLocalKey);return await this.completeTemplateAgent(e,t,r,o,n)}catch(e){throw this.executionError("Apply template",e)}}async completeCreatedAgent(e,t,r,i){for(const t of e.params.bootstrapFiles??[]){if("IDENTITY.md"===t.name){this.logger.warn?.("[runtime-core] agent.create ignoring IDENTITY.md; identity is structured");continue}const e=await r.resources.readContent(t.contentRef);try{await this.requireGateway().request("agents.files.set",{agentId:i.runtimeLocalKey,name:t.name,content:e})}catch(e){this.logger.warn?.(`[runtime-core] bootstrap write failed file=${t.name}: ${errorText(e)}`)}}try{await this.deps.identities.activate(e.params.runtimeAgentUid,i.runtimeLocalKey,t)}catch(r){throw await this.compensateCreatedAgent(e.params.runtimeAgentUid,i.runtimeLocalKey,t,r,"Create agent"),new RuntimeCommandError("EXECUTION_FAILED",`Create agent failed after compensation: ${errorText(r)}`)}return await this.prepareAgentToolCatalog(i.runtimeLocalKey),{runtimeAgentUid:e.params.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,workspacePath:i.workspacePath}}async completeTemplateAgent(e,t,r,i,a){const n=a??await r.resources.readVerifiedArtifact(e.params.artifact);try{for(const[e,t]of n.workspaceFiles){const r=resolve(i.workspacePath,e),a=relative(i.workspacePath,r);if(""===a||a.startsWith("..")||path.isAbsolute(a))throw new Error(`refusing to write outside workspace: ${e}`);await(this.deps.mkdirWorkspace??mkdir)(path.dirname(r),{recursive:!0}),await(this.deps.writeWorkspaceFile??writeFile)(r,t)}await this.deps.identities.activate(e.params.runtimeAgentUid,i.runtimeLocalKey,t)}catch(r){throw await this.compensateCreatedAgent(e.params.runtimeAgentUid,i.runtimeLocalKey,t,r,"Apply template"),new RuntimeCommandError("EXECUTION_FAILED",`Apply template failed after compensation: ${errorText(r)}`,void 0,{cause:r})}return await this.prepareAgentToolCatalog(i.runtimeLocalKey),{runtimeAgentUid:e.params.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,workspacePath:i.workspacePath}}async prepareAgentToolCatalog(e){await prepareOpenClawToolCatalog({request:(e,t)=>this.requireGateway().request(e,t),agentId:e,mode:"catalog",keyKind:"boot",logger:this.logger})}executionError(e,t){return t instanceof RuntimeCommandError?t:(this.logger.error?.(`[runtime-core] ${e.toLowerCase()} failed: ${errorText(t)}`),new RuntimeCommandError("EXECUTION_FAILED",`${e} failed: ${errorText(t)}`,void 0,{cause:t}))}async compensateCreatedAgent(e,t,r,i,a){try{const i=this.requireGateway();requireCommittedOpenClawDeleteAck(await i.request("agents.delete",{agentId:t,deleteFiles:!0}),t),await this.deps.identities.tombstone(e,t,r)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`${a} outcome unknown after ${errorText(i)}; compensation unproven: ${errorText(e)}`,void 0,{cause:e})}}async recoverInterruptedCreates(e){const t=await this.deps.identities.pendingAllocations();for(const r of t){if(r.operationId===e)continue;const t=await this.deps.leases.claimExpiredForRecovery(r.operationId);if(!t)continue;const i=this.deps.leases.startHeartbeat(t);try{await this.deps.identities.adoptRecoveryLease(r.runtimeAgentUid,r.runtimeLocalKey,t);const e=r.observedRuntimeLocalKey;if(!e){const e=r.createOperation?.operationId??r.operationId,i=await this.journal.get(e);if("failed"===i?.phase&&i.command===r.command&&!await this.runtimeAgentExists(r.runtimeLocalKey)){await this.deps.identities.tombstone(r.runtimeAgentUid,r.runtimeLocalKey,t);continue}throw new Error("no persisted gateway effect key; absence cannot be proven")}requireCommittedOpenClawDeleteAck(await this.requireGateway().request("agents.delete",{agentId:e,deleteFiles:!0}),e),await this.deps.identities.tombstone(r.runtimeAgentUid,r.runtimeLocalKey,t)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Interrupted ${r.command} recovery outcome unknown for operation ${r.operationId}: ${errorText(e)}`,void 0,{cause:e})}finally{let e;try{await i.stop()}catch(t){e=t}try{await this.deps.leases.release(t)}catch(t){e??=t}if(e)throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Interrupted recovery lease finalization unknown: ${errorText(e)}`,void 0,{cause:e})}}}}function isRuntimeAgentMutation(e){return"agent.create"===e.name||"agent.update"===e.name||"agent.delete"===e.name||"agent.applyTemplate"===e.name}function servicePlatformAgentId(e){const t=e.verifiedMessageGrant?.claims;return"agent"===t?.scope?t.platformAgentId:void 0}function agentCoreResultHash(e,t){return createHash("sha256").update(runtimeHashPreimage(RUNTIME_HASH_DOMAINS.coreResult,{method:e.name.replace(".","/"),result:t})).digest("hex")}function agentProjectionRecoverySummary(e,t,r){const i="agent.update"===e.name||"agent.delete"===e.name?e.context.agent:createProjectionTarget(e,t),a=t;return Object.freeze({schemaVersion:1,operationId:e.context.operationId,method:e.name,runtimeEpoch:e.context.dispatchEpoch,runtimeAgentUid:i.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,coreResultHash:agentCoreResultHash(e,t),...servicePlatformAgentId(r)?{expectedPlatformAgentId:servicePlatformAgentId(r)}:{},..."agent.delete"===e.name&&Number.isSafeInteger(a?.removedBindings)?{removedBindings:a.removedBindings}:{}})}function createProjectionTarget(e,t){const r=t;if(!r||r.runtimeAgentUid!==e.params.runtimeAgentUid||"string"!=typeof r.runtimeLocalKey||!r.runtimeLocalKey)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed agent effect lacks a recoverable local identity");return{runtimeAgentUid:r.runtimeAgentUid,runtimeLocalKey:r.runtimeLocalKey}}function agentProjectionRecoveryResult(e){return Object.freeze({runtimeAgentUid:e.runtimeAgentUid,runtimeLocalKey:e.runtimeLocalKey,...void 0===e.removedBindings?{}:{removedBindings:e.removedBindings}})}function isProjectionIntent(e){return"projectionRevision"in e}function recoveryMetadata(e){const t=RUNTIME_METHOD_PARITY_MANIFEST.filter(t=>t.serviceAllowed&&t.canonicalCommand===e),r=t[0]?.recoveryClass;return r?{recoveryClass:r,projectionRequired:"mcp.set"===e||"mcp.unset"===e||t.some(e=>!0===e.projectionRequired)}:{recoveryClass:"imperative-ambiguous",projectionRequired:!1}}export function isDeterministicAgentsCreateParamsRejection(e){return e instanceof Error&&/^invalid agents\.create params\b/.test(e.message)}export function requireCommittedOpenClawDeleteAck(e,t){if(!e||"object"!=typeof e)throw new Error("gateway delete lacks the committed target acknowledgement");const r=e,i=Object.keys(r).every(e=>"ok"===e||"agentId"===e||"removedBindings"===e),a=void 0===r.removedBindings||Number.isSafeInteger(r.removedBindings)&&r.removedBindings>=0;if(!i||!0!==r.ok||r.agentId!==t||!a)throw new Error("gateway delete lacks the committed target acknowledgement");return{ok:!0,agentId:t,...void 0===r.removedBindings?{}:{removedBindings:r.removedBindings}}}function errorText(e){return e instanceof Error?e.message:String(e)}
|
|
1
|
+
import{createHash,randomUUID}from"node:crypto";import{mkdir,writeFile}from"node:fs/promises";import{homedir}from"node:os";import path,{join,relative,resolve}from"node:path";import{RUNTIME_HASH_DOMAINS,RUNTIME_METHOD_PARITY_MANIFEST,runtimeHashPreimage}from"@beeos-ai/beeos-types/runtime";import{reduceRuntimeRecoveryPolicy}from"@beeos-ai/beeos-types/runtime/internal";import{assertTrustedCoreExecutionAttempt}from"./core-execution-attempt-context.js";import{InMemoryRuntimeCommandJournal,RuntimeCommandJournalConflictError,runtimeCommandIsReplayableQuery,runtimeCommandResultHash}from"./runtime-command-journal.js";import{RuntimeProjectionTransportError}from"./agent-projection-worker.js";import{ImHotPathAbortedError}from"./im-hot-path-deferral.js";import{prepareOpenClawToolCatalog}from"./prepare-openclaw-tool-catalog.js";const DEFAULT_AGENT_ID="main",AGENT_VALID_ID_RE=/^[a-z0-9][a-z0-9_-]{0,63}$/i,AGENT_INVALID_CHARS_RE=/[^a-z0-9_-]+/g;export function normalizeRuntimeAgentLocalKey(e){const t=(e??"").trim();return t?AGENT_VALID_ID_RE.test(t)?t.toLowerCase():t.toLowerCase().replace(AGENT_INVALID_CHARS_RE,"-").replace(/^-+/,"").replace(/-+$/,"").slice(0,64)||"main":"main"}export async function awaitRuntimeProjection(e){const t=e;return await(t.awaitProjection?.()??Promise.resolve(e.getSnapshot().projection))}export function hasEffectReceiptHandoff(e){const t=e;return t.effectCommitted instanceof Promise&&"function"==typeof t.acknowledgeEffectReceipt}export class RuntimeCommandError extends Error{code;param;constructor(e,t,r,i){super(t,i),this.code=e,this.param=r,this.name="RuntimeCommandError"}}const emptyProgress=async function*(){};function deferred(){let e;return{promise:new Promise(t=>{e=t}),resolve:e}}async function waitForEffectReceipt(e,t){if(!t)return await e;if(t.aborted)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt was not durably published before the Service attempt ended");await new Promise((r,i)=>{const a=()=>i(new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt was not durably published before the Service attempt ended"));t.addEventListener("abort",a,{once:!0}),e.then(()=>{t.removeEventListener("abort",a),r()},e=>{t.removeEventListener("abort",a),i(e)})})}export class OpenClawRuntimeCommandDispatcher{deps;logger;getOpenclawHome;createAgentId;journal;capabilities;constructor(e){this.deps=e,this.logger=e.logger??{},this.getOpenclawHome=e.getOpenclawHome??(()=>process.env.OPENCLAW_HOME||join(homedir(),".openclaw")),this.createAgentId=e.createAgentId??(()=>`agent-${randomUUID().replace(/-/g,"").slice(0,12)}`),this.journal=e.journal??new InMemoryRuntimeCommandJournal,this.capabilities=e.capabilities}setCapabilities(e){this.capabilities=e}dispatch(e,t){const r=e;assertTrustedCoreExecutionAttempt(t,{operationId:r.context.operationId,runtimeEpoch:r.context.dispatchEpoch});let i,a,n,o="running";const s=deferred(),c=deferred();let m;const d="service"===t.origin&&("mcp.set"===r.name||"mcp.unset"===r.name),p=this.executeWithLease(r,t,(e,t)=>{o="committed",m={operationId:r.context.operationId,method:r.name,record:t},s.resolve({...m,result:e,committedAt:t.updatedAt})},async()=>{d?await waitForEffectReceipt(c.promise,t.abortSignal):"acp"!==t.origin||"mcp.set"!==r.name&&"mcp.unset"!==r.name||!m?.record.mcpDesiredStateCommit||(await this.journal.releaseMcpLiveEffect({operationId:r.context.operationId,source:"acp_local"}),await this.journal.promoteMcpDesiredStateActive({operationId:r.context.operationId,source:"acp_local"}))},d,e=>{i=e},e=>{a=e}).then(e=>(o="committed",e),e=>{throw o=e instanceof RuntimeCommandError&&("OUTCOME_UNKNOWN"===e.code||"INSTANCE_EPOCH_MISMATCH"===e.code)?"outcome_unknown":"failed",s.resolve(void 0),e});return{operationId:r.context.operationId,getSnapshot:()=>({effectState:o,...i?{projection:i}:{}}),completion:p,progress:emptyProgress(),effectCommitted:s.promise,acknowledgeEffectReceipt:async e=>{if(!m||e.operationId!==m.operationId||e.method!==m.method)throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt does not match this operation");if(!/^[a-f0-9]{64}$/.test(e.effectRecordHash))throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP effect receipt hash is invalid");await this.journal.releaseMcpLiveEffect({operationId:e.operationId,source:"service",effectRecordHash:e.effectRecordHash}),c.resolve()},acknowledgeTerminalReceipt:async e=>{if(!(d&&m&&e.operationId===m.operationId&&e.method===m.method&&/^[a-f0-9]{64}$/.test(e.effectRecordHash)&&e.terminalMessageId))throw new RuntimeCommandError("OUTCOME_UNKNOWN","MCP terminal receipt does not match this operation");await this.journal.promoteMcpDesiredStateActive({operationId:e.operationId,source:"service",effectRecordHash:e.effectRecordHash,terminalMessageId:e.terminalMessageId});const n=await this.requireReleasedRecord(e.operationId);if(void 0===n.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","active MCP desired state lost its committed result");await this.afterCommittedEffect(r,n.result,n,t,e=>{i=e},e=>{a=e})},cancel:async()=>"running"===o?{status:"cancel_requested"===await(this.capabilities?.cancel?.(r.context.operationId))?"cancel_requested":"not_cancellable"}:{status:"already_terminal"},awaitProjection:async()=>a?(n??=a(),await n):i}}async executeWithLease(e,t,r,i,a,n,o){return await this.withExclusiveLifecycle(e,t.abortSignal,()=>this.executeClaimedLifecycle(e,t,r,i,a,n,o))}async executeClaimedLifecycle(e,t,r,i,a,n,o){const s=await this.deps.leases.claim(e.context.operationId,e.context.dispatchEpoch);if(s.runtimeEpoch!==e.context.dispatchEpoch)throw await this.deps.leases.release(s),new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","runtime operation lease epoch mismatch");const c=this.deps.leases.startHeartbeat(s);try{if(runtimeCommandIsReplayableQuery(e.name))return await this.executeReplayableQuery(e,s,t,r,i);let c;await this.recoverInterruptedCreates(e.context.operationId);try{c=await this.journal.prepare({operationId:e.context.operationId,command:e.name,paramsHash:e.context.paramsHash,runtimeEpoch:s.runtimeEpoch})}catch(e){if(e instanceof RuntimeCommandJournalConflictError)throw new RuntimeCommandError("OUTCOME_UNKNOWN",e.message,void 0,{cause:e});throw e}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&void 0!==c.result){if(r(c.result,c),await i(),c=await this.requireReleasedRecord(c.operationId),void 0===c.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed result disappeared from command journal");return a||await this.afterCommittedEffect(e,c.result,c,t,n,o),c.result}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&"hash_only"===c.resultReceipt?.policy&&runtimeCommandIsReplayableQuery(e.name)){const a=await this.execute(e,s,t);if(runtimeCommandResultHash(a)!==c.resultReceipt.resultHash)throw new RuntimeCommandError("OUTCOME_UNKNOWN","redacted committed query result changed");return r(a,c),await i(),a}if(("effect_committed"===c.phase||"projection_committed"===c.phase)&&"hash_only"===c.resultReceipt?.policy){if(r(void 0,c),await i(),c=await this.requireReleasedRecord(c.operationId),!a){if(isRuntimeAgentMutation(e)&&(c.agentProjectionIntent||c.agentProjectionPreparationFailure)){const r=agentProjectionRecoveryResult(c.agentProjectionIntent??c.agentProjectionPreparationFailure);return await this.afterCommittedEffect(e,r,c,t,n,o),r}await this.runAfterEffect(e,void 0,c,t,n)}throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed mutation result is redacted")}if("effect_committed"===c.phase||"projection_committed"===c.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed result receipt is unavailable");if("outcome_unknown"===c.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","previous execution outcome is unknown");if("started"===c.phase&&isRuntimeAgentMutation(e)){let a;try{a=await this.recoverStartedAgentMutation(e,s,t)}catch(e){throw await this.markJournalUnknown(c),e instanceof RuntimeCommandError?e:new RuntimeCommandError("OUTCOME_UNKNOWN",`agent desired-state recovery could not prove its effect: ${errorText(e)}`,void 0,{cause:e})}const m=this.deps.projection?await this.prepareAgentProjectionCommit(e,a,t):void 0,d=await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:"effect_committed",result:a,...m?{agentProjection:m}:{}});return r(a,d),await i(),await this.afterCommittedEffect(e,a,d,t,n,o),this.scheduleJournalCompaction(),a}if("started"===c.phase&&"outcome_unknown"===this.recoveryDecision(e.name,c.phase))throw await this.markJournalUnknown(c),new RuntimeCommandError("OUTCOME_UNKNOWN","imperative action crossed its execution boundary");if("failed"===c.phase)throw new RuntimeCommandError("EXECUTION_FAILED","previous execution failed");"prepared"===c.phase&&(c=await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:"started"}));let m=!1;try{const d=await this.execute(e,s,t);m=!0;const p=isRuntimeAgentMutation(e)&&this.deps.projection?await this.prepareAgentProjectionCommit(e,d,t):void 0;let u;try{const e=await this.requireReleasedRecord(c.operationId);u=await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"effect_committed",result:d,...p?{agentProjection:p}:{}})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`effect completed before its journal commit: ${errorText(e)}`,void 0,{cause:e})}return r(d,u),await i(),u=await this.requireReleasedRecord(u.operationId),a||await this.afterCommittedEffect(e,d,u,t,n,o),this.scheduleJournalCompaction(),d}catch(t){if(m)throw t;const r=t instanceof RuntimeCommandError&&("OUTCOME_UNKNOWN"===t.code||"INSTANCE_EPOCH_MISMATCH"===t.code);if(r&&"clear-saga"===recoveryMetadata(e.name).recoveryClass)throw t;try{await this.journal.transition({operationId:c.operationId,expectedRevision:c.revision,phase:r?"outcome_unknown":"failed",errorCode:r?"OUTCOME_UNKNOWN":"EXECUTION_FAILED"})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`command and journal outcome unknown: ${errorText(e)}`,void 0,{cause:t})}throw t}}finally{try{await c.stop(),await this.deps.leases.release(s)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`runtime operation lease finalization unknown: ${errorText(e)}`,void 0,{cause:e})}}}async executeReplayableQuery(e,t,r,i,a){const n=await this.execute(e,t,r);return i(n,{operationId:e.context.operationId,command:e.name,paramsHash:e.context.paramsHash,runtimeEpoch:t.runtimeEpoch,phase:"effect_committed",revision:1,updatedAt:(new Date).toISOString(),resultReceipt:{policy:"hash_only",resultHash:runtimeCommandResultHash(n),redacted:{kind:"query_result",command:e.name}}}),await a(),await this.runPostCommit(e,n),n}scheduleJournalCompaction(){this.journal.compact().catch(e=>this.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=effect_committed error=${errorText(e)}`))}async execute(e,t,r){switch(e.name){case"agent.create":return await this.createAgent(e,t,r);case"agent.update":return await this.updateAgent(e);case"agent.delete":return await this.deleteAgent(e,t);case"agent.applyTemplate":return await this.applyTemplate(e,t,r)}if(!this.capabilities)throw new RuntimeCommandError("INVALID_PARAMS",`Unsupported runtime command: ${e.name}`);return await this.capabilities.execute(e,t,r)}async recoverStartedAgentMutation(e,t,r){if("agent.create"===e.name||"agent.applyTemplate"===e.name){let i=await this.bindCreateOperation(e,t,!1);if(i||(i=await this.findCreateRecoveryIdentity(e,!1),"allocated"===i.state&&void 0===i.createOperation?.paramsHash&&await this.bindCreateOperation(e,t,!1),i=await this.findCreateRecoveryIdentity(e)),"active"===i.state)return await this.recoverActiveCreateEffect(i);if(await this.runtimeAgentExists(i.observedRuntimeLocalKey??i.runtimeLocalKey)){const a={runtimeLocalKey:i.observedRuntimeLocalKey??i.runtimeLocalKey,workspacePath:join(this.getOpenclawHome(),`workspace-${i.runtimeLocalKey}`)};return"agent.create"===e.name?await this.completeCreatedAgent(e,t,r,a):await this.completeTemplateAgent(e,t,r,a)}return await this.execute(e,t,r)}const i=e.context.agent,a=await this.runtimeAgentExists(i.runtimeLocalKey);if("agent.delete"===e.name&&!a)return await this.deps.identities.commitDeleteTombstone(i.runtimeAgentUid,i.runtimeLocalKey,t),{runtimeAgentUid:i.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey};if("agent.update"===e.name&&!a)throw new RuntimeCommandError("OUTCOME_UNKNOWN","update recovery target is absent");return await this.execute(e,t,r)}async runtimeAgentExists(e){const t=await this.requireGateway().request("agents.list",{});if(!Array.isArray(t?.agents))throw new RuntimeCommandError("OUTCOME_UNKNOWN","runtime agent directory query is incomplete");return t.agents.some(t=>null!==t&&"object"==typeof t&&(t.id===e||t.name===e))}async findCreateRecoveryIdentity(e,t=!0){const r={operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash,runtimeAgentUid:e.params.runtimeAgentUid},i=void 0!==this.deps.identities.findCreateOperation,a=i?await this.deps.identities.findCreateOperation(r):(await this.deps.identities.pendingAllocations()).filter(e=>e.operationId===r.operationId&&e.command===r.command&&e.runtimeEpoch===r.runtimeEpoch&&e.runtimeAgentUid===r.runtimeAgentUid);if(1!==a.length)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity binding is missing or ambiguous");const n=a[0];if(i&&(!n.createOperation||t&&n.createOperation.paramsHash!==r.paramsHash||n.createOperation.operationId!==r.operationId||n.createOperation.command!==r.command||n.createOperation.runtimeEpoch!==r.runtimeEpoch))throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity hash binding conflicts");return n}async bindCreateOperation(e,t,r=!0){if(!this.deps.identities.findCreateOperation||!this.deps.identities.bindCreateOperation)return;const i={operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash,runtimeAgentUid:e.params.runtimeAgentUid};try{let a=await this.deps.identities.findCreateOperation(i);if(0===a.length){if(!r)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create recovery identity binding is missing");if((await this.deps.identities.allocateCreate(t,e.name,e.params.runtimeAgentUid)).runtimeAgentUid!==e.params.runtimeAgentUid)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create allocation UID does not match the canonical command");a=await this.deps.identities.findCreateOperation(i)}if(1!==a.length)throw new RuntimeCommandError("OUTCOME_UNKNOWN","create identity binding is missing or ambiguous");const n=a[0],o=await this.deps.identities.bindCreateOperation(n.runtimeAgentUid,n.runtimeLocalKey,{operationId:e.context.operationId,command:e.name,runtimeEpoch:e.context.dispatchEpoch,paramsHash:e.context.paramsHash});if(!o.createOperation||o.runtimeAgentUid!==e.params.runtimeAgentUid||o.createOperation.operationId!==i.operationId||o.createOperation.command!==i.command||o.createOperation.runtimeEpoch!==i.runtimeEpoch||o.createOperation.paramsHash!==i.paramsHash)throw new Error("create operation identity binding changed during compare-and-set");if("tombstoned"===o.state)throw new Error("create operation identity is tombstoned");return o}catch(e){if(e instanceof RuntimeCommandError)throw e;throw new RuntimeCommandError("OUTCOME_UNKNOWN",`create operation identity binding is corrupt: ${errorText(e)}`,void 0,{cause:e})}}async recoverActiveCreateEffect(e){const t=e.observedRuntimeLocalKey??e.runtimeLocalKey;if(!await this.runtimeAgentExists(t))throw new RuntimeCommandError("OUTCOME_UNKNOWN","active create identity is absent from the runtime directory");return{runtimeAgentUid:e.runtimeAgentUid,runtimeLocalKey:t,workspacePath:join(this.getOpenclawHome(),`workspace-${e.runtimeLocalKey}`)}}async markJournalUnknown(e){try{await this.journal.transition({operationId:e.operationId,expectedRevision:e.revision,phase:"outcome_unknown",errorCode:"OUTCOME_UNKNOWN"})}catch{}}async requireReleasedRecord(e){const t=await this.journal.get(e);if(!t)throw new RuntimeCommandError("OUTCOME_UNKNOWN","command journal record disappeared");return t}async afterCommittedEffect(e,t,r,i,a,n){if(!isRuntimeAgentMutation(e))return void await this.runAfterEffect(e,t,r,i,a);const o=await this.prepareAgentProjection(e,t,r,i,a);o&&(n(o),"acp"===i.origin&&o().catch(e=>this.logger.warn?.(`[runtime-core] deferred ACP agent projection failed: ${errorText(e)}`)))}async prepareAgentProjectionCommit(e,t,r){const i=agentProjectionRecoverySummary(e,t,r);try{const r=await this.deps.projection.prepareCommittedMutation({command:e,result:t,...i.expectedPlatformAgentId?{expectedPlatformAgentId:i.expectedPlatformAgentId}:{}});return Object.freeze({...r,...i})}catch(e){const t=!(e instanceof RuntimeProjectionTransportError)||e.retryable;return this.logger.warn?.(`[runtime-core] agent projection preparation ${t?"deferred":"blocked"}: ${errorText(e)}`),Object.freeze({...i,state:t?"pending":"blocked",errorKind:t?"snapshot_retryable":"snapshot_nonretryable"})}}async prepareAgentProjection(e,t,r,i,a){if("projection_committed"===r.phase)return a(r.projectionReceipt?.snapshot??Object.freeze({state:"synced",revision:`${Math.max(0,r.revision-1)}`})),r.agentProjectionIntent&&await this.compactAgentProjectionReference(r.agentProjectionIntent),void await this.runPostCommit(e,t);if("effect_committed"!==r.phase||!this.deps.projection)return;let n=r,o=n.agentProjectionIntent;const s=n.agentProjectionPreparationFailure;if(o&&"blocked"===n.agentProjectionTerminal?.state)return a(Object.freeze({state:"blocked",revision:n.agentProjectionTerminal.revision})),await this.compactAgentProjectionReference(o),void await this.runPostCommit(e,t);let c;return o&&a(Object.freeze({state:"pending",revision:o.projectionRevision})),async()=>(c??=(async()=>{if(!o){if(!s||"blocked"===s.state)return Object.freeze({state:"blocked",revision:`${Math.max(0,n.revision)}`});const t=await this.prepareAgentProjectionCommit(e,agentProjectionRecoveryResult(s),i);if(!isProjectionIntent(t))return"blocked"===t.state?Object.freeze({state:"blocked",revision:`${Math.max(0,n.revision)}`}):Object.freeze({state:"pending",revision:`${Math.max(0,n.revision)}`});o=t;try{n=await this.journal.recordAgentProjectionIntent({operationId:n.operationId,expectedRevision:n.revision,intent:o})}catch(e){return void this.logger.warn?.(`[runtime-core] agent projection reservation recovery deferred: ${errorText(e)}`)}a(Object.freeze({state:"pending",revision:o.projectionRevision}))}const r=Object.freeze({state:"pending",revision:o.projectionRevision});let c;try{c=await this.deps.projection.applyCommittedMutation(o)}catch(e){this.logger.warn?.(`[runtime-core] agent projection receipt deferred: ${errorText(e)}`),c=r}if(c.revision!==o.projectionRevision&&(c=Object.freeze({state:"blocked",revision:o.projectionRevision})),"synced"===c.state)try{n=await this.journal.transition({operationId:n.operationId,expectedRevision:n.revision,phase:"projection_committed",projectionSnapshot:c}),await this.compactAgentProjectionReference(o)}catch(e){this.logger.warn?.(`[runtime-core] projection phase commit deferred: ${errorText(e)}`),c=Object.freeze({state:"pending",revision:o.projectionRevision})}if("blocked"===c.state)try{n=await this.journal.recordAgentProjectionBlocked({operationId:n.operationId,expectedRevision:n.revision,revision:o.projectionRevision}),await this.compactAgentProjectionReference(o)}catch(e){this.logger.warn?.(`[runtime-core] blocked projection terminal commit deferred: ${errorText(e)}`),c=r}return"synced"===c.state&&c.platformAgentId&&"projection_committed"===n.phase&&this.reportTemplateOriginBestEffort(e,c.platformAgentId),a(c),await this.runPostCommit(e,t),c})(),await c)}async compactAgentProjectionReference(e){if(this.deps.projection)try{await this.deps.projection.compactCommittedMutation(e)}catch(e){this.logger.warn?.(`[runtime-core] projection reference compaction deferred: ${errorText(e)}`)}}reportTemplateOriginBestEffort(e,t){if("agent.applyTemplate"!==e.name||!this.deps.templateOriginReporter)return;const r=e.params.templateId;r&&this.deps.templateOriginReporter.report({platformAgentId:t,templateId:r}).catch(e=>{this.logger.warn?.(`[runtime-core] active template origin report failed, client fallback remains: ${errorText(e)}`)})}async runAfterEffect(e,t,r,i,a){if("projection_committed"===r.phase)return a(r.projectionReceipt?.snapshot??Object.freeze({state:"synced",revision:`${Math.max(0,r.revision-1)}`})),void await this.runPostCommit(e,t);const n="effect_committed"===r.phase&&await this.runProjection(e,t,i),o=!0===n?Object.freeze({state:"synced",revision:`${r.revision}`}):n&&"object"==typeof n?Object.freeze({...n,revision:`${r.revision}`}):"session.setModel"===e.name?Object.freeze({state:"pending",revision:`${r.revision}`}):void 0;if("synced"===o?.state)try{const e=o;await this.journal.transition({operationId:r.operationId,expectedRevision:r.revision,phase:"projection_committed",projectionSnapshot:e}),a(o)}catch(e){return this.logger.warn?.(`[runtime-core] projection phase commit deferred: ${errorText(e)}`),void a(Object.freeze({revision:o.revision,state:"pending"}))}else o&&a(o);await this.runPostCommit(e,t)}async runPostCommit(e,t){if(this.capabilities?.afterCommit)try{await this.capabilities.afterCommit(e,t)}catch(e){this.logger.warn?.(`[runtime-core] post-commit action failed: ${errorText(e)}`)}}async runProjection(e,t,r){if(!recoveryMetadata(e.name).projectionRequired)return!1;try{return!isRuntimeAgentMutation(e)&&(await(this.capabilities?.projectCommitted?.(e,t,r))??!1)}catch(e){return this.logger.warn?.(`[runtime-core] agent projection deferred: ${errorText(e)}`),!1}}recoveryDecision(e,t){const r=recoveryMetadata(e);return reduceRuntimeRecoveryPolicy({...r,messageServicePhase:"queued",executionBoundaryCrossed:"prepared"!==t,lineageContinuity:"continuous",journalState:"available",journalPhase:t})}requireGateway(){const e=this.deps.getGateway();if(!e?.isConnected)throw new RuntimeCommandError("GATEWAY_NOT_CONNECTED","Gateway not connected");return e}exclusiveLifecycleReason(e){switch(e.name){case"agent.applyTemplate":return"applyTemplate";case"agent.create":return"createAgent";case"agent.delete":return"deleteAgent";case"agent.update":return"updateAgent";default:return}}async withExclusiveLifecycle(e,t,r){const i=this.exclusiveLifecycleReason(e);if(!i)return await r();if(this.deps.runExclusive)try{return await this.deps.runExclusive(i,r,t)}catch(e){if(e instanceof ImHotPathAbortedError)throw new RuntimeCommandError("INVALID_PARAMS",`${i} aborted while waiting for in-flight chat`);throw e}return await(this.deps.waitForChatIdle?.(i,t)),await r()}async createAgentShell(e,t,r,i,a,n){const o=this.requireGateway(),s=(await this.deps.identities.pendingAllocations()).find(t=>t.runtimeAgentUid===e),c=n??s?.runtimeLocalKey??this.createAgentId(),m=join(this.getOpenclawHome(),`workspace-${c}`);let d;try{d=await o.request("agents.create",{name:c,workspace:m,...a?{model:a}:{},...i?.emoji?{emoji:i.emoji}:{},...i?.avatar?{avatar:i.avatar}:{}})}catch(r){if(isDeterministicAgentsCreateParamsRejection(r)&&(void 0!==n||void 0!==s))try{await this.deps.identities.tombstone(e,c,t)}catch(e){this.logger.warn?.(`[runtime-core] rejected-create allocation cleanup deferred: ${errorText(e)}`)}throw r}const p=d?.agentId??c,u=d?.workspace??m;if(await this.deps.identities.observeEffectKey(e,c,p,t),p!==c)throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Create agent outcome unknown: gateway changed reserved local key to ${p}`);try{await o.request("agents.update",{agentId:p,name:r})}catch(e){this.logger.warn?.(`[runtime-core] display-name update failed agent=${p}: ${errorText(e)}`)}return{runtimeLocalKey:p,workspacePath:u}}async createAgent(e,t,r){const i=e.params.name.trim();if(!i)throw new RuntimeCommandError("INVALID_PARAMS","Missing agent name");try{const a=await this.bindCreateOperation(e,t);if("active"===a?.state)return await this.recoverActiveCreateEffect(a);const n=await this.createAgentShell(e.params.runtimeAgentUid,t,i,e.params.identity,e.params.defaultModelId,a?.runtimeLocalKey);return await this.completeCreatedAgent(e,t,r,n)}catch(e){throw this.executionError("Create agent",e)}}async updateAgent(e){const{runtimeAgentUid:t,runtimeLocalKey:r}=e.context.agent;if(!r.trim())throw new RuntimeCommandError("MISSING_PARAM","Missing agentId","agentId");const i=e.params,a=i.name?.trim(),n=i.defaultModelId?.trim(),o=i.identity?.emoji?.trim(),s=i.identity?.avatar?.trim();if(!(a||n||o||s||void 0!==i.description||void 0!==i.version||void 0!==i.capabilities||void 0!==i.skills||void 0!==i.avatarUrl||void 0!==i.homepage||void 0!==i.status||void 0!==i.identity?.vibe))throw new RuntimeCommandError("INVALID_PARAMS","No updatable fields provided (name/model/identity)");try{return await this.deps.identities.requireActive(t,r),await this.requireGateway().request("agents.update",{agentId:r,...a?{name:a}:{},...n?{model:n}:{},...o?{emoji:o}:{},...s?{avatar:s}:{},...i.identity?.vibe?{vibe:i.identity.vibe}:{},...void 0!==i.description?{description:i.description}:{},...void 0!==i.version?{version:i.version}:{},...void 0!==i.capabilities?{capabilities:i.capabilities}:{},...void 0!==i.skills?{skills:i.skills}:{},...void 0!==i.avatarUrl?{avatarUrl:i.avatarUrl}:{},...void 0!==i.homepage?{homepage:i.homepage}:{},...void 0!==i.status?{status:i.status}:{}}),{runtimeAgentUid:t,runtimeLocalKey:r}}catch(e){throw this.executionError("Update agent",e)}}async deleteAgent(e,t){const{runtimeAgentUid:r,runtimeLocalKey:i}=e.context.agent;if(!i.trim())throw new RuntimeCommandError("MISSING_PARAM","Missing agentId","agentId");if("main"===normalizeRuntimeAgentLocalKey(i))throw new RuntimeCommandError("INVALID_PARAMS",'"main" cannot be deleted; delete the instance instead');try{if("tombstoned"===await this.deps.identities.requireDeleteTarget(r,i))return{runtimeAgentUid:r,runtimeLocalKey:i};if(!await this.runtimeAgentExists(i))return await this.deps.identities.commitDeleteTombstone(r,i,t),{runtimeAgentUid:r,runtimeLocalKey:i};const a=requireCommittedOpenClawDeleteAck(await this.requireGateway().request("agents.delete",{agentId:i,deleteFiles:e.params.deleteFiles??!0}),i);try{await this.deps.identities.commitDeleteTombstone(r,i,t)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Delete agent outcome unknown: identity tombstone failed: ${errorText(e)}`,void 0,{cause:e})}return{runtimeAgentUid:r,runtimeLocalKey:i,...void 0===a.removedBindings?{}:{removedBindings:a.removedBindings}}}catch(e){throw this.executionError("Delete agent",e)}}async applyTemplate(e,t,r){const i=e.params.name.trim();if(!i)throw new RuntimeCommandError("INVALID_PARAMS","Missing agent name");this.requireGateway();try{const a=await this.bindCreateOperation(e,t);if("active"===a?.state)return await this.recoverActiveCreateEffect(a);const n=await r.resources.readVerifiedArtifact(e.params.artifact),o=await this.createAgentShell(e.params.runtimeAgentUid,t,i,e.params.identity,e.params.defaultModelId,a?.runtimeLocalKey);return await this.completeTemplateAgent(e,t,r,o,n)}catch(e){throw this.executionError("Apply template",e)}}async completeCreatedAgent(e,t,r,i){for(const t of e.params.bootstrapFiles??[]){if("IDENTITY.md"===t.name){this.logger.warn?.("[runtime-core] agent.create ignoring IDENTITY.md; identity is structured");continue}const e=await r.resources.readContent(t.contentRef);try{await this.requireGateway().request("agents.files.set",{agentId:i.runtimeLocalKey,name:t.name,content:e})}catch(e){this.logger.warn?.(`[runtime-core] bootstrap write failed file=${t.name}: ${errorText(e)}`)}}try{await this.deps.identities.activate(e.params.runtimeAgentUid,i.runtimeLocalKey,t)}catch(r){throw await this.compensateCreatedAgent(e.params.runtimeAgentUid,i.runtimeLocalKey,t,r,"Create agent"),new RuntimeCommandError("EXECUTION_FAILED",`Create agent failed after compensation: ${errorText(r)}`)}return await this.prepareAgentToolCatalog(i.runtimeLocalKey),{runtimeAgentUid:e.params.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,workspacePath:i.workspacePath}}async completeTemplateAgent(e,t,r,i,a){const n=a??await r.resources.readVerifiedArtifact(e.params.artifact);try{for(const[e,t]of n.workspaceFiles){const r=resolve(i.workspacePath,e),a=relative(i.workspacePath,r);if(""===a||a.startsWith("..")||path.isAbsolute(a))throw new Error(`refusing to write outside workspace: ${e}`);await(this.deps.mkdirWorkspace??mkdir)(path.dirname(r),{recursive:!0}),await(this.deps.writeWorkspaceFile??writeFile)(r,t)}await this.deps.identities.activate(e.params.runtimeAgentUid,i.runtimeLocalKey,t)}catch(r){throw await this.compensateCreatedAgent(e.params.runtimeAgentUid,i.runtimeLocalKey,t,r,"Apply template"),new RuntimeCommandError("EXECUTION_FAILED",`Apply template failed after compensation: ${errorText(r)}`,void 0,{cause:r})}return await this.prepareAgentToolCatalog(i.runtimeLocalKey),{runtimeAgentUid:e.params.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,workspacePath:i.workspacePath}}async prepareAgentToolCatalog(e){await prepareOpenClawToolCatalog({request:(e,t)=>this.requireGateway().request(e,t),agentId:e,mode:"catalog",keyKind:"boot",logger:this.logger})}executionError(e,t){return t instanceof RuntimeCommandError?t:(this.logger.error?.(`[runtime-core] ${e.toLowerCase()} failed: ${errorText(t)}`),new RuntimeCommandError("EXECUTION_FAILED",`${e} failed: ${errorText(t)}`,void 0,{cause:t}))}async compensateCreatedAgent(e,t,r,i,a){try{const i=this.requireGateway();requireCommittedOpenClawDeleteAck(await i.request("agents.delete",{agentId:t,deleteFiles:!0}),t),await this.deps.identities.tombstone(e,t,r)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`${a} outcome unknown after ${errorText(i)}; compensation unproven: ${errorText(e)}`,void 0,{cause:e})}}async recoverInterruptedCreates(e){const t=await this.deps.identities.pendingAllocations();for(const r of t){if(r.operationId===e)continue;const t=await this.deps.leases.claimExpiredForRecovery(r.operationId);if(!t)continue;const i=this.deps.leases.startHeartbeat(t);try{await this.deps.identities.adoptRecoveryLease(r.runtimeAgentUid,r.runtimeLocalKey,t);const e=r.observedRuntimeLocalKey;if(!e){const e=r.createOperation?.operationId??r.operationId,i=await this.journal.get(e);if("failed"===i?.phase&&i.command===r.command&&!await this.runtimeAgentExists(r.runtimeLocalKey)){await this.deps.identities.tombstone(r.runtimeAgentUid,r.runtimeLocalKey,t);continue}throw new Error("no persisted gateway effect key; absence cannot be proven")}requireCommittedOpenClawDeleteAck(await this.requireGateway().request("agents.delete",{agentId:e,deleteFiles:!0}),e),await this.deps.identities.tombstone(r.runtimeAgentUid,r.runtimeLocalKey,t)}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Interrupted ${r.command} recovery outcome unknown for operation ${r.operationId}: ${errorText(e)}`,void 0,{cause:e})}finally{let e;try{await i.stop()}catch(t){e=t}try{await this.deps.leases.release(t)}catch(t){e??=t}if(e)throw new RuntimeCommandError("OUTCOME_UNKNOWN",`Interrupted recovery lease finalization unknown: ${errorText(e)}`,void 0,{cause:e})}}}}function isRuntimeAgentMutation(e){return"agent.create"===e.name||"agent.update"===e.name||"agent.delete"===e.name||"agent.applyTemplate"===e.name}function servicePlatformAgentId(e){const t=e.verifiedMessageGrant?.claims;return"agent"===t?.scope?t.platformAgentId:void 0}function agentCoreResultHash(e,t){return createHash("sha256").update(runtimeHashPreimage(RUNTIME_HASH_DOMAINS.coreResult,{method:e.name.replace(".","/"),result:t})).digest("hex")}function agentProjectionRecoverySummary(e,t,r){const i="agent.update"===e.name||"agent.delete"===e.name?e.context.agent:createProjectionTarget(e,t),a=t;return Object.freeze({schemaVersion:1,operationId:e.context.operationId,method:e.name,runtimeEpoch:e.context.dispatchEpoch,runtimeAgentUid:i.runtimeAgentUid,runtimeLocalKey:i.runtimeLocalKey,coreResultHash:agentCoreResultHash(e,t),...servicePlatformAgentId(r)?{expectedPlatformAgentId:servicePlatformAgentId(r)}:{},..."agent.delete"===e.name&&Number.isSafeInteger(a?.removedBindings)?{removedBindings:a.removedBindings}:{}})}function createProjectionTarget(e,t){const r=t;if(!r||r.runtimeAgentUid!==e.params.runtimeAgentUid||"string"!=typeof r.runtimeLocalKey||!r.runtimeLocalKey)throw new RuntimeCommandError("OUTCOME_UNKNOWN","committed agent effect lacks a recoverable local identity");return{runtimeAgentUid:r.runtimeAgentUid,runtimeLocalKey:r.runtimeLocalKey}}function agentProjectionRecoveryResult(e){return Object.freeze({runtimeAgentUid:e.runtimeAgentUid,runtimeLocalKey:e.runtimeLocalKey,...void 0===e.removedBindings?{}:{removedBindings:e.removedBindings}})}function isProjectionIntent(e){return"projectionRevision"in e}function recoveryMetadata(e){const t=RUNTIME_METHOD_PARITY_MANIFEST.filter(t=>t.serviceAllowed&&t.canonicalCommand===e),r=t[0]?.recoveryClass;return r?{recoveryClass:r,projectionRequired:"mcp.set"===e||"mcp.unset"===e||t.some(e=>!0===e.projectionRequired)}:{recoveryClass:"imperative-ambiguous",projectionRequired:!1}}export function isDeterministicAgentsCreateParamsRejection(e){return e instanceof Error&&/^invalid agents\.create params\b/.test(e.message)}export function requireCommittedOpenClawDeleteAck(e,t){if(!e||"object"!=typeof e)throw new Error("gateway delete lacks the committed target acknowledgement");const r=e,i=Object.keys(r).every(e=>"ok"===e||"agentId"===e||"removedBindings"===e),a=void 0===r.removedBindings||Number.isSafeInteger(r.removedBindings)&&r.removedBindings>=0;if(!i||!0!==r.ok||r.agentId!==t||!a)throw new Error("gateway delete lacks the committed target acknowledgement");return{ok:!0,agentId:t,...void 0===r.removedBindings?{}:{removedBindings:r.removedBindings}}}function errorText(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash,randomUUID}from"node:crypto";import{readFile}from"node:fs/promises";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";import{createRuntimeAppendTimingRecorder}from"./runtime-append-timing.js";import{OwnedDirectoryLockContendedError,withOwnedDirectoryLock}from"./owned-directory-lock.js";import{MonotonicJournalSegments}from"./monotonic-journal-segments.js";const HASH_ONLY_RESULT_COMMANDS=new Set(["session.load","session.history","session.list","agent.listProjection","skills.list","models.list","cron.list","cron.status","cron.runs","mcp.list","terminal.ping","terminal.wait"]),SAFE_CANONICAL_RESULT_COMMANDS=new Set(["session.clear","session.setMode","session.setModel","session.setReasoning","session.cancel","skills.install","skills.uninstall","skills.setEnabled","cron.remove","mcp.prepare","mcp.set","mcp.unset","terminal.input","terminal.resize","terminal.close","terminal.release","terminal.kill","canvas.toggle","canvas.clear","canvas.reference","canvas.dimensions"]);export const runtimeCommandResultPersistencePolicy=e=>SAFE_CANONICAL_RESULT_COMMANDS.has(e)?"canonical_result":"hash_only";export const runtimeCommandIsReplayableQuery=e=>HASH_ONLY_RESULT_COMMANDS.has(e);export const runtimeCommandResultHash=e=>createHash("sha256").update(canonicalizeJcs(e)).digest("hex");const emptyDocument=()=>({version:2,lineage:{journalStoreId:randomUUID(),journalGeneration:"1"},records:[],cancellations:[]}),CHECKPOINT_INTERVAL_MS=6e5,CHECKPOINT_DELTA_COUNT=512,CHECKPOINT_DELTA_BYTES=8388608,CHECKPOINT_FOREGROUND_QUIET_MS=50;export class RuntimeCommandJournalConflictError extends Error{constructor(e){super(e),this.name="RuntimeCommandJournalConflictError"}}export class FileRuntimeCommandJournal{file;retentionMs;now;publication;segments;maintenance;forceCheckpointRequested=!1;maintenanceDue;maintenanceDueAtMs;prunePending=!1;foregroundUpdates=0;foregroundRevision=0;constructor(e,t=6048e5,n=Date.now,o={}){this.file=e,this.retentionMs=t,this.now=n,this.publication=o,this.segments=new MonotonicJournalSegments(e)}async lineage(){return await this.update(e=>({...e.lineage}))}async advanceLineageGeneration(e){return await this.update(t=>{if(t.lineage.journalStoreId!==e.journalStoreId)throw new RuntimeCommandJournalConflictError("journal store changed during incarnation advance");const n=BigInt(t.lineage.journalGeneration),o=BigInt(e.floor),r=(n>o?n:o)+1n;if(r>9223372036854775807n)throw new RuntimeCommandJournalConflictError("journal generation overflow");return t.lineage={journalStoreId:t.lineage.journalStoreId,journalGeneration:String(r)},{...t.lineage}})}async get(e){return(await this.read()).records.find(t=>t.operationId===e)??null}async getCancellation(e){return(await this.read()).cancellations.find(t=>t.operationId===e)??null}async listMcpLiveReleases(){const e=await this.read();return Object.freeze(e.records.flatMap(e=>e.mcpLiveRelease?[e.mcpLiveRelease]:[]))}async listMcpActiveDesiredStates(){const e=await this.read();return Object.freeze(e.records.flatMap(e=>e.mcpActiveDesiredState?[e.mcpActiveDesiredState]:[]))}async recordMcpDesiredStateCommit(e){const t=normalizeMcpDesiredStateCommit(e);return await this.update(e=>{const n=e.records.findIndex(e=>e.operationId===t.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP desired state has no command record");const o=e.records[n];if(assertMcpCommitBindsRecord(t,o),"started"!==o.phase){if(sameMcpDesiredStateCommit(o.mcpDesiredStateCommit,t))return o;throw new RuntimeCommandJournalConflictError("MCP desired state commit crossed its journal boundary")}if(o.mcpDesiredStateCommit){if(sameMcpDesiredStateCommit(o.mcpDesiredStateCommit,t))return o;throw new RuntimeCommandJournalConflictError("MCP desired state commit conflicts with journal")}const r={...o,mcpDesiredStateCommit:t,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return e.records[n]=r,r})}async releaseMcpLiveEffect(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP release has no command record");const o=t.records[n];if("effect_committed"!==o.phase&&"projection_committed"!==o.phase)throw new RuntimeCommandJournalConflictError("MCP release requires a committed effect");if(!o.mcpDesiredStateCommit)throw new RuntimeCommandJournalConflictError("MCP release lacks a durable desired-state commit");if("service"===e.source&&!o.messageBinding)throw new RuntimeCommandJournalConflictError("Service MCP release lacks a Message Service request binding");const r=releaseFromCommit(o.mcpDesiredStateCommit,e,new Date(this.now()).toISOString());if(o.mcpLiveRelease){if(sameMcpLiveRelease(o.mcpLiveRelease,r))return o;throw new RuntimeCommandJournalConflictError("MCP release conflicts with journal")}const i={...o,mcpLiveRelease:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async promoteMcpDesiredStateActive(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP active promotion has no command record");const o=t.records[n],r=activeFromRelease(o.mcpLiveRelease,e,new Date(this.now()).toISOString());if(o.mcpActiveDesiredState){if(sameMcpActiveDesiredState(o.mcpActiveDesiredState,r))return o;throw new RuntimeCommandJournalConflictError("MCP active desired state conflicts with journal")}const i={...o,mcpActiveDesiredState:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async acceptMessageRequest(e){return await this.update(t=>{let n=t.records.find(t=>t.operationId===e.operationId);if(n||(n={operationId:e.operationId,command:e.command,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,phase:"prepared",revision:1,updatedAt:new Date(this.now()).toISOString()},t.records.push(n)),n.command!==e.command||n.paramsHash!==e.paramsHash||n.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("message request conflicts with command journal");const o={requestMessageId:e.requestMessageId,requestHash:e.requestHash,acceptedAt:new Date(this.now()).toISOString()};if(n.messageBinding&&(n.messageBinding.requestMessageId!==o.requestMessageId||n.messageBinding.requestHash!==o.requestHash))throw new RuntimeCommandJournalConflictError("operation reused by a different message request");return n.messageBinding??=o,n})}async observeCancellation(e){return await this.update(t=>{const n=t.cancellations.find(t=>t.eventId===e.eventId);if(n){if(n.operationId!==e.operationId||n.requestMessageId!==e.requestMessageId||n.requestHash!==e.requestHash)throw new RuntimeCommandJournalConflictError("operation cancellation observation conflict");return n}const o=t.cancellations.find(t=>t.operationId===e.operationId);if(o&&(o.requestMessageId!==e.requestMessageId||o.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("operation cancellation request correlation conflict");const r={...e,observedAt:new Date(this.now()).toISOString()};return t.cancellations.push(r),r})}async prepare(e){return await this.update(t=>{const n=t.records.find(t=>t.operationId===e.operationId);if(n){if(n.command!==e.command||n.paramsHash!==e.paramsHash)throw new RuntimeCommandJournalConflictError("operation identity reused with different command or params hash");if(n.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("operation belongs to a different runtime epoch");return n}const o={...e,phase:"prepared",revision:1,updatedAt:new Date(this.now()).toISOString()};return t.records.push(o),o})}async transition(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision)throw new RuntimeCommandJournalConflictError("journal revision conflict");const r="effect_committed"===o.phase&&"effect_committed"===e.phase&&void 0!==e.agentProjection&&void 0===o.agentProjectionIntent&&"pending"===o.agentProjectionPreparationFailure?.state;if("projection_committed"===o.phase||"failed"===o.phase||"outcome_unknown"===o.phase||"effect_committed"===o.phase&&"projection_committed"!==e.phase&&!r)throw new RuntimeCommandJournalConflictError("terminal journal record is immutable");if(void 0!==e.projectionSnapshot&&"projection_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("projection receipt requires projection_committed phase");if(void 0!==e.agentProjection&&"effect_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("agent projection intent requires effect_committed phase");const i=void 0===e.agentProjection?void 0:normalizeAgentProjectionPreparation(e.agentProjection,o);if(r&&i&&!sameProjectionPreparationBase(o.agentProjectionPreparationFailure,i))throw new RuntimeCommandJournalConflictError("agent projection preparation conflicts with committed operation");const{agentProjectionIntent:a,agentProjectionPreparationFailure:s,...c}=o,d={...void 0===i?o:c,phase:e.phase,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString(),...void 0===e.result?{}:persistedResult(o.command,e.result),...void 0===e.projectionSnapshot?{}:{projectionReceipt:projectionReceipt(e.projectionSnapshot)},...void 0===i?{}:isAgentProjectionIntent(i)?{agentProjectionIntent:i}:{agentProjectionPreparationFailure:i},...void 0===e.errorCode?{}:{errorCode:e.errorCode}};return t.records[n]=d,d})}async recordAgentProjectionIntent(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision||"effect_committed"!==o.phase)throw new RuntimeCommandJournalConflictError("projection intent cannot mutate this command journal record");const r=normalizeAgentProjectionIntent(e.intent,o);if(o.agentProjectionIntent){if(canonicalizeJcs(o.agentProjectionIntent)!==canonicalizeJcs(r))throw new RuntimeCommandJournalConflictError("agent projection intent conflicts with committed operation");return o}if("pending"!==o.agentProjectionPreparationFailure?.state||!sameProjectionPreparationBase(o.agentProjectionPreparationFailure,r))throw new RuntimeCommandJournalConflictError("projection intent requires matching retryable preparation failure");const{agentProjectionPreparationFailure:i,...a}=o,s={...a,agentProjectionIntent:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=s,s})}async recordAgentProjectionBlocked(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision||"effect_committed"!==o.phase||!o.agentProjectionIntent||o.agentProjectionIntent.projectionRevision!==e.revision)throw new RuntimeCommandJournalConflictError("blocked projection cannot mutate this command journal record");if(o.agentProjectionTerminal){if("blocked"===o.agentProjectionTerminal.state&&o.agentProjectionTerminal.revision===e.revision)return o;throw new RuntimeCommandJournalConflictError("agent projection terminal conflicts with committed operation")}const r=agentProjectionTerminalReceipt(e.revision),i={...o,agentProjectionTerminal:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async compact(){return this.maintenance?await this.maintenance:!1===this.maintenanceDue&&!this.prunePending&&void 0!==this.maintenanceDueAtMs&&Date.now()<this.maintenanceDueAtMs?0:await this.startMaintenance()}async checkpoint(){return this.forceCheckpointRequested=!0,await this.startMaintenance()}async read(){return(await this.readState()).document}async readState(){const e=await this.readLegacy(),t=new Map;if(e){t.set("meta:lineage",{value:e.lineage,logicalRevision:e.lineage.journalGeneration,publisherEpoch:"0"});for(const n of e.records)t.set(`record:${n.operationId}`,{value:n,logicalRevision:String(n.revision),publisherEpoch:"0"});for(const n of e.cancellations)t.set(`cancellation:${n.eventId}`,{value:n,logicalRevision:"1",publisherEpoch:"0"})}const n=await this.segments.readState(t),o=n.values,r=o.get("meta:lineage")?.value;return{document:{version:2,lineage:r??emptyDocument().lineage,records:[...o.entries()].filter(([e])=>e.startsWith("record:")).map(([,e])=>validateRecordReceipts(migrateLegacyCommittedPhase(e.value))),cancellations:[...o.entries()].filter(([e])=>e.startsWith("cancellation:")).map(([,e])=>e.value)},authorityFloor:n.authorityFloor,checkpointAtMs:n.checkpointAtMs,deltaCount:n.deltaCount,deltaBytes:n.deltaBytes,oldestDeltaAtMs:n.oldestDeltaAtMs,hasDurableLineage:o.has("meta:lineage")&&n.hasDurableState}}async readLegacy(){try{const e=JSON.parse(await readFile(this.file,"utf8"));if(!Array.isArray(e.records))throw new Error("unsupported command journal");const t=e.records.map(e=>validateRecordReceipts(migrateLegacyCommittedPhase(e)));if(1===e.version)return{...emptyDocument(),records:t};if(2!==e.version||!e.lineage?.journalStoreId||!/^[1-9][0-9]*$/.test(e.lineage.journalGeneration))throw new Error("unsupported command journal");return{...e,records:t,cancellations:Array.isArray(e.cancellations)?e.cancellations:[]}}catch(e){if("ENOENT"===e.code)return null;throw e}}async update(e){const t=createRuntimeAppendTimingRecorder("journal.update",{file:this.file});let n=!1;this.foregroundUpdates+=1;try{return await withOwnedDirectoryLock(`${this.file}.lock`,async o=>{t.mark("lock");const r=await this.readState();t.mark("read");const i=r.document,a=structuredClone(i),s=e(i),c=[];if(r.hasDurableLineage&&sameValue(a.lineage,i.lineage)||c.push({key:"meta:lineage",logicalRevision:i.lineage.journalGeneration,value:i.lineage}),diffValues(a.records,i.records,e=>e.operationId,e=>String(e.revision),"record:",c),diffValues(a.cancellations,i.cancellations,e=>e.eventId,()=>"1","cancellation:",c),0===c.length)return t.mark("noop"),s;await(this.publication.beforePublish?.(o.epoch)),t.mark("before-publish"),await o.assertOwned(),t.mark("assert-owned");const d=await this.segments.publishDelta(o.epoch,c,r.authorityFloor);t.mark("publish-delta");const m=Date.now();return this.maintenanceDueAtMs=checkpointDueAt(r,1,d,m),n=this.maintenanceDueAtMs<=m,this.maintenanceDue=n,s},{...this.publication.lockOptions,epochFloor:()=>this.segments.authorityFloor()})}finally{this.foregroundUpdates-=1,this.foregroundRevision+=1,t.finish(),n&&this.scheduleMaintenance()}}scheduleMaintenance(){this.startMaintenance().catch(e=>{try{this.publication.onMaintenanceError?this.publication.onMaintenanceError(e):emitMaintenanceWarning(e)}catch(e){emitMaintenanceWarning(e)}})}startMaintenance(){if(this.maintenance)return this.maintenance;const e=(async()=>{let e=0,t=!1;do{let n=this.forceCheckpointRequested;this.forceCheckpointRequested=!1,n||(await this.waitForForegroundQuiet(),n=this.forceCheckpointRequested,this.forceCheckpointRequested=!1);const o=await this.runMaintenance(n);e+=o.removed,t=o.contended}while(this.forceCheckpointRequested||t);return e})().finally(()=>{this.maintenance===e&&(this.maintenance=void 0)});return this.maintenance=e,e}async waitForForegroundQuiet(){for(;;){if(this.forceCheckpointRequested)return;const e=this.foregroundRevision;if(0===this.foregroundUpdates){if(await new Promise(e=>setTimeout(e,50)),this.forceCheckpointRequested||0===this.foregroundUpdates&&this.foregroundRevision===e)return}else await new Promise(e=>setTimeout(e,50))}}async runMaintenance(e){const t=createRuntimeAppendTimingRecorder("journal.checkpoint",{file:this.file});try{if(!e&&this.prunePending)return await this.segments.prune(),this.prunePending=!1,t.mark("prune-pending"),{removed:0,contended:!1};let n=!1;const o=await withOwnedDirectoryLock(`${this.file}.lock`,async o=>{t.mark("lock");const r=await this.readState();if(t.mark("read"),!e&&!checkpointDue(r))return this.maintenanceDue=!1,this.maintenanceDueAtMs=checkpointDueAt(r),t.mark("not-due"),0;const i=r.document,a=this.now()-this.retentionMs,s=i.records.length;i.records=i.records.filter(e=>"prepared"===e.phase||"started"===e.phase||Date.parse(e.updatedAt)>=a);const c=i.cancellations.length;i.cancellations=i.cancellations.filter(e=>Date.parse(e.observedAt)>=a);const d=s-i.records.length+c-i.cancellations.length,m=documentValues(i);return await(this.publication.beforePublish?.(o.epoch)),t.mark("before-publish"),await o.assertOwned(),t.mark("assert-owned"),await this.segments.checkpointSnapshot(o.epoch,m,r.authorityFloor),t.mark("publish-snapshot"),this.maintenanceDue=!1,this.maintenanceDueAtMs=Number.POSITIVE_INFINITY,this.prunePending=!0,n=!0,d},{...this.publication.lockOptions,failIfContended:!e,epochFloor:()=>this.segments.authorityFloor()});return t.mark("lock-released"),n&&(await this.segments.prune(),this.prunePending=!1,t.mark("prune")),{removed:o,contended:!1}}catch(n){if(!e&&n instanceof OwnedDirectoryLockContendedError)return t.mark("deferred-busy"),{removed:0,contended:!0};throw n}finally{t.finish(e?"forced":"scheduled")}}}function checkpointDue(e,t=0,n=0,o=Date.now()){return checkpointDueAt(e,t,n,o)<=o}function checkpointDueAt(e,t=0,n=0,o=Date.now()){const r=e.deltaCount+t,i=e.deltaBytes+n,a=e.oldestDeltaAtMs||(t>0?o:0),s=e.checkpointAtMs||a;return r>=512||i>=8388608?o:r>0&&s>0?s+6e5:Number.POSITIVE_INFINITY}function emitMaintenanceWarning(e){process.emitWarning(e instanceof Error?e.message:String(e),{code:"BEEOS_RUNTIME_JOURNAL_CHECKPOINT_FAILED"})}function diffValues(e,t,n,o,r,i){const a=new Map(e.map(e=>[n(e),e])),s=new Map(t.map(e=>[n(e),e]));for(const[e,t]of s){const n=a.get(e);void 0!==n&&sameValue(n,t)||i.push({key:`${r}${e}`,logicalRevision:o(t),value:t})}for(const[e,t]of a)s.has(e)||i.push({key:`${r}${e}`,logicalRevision:o(t),tombstone:!0})}function documentValues(e){return[{key:"meta:lineage",logicalRevision:e.lineage.journalGeneration,value:e.lineage},...e.records.map(e=>({key:`record:${e.operationId}`,logicalRevision:String(e.revision),value:e})),...e.cancellations.map(e=>({key:`cancellation:${e.eventId}`,logicalRevision:"1",value:e}))]}function sameValue(e,t){return canonicalizeJcs(e)===canonicalizeJcs(t)}function migrateLegacyCommittedPhase(e){return{...e,phase:"committed"===e.phase?"effect_committed":e.phase}}export class InMemoryRuntimeCommandJournal{records=new Map;cancellations=new Map;async get(e){return this.records.get(e)??null}async getCancellation(e){return[...this.cancellations.values()].find(t=>t.operationId===e)??null}async listMcpLiveReleases(){return Object.freeze([...this.records.values()].flatMap(e=>e.mcpLiveRelease?[e.mcpLiveRelease]:[]))}async listMcpActiveDesiredStates(){return Object.freeze([...this.records.values()].flatMap(e=>e.mcpActiveDesiredState?[e.mcpActiveDesiredState]:[]))}async recordMcpDesiredStateCommit(e){const t=normalizeMcpDesiredStateCommit(e),n=this.records.get(t.operationId);if(!n)throw new RuntimeCommandJournalConflictError("MCP desired state has no command record");if(assertMcpCommitBindsRecord(t,n),"started"!==n.phase){if(sameMcpDesiredStateCommit(n.mcpDesiredStateCommit,t))return n;throw new RuntimeCommandJournalConflictError("MCP desired state commit crossed its journal boundary")}if(n.mcpDesiredStateCommit){if(sameMcpDesiredStateCommit(n.mcpDesiredStateCommit,t))return n;throw new RuntimeCommandJournalConflictError("MCP desired state commit conflicts with journal")}const o={...n,mcpDesiredStateCommit:t,revision:n.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(t.operationId,o),o}async releaseMcpLiveEffect(e){const t=this.records.get(e.operationId);if(!t)throw new RuntimeCommandJournalConflictError("MCP release has no command record");if("effect_committed"!==t.phase&&"projection_committed"!==t.phase)throw new RuntimeCommandJournalConflictError("MCP release requires a committed effect");if(!t.mcpDesiredStateCommit)throw new RuntimeCommandJournalConflictError("MCP release lacks a durable desired-state commit");if("service"===e.source&&!t.messageBinding)throw new RuntimeCommandJournalConflictError("Service MCP release lacks a Message Service request binding");const n=releaseFromCommit(t.mcpDesiredStateCommit,e,(new Date).toISOString());if(t.mcpLiveRelease){if(sameMcpLiveRelease(t.mcpLiveRelease,n))return t;throw new RuntimeCommandJournalConflictError("MCP release conflicts with journal")}const o={...t,mcpLiveRelease:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,o),o}async promoteMcpDesiredStateActive(e){const t=this.records.get(e.operationId);if(!t)throw new RuntimeCommandJournalConflictError("MCP active promotion has no command record");const n=activeFromRelease(t.mcpLiveRelease,e,(new Date).toISOString());if(t.mcpActiveDesiredState){if(sameMcpActiveDesiredState(t.mcpActiveDesiredState,n))return t;throw new RuntimeCommandJournalConflictError("MCP active desired state conflicts with journal")}const o={...t,mcpActiveDesiredState:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,o),o}async acceptMessageRequest(e){let t=this.records.get(e.operationId);if(t||(t={operationId:e.operationId,command:e.command,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,phase:"prepared",revision:1,updatedAt:(new Date).toISOString()},this.records.set(e.operationId,t)),t.command!==e.command||t.paramsHash!==e.paramsHash||t.runtimeEpoch!==e.runtimeEpoch||t.messageBinding&&(t.messageBinding.requestMessageId!==e.requestMessageId||t.messageBinding.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("message request conflicts with command journal");return t.messageBinding??={requestMessageId:e.requestMessageId,requestHash:e.requestHash,acceptedAt:(new Date).toISOString()},t}async observeCancellation(e){const t=this.cancellations.get(e.eventId);if(t){if(t.operationId!==e.operationId||t.requestMessageId!==e.requestMessageId||t.requestHash!==e.requestHash)throw new RuntimeCommandJournalConflictError("operation cancellation observation conflict");return t}const n=[...this.cancellations.values()].find(t=>t.operationId===e.operationId);if(n&&(n.requestMessageId!==e.requestMessageId||n.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("operation cancellation request correlation conflict");const o={...e,observedAt:(new Date).toISOString()};return this.cancellations.set(e.eventId,o),o}async prepare(e){const t=this.records.get(e.operationId);if(t){if(t.command!==e.command||t.paramsHash!==e.paramsHash||t.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("operation identity conflict");return t}const n={...e,phase:"prepared",revision:1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,n),n}async transition(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision)throw new RuntimeCommandJournalConflictError("revision conflict");const n="effect_committed"===t.phase&&"effect_committed"===e.phase&&void 0!==e.agentProjection&&void 0===t.agentProjectionIntent&&"pending"===t.agentProjectionPreparationFailure?.state;if("projection_committed"===t.phase||"failed"===t.phase||"outcome_unknown"===t.phase||"effect_committed"===t.phase&&"projection_committed"!==e.phase&&!n)throw new RuntimeCommandJournalConflictError("terminal journal record is immutable");if(void 0!==e.projectionSnapshot&&"projection_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("projection receipt requires projection_committed phase");if(void 0!==e.agentProjection&&"effect_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("agent projection intent requires effect_committed phase");const o=void 0===e.agentProjection?void 0:normalizeAgentProjectionPreparation(e.agentProjection,t);if(n&&o&&!sameProjectionPreparationBase(t.agentProjectionPreparationFailure,o))throw new RuntimeCommandJournalConflictError("agent projection preparation conflicts with committed operation");const{agentProjectionIntent:r,agentProjectionPreparationFailure:i,...a}=t,s={...void 0===o?t:a,phase:e.phase,revision:t.revision+1,updatedAt:(new Date).toISOString(),...void 0===e.result?{}:persistedResult(t.command,e.result),...void 0===e.projectionSnapshot?{}:{projectionReceipt:projectionReceipt(e.projectionSnapshot)},...void 0===o?{}:isAgentProjectionIntent(o)?{agentProjectionIntent:o}:{agentProjectionPreparationFailure:o},...void 0===e.errorCode?{}:{errorCode:e.errorCode}};return this.records.set(e.operationId,s),s}async recordAgentProjectionIntent(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision||"effect_committed"!==t.phase)throw new RuntimeCommandJournalConflictError("projection intent cannot mutate this command journal record");const n=normalizeAgentProjectionIntent(e.intent,t);if(t.agentProjectionIntent){if(canonicalizeJcs(t.agentProjectionIntent)!==canonicalizeJcs(n))throw new RuntimeCommandJournalConflictError("agent projection intent conflicts with committed operation");return t}if("pending"!==t.agentProjectionPreparationFailure?.state||!sameProjectionPreparationBase(t.agentProjectionPreparationFailure,n))throw new RuntimeCommandJournalConflictError("projection intent requires matching retryable preparation failure");const{agentProjectionPreparationFailure:o,...r}=t,i={...r,agentProjectionIntent:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,i),i}async recordAgentProjectionBlocked(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision||"effect_committed"!==t.phase||!t.agentProjectionIntent||t.agentProjectionIntent.projectionRevision!==e.revision)throw new RuntimeCommandJournalConflictError("blocked projection cannot mutate this command journal record");if(t.agentProjectionTerminal){if("blocked"===t.agentProjectionTerminal.state&&t.agentProjectionTerminal.revision===e.revision)return t;throw new RuntimeCommandJournalConflictError("agent projection terminal conflicts with committed operation")}const n={...t,agentProjectionTerminal:agentProjectionTerminalReceipt(e.revision),revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,n),n}async compact(){return 0}async checkpoint(){return 0}}function persistedResult(e,t){return"canonical_result"===runtimeCommandResultPersistencePolicy(e)?{result:t}:{resultReceipt:{policy:"hash_only",resultHash:runtimeCommandResultHash(t),redacted:{kind:runtimeCommandIsReplayableQuery(e)?"query_result":"mutation_result",command:e}}}}function projectionReceipt(e){if("synced"!==e.state||!/^(0|[1-9][0-9]*)$/.test(e.revision))throw new Error("invalid projection revision");if(void 0!==e.platformAgentId&&!/^[a-zA-Z0-9._:-]{1,256}$/.test(e.platformAgentId))throw new Error("invalid projection platform agent id");const t=void 0===e.mcpReceipt?void 0:normalizeMcpProjectionReceipt(e.mcpReceipt),n=Object.freeze({revision:e.revision,state:"synced",..."string"==typeof e.platformAgentId&&e.platformAgentId?{platformAgentId:e.platformAgentId}:{},...t?{mcpReceipt:t}:{}});return Object.freeze({schemaVersion:1,revision:n.revision,snapshot:n,snapshotHash:runtimeCommandResultHash(n)})}function validateRecordReceipts(e){if(void 0!==e.agentProjectionIntent&&void 0!==e.agentProjectionPreparationFailure)throw new Error("agent projection journal record is ambiguous");const t=void 0!==e.agentProjectionIntent?{...e,agentProjectionIntent:normalizeAgentProjectionIntent(e.agentProjectionIntent,e)}:void 0!==e.agentProjectionPreparationFailure?{...e,agentProjectionPreparationFailure:normalizeAgentProjectionPreparation(e.agentProjectionPreparationFailure,e)}:e,n=void 0===t.agentProjectionTerminal?t:{...t,agentProjectionTerminal:normalizeAgentProjectionTerminal(t.agentProjectionTerminal)};if(n.agentProjectionTerminal&&(!n.agentProjectionIntent||"effect_committed"!==n.phase||n.agentProjectionIntent.projectionRevision!==n.agentProjectionTerminal.revision))throw new Error("invalid agent projection terminal receipt");const o=void 0===n.mcpDesiredStateCommit?void 0:normalizeMcpDesiredStateCommit(n.mcpDesiredStateCommit);o&&assertMcpCommitBindsRecord(o,n);const r=void 0===n.mcpLiveRelease?void 0:normalizeMcpLiveRelease(n.mcpLiveRelease);if(r&&(!o||!sameMcpDesiredStateCommit(o,r)||"effect_committed"!==n.phase&&"projection_committed"!==n.phase||"service"===r.source&&!n.messageBinding))throw new Error("invalid MCP live release receipt");const i=void 0===n.mcpActiveDesiredState?void 0:normalizeMcpActiveDesiredState(n.mcpActiveDesiredState);if(i&&(!r||!sameMcpDesiredStateCommit(i,r)||i.effectRecordHash!==r.effectRecordHash||i.releasedAt!==r.releasedAt))throw new Error("invalid MCP active desired-state receipt");const a={...n,...o?{mcpDesiredStateCommit:o}:{},...r?{mcpLiveRelease:r}:{},...i?{mcpActiveDesiredState:i}:{}};if(!a.projectionReceipt)return a;const s=a.projectionReceipt,c=["revision","state",...void 0===s.snapshot?.platformAgentId?[]:["platformAgentId"],...void 0===s.snapshot?.mcpReceipt?[]:["mcpReceipt"]].sort().join(",");if("revision,schemaVersion,snapshot,snapshotHash"!==Object.keys(s).sort().join(",")||Object.keys(s.snapshot??{}).sort().join(",")!==c||"projection_committed"!==a.phase||1!==s.schemaVersion||!/^(0|[1-9][0-9]*)$/.test(s.revision)||"synced"!==s.snapshot?.state||s.snapshot.revision!==s.revision)throw new Error("invalid projection receipt");const d=projectionReceipt(s.snapshot),m=d.snapshot.mcpReceipt;if(m&&(m.operationId!==a.operationId||m.method!==a.command||m.runtimeEpoch!==a.runtimeEpoch))throw new Error("MCP projection receipt does not bind journal operation");if(d.snapshotHash!==s.snapshotHash)throw new Error("invalid projection receipt hash");return{...a,projectionReceipt:d}}function normalizeMcpDesiredStateCommit(e){if(!e||"object"!=typeof e||"desiredStateHash,desiredStateRevision,method,operationId,paramsHash,runtimeEpoch,schemaVersion,server,source"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||"service"!==e.source&&"acp_local"!==e.source||!safeReceiptIdentifier(e.operationId)||"mcp.set"!==e.method&&"mcp.unset"!==e.method||!isSha256(e.paramsHash)||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||!/^(0|[1-9][0-9]*)$/.test(e.desiredStateRevision)||!isSha256(e.desiredStateHash))throw new Error("invalid MCP desired-state commit");return Object.freeze({schemaVersion:1,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:normalizeMcpReleaseServer(e.server)})}function normalizeMcpLiveRelease(e){if(!e||"object"!=typeof e)throw new Error("invalid MCP live release receipt");const t=["desiredStateHash","desiredStateRevision","method","operationId","paramsHash","releasedAt","runtimeEpoch","schemaVersion","server","source",..."service"===e.source?["effectRecordHash"]:[]].sort().join(",");if(Object.keys(e).sort().join(",")!==t||"service"===e.source&&!isSha256(e.effectRecordHash)||"acp_local"===e.source&&void 0!==e.effectRecordHash||"string"!=typeof e.releasedAt||!Number.isFinite(Date.parse(e.releasedAt)))throw new Error("invalid MCP live release receipt");const n=normalizeMcpDesiredStateCommit({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server});return Object.freeze({...n,...e.effectRecordHash?{effectRecordHash:e.effectRecordHash}:{},releasedAt:e.releasedAt})}function normalizeMcpActiveDesiredState(e){if(!e||"object"!=typeof e)throw new Error("invalid MCP active desired-state receipt");const t=["activatedAt","desiredStateHash","desiredStateRevision","method","operationId","paramsHash","releasedAt","runtimeEpoch","schemaVersion","server","source",..."service"===e.source?["effectRecordHash","terminalMessageId"]:[]].sort().join(",");if(Object.keys(e).sort().join(",")!==t||"string"!=typeof e.activatedAt||!Number.isFinite(Date.parse(e.activatedAt))||"service"===e.source&&!safeReceiptIdentifier(e.terminalMessageId))throw new Error("invalid MCP active desired-state receipt");const n=normalizeMcpLiveRelease({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server,releasedAt:e.releasedAt,...e.effectRecordHash?{effectRecordHash:e.effectRecordHash}:{}});return Object.freeze({...n,...e.terminalMessageId?{terminalMessageId:e.terminalMessageId}:{},activatedAt:e.activatedAt})}function normalizeMcpReleaseServer(e){const t=e&&"object"==typeof e?Object.keys(e).sort().join(","):"",n=!0===e?.removed;if(!(t===(n?"name,removed":void 0===e?.credentialRef?"definitionRef,definitionSha256,name,version":"credentialRef,definitionRef,definitionSha256,name,version")&&safeReceiptIdentifier(e?.name)&&(n||safeMcpReference(e?.definitionRef)&&safeMcpReference(e?.version)&&isSha256(e?.definitionSha256)&&(void 0===e?.credentialRef||safeMcpReference(e.credentialRef)))))throw new Error("invalid MCP desired-state server identity");return Object.freeze(n?{name:e.name,removed:!0}:{name:e.name,definitionRef:e.definitionRef,version:e.version,definitionSha256:e.definitionSha256,...e.credentialRef?{credentialRef:e.credentialRef}:{}})}function assertMcpCommitBindsRecord(e,t){if(e.operationId!==t.operationId||e.method!==t.command||e.paramsHash!==t.paramsHash||e.runtimeEpoch!==t.runtimeEpoch)throw new RuntimeCommandJournalConflictError("MCP desired-state commit does not bind command journal")}function releaseFromCommit(e,t,n){if(t.operationId!==e.operationId||t.source!==e.source||"service"===t.source&&!isSha256(t.effectRecordHash)||"acp_local"===t.source&&void 0!==t.effectRecordHash)throw new RuntimeCommandJournalConflictError("MCP live release proof does not bind desired state");return Object.freeze({...e,...t.effectRecordHash?{effectRecordHash:t.effectRecordHash}:{},releasedAt:n})}function activeFromRelease(e,t,n){if(!(e&&t.operationId===e.operationId&&t.source===e.source&&Number.isFinite(Date.parse(n))&&("service"!==t.source||isSha256(t.effectRecordHash)&&t.effectRecordHash===e.effectRecordHash&&safeReceiptIdentifier(t.terminalMessageId))&&("acp_local"!==t.source||void 0===t.effectRecordHash&&void 0===t.terminalMessageId)))throw new RuntimeCommandJournalConflictError("MCP active promotion does not bind terminal release proof");return Object.freeze({...e,...t.terminalMessageId?{terminalMessageId:t.terminalMessageId}:{},activatedAt:n})}function sameMcpDesiredStateCommit(e,t){if(!e||!t)return!1;const n=e=>({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function sameMcpLiveRelease(e,t){const n=e=>({...e,releasedAt:""});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function sameMcpActiveDesiredState(e,t){const n=e=>({...e,releasedAt:"",activatedAt:""});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function normalizeMcpProjectionReceipt(e){if(!e||"object"!=typeof e||"desiredStateHash,desiredStateRevision,method,operationId,runtimeEpoch,schemaVersion,server"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||!safeReceiptIdentifier(e.operationId)||"mcp.set"!==e.method&&"mcp.unset"!==e.method||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||!/^(0|[1-9][0-9]*)$/.test(e.desiredStateRevision)||!isSha256(e.desiredStateHash))throw new Error("invalid MCP projection receipt");const t=e.server;if((t&&"object"==typeof t?Object.keys(t).sort().join(","):"")!==(!0===t?.removed?"name,removed":void 0===t?.definitionRef?"name":"definitionRef,definitionSha256,name")||!safeReceiptIdentifier(t?.name)||void 0!==t?.definitionRef&&(!safeReceiptIdentifier(t.definitionRef)||!isSha256(t.definitionSha256)))throw new Error("invalid MCP projection server receipt");return Object.freeze({schemaVersion:1,operationId:e.operationId,method:e.method,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:Object.freeze(!0===t.removed?{name:t.name,removed:!0}:void 0===t.definitionRef?{name:t.name}:{name:t.name,definitionRef:t.definitionRef,definitionSha256:t.definitionSha256})})}function isSha256(e){return"string"==typeof e&&/^[a-f0-9]{64}$/.test(e)}function safeReceiptIdentifier(e){return"string"==typeof e&&/^[a-zA-Z0-9._:@/-]{1,512}$/.test(e)&&!/(authorization|bearer|credential|secret|token|password|private(?:_|-)?key|headers?|env)/i.test(e)}function safeMcpReference(e){return"string"==typeof e&&/^[a-zA-Z0-9._:@/-]{1,512}$/.test(e)&&!/(authorization|bearer|secret|token|password|private(?:_|-)?key|headers?|env)/i.test(e)}function agentProjectionTerminalReceipt(e){if(!/^(0|[1-9][0-9]*)$/.test(e))throw new Error("invalid agent projection terminal revision");return Object.freeze({schemaVersion:1,state:"blocked",revision:e})}function normalizeAgentProjectionTerminal(e){if("revision,schemaVersion,state"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||"blocked"!==e.state)throw new Error("invalid agent projection terminal receipt");return agentProjectionTerminalReceipt(e.revision)}function normalizeAgentProjectionIntent(e,t){const n=Object.keys(e).sort(),o=["canonicalHash","coreResultHash","method","operationId","projectionRevision","runtimeAgentUid","runtimeEpoch","runtimeLocalKey","schemaVersion","snapshotRef",...void 0===e.expectedPlatformAgentId?[]:["expectedPlatformAgentId"],...void 0===e.removedBindings?[]:["removedBindings"]].sort();if(n.length!==o.length||n.some((e,t)=>e!==o[t])||1!==e.schemaVersion||!["agent.create","agent.update","agent.delete","agent.applyTemplate"].includes(e.method)||!nonEmptyText(e.operationId)||!nonEmptyText(e.runtimeAgentUid)||!nonEmptyText(e.runtimeLocalKey)||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||e.operationId!==t.operationId||e.method!==t.command||e.runtimeEpoch!==t.runtimeEpoch||void 0!==e.expectedPlatformAgentId&&!nonEmptyText(e.expectedPlatformAgentId)||!/^[0-9a-f]{64}$/.test(e.coreResultHash)||!/^(0|[1-9][0-9]*)$/.test(e.projectionRevision)||!/^[0-9a-f]{64}$/.test(e.canonicalHash)||!nonEmptyText(e.snapshotRef)||e.snapshotRef!==projectionSnapshotRef(e.runtimeEpoch,e.projectionRevision,e.canonicalHash)||void 0!==e.removedBindings&&(!Number.isSafeInteger(e.removedBindings)||e.removedBindings<0))throw new Error("invalid agent projection intent");return Object.freeze({...e})}function normalizeAgentProjectionPreparation(e,t){if(isAgentProjectionIntent(e))return normalizeAgentProjectionIntent(e,t);const n=e,o=Object.keys(n).sort(),r=["coreResultHash","errorKind","method","operationId","runtimeAgentUid","runtimeEpoch","runtimeLocalKey","schemaVersion","state",...void 0===n.expectedPlatformAgentId?[]:["expectedPlatformAgentId"],...void 0===n.removedBindings?[]:["removedBindings"]].sort();if(o.length!==r.length||o.some((e,t)=>e!==r[t])||1!==n.schemaVersion||!["agent.create","agent.update","agent.delete","agent.applyTemplate"].includes(n.method)||n.operationId!==t.operationId||n.method!==t.command||n.runtimeEpoch!==t.runtimeEpoch||!nonEmptyText(n.runtimeAgentUid)||!nonEmptyText(n.runtimeLocalKey)||!/^(0|[1-9][0-9]*)$/.test(n.runtimeEpoch)||!/^[0-9a-f]{64}$/.test(n.coreResultHash)||"pending"!==n.state&&"blocked"!==n.state||"snapshot_retryable"!==n.errorKind&&"snapshot_nonretryable"!==n.errorKind||"pending"===n.state!=("snapshot_retryable"===n.errorKind)||void 0!==n.expectedPlatformAgentId&&!nonEmptyText(n.expectedPlatformAgentId)||void 0!==n.removedBindings&&(!Number.isSafeInteger(n.removedBindings)||n.removedBindings<0))throw new Error("invalid agent projection preparation failure");return Object.freeze({...n})}function sameProjectionPreparationBase(e,t){return e.operationId===t.operationId&&e.method===t.method&&e.runtimeEpoch===t.runtimeEpoch&&e.runtimeAgentUid===t.runtimeAgentUid&&e.runtimeLocalKey===t.runtimeLocalKey&&e.coreResultHash===t.coreResultHash&&e.expectedPlatformAgentId===t.expectedPlatformAgentId&&e.removedBindings===t.removedBindings}function isAgentProjectionIntent(e){return"projectionRevision"in e}function projectionSnapshotRef(e,t,n){return`runtime-agent-projection:v1:${e}:${t}:${n}`}function nonEmptyText(e){return"string"==typeof e&&e.length>0}
|
|
1
|
+
import{createHash,randomUUID}from"node:crypto";import{readFile}from"node:fs/promises";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";import{createRuntimeAppendTimingRecorder}from"./runtime-append-timing.js";import{OwnedDirectoryLockContendedError,withOwnedDirectoryLock}from"./owned-directory-lock.js";import{MonotonicJournalSegments}from"./monotonic-journal-segments.js";const HASH_ONLY_RESULT_COMMANDS=new Set(["session.load","session.history","session.list","agent.listProjection","skills.list","models.list","cron.list","cron.status","cron.runs","mcp.list","terminal.ping","terminal.wait"]),SAFE_CANONICAL_RESULT_COMMANDS=new Set(["session.clear","session.setMode","session.setModel","session.cancel","skills.install","skills.uninstall","skills.setEnabled","cron.remove","mcp.prepare","mcp.set","mcp.unset","terminal.input","terminal.resize","terminal.close","terminal.release","terminal.kill","canvas.toggle","canvas.clear","canvas.reference","canvas.dimensions"]);export const runtimeCommandResultPersistencePolicy=e=>SAFE_CANONICAL_RESULT_COMMANDS.has(e)?"canonical_result":"hash_only";export const runtimeCommandIsReplayableQuery=e=>HASH_ONLY_RESULT_COMMANDS.has(e);export const runtimeCommandResultHash=e=>createHash("sha256").update(canonicalizeJcs(e)).digest("hex");const emptyDocument=()=>({version:2,lineage:{journalStoreId:randomUUID(),journalGeneration:"1"},records:[],cancellations:[]}),CHECKPOINT_INTERVAL_MS=6e5,CHECKPOINT_DELTA_COUNT=512,CHECKPOINT_DELTA_BYTES=8388608,CHECKPOINT_FOREGROUND_QUIET_MS=50;export class RuntimeCommandJournalConflictError extends Error{constructor(e){super(e),this.name="RuntimeCommandJournalConflictError"}}export class FileRuntimeCommandJournal{file;retentionMs;now;publication;segments;maintenance;forceCheckpointRequested=!1;maintenanceDue;maintenanceDueAtMs;prunePending=!1;foregroundUpdates=0;foregroundRevision=0;constructor(e,t=6048e5,n=Date.now,o={}){this.file=e,this.retentionMs=t,this.now=n,this.publication=o,this.segments=new MonotonicJournalSegments(e)}async lineage(){return await this.update(e=>({...e.lineage}))}async advanceLineageGeneration(e){return await this.update(t=>{if(t.lineage.journalStoreId!==e.journalStoreId)throw new RuntimeCommandJournalConflictError("journal store changed during incarnation advance");const n=BigInt(t.lineage.journalGeneration),o=BigInt(e.floor),r=(n>o?n:o)+1n;if(r>9223372036854775807n)throw new RuntimeCommandJournalConflictError("journal generation overflow");return t.lineage={journalStoreId:t.lineage.journalStoreId,journalGeneration:String(r)},{...t.lineage}})}async get(e){return(await this.read()).records.find(t=>t.operationId===e)??null}async getCancellation(e){return(await this.read()).cancellations.find(t=>t.operationId===e)??null}async listMcpLiveReleases(){const e=await this.read();return Object.freeze(e.records.flatMap(e=>e.mcpLiveRelease?[e.mcpLiveRelease]:[]))}async listMcpActiveDesiredStates(){const e=await this.read();return Object.freeze(e.records.flatMap(e=>e.mcpActiveDesiredState?[e.mcpActiveDesiredState]:[]))}async recordMcpDesiredStateCommit(e){const t=normalizeMcpDesiredStateCommit(e);return await this.update(e=>{const n=e.records.findIndex(e=>e.operationId===t.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP desired state has no command record");const o=e.records[n];if(assertMcpCommitBindsRecord(t,o),"started"!==o.phase){if(sameMcpDesiredStateCommit(o.mcpDesiredStateCommit,t))return o;throw new RuntimeCommandJournalConflictError("MCP desired state commit crossed its journal boundary")}if(o.mcpDesiredStateCommit){if(sameMcpDesiredStateCommit(o.mcpDesiredStateCommit,t))return o;throw new RuntimeCommandJournalConflictError("MCP desired state commit conflicts with journal")}const r={...o,mcpDesiredStateCommit:t,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return e.records[n]=r,r})}async releaseMcpLiveEffect(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP release has no command record");const o=t.records[n];if("effect_committed"!==o.phase&&"projection_committed"!==o.phase)throw new RuntimeCommandJournalConflictError("MCP release requires a committed effect");if(!o.mcpDesiredStateCommit)throw new RuntimeCommandJournalConflictError("MCP release lacks a durable desired-state commit");if("service"===e.source&&!o.messageBinding)throw new RuntimeCommandJournalConflictError("Service MCP release lacks a Message Service request binding");const r=releaseFromCommit(o.mcpDesiredStateCommit,e,new Date(this.now()).toISOString());if(o.mcpLiveRelease){if(sameMcpLiveRelease(o.mcpLiveRelease,r))return o;throw new RuntimeCommandJournalConflictError("MCP release conflicts with journal")}const i={...o,mcpLiveRelease:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async promoteMcpDesiredStateActive(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("MCP active promotion has no command record");const o=t.records[n],r=activeFromRelease(o.mcpLiveRelease,e,new Date(this.now()).toISOString());if(o.mcpActiveDesiredState){if(sameMcpActiveDesiredState(o.mcpActiveDesiredState,r))return o;throw new RuntimeCommandJournalConflictError("MCP active desired state conflicts with journal")}const i={...o,mcpActiveDesiredState:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async acceptMessageRequest(e){return await this.update(t=>{let n=t.records.find(t=>t.operationId===e.operationId);if(n||(n={operationId:e.operationId,command:e.command,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,phase:"prepared",revision:1,updatedAt:new Date(this.now()).toISOString()},t.records.push(n)),n.command!==e.command||n.paramsHash!==e.paramsHash||n.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("message request conflicts with command journal");const o={requestMessageId:e.requestMessageId,requestHash:e.requestHash,acceptedAt:new Date(this.now()).toISOString()};if(n.messageBinding&&(n.messageBinding.requestMessageId!==o.requestMessageId||n.messageBinding.requestHash!==o.requestHash))throw new RuntimeCommandJournalConflictError("operation reused by a different message request");return n.messageBinding??=o,n})}async observeCancellation(e){return await this.update(t=>{const n=t.cancellations.find(t=>t.eventId===e.eventId);if(n){if(n.operationId!==e.operationId||n.requestMessageId!==e.requestMessageId||n.requestHash!==e.requestHash)throw new RuntimeCommandJournalConflictError("operation cancellation observation conflict");return n}const o=t.cancellations.find(t=>t.operationId===e.operationId);if(o&&(o.requestMessageId!==e.requestMessageId||o.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("operation cancellation request correlation conflict");const r={...e,observedAt:new Date(this.now()).toISOString()};return t.cancellations.push(r),r})}async prepare(e){return await this.update(t=>{const n=t.records.find(t=>t.operationId===e.operationId);if(n){if(n.command!==e.command||n.paramsHash!==e.paramsHash)throw new RuntimeCommandJournalConflictError("operation identity reused with different command or params hash");if(n.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("operation belongs to a different runtime epoch");return n}const o={...e,phase:"prepared",revision:1,updatedAt:new Date(this.now()).toISOString()};return t.records.push(o),o})}async transition(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision)throw new RuntimeCommandJournalConflictError("journal revision conflict");const r="effect_committed"===o.phase&&"effect_committed"===e.phase&&void 0!==e.agentProjection&&void 0===o.agentProjectionIntent&&"pending"===o.agentProjectionPreparationFailure?.state;if("projection_committed"===o.phase||"failed"===o.phase||"outcome_unknown"===o.phase||"effect_committed"===o.phase&&"projection_committed"!==e.phase&&!r)throw new RuntimeCommandJournalConflictError("terminal journal record is immutable");if(void 0!==e.projectionSnapshot&&"projection_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("projection receipt requires projection_committed phase");if(void 0!==e.agentProjection&&"effect_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("agent projection intent requires effect_committed phase");const i=void 0===e.agentProjection?void 0:normalizeAgentProjectionPreparation(e.agentProjection,o);if(r&&i&&!sameProjectionPreparationBase(o.agentProjectionPreparationFailure,i))throw new RuntimeCommandJournalConflictError("agent projection preparation conflicts with committed operation");const{agentProjectionIntent:a,agentProjectionPreparationFailure:s,...c}=o,d={...void 0===i?o:c,phase:e.phase,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString(),...void 0===e.result?{}:persistedResult(o.command,e.result),...void 0===e.projectionSnapshot?{}:{projectionReceipt:projectionReceipt(e.projectionSnapshot)},...void 0===i?{}:isAgentProjectionIntent(i)?{agentProjectionIntent:i}:{agentProjectionPreparationFailure:i},...void 0===e.errorCode?{}:{errorCode:e.errorCode}};return t.records[n]=d,d})}async recordAgentProjectionIntent(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision||"effect_committed"!==o.phase)throw new RuntimeCommandJournalConflictError("projection intent cannot mutate this command journal record");const r=normalizeAgentProjectionIntent(e.intent,o);if(o.agentProjectionIntent){if(canonicalizeJcs(o.agentProjectionIntent)!==canonicalizeJcs(r))throw new RuntimeCommandJournalConflictError("agent projection intent conflicts with committed operation");return o}if("pending"!==o.agentProjectionPreparationFailure?.state||!sameProjectionPreparationBase(o.agentProjectionPreparationFailure,r))throw new RuntimeCommandJournalConflictError("projection intent requires matching retryable preparation failure");const{agentProjectionPreparationFailure:i,...a}=o,s={...a,agentProjectionIntent:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=s,s})}async recordAgentProjectionBlocked(e){return await this.update(t=>{const n=t.records.findIndex(t=>t.operationId===e.operationId);if(n<0)throw new RuntimeCommandJournalConflictError("operation was not prepared");const o=t.records[n];if(o.revision!==e.expectedRevision||"effect_committed"!==o.phase||!o.agentProjectionIntent||o.agentProjectionIntent.projectionRevision!==e.revision)throw new RuntimeCommandJournalConflictError("blocked projection cannot mutate this command journal record");if(o.agentProjectionTerminal){if("blocked"===o.agentProjectionTerminal.state&&o.agentProjectionTerminal.revision===e.revision)return o;throw new RuntimeCommandJournalConflictError("agent projection terminal conflicts with committed operation")}const r=agentProjectionTerminalReceipt(e.revision),i={...o,agentProjectionTerminal:r,revision:o.revision+1,updatedAt:new Date(this.now()).toISOString()};return t.records[n]=i,i})}async compact(){return this.maintenance?await this.maintenance:!1===this.maintenanceDue&&!this.prunePending&&void 0!==this.maintenanceDueAtMs&&Date.now()<this.maintenanceDueAtMs?0:await this.startMaintenance()}async checkpoint(){return this.forceCheckpointRequested=!0,await this.startMaintenance()}async read(){return(await this.readState()).document}async readState(){const e=await this.readLegacy(),t=new Map;if(e){t.set("meta:lineage",{value:e.lineage,logicalRevision:e.lineage.journalGeneration,publisherEpoch:"0"});for(const n of e.records)t.set(`record:${n.operationId}`,{value:n,logicalRevision:String(n.revision),publisherEpoch:"0"});for(const n of e.cancellations)t.set(`cancellation:${n.eventId}`,{value:n,logicalRevision:"1",publisherEpoch:"0"})}const n=await this.segments.readState(t),o=n.values,r=o.get("meta:lineage")?.value;return{document:{version:2,lineage:r??emptyDocument().lineage,records:[...o.entries()].filter(([e])=>e.startsWith("record:")).map(([,e])=>validateRecordReceipts(migrateLegacyCommittedPhase(e.value))),cancellations:[...o.entries()].filter(([e])=>e.startsWith("cancellation:")).map(([,e])=>e.value)},authorityFloor:n.authorityFloor,checkpointAtMs:n.checkpointAtMs,deltaCount:n.deltaCount,deltaBytes:n.deltaBytes,oldestDeltaAtMs:n.oldestDeltaAtMs,hasDurableLineage:o.has("meta:lineage")&&n.hasDurableState}}async readLegacy(){try{const e=JSON.parse(await readFile(this.file,"utf8"));if(!Array.isArray(e.records))throw new Error("unsupported command journal");const t=e.records.map(e=>validateRecordReceipts(migrateLegacyCommittedPhase(e)));if(1===e.version)return{...emptyDocument(),records:t};if(2!==e.version||!e.lineage?.journalStoreId||!/^[1-9][0-9]*$/.test(e.lineage.journalGeneration))throw new Error("unsupported command journal");return{...e,records:t,cancellations:Array.isArray(e.cancellations)?e.cancellations:[]}}catch(e){if("ENOENT"===e.code)return null;throw e}}async update(e){const t=createRuntimeAppendTimingRecorder("journal.update",{file:this.file});let n=!1;this.foregroundUpdates+=1;try{return await withOwnedDirectoryLock(`${this.file}.lock`,async o=>{t.mark("lock");const r=await this.readState();t.mark("read");const i=r.document,a=structuredClone(i),s=e(i),c=[];if(r.hasDurableLineage&&sameValue(a.lineage,i.lineage)||c.push({key:"meta:lineage",logicalRevision:i.lineage.journalGeneration,value:i.lineage}),diffValues(a.records,i.records,e=>e.operationId,e=>String(e.revision),"record:",c),diffValues(a.cancellations,i.cancellations,e=>e.eventId,()=>"1","cancellation:",c),0===c.length)return t.mark("noop"),s;await(this.publication.beforePublish?.(o.epoch)),t.mark("before-publish"),await o.assertOwned(),t.mark("assert-owned");const d=await this.segments.publishDelta(o.epoch,c,r.authorityFloor);t.mark("publish-delta");const m=Date.now();return this.maintenanceDueAtMs=checkpointDueAt(r,1,d,m),n=this.maintenanceDueAtMs<=m,this.maintenanceDue=n,s},{...this.publication.lockOptions,epochFloor:()=>this.segments.authorityFloor()})}finally{this.foregroundUpdates-=1,this.foregroundRevision+=1,t.finish(),n&&this.scheduleMaintenance()}}scheduleMaintenance(){this.startMaintenance().catch(e=>{try{this.publication.onMaintenanceError?this.publication.onMaintenanceError(e):emitMaintenanceWarning(e)}catch(e){emitMaintenanceWarning(e)}})}startMaintenance(){if(this.maintenance)return this.maintenance;const e=(async()=>{let e=0,t=!1;do{let n=this.forceCheckpointRequested;this.forceCheckpointRequested=!1,n||(await this.waitForForegroundQuiet(),n=this.forceCheckpointRequested,this.forceCheckpointRequested=!1);const o=await this.runMaintenance(n);e+=o.removed,t=o.contended}while(this.forceCheckpointRequested||t);return e})().finally(()=>{this.maintenance===e&&(this.maintenance=void 0)});return this.maintenance=e,e}async waitForForegroundQuiet(){for(;;){if(this.forceCheckpointRequested)return;const e=this.foregroundRevision;if(0===this.foregroundUpdates){if(await new Promise(e=>setTimeout(e,50)),this.forceCheckpointRequested||0===this.foregroundUpdates&&this.foregroundRevision===e)return}else await new Promise(e=>setTimeout(e,50))}}async runMaintenance(e){const t=createRuntimeAppendTimingRecorder("journal.checkpoint",{file:this.file});try{if(!e&&this.prunePending)return await this.segments.prune(),this.prunePending=!1,t.mark("prune-pending"),{removed:0,contended:!1};let n=!1;const o=await withOwnedDirectoryLock(`${this.file}.lock`,async o=>{t.mark("lock");const r=await this.readState();if(t.mark("read"),!e&&!checkpointDue(r))return this.maintenanceDue=!1,this.maintenanceDueAtMs=checkpointDueAt(r),t.mark("not-due"),0;const i=r.document,a=this.now()-this.retentionMs,s=i.records.length;i.records=i.records.filter(e=>"prepared"===e.phase||"started"===e.phase||Date.parse(e.updatedAt)>=a);const c=i.cancellations.length;i.cancellations=i.cancellations.filter(e=>Date.parse(e.observedAt)>=a);const d=s-i.records.length+c-i.cancellations.length,m=documentValues(i);return await(this.publication.beforePublish?.(o.epoch)),t.mark("before-publish"),await o.assertOwned(),t.mark("assert-owned"),await this.segments.checkpointSnapshot(o.epoch,m,r.authorityFloor),t.mark("publish-snapshot"),this.maintenanceDue=!1,this.maintenanceDueAtMs=Number.POSITIVE_INFINITY,this.prunePending=!0,n=!0,d},{...this.publication.lockOptions,failIfContended:!e,epochFloor:()=>this.segments.authorityFloor()});return t.mark("lock-released"),n&&(await this.segments.prune(),this.prunePending=!1,t.mark("prune")),{removed:o,contended:!1}}catch(n){if(!e&&n instanceof OwnedDirectoryLockContendedError)return t.mark("deferred-busy"),{removed:0,contended:!0};throw n}finally{t.finish(e?"forced":"scheduled")}}}function checkpointDue(e,t=0,n=0,o=Date.now()){return checkpointDueAt(e,t,n,o)<=o}function checkpointDueAt(e,t=0,n=0,o=Date.now()){const r=e.deltaCount+t,i=e.deltaBytes+n,a=e.oldestDeltaAtMs||(t>0?o:0),s=e.checkpointAtMs||a;return r>=512||i>=8388608?o:r>0&&s>0?s+6e5:Number.POSITIVE_INFINITY}function emitMaintenanceWarning(e){process.emitWarning(e instanceof Error?e.message:String(e),{code:"BEEOS_RUNTIME_JOURNAL_CHECKPOINT_FAILED"})}function diffValues(e,t,n,o,r,i){const a=new Map(e.map(e=>[n(e),e])),s=new Map(t.map(e=>[n(e),e]));for(const[e,t]of s){const n=a.get(e);void 0!==n&&sameValue(n,t)||i.push({key:`${r}${e}`,logicalRevision:o(t),value:t})}for(const[e,t]of a)s.has(e)||i.push({key:`${r}${e}`,logicalRevision:o(t),tombstone:!0})}function documentValues(e){return[{key:"meta:lineage",logicalRevision:e.lineage.journalGeneration,value:e.lineage},...e.records.map(e=>({key:`record:${e.operationId}`,logicalRevision:String(e.revision),value:e})),...e.cancellations.map(e=>({key:`cancellation:${e.eventId}`,logicalRevision:"1",value:e}))]}function sameValue(e,t){return canonicalizeJcs(e)===canonicalizeJcs(t)}function migrateLegacyCommittedPhase(e){return{...e,phase:"committed"===e.phase?"effect_committed":e.phase}}export class InMemoryRuntimeCommandJournal{records=new Map;cancellations=new Map;async get(e){return this.records.get(e)??null}async getCancellation(e){return[...this.cancellations.values()].find(t=>t.operationId===e)??null}async listMcpLiveReleases(){return Object.freeze([...this.records.values()].flatMap(e=>e.mcpLiveRelease?[e.mcpLiveRelease]:[]))}async listMcpActiveDesiredStates(){return Object.freeze([...this.records.values()].flatMap(e=>e.mcpActiveDesiredState?[e.mcpActiveDesiredState]:[]))}async recordMcpDesiredStateCommit(e){const t=normalizeMcpDesiredStateCommit(e),n=this.records.get(t.operationId);if(!n)throw new RuntimeCommandJournalConflictError("MCP desired state has no command record");if(assertMcpCommitBindsRecord(t,n),"started"!==n.phase){if(sameMcpDesiredStateCommit(n.mcpDesiredStateCommit,t))return n;throw new RuntimeCommandJournalConflictError("MCP desired state commit crossed its journal boundary")}if(n.mcpDesiredStateCommit){if(sameMcpDesiredStateCommit(n.mcpDesiredStateCommit,t))return n;throw new RuntimeCommandJournalConflictError("MCP desired state commit conflicts with journal")}const o={...n,mcpDesiredStateCommit:t,revision:n.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(t.operationId,o),o}async releaseMcpLiveEffect(e){const t=this.records.get(e.operationId);if(!t)throw new RuntimeCommandJournalConflictError("MCP release has no command record");if("effect_committed"!==t.phase&&"projection_committed"!==t.phase)throw new RuntimeCommandJournalConflictError("MCP release requires a committed effect");if(!t.mcpDesiredStateCommit)throw new RuntimeCommandJournalConflictError("MCP release lacks a durable desired-state commit");if("service"===e.source&&!t.messageBinding)throw new RuntimeCommandJournalConflictError("Service MCP release lacks a Message Service request binding");const n=releaseFromCommit(t.mcpDesiredStateCommit,e,(new Date).toISOString());if(t.mcpLiveRelease){if(sameMcpLiveRelease(t.mcpLiveRelease,n))return t;throw new RuntimeCommandJournalConflictError("MCP release conflicts with journal")}const o={...t,mcpLiveRelease:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,o),o}async promoteMcpDesiredStateActive(e){const t=this.records.get(e.operationId);if(!t)throw new RuntimeCommandJournalConflictError("MCP active promotion has no command record");const n=activeFromRelease(t.mcpLiveRelease,e,(new Date).toISOString());if(t.mcpActiveDesiredState){if(sameMcpActiveDesiredState(t.mcpActiveDesiredState,n))return t;throw new RuntimeCommandJournalConflictError("MCP active desired state conflicts with journal")}const o={...t,mcpActiveDesiredState:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,o),o}async acceptMessageRequest(e){let t=this.records.get(e.operationId);if(t||(t={operationId:e.operationId,command:e.command,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,phase:"prepared",revision:1,updatedAt:(new Date).toISOString()},this.records.set(e.operationId,t)),t.command!==e.command||t.paramsHash!==e.paramsHash||t.runtimeEpoch!==e.runtimeEpoch||t.messageBinding&&(t.messageBinding.requestMessageId!==e.requestMessageId||t.messageBinding.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("message request conflicts with command journal");return t.messageBinding??={requestMessageId:e.requestMessageId,requestHash:e.requestHash,acceptedAt:(new Date).toISOString()},t}async observeCancellation(e){const t=this.cancellations.get(e.eventId);if(t){if(t.operationId!==e.operationId||t.requestMessageId!==e.requestMessageId||t.requestHash!==e.requestHash)throw new RuntimeCommandJournalConflictError("operation cancellation observation conflict");return t}const n=[...this.cancellations.values()].find(t=>t.operationId===e.operationId);if(n&&(n.requestMessageId!==e.requestMessageId||n.requestHash!==e.requestHash))throw new RuntimeCommandJournalConflictError("operation cancellation request correlation conflict");const o={...e,observedAt:(new Date).toISOString()};return this.cancellations.set(e.eventId,o),o}async prepare(e){const t=this.records.get(e.operationId);if(t){if(t.command!==e.command||t.paramsHash!==e.paramsHash||t.runtimeEpoch!==e.runtimeEpoch)throw new RuntimeCommandJournalConflictError("operation identity conflict");return t}const n={...e,phase:"prepared",revision:1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,n),n}async transition(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision)throw new RuntimeCommandJournalConflictError("revision conflict");const n="effect_committed"===t.phase&&"effect_committed"===e.phase&&void 0!==e.agentProjection&&void 0===t.agentProjectionIntent&&"pending"===t.agentProjectionPreparationFailure?.state;if("projection_committed"===t.phase||"failed"===t.phase||"outcome_unknown"===t.phase||"effect_committed"===t.phase&&"projection_committed"!==e.phase&&!n)throw new RuntimeCommandJournalConflictError("terminal journal record is immutable");if(void 0!==e.projectionSnapshot&&"projection_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("projection receipt requires projection_committed phase");if(void 0!==e.agentProjection&&"effect_committed"!==e.phase)throw new RuntimeCommandJournalConflictError("agent projection intent requires effect_committed phase");const o=void 0===e.agentProjection?void 0:normalizeAgentProjectionPreparation(e.agentProjection,t);if(n&&o&&!sameProjectionPreparationBase(t.agentProjectionPreparationFailure,o))throw new RuntimeCommandJournalConflictError("agent projection preparation conflicts with committed operation");const{agentProjectionIntent:r,agentProjectionPreparationFailure:i,...a}=t,s={...void 0===o?t:a,phase:e.phase,revision:t.revision+1,updatedAt:(new Date).toISOString(),...void 0===e.result?{}:persistedResult(t.command,e.result),...void 0===e.projectionSnapshot?{}:{projectionReceipt:projectionReceipt(e.projectionSnapshot)},...void 0===o?{}:isAgentProjectionIntent(o)?{agentProjectionIntent:o}:{agentProjectionPreparationFailure:o},...void 0===e.errorCode?{}:{errorCode:e.errorCode}};return this.records.set(e.operationId,s),s}async recordAgentProjectionIntent(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision||"effect_committed"!==t.phase)throw new RuntimeCommandJournalConflictError("projection intent cannot mutate this command journal record");const n=normalizeAgentProjectionIntent(e.intent,t);if(t.agentProjectionIntent){if(canonicalizeJcs(t.agentProjectionIntent)!==canonicalizeJcs(n))throw new RuntimeCommandJournalConflictError("agent projection intent conflicts with committed operation");return t}if("pending"!==t.agentProjectionPreparationFailure?.state||!sameProjectionPreparationBase(t.agentProjectionPreparationFailure,n))throw new RuntimeCommandJournalConflictError("projection intent requires matching retryable preparation failure");const{agentProjectionPreparationFailure:o,...r}=t,i={...r,agentProjectionIntent:n,revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,i),i}async recordAgentProjectionBlocked(e){const t=this.records.get(e.operationId);if(!t||t.revision!==e.expectedRevision||"effect_committed"!==t.phase||!t.agentProjectionIntent||t.agentProjectionIntent.projectionRevision!==e.revision)throw new RuntimeCommandJournalConflictError("blocked projection cannot mutate this command journal record");if(t.agentProjectionTerminal){if("blocked"===t.agentProjectionTerminal.state&&t.agentProjectionTerminal.revision===e.revision)return t;throw new RuntimeCommandJournalConflictError("agent projection terminal conflicts with committed operation")}const n={...t,agentProjectionTerminal:agentProjectionTerminalReceipt(e.revision),revision:t.revision+1,updatedAt:(new Date).toISOString()};return this.records.set(e.operationId,n),n}async compact(){return 0}async checkpoint(){return 0}}function persistedResult(e,t){return"canonical_result"===runtimeCommandResultPersistencePolicy(e)?{result:t}:{resultReceipt:{policy:"hash_only",resultHash:runtimeCommandResultHash(t),redacted:{kind:runtimeCommandIsReplayableQuery(e)?"query_result":"mutation_result",command:e}}}}function projectionReceipt(e){if("synced"!==e.state||!/^(0|[1-9][0-9]*)$/.test(e.revision))throw new Error("invalid projection revision");if(void 0!==e.platformAgentId&&!/^[a-zA-Z0-9._:-]{1,256}$/.test(e.platformAgentId))throw new Error("invalid projection platform agent id");const t=void 0===e.mcpReceipt?void 0:normalizeMcpProjectionReceipt(e.mcpReceipt),n=Object.freeze({revision:e.revision,state:"synced",..."string"==typeof e.platformAgentId&&e.platformAgentId?{platformAgentId:e.platformAgentId}:{},...t?{mcpReceipt:t}:{}});return Object.freeze({schemaVersion:1,revision:n.revision,snapshot:n,snapshotHash:runtimeCommandResultHash(n)})}function validateRecordReceipts(e){if(void 0!==e.agentProjectionIntent&&void 0!==e.agentProjectionPreparationFailure)throw new Error("agent projection journal record is ambiguous");const t=void 0!==e.agentProjectionIntent?{...e,agentProjectionIntent:normalizeAgentProjectionIntent(e.agentProjectionIntent,e)}:void 0!==e.agentProjectionPreparationFailure?{...e,agentProjectionPreparationFailure:normalizeAgentProjectionPreparation(e.agentProjectionPreparationFailure,e)}:e,n=void 0===t.agentProjectionTerminal?t:{...t,agentProjectionTerminal:normalizeAgentProjectionTerminal(t.agentProjectionTerminal)};if(n.agentProjectionTerminal&&(!n.agentProjectionIntent||"effect_committed"!==n.phase||n.agentProjectionIntent.projectionRevision!==n.agentProjectionTerminal.revision))throw new Error("invalid agent projection terminal receipt");const o=void 0===n.mcpDesiredStateCommit?void 0:normalizeMcpDesiredStateCommit(n.mcpDesiredStateCommit);o&&assertMcpCommitBindsRecord(o,n);const r=void 0===n.mcpLiveRelease?void 0:normalizeMcpLiveRelease(n.mcpLiveRelease);if(r&&(!o||!sameMcpDesiredStateCommit(o,r)||"effect_committed"!==n.phase&&"projection_committed"!==n.phase||"service"===r.source&&!n.messageBinding))throw new Error("invalid MCP live release receipt");const i=void 0===n.mcpActiveDesiredState?void 0:normalizeMcpActiveDesiredState(n.mcpActiveDesiredState);if(i&&(!r||!sameMcpDesiredStateCommit(i,r)||i.effectRecordHash!==r.effectRecordHash||i.releasedAt!==r.releasedAt))throw new Error("invalid MCP active desired-state receipt");const a={...n,...o?{mcpDesiredStateCommit:o}:{},...r?{mcpLiveRelease:r}:{},...i?{mcpActiveDesiredState:i}:{}};if(!a.projectionReceipt)return a;const s=a.projectionReceipt,c=["revision","state",...void 0===s.snapshot?.platformAgentId?[]:["platformAgentId"],...void 0===s.snapshot?.mcpReceipt?[]:["mcpReceipt"]].sort().join(",");if("revision,schemaVersion,snapshot,snapshotHash"!==Object.keys(s).sort().join(",")||Object.keys(s.snapshot??{}).sort().join(",")!==c||"projection_committed"!==a.phase||1!==s.schemaVersion||!/^(0|[1-9][0-9]*)$/.test(s.revision)||"synced"!==s.snapshot?.state||s.snapshot.revision!==s.revision)throw new Error("invalid projection receipt");const d=projectionReceipt(s.snapshot),m=d.snapshot.mcpReceipt;if(m&&(m.operationId!==a.operationId||m.method!==a.command||m.runtimeEpoch!==a.runtimeEpoch))throw new Error("MCP projection receipt does not bind journal operation");if(d.snapshotHash!==s.snapshotHash)throw new Error("invalid projection receipt hash");return{...a,projectionReceipt:d}}function normalizeMcpDesiredStateCommit(e){if(!e||"object"!=typeof e||"desiredStateHash,desiredStateRevision,method,operationId,paramsHash,runtimeEpoch,schemaVersion,server,source"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||"service"!==e.source&&"acp_local"!==e.source||!safeReceiptIdentifier(e.operationId)||"mcp.set"!==e.method&&"mcp.unset"!==e.method||!isSha256(e.paramsHash)||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||!/^(0|[1-9][0-9]*)$/.test(e.desiredStateRevision)||!isSha256(e.desiredStateHash))throw new Error("invalid MCP desired-state commit");return Object.freeze({schemaVersion:1,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:normalizeMcpReleaseServer(e.server)})}function normalizeMcpLiveRelease(e){if(!e||"object"!=typeof e)throw new Error("invalid MCP live release receipt");const t=["desiredStateHash","desiredStateRevision","method","operationId","paramsHash","releasedAt","runtimeEpoch","schemaVersion","server","source",..."service"===e.source?["effectRecordHash"]:[]].sort().join(",");if(Object.keys(e).sort().join(",")!==t||"service"===e.source&&!isSha256(e.effectRecordHash)||"acp_local"===e.source&&void 0!==e.effectRecordHash||"string"!=typeof e.releasedAt||!Number.isFinite(Date.parse(e.releasedAt)))throw new Error("invalid MCP live release receipt");const n=normalizeMcpDesiredStateCommit({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server});return Object.freeze({...n,...e.effectRecordHash?{effectRecordHash:e.effectRecordHash}:{},releasedAt:e.releasedAt})}function normalizeMcpActiveDesiredState(e){if(!e||"object"!=typeof e)throw new Error("invalid MCP active desired-state receipt");const t=["activatedAt","desiredStateHash","desiredStateRevision","method","operationId","paramsHash","releasedAt","runtimeEpoch","schemaVersion","server","source",..."service"===e.source?["effectRecordHash","terminalMessageId"]:[]].sort().join(",");if(Object.keys(e).sort().join(",")!==t||"string"!=typeof e.activatedAt||!Number.isFinite(Date.parse(e.activatedAt))||"service"===e.source&&!safeReceiptIdentifier(e.terminalMessageId))throw new Error("invalid MCP active desired-state receipt");const n=normalizeMcpLiveRelease({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server,releasedAt:e.releasedAt,...e.effectRecordHash?{effectRecordHash:e.effectRecordHash}:{}});return Object.freeze({...n,...e.terminalMessageId?{terminalMessageId:e.terminalMessageId}:{},activatedAt:e.activatedAt})}function normalizeMcpReleaseServer(e){const t=e&&"object"==typeof e?Object.keys(e).sort().join(","):"",n=!0===e?.removed;if(!(t===(n?"name,removed":void 0===e?.credentialRef?"definitionRef,definitionSha256,name,version":"credentialRef,definitionRef,definitionSha256,name,version")&&safeReceiptIdentifier(e?.name)&&(n||safeMcpReference(e?.definitionRef)&&safeMcpReference(e?.version)&&isSha256(e?.definitionSha256)&&(void 0===e?.credentialRef||safeMcpReference(e.credentialRef)))))throw new Error("invalid MCP desired-state server identity");return Object.freeze(n?{name:e.name,removed:!0}:{name:e.name,definitionRef:e.definitionRef,version:e.version,definitionSha256:e.definitionSha256,...e.credentialRef?{credentialRef:e.credentialRef}:{}})}function assertMcpCommitBindsRecord(e,t){if(e.operationId!==t.operationId||e.method!==t.command||e.paramsHash!==t.paramsHash||e.runtimeEpoch!==t.runtimeEpoch)throw new RuntimeCommandJournalConflictError("MCP desired-state commit does not bind command journal")}function releaseFromCommit(e,t,n){if(t.operationId!==e.operationId||t.source!==e.source||"service"===t.source&&!isSha256(t.effectRecordHash)||"acp_local"===t.source&&void 0!==t.effectRecordHash)throw new RuntimeCommandJournalConflictError("MCP live release proof does not bind desired state");return Object.freeze({...e,...t.effectRecordHash?{effectRecordHash:t.effectRecordHash}:{},releasedAt:n})}function activeFromRelease(e,t,n){if(!(e&&t.operationId===e.operationId&&t.source===e.source&&Number.isFinite(Date.parse(n))&&("service"!==t.source||isSha256(t.effectRecordHash)&&t.effectRecordHash===e.effectRecordHash&&safeReceiptIdentifier(t.terminalMessageId))&&("acp_local"!==t.source||void 0===t.effectRecordHash&&void 0===t.terminalMessageId)))throw new RuntimeCommandJournalConflictError("MCP active promotion does not bind terminal release proof");return Object.freeze({...e,...t.terminalMessageId?{terminalMessageId:t.terminalMessageId}:{},activatedAt:n})}function sameMcpDesiredStateCommit(e,t){if(!e||!t)return!1;const n=e=>({schemaVersion:e.schemaVersion,source:e.source,operationId:e.operationId,method:e.method,paramsHash:e.paramsHash,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:e.server});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function sameMcpLiveRelease(e,t){const n=e=>({...e,releasedAt:""});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function sameMcpActiveDesiredState(e,t){const n=e=>({...e,releasedAt:"",activatedAt:""});return canonicalizeJcs(n(e))===canonicalizeJcs(n(t))}function normalizeMcpProjectionReceipt(e){if(!e||"object"!=typeof e||"desiredStateHash,desiredStateRevision,method,operationId,runtimeEpoch,schemaVersion,server"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||!safeReceiptIdentifier(e.operationId)||"mcp.set"!==e.method&&"mcp.unset"!==e.method||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||!/^(0|[1-9][0-9]*)$/.test(e.desiredStateRevision)||!isSha256(e.desiredStateHash))throw new Error("invalid MCP projection receipt");const t=e.server;if((t&&"object"==typeof t?Object.keys(t).sort().join(","):"")!==(!0===t?.removed?"name,removed":void 0===t?.definitionRef?"name":"definitionRef,definitionSha256,name")||!safeReceiptIdentifier(t?.name)||void 0!==t?.definitionRef&&(!safeReceiptIdentifier(t.definitionRef)||!isSha256(t.definitionSha256)))throw new Error("invalid MCP projection server receipt");return Object.freeze({schemaVersion:1,operationId:e.operationId,method:e.method,runtimeEpoch:e.runtimeEpoch,desiredStateRevision:e.desiredStateRevision,desiredStateHash:e.desiredStateHash,server:Object.freeze(!0===t.removed?{name:t.name,removed:!0}:void 0===t.definitionRef?{name:t.name}:{name:t.name,definitionRef:t.definitionRef,definitionSha256:t.definitionSha256})})}function isSha256(e){return"string"==typeof e&&/^[a-f0-9]{64}$/.test(e)}function safeReceiptIdentifier(e){return"string"==typeof e&&/^[a-zA-Z0-9._:@/-]{1,512}$/.test(e)&&!/(authorization|bearer|credential|secret|token|password|private(?:_|-)?key|headers?|env)/i.test(e)}function safeMcpReference(e){return"string"==typeof e&&/^[a-zA-Z0-9._:@/-]{1,512}$/.test(e)&&!/(authorization|bearer|secret|token|password|private(?:_|-)?key|headers?|env)/i.test(e)}function agentProjectionTerminalReceipt(e){if(!/^(0|[1-9][0-9]*)$/.test(e))throw new Error("invalid agent projection terminal revision");return Object.freeze({schemaVersion:1,state:"blocked",revision:e})}function normalizeAgentProjectionTerminal(e){if("revision,schemaVersion,state"!==Object.keys(e).sort().join(",")||1!==e.schemaVersion||"blocked"!==e.state)throw new Error("invalid agent projection terminal receipt");return agentProjectionTerminalReceipt(e.revision)}function normalizeAgentProjectionIntent(e,t){const n=Object.keys(e).sort(),o=["canonicalHash","coreResultHash","method","operationId","projectionRevision","runtimeAgentUid","runtimeEpoch","runtimeLocalKey","schemaVersion","snapshotRef",...void 0===e.expectedPlatformAgentId?[]:["expectedPlatformAgentId"],...void 0===e.removedBindings?[]:["removedBindings"]].sort();if(n.length!==o.length||n.some((e,t)=>e!==o[t])||1!==e.schemaVersion||!["agent.create","agent.update","agent.delete","agent.applyTemplate"].includes(e.method)||!nonEmptyText(e.operationId)||!nonEmptyText(e.runtimeAgentUid)||!nonEmptyText(e.runtimeLocalKey)||!/^(0|[1-9][0-9]*)$/.test(e.runtimeEpoch)||e.operationId!==t.operationId||e.method!==t.command||e.runtimeEpoch!==t.runtimeEpoch||void 0!==e.expectedPlatformAgentId&&!nonEmptyText(e.expectedPlatformAgentId)||!/^[0-9a-f]{64}$/.test(e.coreResultHash)||!/^(0|[1-9][0-9]*)$/.test(e.projectionRevision)||!/^[0-9a-f]{64}$/.test(e.canonicalHash)||!nonEmptyText(e.snapshotRef)||e.snapshotRef!==projectionSnapshotRef(e.runtimeEpoch,e.projectionRevision,e.canonicalHash)||void 0!==e.removedBindings&&(!Number.isSafeInteger(e.removedBindings)||e.removedBindings<0))throw new Error("invalid agent projection intent");return Object.freeze({...e})}function normalizeAgentProjectionPreparation(e,t){if(isAgentProjectionIntent(e))return normalizeAgentProjectionIntent(e,t);const n=e,o=Object.keys(n).sort(),r=["coreResultHash","errorKind","method","operationId","runtimeAgentUid","runtimeEpoch","runtimeLocalKey","schemaVersion","state",...void 0===n.expectedPlatformAgentId?[]:["expectedPlatformAgentId"],...void 0===n.removedBindings?[]:["removedBindings"]].sort();if(o.length!==r.length||o.some((e,t)=>e!==r[t])||1!==n.schemaVersion||!["agent.create","agent.update","agent.delete","agent.applyTemplate"].includes(n.method)||n.operationId!==t.operationId||n.method!==t.command||n.runtimeEpoch!==t.runtimeEpoch||!nonEmptyText(n.runtimeAgentUid)||!nonEmptyText(n.runtimeLocalKey)||!/^(0|[1-9][0-9]*)$/.test(n.runtimeEpoch)||!/^[0-9a-f]{64}$/.test(n.coreResultHash)||"pending"!==n.state&&"blocked"!==n.state||"snapshot_retryable"!==n.errorKind&&"snapshot_nonretryable"!==n.errorKind||"pending"===n.state!=("snapshot_retryable"===n.errorKind)||void 0!==n.expectedPlatformAgentId&&!nonEmptyText(n.expectedPlatformAgentId)||void 0!==n.removedBindings&&(!Number.isSafeInteger(n.removedBindings)||n.removedBindings<0))throw new Error("invalid agent projection preparation failure");return Object.freeze({...n})}function sameProjectionPreparationBase(e,t){return e.operationId===t.operationId&&e.method===t.method&&e.runtimeEpoch===t.runtimeEpoch&&e.runtimeAgentUid===t.runtimeAgentUid&&e.runtimeLocalKey===t.runtimeLocalKey&&e.coreResultHash===t.coreResultHash&&e.expectedPlatformAgentId===t.expectedPlatformAgentId&&e.removedBindings===t.removedBindings}function isAgentProjectionIntent(e){return"projectionRevision"in e}function projectionSnapshotRef(e,t,n){return`runtime-agent-projection:v1:${e}:${t}:${n}`}function nonEmptyText(e){return"string"==typeof e&&e.length>0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const RUNTIME_ERROR_PART_KIND="runtime_error";const RUNTIME_ERROR_CODES=["insufficient_credits"];export function createRuntimeErrorPart(r){return{type:"custom",kind:"runtime_error",data:{code:r}}}export function parseRuntimeErrorPart(r){if(!r||"object"!=typeof r||Array.isArray(r))return;const t=r;if("custom"!==t.type||"runtime_error"!==t.kind)return;const e=t.data;if(!e||"object"!=typeof e||Array.isArray(e))return;const n=e.code;return"string"==typeof n&&RUNTIME_ERROR_CODES.includes(n)?createRuntimeErrorPart(n):void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RUNTIME_INVOCATION_RECOVERY_CLASSES,RUNTIME_METHOD_PARITY_MANIFEST}from"@beeos-ai/beeos-types/runtime";export const RUNTIME_LOCAL_PARITY_MATRIX=Object.freeze(RUNTIME_METHOD_PARITY_MANIFEST.filter(e=>"request"===e.acpMessage&&e.serviceAllowed&&e.canonicalCommand&&e.acpMethod in RUNTIME_INVOCATION_RECOVERY_CLASSES&&("methods"===e.serviceRoute||"conversation-api"===e.serviceRoute)).map(e=>{const r=e.acpMethod,t="query"===e.recoveryClass?[]:["runtime_effect_committed"];return Object.freeze({method:r,acp:Object.freeze({params:e.acpParamsType,result:e.acpResultType,errors:Object.freeze([...e.acpErrors])}),service:Object.freeze({method:e.serviceMethod,command:e.canonicalCommand,events:Object.freeze(["runtime_operation_started","runtime_operation_progress*",...t,"runtime_rpc_response"]),finalResult:`CanonicalCommandResult<${JSON.stringify(e.canonicalCommand)}>`,errors:Object.freeze([...e.serviceErrors])}),fixture:Object.freeze({status:"ready",kind:"wire-fixture",acpEvidence:"src/acp-gateway/bridge-core shared-Core request/result/error fixtures",serviceEvidence:"src/runtime/ms-runtime-rpc-adapter-parity.test.ts canonical/events/final fixtures"}),activation:Object.freeze({status:"ready",requirements:Object.freeze([])})})}));export const RUNTIME_LOCAL_FIXTURE_READY_METHODS=Object.freeze(new Set(RUNTIME_LOCAL_PARITY_MATRIX.filter(e=>"ready"===e.fixture.status).map(e=>e.method)));
|
|
1
|
+
import{RUNTIME_INVOCATION_RECOVERY_CLASSES,RUNTIME_METHOD_PARITY_MANIFEST}from"@beeos-ai/beeos-types/runtime";export const RUNTIME_LOCAL_PARITY_MATRIX=Object.freeze(RUNTIME_METHOD_PARITY_MANIFEST.filter(e=>"request"===e.acpMessage&&e.serviceAllowed&&e.canonicalCommand&&e.acpMethod in RUNTIME_INVOCATION_RECOVERY_CLASSES&&("methods"===e.serviceRoute||"conversation-api"===e.serviceRoute)).map(e=>{const r=e.acpMethod,t="query"===e.recoveryClass||"session/new"===r?[]:["runtime_effect_committed"];return Object.freeze({method:r,acp:Object.freeze({params:e.acpParamsType,result:e.acpResultType,errors:Object.freeze([...e.acpErrors])}),service:Object.freeze({method:e.serviceMethod,command:e.canonicalCommand,events:Object.freeze(["runtime_operation_started","runtime_operation_progress*",...t,"runtime_rpc_response"]),finalResult:`CanonicalCommandResult<${JSON.stringify(e.canonicalCommand)}>`,errors:Object.freeze([...e.serviceErrors])}),fixture:Object.freeze({status:"ready",kind:"wire-fixture",acpEvidence:"src/acp-gateway/bridge-core shared-Core request/result/error fixtures",serviceEvidence:"session/new"===r?"src/runtime/native-session-new-go-wire.test.ts Go/MS HTTP/RS256/Core/sync/final fixture":"src/runtime/ms-runtime-rpc-adapter-parity.test.ts canonical/events/final fixtures"}),activation:Object.freeze({status:"ready",requirements:Object.freeze([])})})}));export const RUNTIME_LOCAL_FIXTURE_READY_METHODS=Object.freeze(new Set(RUNTIME_LOCAL_PARITY_MATRIX.filter(e=>"ready"===e.fixture.status).map(e=>e.method)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{CONVERSATION_RUNTIME_CANONICAL_COMMAND_NAMES,RUNTIME_HASH_DOMAINS,RUNTIME_INVOCATION_RECOVERY_CLASSES,RUNTIME_RESOURCE_BINDING_CONTRACT_REVISION,SERVICE_CANONICAL_COMMAND_NAMES,canonicalizeJcs,runtimeIdempotencyFingerprintPayload,runtimeHashPreimage,validateRuntimeRpcRequestResourceBindings}from"@beeos-ai/beeos-types/runtime";import{sessionSetModelMappingMatches}from"./session-set-model-mapping.js";export const RUNTIME_MESSAGE_TYPES=Object.freeze({request:"runtime_rpc_request",started:"runtime_operation_started",progress:"runtime_operation_progress",effectCommitted:"runtime_effect_committed",final:"runtime_rpc_response",projectionPending:"runtime_projection_pending",projectionSynced:"runtime_projection_synced",projectionBlocked:"runtime_projection_blocked",cancel:"runtime_operation_cancel_requested"});const methods=new Set(Object.keys(RUNTIME_INVOCATION_RECOVERY_CLASSES)),commandNames={...SERVICE_CANONICAL_COMMAND_NAMES,...CONVERSATION_RUNTIME_CANONICAL_COMMAND_NAMES},sha=/^[0-9a-f]{64}$/,decimal=/^(0|[1-9][0-9]*)$/;export function validateRuntimeRequestEnvelope(e){if(!record(e)||e.type!==RUNTIME_MESSAGE_TYPES.request||!record(e.payload))return{ok:!1,reason:"delivery is not a runtime request"};const t=e,n=t.payload;if(!exactKeys(t,["message_id","offset","channel_id","type","payload","publisher_id","idempotency_key","created_at","state",...void 0===t.in_reply_to?[]:["in_reply_to"]])||void 0!==t.in_reply_to||"completed"!==t.state||!nonempty(t.message_id)||!nonempty(t.channel_id)||!Number.isInteger(t.offset)||t.offset<1||!nonempty(t.publisher_id)||!nonempty(t.idempotency_key))return{ok:!1,reason:"invalid persisted envelope"};const r=void 0!==n.resourceBindingContractRevision,a=void 0!==n.resourceBindings;if(!exactKeys(n,["schemaVersion","operationId","requestMessageId","requestHash","paramsHash","commandHash","idempotencyKeyHash","idempotencyFingerprint","callerIntentHash","callerUserId","callerIdentityId","instanceId","runtimeHandlerIdentity","dispatchEpoch","method","request","command","executionGrantHash","claimDeadlineAt","executionDeadlineAt","createdAt",...r||a?["resourceBindingContractRevision","resourceBindings"]:[]]))return{ok:!1,reason:"request payload fields do not match v1.3"};if(r!==a||r&&n.resourceBindingContractRevision!==RUNTIME_RESOURCE_BINDING_CONTRACT_REVISION||a&&!Array.isArray(n.resourceBindings))return{ok:!1,reason:"resource binding carrier is invalid"};if(!(1===n.schemaVersion&&methods.has(n.method)&&decimal.test(n.dispatchEpoch)&&[n.operationId,n.requestMessageId,n.callerUserId,n.callerIdentityId,n.instanceId,n.runtimeHandlerIdentity].every(nonempty)&&[n.requestHash,n.paramsHash,n.commandHash,n.idempotencyKeyHash,n.idempotencyFingerprint,n.callerIntentHash,n.executionGrantHash].every(e=>"string"==typeof e&&sha.test(e))&&record(n.request)&&record(n.command)&&"2.0"===n.request.jsonrpc&&n.request.method===n.method&&n.command.name===commandNames[n.method]))return{ok:!1,reason:"invalid request union"};if(!sessionSetModelMappingMatches(n.request,n.command))return{ok:!1,reason:"request command mapping mismatch"};if(t.channel_id!==n.operationId||t.message_id!==n.requestMessageId||n.command.context?.operationId!==n.operationId||n.command.context?.runtimeInstanceUid!==n.instanceId||n.command.context?.dispatchEpoch!==n.dispatchEpoch||n.command.context?.paramsHash!==n.paramsHash||n.command.context?.idempotencyKeyHash!==n.idempotencyKeyHash||n.command.context?.claimDeadline!==n.claimDeadlineAt||n.command.context?.executionDeadline!==n.executionDeadlineAt)return{ok:!1,reason:"request correlation mismatch"};try{const e={callerUserId:n.callerUserId,instanceId:n.instanceId,method:n.method,params:n.request.params};if(digest(RUNTIME_HASH_DOMAINS.request,n.request)!==n.requestHash||digest(RUNTIME_HASH_DOMAINS.params,{method:n.method,params:n.request.params})!==n.paramsHash||digest(RUNTIME_HASH_DOMAINS.command,{command:n.command})!==n.commandHash||digest(RUNTIME_HASH_DOMAINS.callerIntent,e)!==n.callerIntentHash||digest(RUNTIME_HASH_DOMAINS.idempotencyFingerprint,runtimeIdempotencyFingerprintPayload(n.callerUserId,n.instanceId,n.method,n.callerIntentHash))!==n.idempotencyFingerprint)return{ok:!1,reason:"canonical hash mismatch"}}catch{return{ok:!1,reason:"canonical hash mismatch"}}if(![n.claimDeadlineAt,n.executionDeadlineAt,n.createdAt].every(e=>"string"==typeof e&&Number.isFinite(Date.parse(e))))return{ok:!1,reason:"invalid request timestamp"};if(r){let e;try{e=validateRuntimeRpcRequestResourceBindings({type:"runtime_rpc_request",operationId:n.operationId,requestMessageId:n.requestMessageId,payload:n},Math.floor(Date.now()/1e3))}catch{return{ok:!1,reason:"resource binding validation failed"}}if(e.length)return{ok:!1,reason:"resource binding validation failed"}}return{ok:!0,envelope:t}}export function validateRuntimeCancelEnvelope(e){if(!record(e)||e.type!==RUNTIME_MESSAGE_TYPES.cancel||!record(e.payload))return{ok:!1,reason:"delivery is not a runtime cancel"};const t=e,n=t.payload;return exactKeys(n,["schemaVersion","operationId","requestMessageId","requestHash","dispatchEpoch","method","eventId","requestedBy",...void 0===n.reason?[]:["reason"]])&&exactKeys(t,["message_id","offset","channel_id","type","payload","publisher_id","idempotency_key","created_at","state"])&&"completed"===t.state&&nonempty(t.message_id)&&Number.isInteger(t.offset)&&!(t.offset<1)&&nonempty(t.publisher_id)&&nonempty(t.idempotency_key)&&1===n.schemaVersion&&methods.has(n.method)&&decimal.test(n.dispatchEpoch)&&sha.test(n.requestHash)&&t.channel_id===n.operationId&&void 0===t.in_reply_to&&nonempty(n.eventId)&&nonempty(n.requestedBy)&&(void 0===n.reason||"string"==typeof n.reason)?{ok:!0,envelope:t}:{ok:!1,reason:"invalid cancel correlation"}}export function runtimeMessageBase(e){return{schemaVersion:1,operationId:e.operationId,requestMessageId:e.requestMessageId,requestHash:e.requestHash,dispatchEpoch:e.dispatchEpoch,method:e.method}}export function runtimeMessageHash(e,t){return digest(e,t)}function digest(e,t){return createHash("sha256").update(runtimeHashPreimage(e,t)).digest("hex")}function record(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function nonempty(e){return"string"==typeof e&&e.length>0}function exactKeys(e,t){const n=Object.keys(e).sort(),r=[...t].sort();return n.length===r.length&&n.every((e,t)=>e===r[t])}export function semanticEqual(e,t){return canonicalizeJcs(e)===canonicalizeJcs(t)}
|
|
1
|
+
import{createHash}from"node:crypto";import{CONVERSATION_RUNTIME_CANONICAL_COMMAND_NAMES,RUNTIME_HASH_DOMAINS,RUNTIME_INVOCATION_RECOVERY_CLASSES,RUNTIME_RESOURCE_BINDING_CONTRACT_REVISION,SERVICE_CANONICAL_COMMAND_NAMES,canonicalizeJcs,isCloudRuntimeMessageRequest,runtimeIdempotencyFingerprintPayload,runtimeHashPreimage,validateRuntimeRpcRequestResourceBindings}from"@beeos-ai/beeos-types/runtime";import{sessionSetModelMappingMatches}from"./session-set-model-mapping.js";export const RUNTIME_MESSAGE_TYPES=Object.freeze({request:"runtime_rpc_request",started:"runtime_operation_started",progress:"runtime_operation_progress",effectCommitted:"runtime_effect_committed",final:"runtime_rpc_response",projectionPending:"runtime_projection_pending",projectionSynced:"runtime_projection_synced",projectionBlocked:"runtime_projection_blocked",cancel:"runtime_operation_cancel_requested"});const methods=new Set(Object.keys(RUNTIME_INVOCATION_RECOVERY_CLASSES)),commandNames={...SERVICE_CANONICAL_COMMAND_NAMES,...CONVERSATION_RUNTIME_CANONICAL_COMMAND_NAMES},sha=/^[0-9a-f]{64}$/,decimal=/^(0|[1-9][0-9]*)$/;export function validateRuntimeRequestEnvelope(e){if(!record(e)||e.type!==RUNTIME_MESSAGE_TYPES.request||!record(e.payload))return{ok:!1,reason:"delivery is not a runtime request"};const t=e,n=t.payload;if(!exactKeys(t,["message_id","offset","channel_id","type","payload","publisher_id","idempotency_key","created_at","state",...void 0===t.in_reply_to?[]:["in_reply_to"]])||void 0!==t.in_reply_to||"completed"!==t.state||!nonempty(t.message_id)||!nonempty(t.channel_id)||!Number.isInteger(t.offset)||t.offset<1||!nonempty(t.publisher_id)||!nonempty(t.idempotency_key))return{ok:!1,reason:"invalid persisted envelope"};if(2===n.schemaVersion)return isCloudRuntimeMessageRequest(n,digest)?t.channel_id!==n.operationId||t.message_id!==n.requestMessageId?{ok:!1,reason:"request correlation mismatch"}:{ok:!0,envelope:t}:{ok:!1,reason:"invalid Cloud runtime request"};const r=void 0!==n.resourceBindingContractRevision,a=void 0!==n.resourceBindings;if(!exactKeys(n,["schemaVersion","operationId","requestMessageId","requestHash","paramsHash","commandHash","idempotencyKeyHash","idempotencyFingerprint","callerIntentHash","callerUserId","callerIdentityId","instanceId","runtimeHandlerIdentity","dispatchEpoch","method","request","command","executionGrantHash","claimDeadlineAt","executionDeadlineAt","createdAt",...r||a?["resourceBindingContractRevision","resourceBindings"]:[]]))return{ok:!1,reason:"request payload fields do not match v1.3"};if(r!==a||r&&n.resourceBindingContractRevision!==RUNTIME_RESOURCE_BINDING_CONTRACT_REVISION||a&&!Array.isArray(n.resourceBindings))return{ok:!1,reason:"resource binding carrier is invalid"};if(!(1===n.schemaVersion&&methods.has(n.method)&&decimal.test(n.dispatchEpoch)&&[n.operationId,n.requestMessageId,n.callerUserId,n.callerIdentityId,n.instanceId,n.runtimeHandlerIdentity].every(nonempty)&&[n.requestHash,n.paramsHash,n.commandHash,n.idempotencyKeyHash,n.idempotencyFingerprint,n.callerIntentHash,n.executionGrantHash].every(e=>"string"==typeof e&&sha.test(e))&&record(n.request)&&record(n.command)&&"2.0"===n.request.jsonrpc&&n.request.method===n.method&&n.command.name===commandNames[n.method]))return{ok:!1,reason:"invalid request union"};if(!sessionSetModelMappingMatches(n.request,n.command))return{ok:!1,reason:"request command mapping mismatch"};if(t.channel_id!==n.operationId||t.message_id!==n.requestMessageId||n.command.context?.operationId!==n.operationId||n.command.context?.runtimeInstanceUid!==n.instanceId||n.command.context?.dispatchEpoch!==n.dispatchEpoch||n.command.context?.paramsHash!==n.paramsHash||n.command.context?.idempotencyKeyHash!==n.idempotencyKeyHash||n.command.context?.claimDeadline!==n.claimDeadlineAt||n.command.context?.executionDeadline!==n.executionDeadlineAt)return{ok:!1,reason:"request correlation mismatch"};try{const e={callerUserId:n.callerUserId,instanceId:n.instanceId,method:n.method,params:n.request.params};if(digest(RUNTIME_HASH_DOMAINS.request,n.request)!==n.requestHash||digest(RUNTIME_HASH_DOMAINS.params,{method:n.method,params:n.request.params})!==n.paramsHash||digest(RUNTIME_HASH_DOMAINS.command,{command:n.command})!==n.commandHash||digest(RUNTIME_HASH_DOMAINS.callerIntent,e)!==n.callerIntentHash||digest(RUNTIME_HASH_DOMAINS.idempotencyFingerprint,runtimeIdempotencyFingerprintPayload(n.callerUserId,n.instanceId,n.method,n.callerIntentHash))!==n.idempotencyFingerprint)return{ok:!1,reason:"canonical hash mismatch"}}catch{return{ok:!1,reason:"canonical hash mismatch"}}if(![n.claimDeadlineAt,n.executionDeadlineAt,n.createdAt].every(e=>"string"==typeof e&&Number.isFinite(Date.parse(e))))return{ok:!1,reason:"invalid request timestamp"};if(r){let e;try{e=validateRuntimeRpcRequestResourceBindings({type:"runtime_rpc_request",operationId:n.operationId,requestMessageId:n.requestMessageId,payload:n},Math.floor(Date.now()/1e3))}catch{return{ok:!1,reason:"resource binding validation failed"}}if(e.length)return{ok:!1,reason:"resource binding validation failed"}}return{ok:!0,envelope:t}}export function validateRuntimeCancelEnvelope(e){if(!record(e)||e.type!==RUNTIME_MESSAGE_TYPES.cancel||!record(e.payload))return{ok:!1,reason:"delivery is not a runtime cancel"};const t=e,n=t.payload;return exactKeys(n,["schemaVersion","operationId","requestMessageId","requestHash","dispatchEpoch","method","eventId","requestedBy",...void 0===n.reason?[]:["reason"]])&&exactKeys(t,["message_id","offset","channel_id","type","payload","publisher_id","idempotency_key","created_at","state"])&&"completed"===t.state&&nonempty(t.message_id)&&Number.isInteger(t.offset)&&!(t.offset<1)&&nonempty(t.publisher_id)&&nonempty(t.idempotency_key)&&1===n.schemaVersion&&methods.has(n.method)&&decimal.test(n.dispatchEpoch)&&sha.test(n.requestHash)&&t.channel_id===n.operationId&&void 0===t.in_reply_to&&nonempty(n.eventId)&&nonempty(n.requestedBy)&&(void 0===n.reason||"string"==typeof n.reason)?{ok:!0,envelope:t}:{ok:!1,reason:"invalid cancel correlation"}}export function runtimeMessageBase(e){return{schemaVersion:1,operationId:e.operationId,requestMessageId:e.requestMessageId,requestHash:e.requestHash,dispatchEpoch:e.dispatchEpoch,method:e.method}}export function runtimeMessageHash(e,t){return digest(e,t)}function digest(e,t){return createHash("sha256").update(runtimeHashPreimage(e,t)).digest("hex")}function record(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function nonempty(e){return"string"==typeof e&&e.length>0}function exactKeys(e,t){const n=Object.keys(e).sort(),r=[...t].sort();return n.length===r.length&&n.every((e,t)=>e===r[t])}export function semanticEqual(e,t){return canonicalizeJcs(e)===canonicalizeJcs(t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{
|
|
1
|
+
import{createHash}from"node:crypto";import{hashRuntimeResourceRedemptionPayload,normalizeRuntimeResourceRedemptionHashPayload,validateRuntimeMcpResourceRedemptionCompletion,validateRuntimeSkillResourceRedemptionCompletion}from"@beeos-ai/beeos-types/runtime";import{parseRfc3339Instant}from"../acp-gateway/mcp-desired-state-store.js";export class RuntimeResourceResolutionError extends Error{kind;code;diagnostic;constructor(e,t,i,r){super(r?`${t} [${r}]`:t),this.kind=e,this.code=i,this.diagnostic=r,this.name="RuntimeResourceResolutionError"}}export class HttpRuntimeOperationResourceResolver{options;attempts=new Map;byRef;mcp;skill;constructor(e){this.options=e;const t=e.bindings.map(e=>[e.resourceRef,Object.freeze({...e})]);if(new Set(t.map(([e])=>e)).size!==t.length)throw new Error("duplicate resource binding");this.byRef=new Map(t)}async readContent(){throw new Error("Service inline content is forbidden; use a trusted artifact reference")}async resolveMcpDefinition(e){this.mcp||(this.mcp=this.redeemMcp(e).catch(e=>{throw this.mcp=void 0,e}));const t=await this.mcp;if(!sameMcpDescriptor(t.descriptor,e))throw new Error("MCP resource descriptor mismatch");return t.config}async resolveMcpCredential(e){this.mcp||(this.mcp=this.redeemMcp(e).catch(e=>{throw this.mcp=void 0,e}));const t=await this.mcp;if(!sameMcpDescriptor(t.descriptor,e))throw new Error("MCP resource descriptor mismatch");return t.credential}async readVerifiedArtifact(e){this.skill||(this.skill=this.redeemSkill(e).catch(e=>{throw this.skill=void 0,e}));const t=await this.skill;if(!sameArtifactDescriptor(t.descriptor,e))throw new Error("skill resource descriptor mismatch");return t.parsed}async redeemMcp(e){const t=this.bindingFor("mcp",e.definitionRef);if(t.version!==e.version||t.sha256!==e.sha256)throw resolution("MCP descriptor does not match the immutable authority binding","descriptor_binding_mismatch");const{request:i,reservation:r}=this.requestFor(t),s=await this.redeem(t,i);let n;try{n=await s.json()}catch{throw integrity("MCP authority response is invalid","response_not_json")}const o=validateRuntimeMcpResourceRedemptionCompletion({request:i,binding:t,reservation:r,expectedDisposition:n.disposition,result:n,sha256Utf8:sha256Utf8});if(!o.valid)throw integrity("MCP resource integrity failed",`violations=${o.violations.join(",")}`);if(!isPlainObject(n.resource.config))throw integrity("MCP authority payload must contain public object config","config_not_object");const a=void 0===n.resource.credential?void 0:credentialMaterial(n.resource.credential);if(a&&!a.expiresAt&&this.options.requireCredentialExpiry)throw integrity("MCP credential has no expiry","credential_expiry_missing");return{descriptor:e,config:Object.freeze({...n.resource.config}),credential:a}}async redeemSkill(e){const t=this.bindingFor("skill",e.artifactRef);if(t.version!==e.version||t.sha256!==e.sha256||t.sizeBytes!==e.sizeBytes)throw resolution("skill descriptor does not match the immutable authority binding","descriptor_binding_mismatch");const{request:i,reservation:r}=this.requestFor(t),s=await this.redeem(t,i),n=new Uint8Array(await s.arrayBuffer()),o=skillHeaders(s),a=validateRuntimeSkillResourceRedemptionCompletion({request:i,binding:t,reservation:r,expectedDisposition:o["X-BeeOS-Redemption-Disposition"],headers:o,chunks:[n],sha256Utf8:sha256Utf8,sha256Bytes:sha256Bytes});if(!a.valid)throw integrity("skill resource integrity failed",`violations=${a.violations.join(",")} bytes=${n.byteLength}`);return{descriptor:e,parsed:await this.options.parseSkillArtifact(n)}}bindingFor(e,t){const i=this.byRef.get(t);if(!i||i.kind!==e||i.operationId!==this.options.operationId||i.instanceId!==this.options.instanceId||i.requestMessageId!==this.options.requestMessageId||i.paramsHash!==this.options.paramsHash)throw resolution("resource authority binding mismatch",`kind=${e} ${i?i.kind!==e?"field=kind":i.operationId!==this.options.operationId?"field=operationId":i.instanceId!==this.options.instanceId?"field=instanceId":i.requestMessageId!==this.options.requestMessageId?"field=requestMessageId":"field=paramsHash":"resourceRef=unbound"}`);return i}requestFor(e){const t=this.options.getAuthorization(),i=this.attempts.get(e.resourceRef),r=i?.redemptionId??(this.options.redemptionId?this.options.redemptionId():stableRedemptionId(e)),s={redemptionId:r,operationId:this.options.operationId,requestMessageId:this.options.requestMessageId,kind:e.kind,resourceRef:e.resourceRef,paramsHash:this.options.paramsHash,executionGrant:t.executionGrant,runtimeLeaseCredential:t.runtimeLeaseCredential,fence:t.fence},n=normalizeRuntimeResourceRedemptionHashPayload(s,e);if(!n)throw resolution("resource redemption request does not match immutable binding","request_binding_mismatch");const o=hashRuntimeResourceRedemptionPayload(n,sha256Utf8);if(i&&i.requestHash!==o)throw resolution("resource redemption intent changed","redemption_intent_changed");return this.attempts.set(e.resourceRef,{redemptionId:r,requestHash:o}),{request:s,reservation:{state:"reserved",redemptionId:r,redemptionRequestHash:o}}}async redeem(e,t){let i;try{i=await this.options.gateway.runtime.redeemResource(e.operationId,e.kind,e.resourceRef,t,this.options.signal?{signal:this.options.signal}:void 0)}catch{throw transient("runtime resource authority is unavailable","fetch_rejected")}return i.ok||await throwRedemptionFailure(i,e.kind),i}}function skillHeaders(e){const t=t=>{const i=e.headers.get(t);if(!i)throw integrity(`skill authority response omitted ${t}`,`missing_header=${t}`);return i};return{"X-BeeOS-Redemption-Id":t("X-BeeOS-Redemption-Id"),"X-BeeOS-Redemption-Disposition":t("X-BeeOS-Redemption-Disposition"),"X-BeeOS-Artifact-Ref":t("X-BeeOS-Artifact-Ref"),"X-BeeOS-Artifact-Version":t("X-BeeOS-Artifact-Version"),"X-BeeOS-Artifact-SHA256":t("X-BeeOS-Artifact-SHA256"),"X-BeeOS-Artifact-Size":t("X-BeeOS-Artifact-Size")}}function sha256Utf8(e){return createHash("sha256").update(e).digest("hex")}function stableRedemptionId(e){return`redemption:${sha256Utf8(`${e.operationId}\n${e.requestMessageId}\n${e.kind}\n${e.resourceRef}`)}`}function sha256Bytes(e){const t=createHash("sha256");for(const i of e)t.update(i);return t.digest("hex")}function sameMcpDescriptor(e,t){return e.definitionRef===t.definitionRef&&e.version===t.version&&e.sha256===t.sha256}function sameArtifactDescriptor(e,t){return e.artifactRef===t.artifactRef&&e.version===t.version&&e.sha256===t.sha256&&e.sizeBytes===t.sizeBytes&&e.source===t.source}function isPlainObject(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||null===Object.getPrototypeOf(e))}function credentialMaterial(e){if(!isPlainObject(e)||Object.keys(e).some(e=>"headers"!==e&&"env"!==e&&"expiresAt"!==e))throw integrity("MCP credential payload is invalid","credential_payload_invalid");const t=stringMap(e.headers,"MCP credential headers"),i=stringMap(e.env,"MCP credential environment");if(!t&&!i)throw integrity("MCP credential payload is empty","credential_payload_empty");const r=credentialExpiry(e.expiresAt);return Object.freeze({...t?{headers:Object.freeze(t)}:{},...i?{env:Object.freeze(i)}:{},...r?{expiresAt:r}:{}})}function credentialExpiry(e){if(void 0===e)return;const t=parseRfc3339Instant(e);if(!t)throw integrity("MCP credential expiry is invalid","credential_expiry_invalid");return t}function stringMap(e,t){if(void 0!==e){if(!isPlainObject(e)||Object.entries(e).some(([e,t])=>!e||e.length>256||/[\u0000-\u001f\u007f]/.test(e)||"string"!=typeof t||t.length>16384))throw integrity(`${t} are invalid`,"credential_string_map_invalid");return{...e}}}async function throwRedemptionFailure(e,t){if(408===e.status||425===e.status||429===e.status||e.status>=500)throw transient(`runtime ${t} redemption is temporarily unavailable`,`http_status=${e.status}`);let i;try{i=await e.json()}catch{throw integrity(`runtime ${t} redemption error is invalid`,`http_status=${e.status} error_body=not_json`)}const r=redemptionError(i);if(!r)throw integrity(`runtime ${t} redemption error is invalid`,`http_status=${e.status} error_body=unrecognized_shape`);throw new RuntimeResourceResolutionError("resolution_rejected",`runtime ${t} redemption was rejected`,r.code,`http_status=${e.status} code=${r.code}`)}function redemptionError(e){if(!isPlainObject(e)||"string"!=typeof e.status||"string"!=typeof e.code)return;if("fenced"===e.status&&"FENCED"===e.code&&"string"==typeof e.activeRuntimeEpoch&&/^(0|[1-9][0-9]*)$/.test(e.activeRuntimeEpoch)&&exact(e,["status","code","activeRuntimeEpoch"]))return e;return[["expired","EXPIRED"],["resource_not_found","RESOURCE_NOT_FOUND"],["redemption_conflict","REDEMPTION_CONFLICT"],["resource_integrity_failed","RESOURCE_INTEGRITY_FAILED"],["unauthorized","UNAUTHORIZED"]].some(([t,i])=>e.status===t&&e.code===i&&exact(e,["status","code"]))?e:void 0}function exact(e,t){const i=Object.keys(e).sort(),r=[...t].sort();return i.length===r.length&&i.every((e,t)=>e===r[t])}function resolution(e,t){return new RuntimeResourceResolutionError("resolution_rejected",e,void 0,t)}function integrity(e,t){return new RuntimeResourceResolutionError("integrity_mismatch",e,void 0,t)}function transient(e,t){return new RuntimeResourceResolutionError("transient",e,"TRANSIENT",t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{readFileSync}from"node:fs";import{createRequire}from"node:module";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";export const EXPECTED_RUNTIME_PARITY_MANIFEST_DIGEST="
|
|
1
|
+
import{createHash}from"node:crypto";import{readFileSync}from"node:fs";import{createRequire}from"node:module";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";export const EXPECTED_RUNTIME_PARITY_MANIFEST_DIGEST="2e58dbc13b8bef2491b95f89920945cb905085828b2fa7a4d4f621624971b186";const require=createRequire(import.meta.url);export function computeRuntimeParityManifestDigest(){const e=require.resolve("@beeos-ai/beeos-types/contracts/runtime-method-manifest.v1.json"),t=JSON.parse(readFileSync(e,"utf8"));return createHash("sha256").update(canonicalizeJcs(t),"utf8").digest("hex")}export function verifiedRuntimeParityManifestDigest(){return requireExpectedRuntimeParityManifestDigest(computeRuntimeParityManifestDigest())}export function requireExpectedRuntimeParityManifestDigest(e){if(e!==EXPECTED_RUNTIME_PARITY_MANIFEST_DIGEST)throw new Error(`BeeOS Types parity manifest digest mismatch: expected ${EXPECTED_RUNTIME_PARITY_MANIFEST_DIGEST}, received ${e}`);return e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RUNTIME_MESSAGE_CHANNEL_REVISION="beeos.runtime-message-channel.v2.
|
|
1
|
+
export const RUNTIME_MESSAGE_CHANNEL_REVISION="beeos.runtime-message-channel.v2.0.0";export const RUNTIME_MESSAGE_CHANNEL_RAW_SHA256="dd791ce5f49b7bee1dba21a71e7b2cfbf4db7d77cb787aab5f04c7f4b0e3101b";export const RUNTIME_MESSAGE_CHANNEL_SHA256="e950f1a86bf2bd8bf472603a91111c15b920fcac4c06fd8ac70e2c3f4c3a408f";export const RUNTIME_AUTHORITY_PORTS_REVISION="beeos.runtime-authority-ports.v2.0.0";export const RUNTIME_AUTHORITY_PORTS_RAW_SHA256="a2e9565ae617bcaeb4d837fe176a3602be041913d28a3f0a3a9ec2e3dae0d7b4";export const RUNTIME_AUTHORITY_PORTS_SHA256="3bd582f1f6babcdbe953a082faf813247c960f6bbf4c0f713e7fd92e27d163f5";export const RUNTIME_SESSION_CANCEL_REVISION="beeos.runtime-session-cancel.v1.0.0";export const RUNTIME_SESSION_CANCEL_SHA256="ad32581546f3a97d62df3a6785e3ec057e7dd888b31885f46cfb43d07c966d3e";export const RUNTIME_PARITY_MANIFEST_REVISION="beeos.runtime-parity.v1.1.0";export const RUNTIME_PARITY_MANIFEST_RAW_SHA256="f1030e7bf2084f584d558c22b9bffde0f823d6950c696a6f0571adaffcdbcee0";export const RUNTIME_PARITY_MANIFEST_SHA256="c98ed2aa822b29530cb02badd51654f2766f1dc0ff2c53b660be6431b1f23747";const manifestEntries=[{method:"session/new",acpSource:"service",route:"POST /api/v1/runtime/conversations",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"session/set_mode",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"agent/create",acpSource:"service",route:"POST /api/v1/agents/sync",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"agent/update",acpSource:"service",route:"POST /api/v1/agents/sync",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"agent/delete",acpSource:"service",route:"POST /api/v1/agents/sync",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"agent/applyTemplate",acpSource:"service",route:"POST /api/v1/agents/sync",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"skills/list",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"skills/install",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"skills/uninstall",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"skills/update",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"models/list",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/list",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/status",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/add",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/update",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/remove",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/run",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"cron/runs",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"mcp/list",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"mcp/prepare",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"mcp/set",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"mcp/unset",acpSource:"service",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""},{method:"session/clear",acpSource:"conversation",route:"POST /api/v1/runtime/conversations/{conversationId}/history-boundary/{action}",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"session/set_model",acpSource:"conversation",route:"POST /api/v1/runtime/conversations/{conversationId}/metadata/model",contractRevision:RUNTIME_AUTHORITY_PORTS_REVISION,status:"ready",blockerOwner:""},{method:"session/cancel",acpSource:"conversation",route:"POST /api/v1/runtime/operations",contractRevision:RUNTIME_MESSAGE_CHANNEL_REVISION,status:"ready",blockerOwner:""}];export const RUNTIME_PARITY_MANIFEST=Object.freeze(manifestEntries.map(e=>Object.freeze(e)));export const RUNTIME_PARITY_READY_METHODS=Object.freeze(new Set(RUNTIME_PARITY_MANIFEST.filter(e=>"ready"===e.status).map(e=>e.method)));
|