beeos-claw 0.6.66-cloud.5 → 0.6.66-cloud.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{randomUUID}from"node:crypto";import{CloudHttpError}from"@beeos-ai/cloud-harness-sdk";const UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function asObject(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function stringValue(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toolResult(e){return{content:JSON.stringify(e,null,2)}}function isUuid(e){return Boolean(e&&UUID_RE.test(e))}function resolveTarget(e){const t=e.getDefaultAgent?.(),r=stringValue(t?.instanceId),o=stringValue(t?.id);if(r&&o)return{instanceId:r,agentId:o}}function resolveConversationId(e,t){const r=stringValue(e.getCurrentConversationId?.(t));return isUuid(r)?r:void 0}async function request(e){try{const t=await e()??{},r=asObject(t);return{ok:!0,data:Object.hasOwn(r,"data")?r.data:t}}catch(e){if(e instanceof CloudHttpError){let t=e.body;try{t=e.body?JSON.parse(e.body):{}}catch{}return{ok:!1,status:e.status,error:`Automation request failed: HTTP ${e.status}`,details:t}}return{ok:!1,status:0,error:e instanceof Error?e.message:String(e),details:void 0}}}function listQuery(e){const t={};for(const r of["status","cursor"]){const o=stringValue(e[r]);o&&(t[r]=o)}return"number"==typeof e.limit&&Number.isFinite(e.limit)&&(t.limit=String(Math.trunc(e.limit))),t}function buildSchedule(e){const t=stringValue(e.kind)??"every",r={kind:t,tz:stringValue(e.tz)??"UTC"};switch(t){case"every":{r.intervalSeconds="number"==typeof e.intervalSeconds?String(Math.trunc(e.intervalSeconds)):stringValue(e.intervalSeconds)??"3600";const t=stringValue(e.anchorAt);t&&(r.anchorAt=t);break}case"at":{const t=stringValue(e.at);t&&(r.at=t);break}case"cron":{const t=stringValue(e.expression);t&&(r.expression=t);break}default:return{error:"schedule.kind must be one of at, every, or cron"}}return r}function buildSession(e,t,r){const o=stringValue(asObject(e.session).mode)??"new";if("new"!==o&&"bound"!==o)return{error:"session.mode must be new or bound"};const n={mode:o},a=resolveConversationId(t,r);if("bound"===o){if(!a)return{error:"bound Automation requires the current conversation context"};n.boundConversationId=a}return n}function createInput(e,t,r){const o=asObject(e),n=stringValue(o.name),a=stringValue(o.prompt),s=resolveTarget(t);if(!n||!a||!s)return{error:"name, prompt, and a resolvable target agent are required"};const i=buildSchedule(asObject(o.schedule));if("error"in i)return i;const u=buildSession(o,t,r);if("error"in u)return u;const c={name:n,prompt:a,target:s,schedule:i,session:u},l=stringValue(o.validFrom),d=stringValue(o.validUntil);l&&(c.validFrom=l),d&&(c.validUntil=d);const m=resolveConversationId(t,r);return m&&(c.createdInConversationId=m),c}function createWebhookInput(e,t,r){const o=asObject(e),n=stringValue(o.name),a=stringValue(o.prompt),s=(stringValue(o.source)??"").toLowerCase(),i=resolveTarget(t);if(!n||!a||!i)return{error:"name, prompt, and a resolvable target agent are required"};if("github"!==s&&"gmail"!==s)return{error:"source must be github or gmail"};const u=o.events,c=Array.isArray(u)?u.filter(e=>"string"==typeof e&&Boolean(e.trim())).map(e=>e.trim()):[],l=stringValue(o.repoOwner),d=stringValue(o.repoName),m=stringValue(o.mailbox);if(!("github"!==s||0!==c.length&&l&&d))return{error:"github webhook requires events, repoOwner, and repoName"};if("gmail"===s&&!m)return{error:"gmail webhook requires mailbox"};const p=buildSession(o,t,r);if("error"in p)return p;const g={name:n,prompt:a,target:i,session:p,source:s};"github"===s?(g.events=c,g.repoOwner=l,g.repoName=d):g.mailbox=m;const y=stringValue(o.eventFilter);y&&(g.eventFilter=y);const f=stringValue(o.validFrom),b=stringValue(o.validUntil);f&&(g.validFrom=f),b&&(g.validUntil=b);const h=resolveConversationId(t,r);return h&&(g.createdInConversationId=h),g}function unwrapConnectorMcp(e){let t=e;if("string"==typeof t)try{t=JSON.parse(t)}catch{return}if(!t||"object"!=typeof t||Array.isArray(t))return;const r=t;if(null!=r.error)return;let o=r.result??r;if(!o||"object"!=typeof o||Array.isArray(o))return;const n=o;if(n.isError)return;const a=n.structuredContent;if(a&&"object"==typeof a&&!Array.isArray(a))return a;const s=n.content;if(Array.isArray(s))for(const e of s){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;if("text"===t.type&&"string"==typeof t.text)try{const e=JSON.parse(t.text);if(e&&"object"==typeof e&&!Array.isArray(e))return e}catch{continue}}return n}async function runPreflight(e,t,r){const o=asObject(t),n=(stringValue(o.source)??"").toLowerCase(),a=resolveConversationId(e,r),s=resolveTarget(e),i={source:n,operation:"webhook",ready:!1,platform:{reachable:!1,authorized:!1},connector:{id:n,installed:!1,credentialStatus:"unknown"},operationSupported:"github"===n||"gmail"===n,target:{resolved:Boolean(s)},session:{canBindCurrentConversation:Boolean(a)},nextAction:"retry_or_check_connection"};if("github"!==n&&"gmail"!==n)return i.blockingReason="unsupported_source",i.nextAction="retry_or_check_connection",i;if("gmail"===n&&!stringValue(o.mailbox))return i.blockingReason="mailbox_required",i.nextAction="provide_mailbox",i;if("github"===n){const e=o.events,t=Array.isArray(e)&&e.some(e=>"string"==typeof e&&e.trim());if(!stringValue(o.repoOwner)||!stringValue(o.repoName)||!t)return i.blockingReason="github_webhook_input_required",i.nextAction="provide_repository_and_events",i}const u=await request(()=>e.gateway.automations.list({limit:1}));if(!u.ok)return i.blockingReason="automation_gateway_unavailable",i.platform={reachable:!1,authorized:!1,status:u.status,error:u.error},i.nextAction="retry_or_check_connection",i;i.platform={reachable:!0,authorized:!0};const c={jsonrpc:"2.0",id:randomUUID(),method:"tools/call",params:{name:"list_connectors",arguments:{}}},l=await request(()=>e.gateway.connectors.callJson(c));if(!l.ok)return i.blockingReason="mcp_unavailable",i.connector={id:n,installed:!1,credentialStatus:"unknown",error:l.error,status:l.status},i.nextAction="retry_or_check_connection",i;const d=unwrapConnectorMcp(l.data),m=d&&Array.isArray(d.connectors)?d.connectors:void 0;let p;if(Array.isArray(m))for(const e of m){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;if((stringValue(t.connectorId)??stringValue(t.connector_id)??"").toLowerCase()===n){p=t;break}}if(!p)return i.blockingReason="mcp_not_connected",i.nextAction="install_connector",i;const g=(stringValue(p.credentialStatus)??stringValue(p.credential_status)??"unknown").toLowerCase();return i.connector={id:n,installed:!0,credentialStatus:g},"active"!==g?(i.blockingReason="credential_missing",i.nextAction="authorize_connector",i):s?(i.ready=!0,i.nextAction="create_automation",i.sideEffects="gmail"===n?["create_rule","ensure_shared_gmail_watch"]:["create_rule","issue_hook","register_connector_webhook"],i):(i.blockingReason="target_not_resolved",i.nextAction="sync_openclaw_agent",i)}async function runCapabilities(e,t){const r=resolveTarget(e),o=resolveConversationId(e,t),n={platform:{reachable:!1,authorized:!1},capabilities:{createSchedule:Boolean(r),createWebhook:Boolean(r),run:!0},target:{resolved:Boolean(r)},session:{currentConversationAvailable:Boolean(o),canBindCurrentConversation:Boolean(o)}},a=await request(()=>e.gateway.automations.list({limit:1}));return a.ok?n.platform={reachable:!0,authorized:!0}:n.platform={reachable:!1,authorized:!1,status:a.status,error:a.error},n}function requestErrorResult(e){return toolResult({error:e.error,status:e.status,details:e.details})}export function registerAutomationTools(e,t){e.registerTool({name:"beeos_automation_create",description:"Create a BeeOS platform Automation owned by the current user. The target is the current Agent and is resolved automatically. Prefer session.mode=bound for a task created in this chat.",parameters:{type:"object",properties:{name:{type:"string",description:"Human-readable automation name"},prompt:{type:"string",description:"Prompt sent to the target agent when the automation fires"},schedule:{type:"object",properties:{kind:{type:"string",enum:["at","every","cron"]},tz:{type:"string"},at:{type:"string"},intervalSeconds:{type:"integer",minimum:1},anchorAt:{type:"string"},expression:{type:"string"}}},session:{type:"object",description:"Always set session.mode. Prefer bound for tasks created in the current BeeOS chat so every run returns here. Use new if the user requests a separate conversation per run or the current chat cannot bind. The plugin fills the bound conversation ID; do not supply it.",properties:{mode:{type:"string",enum:["new","bound"]}}},validFrom:{type:"string"},validUntil:{type:"string"}},required:["name","prompt"]},async execute(e,r,o){const n=createInput(r,t,e);if("error"in n)return toolResult(n);try{const e=await request(()=>t.gateway.automations.create(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return t.logger?.warn?.(`[beeos_automation_create] ${e instanceof Error?e.message:String(e)}`),toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_create_webhook",description:"Create a BeeOS platform Webhook Automation. GitHub uses source/events/repoOwner/repoName; Gmail uses source/mailbox only (never hookId/hookUrl/repo*). Runs preflight first. Prefer session.mode=bound for a task created in this chat.",parameters:{type:"object",properties:{name:{type:"string"},prompt:{type:"string"},source:{type:"string",enum:["github","gmail"]},events:{type:"array",items:{type:"string"},minItems:1},repoOwner:{type:"string"},repoName:{type:"string"},eventFilter:{type:"string"},mailbox:{type:"string"},session:{type:"object",description:"Always set session.mode. Prefer bound for tasks created in the current BeeOS chat so every event returns here. Use new if the user requests a separate conversation per event or the current chat cannot bind. The plugin fills the bound conversation ID; do not supply it.",properties:{mode:{type:"string",enum:["new","bound"]}}},validFrom:{type:"string"},validUntil:{type:"string"}},required:["name","prompt","source"]},async execute(e,r,o){const n=createWebhookInput(r,t,e);if("error"in n)return toolResult(n);try{const a=await runPreflight(t,r,e);if(!a.ready)return toolResult({error:"automation_preflight_failed",preflight:a});const s=await request(()=>t.gateway.automations.createWebhook(n,{signal:o}));return s.ok?toolResult(s.data):requestErrorResult(s)}catch(e){return t.logger?.warn?.(`[beeos_automation_create_webhook] ${e instanceof Error?e.message:String(e)}`),toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_capabilities",description:"Check whether the BeeOS Automation platform is reachable/authorized and whether the current chat can bind as an Automation session. Read-only.",parameters:{type:"object",properties:{}},async execute(e){try{return toolResult(await runCapabilities(t,e))}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_preflight",description:"Read-only readiness check for creating a BeeOS Webhook Automation. Returns nextAction such as authorize_connector, install_connector, provide_mailbox, provide_repository_and_events, sync_openclaw_agent, retry_or_check_connection, or create_automation.",parameters:{type:"object",properties:{source:{type:"string",enum:["github","gmail"]},events:{type:"array",items:{type:"string"}},repoOwner:{type:"string"},repoName:{type:"string"},mailbox:{type:"string"},session:{type:"object",properties:{mode:{type:"string",enum:["new","bound"]}}}},required:["source"]},async execute(e,r){try{return toolResult(await runPreflight(t,r,e))}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_list",description:"List BeeOS platform Automations owned by the current user.",parameters:{type:"object",properties:{status:{type:"string",enum:["enabled","paused","expired"]},limit:{type:"integer",minimum:1,maximum:100},cursor:{type:"string"}}},async execute(e,r,o){const n=listQuery(asObject(r));try{const e=await request(()=>t.gateway.automations.list(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_get",description:"Get one BeeOS platform Automation by its automation ID.",parameters:{type:"object",properties:{automationId:{type:"string"}},required:["automationId"]},async execute(e,r,o){const n=stringValue(asObject(r).automationId);if(!n)return toolResult({error:"automationId is required"});try{const e=await request(()=>t.gateway.automations.get(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_run",description:"Trigger an existing BeeOS platform Automation immediately and return its Run record.",parameters:{type:"object",properties:{automationId:{type:"string"},requestKey:{type:"string",description:"Optional idempotency key; generated when omitted"},sourceRunId:{type:"string"},rerunSessionMode:{type:"string",enum:["original","new"]}},required:["automationId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId);if(!a)return toolResult({error:"automationId is required"});const s=stringValue(n.requestKey)??randomUUID(),i=stringValue(n.sourceRunId),u=stringValue(n.rerunSessionMode),c={};i&&(c.sourceRunId=i),u&&(c.rerunSessionMode=u);try{const e=await request(()=>t.gateway.automations.run(a,c,s,{signal:o}));return e.ok?toolResult({requestKey:s,data:e.data}):toolResult({error:e.error,status:e.status,details:e.details,requestKey:s})}catch(e){return toolResult({error:e instanceof Error?e.message:String(e),requestKey:s})}}}),e.registerTool({name:"beeos_automation_runs",description:"List Runs for one BeeOS platform Automation.",parameters:{type:"object",properties:{automationId:{type:"string"},status:{type:"string",enum:["scheduled","dispatched","failed","skipped"]},limit:{type:"integer",minimum:1,maximum:100},cursor:{type:"string"}},required:["automationId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId);if(!a)return toolResult({error:"automationId is required"});const s=listQuery(n);try{const e=await request(()=>t.gateway.automations.runs(a,s,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_get_run",description:"Get one Run record for a BeeOS platform Automation.",parameters:{type:"object",properties:{automationId:{type:"string"},runId:{type:"string"}},required:["automationId","runId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId),s=stringValue(n.runId);if(!a||!s)return toolResult({error:"automationId and runId are required"});try{const e=await request(()=>t.gateway.automations.runDetail(a,s,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}})}
1
+ import{randomUUID}from"node:crypto";import{CloudHttpError}from"@beeos-ai/cloud-harness-sdk";const UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function asObject(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function stringValue(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toolResult(e){return{content:JSON.stringify(e,null,2)}}function isUuid(e){return Boolean(e&&UUID_RE.test(e))}function resolveTarget(e){const t=e.getDefaultAgent?.(),r=stringValue(t?.instanceId),o=stringValue(t?.id);if(r&&o)return{instanceId:r,agentId:o}}function resolveConversationId(e,t){const r=stringValue(e.getCurrentConversationId?.(t));return isUuid(r)?r:void 0}async function request(e){try{const t=await e()??{},r=asObject(t);return{ok:!0,data:Object.hasOwn(r,"data")?r.data:t}}catch(e){if(e instanceof CloudHttpError){let t=e.body;try{t=e.body?JSON.parse(e.body):{}}catch{}return{ok:!1,status:e.status,error:`Automation request failed: HTTP ${e.status}`,details:t}}return{ok:!1,status:0,error:e instanceof Error?e.message:String(e),details:void 0}}}function listQuery(e){const t={};for(const r of["status","cursor"]){const o=stringValue(e[r]);o&&(t[r]=o)}return"number"==typeof e.limit&&Number.isFinite(e.limit)&&(t.limit=String(Math.trunc(e.limit))),t}function buildSchedule(e){const t=stringValue(e.kind)??"every",r={kind:t,tz:stringValue(e.tz)??"UTC"};switch(t){case"every":{r.intervalSeconds="number"==typeof e.intervalSeconds?String(Math.trunc(e.intervalSeconds)):stringValue(e.intervalSeconds)??"3600";const t=stringValue(e.anchorAt);t&&(r.anchorAt=t);break}case"at":{const t=stringValue(e.at);t&&(r.at=t);break}case"cron":{const t=stringValue(e.expression);t&&(r.expression=t);break}default:return{error:"schedule.kind must be one of at, every, or cron"}}return r}function buildSession(e,t,r){const o=stringValue(asObject(e.session).mode)??"new";if("new"!==o&&"bound"!==o)return{error:"session.mode must be new or bound"};const n={mode:o},a=resolveConversationId(t,r);if("bound"===o){if(!a)return{error:"bound Automation requires the current conversation context"};n.boundConversationId=a}return n}function createInput(e,t,r){const o=asObject(e),n=stringValue(o.name),a=stringValue(o.prompt),s=resolveTarget(t);if(!n||!a||!s)return{error:"name, prompt, and a resolvable target agent are required"};const i=buildSchedule(asObject(o.schedule));if("error"in i)return i;const u=buildSession(o,t,r);if("error"in u)return u;const c={name:n,prompt:a,target:s,schedule:i,session:u},l=stringValue(o.validFrom),d=stringValue(o.validUntil);l&&(c.validFrom=l),d&&(c.validUntil=d);const p=resolveConversationId(t,r);return p&&(c.createdInConversationId=p),c}function createWebhookInput(e,t,r){const o=asObject(e),n=stringValue(o.name),a=stringValue(o.prompt),s=(stringValue(o.source)??"").toLowerCase(),i=resolveTarget(t);if(!n||!a||!i)return{error:"name, prompt, and a resolvable target agent are required"};if("github"!==s&&"gmail"!==s)return{error:"source must be github or gmail"};const u=o.events,c=Array.isArray(u)?u.filter(e=>"string"==typeof e&&Boolean(e.trim())).map(e=>e.trim()):[],l=stringValue(o.repoOwner),d=stringValue(o.repoName),p=stringValue(o.mailbox);if(!("github"!==s||0!==c.length&&l&&d))return{error:"github webhook requires events, repoOwner, and repoName"};if("gmail"===s&&!p)return{error:"gmail webhook requires mailbox"};const m=buildSession(o,t,r);if("error"in m)return m;const g={name:n,prompt:a,target:i,session:m,source:s};"github"===s?(g.events=c,g.repoOwner=l,g.repoName=d):g.mailbox=p;const y=stringValue(o.eventFilter);y&&(g.eventFilter=y);const f=stringValue(o.validFrom),b=stringValue(o.validUntil);f&&(g.validFrom=f),b&&(g.validUntil=b);const h=resolveConversationId(t,r);return h&&(g.createdInConversationId=h),g}function unwrapConnectorMcp(e){let t=e;if("string"==typeof t)try{t=JSON.parse(t)}catch{return}if(!t||"object"!=typeof t||Array.isArray(t))return;const r=t;if(null!=r.error)return;let o=r.result??r;if(!o||"object"!=typeof o||Array.isArray(o))return;const n=o;if(n.isError)return;const a=n.structuredContent;if(a&&"object"==typeof a&&!Array.isArray(a))return a;const s=n.content;if(Array.isArray(s))for(const e of s){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;if("text"===t.type&&"string"==typeof t.text)try{const e=JSON.parse(t.text);if(e&&"object"==typeof e&&!Array.isArray(e))return e}catch{continue}}return n}function isMcpToolError(e){if(!e||"object"!=typeof e||Array.isArray(e))return!1;const t=e;if(null!=t.error||!0===t.isError)return!0;const r=t.result;return Boolean(r&&"object"==typeof r&&!Array.isArray(r)&&!0===r.isError)}async function runPreflight(e,t,r){const o=asObject(t),n=(stringValue(o.source)??"").toLowerCase(),a=resolveConversationId(e,r),s=resolveTarget(e),i={source:n,operation:"webhook",ready:!1,platform:{reachable:!1,authorized:!1},connector:{id:n,installed:!1,credentialStatus:"unknown"},operationSupported:"github"===n||"gmail"===n,target:{resolved:Boolean(s)},session:{canBindCurrentConversation:Boolean(a)},nextAction:"retry_or_check_connection"};if("github"!==n&&"gmail"!==n)return i.blockingReason="unsupported_source",i.nextAction="retry_or_check_connection",i;if("gmail"===n&&!stringValue(o.mailbox))return i.blockingReason="mailbox_required",i.nextAction="provide_mailbox",i;if("github"===n){const e=o.events,t=Array.isArray(e)&&e.some(e=>"string"==typeof e&&e.trim());if(!stringValue(o.repoOwner)||!stringValue(o.repoName)||!t)return i.blockingReason="github_webhook_input_required",i.nextAction="provide_repository_and_events",i}const u=await request(()=>e.gateway.automations.list({limit:1}));if(!u.ok)return i.blockingReason="automation_gateway_unavailable",i.platform={reachable:!1,authorized:!1,status:u.status,error:u.error},i.nextAction="retry_or_check_connection",i;let c;i.platform={reachable:!0,authorized:!0};let l=!1;try{c=await e.callConnectorTool(n,"list_connectors",{})}catch{l=!0}if(l||isMcpToolError(c))return i.blockingReason="mcp_unavailable",i.connector={id:n,installed:!1,credentialStatus:"unknown",error:"connector MCP call failed"},i.nextAction="retry_or_check_connection",i;if(void 0===c)return i.blockingReason="mcp_not_connected",i.nextAction="install_connector",i;const d=unwrapConnectorMcp(c),p=d&&Array.isArray(d.connectors)?d.connectors:void 0;let m;if(Array.isArray(p))for(const e of p){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;if([t.connectorId,t.connector_id,t.slug].map(e=>stringValue(e)?.toLowerCase()).includes(n)){m=t;break}}if(!m)return i.blockingReason="mcp_not_connected",i.nextAction="install_connector",i;const g=(stringValue(m.credentialStatus)??stringValue(m.credential_status)??"unknown").toLowerCase();return i.connector={id:n,installed:!0,credentialStatus:g},"active"!==g?(i.blockingReason="credential_missing",i.nextAction="authorize_connector",i):s?(i.ready=!0,i.nextAction="create_automation",i.sideEffects="gmail"===n?["create_rule","ensure_shared_gmail_watch"]:["create_rule","issue_hook","register_connector_webhook"],i):(i.blockingReason="target_not_resolved",i.nextAction="sync_openclaw_agent",i)}async function runCapabilities(e,t){const r=resolveTarget(e),o=resolveConversationId(e,t),n={platform:{reachable:!1,authorized:!1},capabilities:{createSchedule:Boolean(r),createWebhook:Boolean(r),run:!0},target:{resolved:Boolean(r)},session:{currentConversationAvailable:Boolean(o),canBindCurrentConversation:Boolean(o)}},a=await request(()=>e.gateway.automations.list({limit:1}));return a.ok?n.platform={reachable:!0,authorized:!0}:n.platform={reachable:!1,authorized:!1,status:a.status,error:a.error},n}function requestErrorResult(e){return toolResult({error:e.error,status:e.status,details:e.details})}export function registerAutomationTools(e,t){e.registerTool({name:"beeos_automation_create",description:"Create a BeeOS platform Automation owned by the current user. The target is the current Agent and is resolved automatically. Prefer session.mode=bound for a task created in this chat.",parameters:{type:"object",properties:{name:{type:"string",description:"Human-readable automation name"},prompt:{type:"string",description:"Prompt sent to the target agent when the automation fires"},schedule:{type:"object",properties:{kind:{type:"string",enum:["at","every","cron"]},tz:{type:"string"},at:{type:"string"},intervalSeconds:{type:"integer",minimum:1},anchorAt:{type:"string"},expression:{type:"string"}}},session:{type:"object",description:"Always set session.mode. Prefer bound for tasks created in the current BeeOS chat so every run returns here. Use new if the user requests a separate conversation per run or the current chat cannot bind. The plugin fills the bound conversation ID; do not supply it.",properties:{mode:{type:"string",enum:["new","bound"]}}},validFrom:{type:"string"},validUntil:{type:"string"}},required:["name","prompt"]},async execute(e,r,o){const n=createInput(r,t,e);if("error"in n)return toolResult(n);try{const e=await request(()=>t.gateway.automations.create(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return t.logger?.warn?.(`[beeos_automation_create] ${e instanceof Error?e.message:String(e)}`),toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_create_webhook",description:"Create a BeeOS platform Webhook Automation. GitHub uses source/events/repoOwner/repoName; Gmail uses source/mailbox only (never hookId/hookUrl/repo*). Runs preflight first. Prefer session.mode=bound for a task created in this chat.",parameters:{type:"object",properties:{name:{type:"string"},prompt:{type:"string"},source:{type:"string",enum:["github","gmail"]},events:{type:"array",items:{type:"string"},minItems:1},repoOwner:{type:"string"},repoName:{type:"string"},eventFilter:{type:"string"},mailbox:{type:"string"},session:{type:"object",description:"Always set session.mode. Prefer bound for tasks created in the current BeeOS chat so every event returns here. Use new if the user requests a separate conversation per event or the current chat cannot bind. The plugin fills the bound conversation ID; do not supply it.",properties:{mode:{type:"string",enum:["new","bound"]}}},validFrom:{type:"string"},validUntil:{type:"string"}},required:["name","prompt","source"]},async execute(e,r,o){const n=createWebhookInput(r,t,e);if("error"in n)return toolResult(n);try{const a=await runPreflight(t,r,e);if(!a.ready)return toolResult({error:"automation_preflight_failed",preflight:a});const s=await request(()=>t.gateway.automations.createWebhook(n,{signal:o}));return s.ok?toolResult(s.data):requestErrorResult(s)}catch(e){return t.logger?.warn?.(`[beeos_automation_create_webhook] ${e instanceof Error?e.message:String(e)}`),toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_capabilities",description:"Check whether the BeeOS Automation platform is reachable/authorized and whether the current chat can bind as an Automation session. Read-only.",parameters:{type:"object",properties:{}},async execute(e){try{return toolResult(await runCapabilities(t,e))}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_preflight",description:"Read-only readiness check for creating a BeeOS Webhook Automation. Returns nextAction such as authorize_connector, install_connector, provide_mailbox, provide_repository_and_events, sync_openclaw_agent, retry_or_check_connection, or create_automation.",parameters:{type:"object",properties:{source:{type:"string",enum:["github","gmail"]},events:{type:"array",items:{type:"string"}},repoOwner:{type:"string"},repoName:{type:"string"},mailbox:{type:"string"},session:{type:"object",properties:{mode:{type:"string",enum:["new","bound"]}}}},required:["source"]},async execute(e,r){try{return toolResult(await runPreflight(t,r,e))}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_list",description:"List BeeOS platform Automations owned by the current user.",parameters:{type:"object",properties:{status:{type:"string",enum:["enabled","paused","expired"]},limit:{type:"integer",minimum:1,maximum:100},cursor:{type:"string"}}},async execute(e,r,o){const n=listQuery(asObject(r));try{const e=await request(()=>t.gateway.automations.list(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_get",description:"Get one BeeOS platform Automation by its automation ID.",parameters:{type:"object",properties:{automationId:{type:"string"}},required:["automationId"]},async execute(e,r,o){const n=stringValue(asObject(r).automationId);if(!n)return toolResult({error:"automationId is required"});try{const e=await request(()=>t.gateway.automations.get(n,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_run",description:"Trigger an existing BeeOS platform Automation immediately and return its Run record.",parameters:{type:"object",properties:{automationId:{type:"string"},requestKey:{type:"string",description:"Optional idempotency key; generated when omitted"},sourceRunId:{type:"string"},rerunSessionMode:{type:"string",enum:["original","new"]}},required:["automationId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId);if(!a)return toolResult({error:"automationId is required"});const s=stringValue(n.requestKey)??randomUUID(),i=stringValue(n.sourceRunId),u=stringValue(n.rerunSessionMode),c={};i&&(c.sourceRunId=i),u&&(c.rerunSessionMode=u);try{const e=await request(()=>t.gateway.automations.run(a,c,s,{signal:o}));return e.ok?toolResult({requestKey:s,data:e.data}):toolResult({error:e.error,status:e.status,details:e.details,requestKey:s})}catch(e){return toolResult({error:e instanceof Error?e.message:String(e),requestKey:s})}}}),e.registerTool({name:"beeos_automation_runs",description:"List Runs for one BeeOS platform Automation.",parameters:{type:"object",properties:{automationId:{type:"string"},status:{type:"string",enum:["scheduled","dispatched","failed","skipped"]},limit:{type:"integer",minimum:1,maximum:100},cursor:{type:"string"}},required:["automationId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId);if(!a)return toolResult({error:"automationId is required"});const s=listQuery(n);try{const e=await request(()=>t.gateway.automations.runs(a,s,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}}),e.registerTool({name:"beeos_automation_get_run",description:"Get one Run record for a BeeOS platform Automation.",parameters:{type:"object",properties:{automationId:{type:"string"},runId:{type:"string"}},required:["automationId","runId"]},async execute(e,r,o){const n=asObject(r),a=stringValue(n.automationId),s=stringValue(n.runId);if(!a||!s)return toolResult({error:"automationId and runId are required"});try{const e=await request(()=>t.gateway.automations.runDetail(a,s,{signal:o}));return e.ok?toolResult(e.data):requestErrorResult(e)}catch(e){return toolResult({error:e instanceof Error?e.message:String(e)})}}})}
@@ -0,0 +1 @@
1
+ import{listMcpServers}from"../openclaw-cli.js";import{connectMcpServer}from"../acp-gateway/mcp-tool-bridge.js";export function harnessConnectorToolCaller(r={}){const t=r.list??listMcpServers,o=r.connect??connectMcpServer;return async(r,e,n,c)=>{const s=await t();if(!Object.hasOwn(s,r))return;const a=s[r];if("streamable-http"!==a.transport&&"sse"!==a.transport)throw new Error(`connector MCP server ${r} is not a remote server`);if("string"!=typeof a.url)throw new Error(`connector MCP server ${r} has no url`);const i=await o({transport:a.transport,url:a.url,..."number"==typeof a.connectionTimeoutMs?{connectionTimeoutMs:a.connectionTimeoutMs}:{}},a.headers?{headers:a.headers}:void 0);try{return await i.callTool(e,n,c)}catch{throw new Error("MCP tool invocation failed")}finally{await i.close().catch(()=>{})}}}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{registerManagedConnectorTools}from"./connectors/managed-connector-tools.js";import{consumeNativeOutputTool}from"./runtime/native-output-file-attempt.js";import{uploadNativeOutputFile}from"./upload/upload-file.js";import{nativeOutputToolCallGate}from"./upload/native-output-tool-hook.js";import{NativeInputFilesHttpClient}from"./runtime/native-input-files-http.js";import{fileDeliveryFinalizeDecision}from"./upload/finalize-hook.js";import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.js";import{createMcpNativeProjectionNudge,fingerprintMcpServers}from"./acp-gateway/mcp-native-projection-nudge.js";import{createImHotPathDeferral}from"./runtime/im-hot-path-deferral.js";import{SessionWriteGate}from"./acp-gateway/session-write-gate.js";import{OpenClawSessionWriteQuiescence}from"./runtime/openclaw-session-write-quiescence.js";import{SessionMutationCoordinator}from"./runtime/session-mutation-coordinator.js";import{scheduleProcessRuntimeRestart}from"./runtime/runtime-restart-scheduler.js";import{createImInboundHandler}from"./im-inbound-handler.js";import{AgentGatewayClient,NodeRuntimeDeliveryPort,agentIdentityFromKeyPair,loadAgentKeyPair,signAgentMessage}from"@beeos-ai/cloud-harness-sdk";import{MessageServiceConversationRunBoundary}from"./runtime/message-service-conversation-run-boundary.js";import{AutomationTurnPolicy}from"./automation/turn-policy.js";import{ApprovalGate}from"./approval/gate.js";import{FileApprovalJournal}from"./approval/journal.js";import{ApprovalTurnPolicy}from"./approval/turn-policy.js";import{toMessagePart}from"./message-client-types.js";import{registerAutomationTools}from"./automation/tools.js";import{extractBeeosConversationIdFromSessionKey}from"./runtime/openclaw-session-key-resolution.js";import{setOpenClawConfigSnapshot}from"./runtime/openclaw-session-model.js";import{BeeosClawMessageClientProcessOwner,createBeeosClawMessageTokenProvider}from"./message-client-composition.js";import{MessageProjectionInboundConsumer}from"./message-projection-inbound-consumer.js";import{MessageClientTerminalStateRecovery}from"./runtime/message-client-terminal-state-recovery.js";import{RuntimeAuthorityMessageBusLifecycle}from"./runtime/runtime-authority-message-bus-lifecycle.js";import{createNativeCloudChatComposition,nativeCloudChatAuthorityFromRuntimeAuthority}from"./runtime/native-cloud-chat-composition.js";import{MSConnectionStatusSnapshot}from"./runtime/ms-connection-status.js";import{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{completeA2ATask,registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,REQUEST_TIMEOUT_MS as BEEOS_UPLOAD_REQUEST_TIMEOUT_MS,executeUpload}from"./upload/tool.js";import{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,executeDesktopScreenshot}from"./upload/desktop-screenshot-tool.js";import{BEEOS_LIST_FILES_TOOL_NAME,BEEOS_LIST_FILES_TOOL_SCHEMA,BEEOS_LIST_FILES_TOOL_DESCRIPTION,executeListFiles}from"./files/list-tool.js";import{BEEOS_FETCH_FILE_TOOL_NAME,BEEOS_FETCH_FILE_TOOL_SCHEMA,BEEOS_FETCH_FILE_TOOL_DESCRIPTION,executeFetchFile}from"./files/fetch-tool.js";import{writeUploadToolResult,cleanupUploadToolResultCache}from"./upload/result-cache.js";import{handleFileStage}from"./upload/file-stage.js";import{handleStatusRequest}from"./status.js";import{ACPServer}from"./acp-server.js";import{GatewayClient}from"./gateway-client.js";import{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{setClaimedCloudRuntimeInstanceId,setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{deliverableFileExtractor}from"./upload/deliverable-extractor.js";import{observeToolCallForDelivery,rememberDeliveryWorkspace}from"./upload/delivery-observe.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{marksFullRuntimeRegistered,planPluginRegistration,replayCachedPluginTools,resolveCapabilityToolReplay}from"./plugin-registration-plan.js";import{buildAppendSystemContext,buildToolRoutingHint,canvasToolBlockReason}from"./prompt-system-context.js";import{CONNECTOR_MCP_PROXY_PATH,handleConnectorMcpRequest}from"./mcp-connector-proxy.js";import{CanvasStateManager}from"./canvas/state.js";import{createStaticCanvasHtmlPublisher}from"./canvas/static-html.js";import{CanvasRelayClient}from"./canvas/relay-client.js";import{createCanvasRelayService}from"./canvas/relay-service.js";import{RENDER_UI_TOOL_NAME,RENDER_UI_TOOL_DESCRIPTION,RENDER_UI_TOOL_SCHEMA,CLOSE_UI_TOOL_NAME,CLOSE_UI_TOOL_DESCRIPTION,CLOSE_UI_TOOL_SCHEMA,createRenderUiToolExecutor,createCloseUiHandler,CANVAS_PRESENTATION_GATE,CANVAS_SYSTEM_PROMPT}from"./canvas/tools.js";import{FormSchemaRegistry}from"./surface/form-schema-registry.js";import{buildCronSchemas}from"./surface/cron-schemas.js";import{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./surface/render-form-tool.js";import{ResourceDescriptorRegistry}from"./surface/resource-descriptor-registry.js";import{CRON_RESOURCE}from"./surface/cron-resource.js";import{generateActionTools}from"./surface/action-tool-generator.js";import{buildThirdPartyChannelSet,isThirdPartyChannel}from"./channel-detection.js";import{registerArouterMediaProviders}from"./media/index.js";import{homedir}from"node:os";import{join}from"node:path";import{RuntimeProductionAuthority,cloudRuntimeTargetInstanceId}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{OpenClawNativeMcpProjection}from"./acp-gateway/openclaw-native-mcp-projection.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,CloudRuntimeServiceTransportReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";import{fetchRuntimeLeaseAttempt}from"./runtime/message-service-runtime-authenticated-fetch.js";import{MessageServiceCronDeliveryHttpAuthority}from"./runtime/message-service-cron-delivery-http-authority.js";import{AgentMappingRegistry}from"./runtime/agent-mapping-registry.js";import{OpenClawRuntimeProcessOwner}from"./runtime/openclaw-runtime-process-owner.js";import{AgentGatewayHttpProjectionTransport,AgentGatewayTemplateOriginReporter,AgentProjectionProduction,OpenClawAgentProjectionSource}from"./runtime/agent-projection-production.js";import{MessageServiceRunOutputChannel}from"./runtime/message-service-run-output-channel.js";import{AssistantMessageCommitRouter}from"./runtime/assistant-message-commit-router.js";import{ToolResultObservationRouter}from"./runtime/tool-result-observation-router.js";import{ModelCallObservationRouter,registerModelCallObservationHooks}from"./runtime/model-call-observability.js";import{registerArouterLatencyRouting}from"./runtime/arouter-latency-routing.js";import{createPeerRunOutputRouterFactory}from"./runtime/run-output-composition.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,agentGateway=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore,sharedAutomationTurnPolicy=new AutomationTurnPolicy,APPROVAL_V1_MS_ENABLED="1"===process.env.BEEOS_APPROVAL_V1_MS;let sharedApprovalJournal,sharedApprovalGate,sharedApprovalPolicy,sharedApprovalPublisher,lastOpenclawConfig;const sharedMcpNativeProjectionNudge=createMcpNativeProjectionNudge({getActiveImRunCount:()=>sharedPromptRunStore.size(),nudge:()=>{sharedAcpServer?.nudgeMcpNativeProjection()}}),sharedImHotPathDeferral=createImHotPathDeferral({getActiveImRunCount:()=>sharedPromptRunStore.size()});sharedPromptRunStore.setOnBecameIdle(()=>{sharedMcpNativeProjectionNudge.flushIfIdle({fingerprint:fingerprintMcpServers(lastOpenclawConfig)}),sharedImHotPathDeferral.notifyIdle()});const sharedAssistantMessageCommitRouter=new AssistantMessageCommitRouter,sharedToolResultObservationRouter=new ToolResultObservationRouter,sharedModelCallObservationRouter=new ModelCallObservationRouter;let sharedSessionMutationCoordinator,sharedRuntimeAuthority,sharedNativeChatService,sharedNativeCloudChat,sharedWriteObs=()=>{};const sharedMSConnectionStatus=new MSConnectionStatusSnapshot,sharedAgentMappings=new AgentMappingRegistry;let sharedGatewayClient,sharedRuntimeOwner,sharedAgentProjection,sharedRuntimeAgentCapabilities,sharedMcpProjection,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0,_fullRuntimeRegistered=!1;const cachedCapabilityTools=[];let rawRegisterTool,wrappedRegisterTool;const cachedRuntimeServices=[],cachedRuntimeHooks=[];let rawRegisterService,wrappedRegisterService,rawOn,wrappedOn;function cacheRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService;if(rawRegisterService=t,wrappedRegisterService=r=>{cachedRuntimeServices.push(r),t.call(e,r)},e.registerService=wrappedRegisterService,cachedRuntimeServices.length=0,cachedRuntimeHooks.length=0,e.on){const t=e.on===wrappedOn?rawOn:e.on;rawOn=t,wrappedOn=(...r)=>{cachedRuntimeHooks.push(r),t.call(e,...r)},e.on=wrappedOn}}function replayRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService,r=e.on===wrappedOn?rawOn:e.on;for(const t of cachedRuntimeHooks)r.call(e,...t);for(const r of cachedRuntimeServices)t.call(e,r)}const ensureRegisterToolCache=e=>{const t=e.registerTool===wrappedRegisterTool?rawRegisterTool:e.registerTool;rawRegisterTool=t.bind(e),wrappedRegisterTool=e=>(cachedCapabilityTools.push(e),rawRegisterTool(e)),e.registerTool=wrappedRegisterTool};function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async t=>signAgentMessage(t,e.privateKey)}}let sharedPluginContext=null,unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,t,r){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",r=>{const o=r instanceof Error?r.message:String(r),a=r instanceof Error?r.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${a?`\n${a}`:""}`),t({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...a?{stack:a}:{}}})}),process.on("uncaughtException",r=>{const o=r instanceof Error?r.message:String(r);e.logger.error?.(`[beeos-claw] uncaughtException: ${r instanceof Error?r.stack??r.message:String(r)}`),t({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let t,r;try{t=e.runtime?.config?.loadConfig?.()}catch{}try{r=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:t})}catch(t){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${t instanceof Error?t.message:String(t)}`),null}const o=r.config,a=buildThirdPartyChannelSet(t);a.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...a].join(", ")}`);const n=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};n({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),n({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:r.sources,openclawConfigPath:r.openclawConfigPath}});for(const t of r.validation)n({component:"plugin",domain:"config",name:"config.validation",severity:t.severity,summary:t.message,error:{code:t.code,message:t.message,nextSteps:t.nextSteps}}),"error"===t.severity?e.logger.error?.(`[beeos-claw] ${t.message}`):e.logger.warn?.(`[beeos-claw] ${t.message}`);if(r.validation.some(e=>"error"===e.severity)&&e.logger.error?.("[beeos-claw] Plugin has configuration errors — some features may not work."),o.keyFile)try{agentKeys=loadAgentKeyPair(o.keyFile),agentGateway=o.agentGatewayUrl?new AgentGatewayClient({baseUrl:o.agentGatewayUrl,identity:agentIdentityFromKeyPair(agentKeys),onRetry:({method:t,path:r,attempt:o,delayMs:a,error:n})=>e.logger.warn?.(`[beeos-claw] Agent Gateway ${t} ${r} retry ${o} in ${a}ms: ${n instanceof Error?n.message:String(n)}`)}):null;const t=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${t})`)}catch(t){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${t}`),e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no key pair — signed requests disabled)`)}else e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no keyFile configured)`);return agentGateway&&(setUploadDeps({gateway:agentGateway,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),registerLocalFileExtractor(deliverableFileExtractor),e.logger.info?.("[beeos-claw] Upload deps + local file extractors registered")),lastOpenclawConfig=t,sharedWriteObs=n,setOpenClawConfigSnapshot(t),{cfg:o,writeObs:n,thirdPartyChannels:a,openclawConfig:t}}function registerUploadTools(e,t,r){const{cfg:o,writeObs:a}=t,n=Boolean(pluginCloudRuntimeTarget(e));if(n){if(!e.on)throw new Error("native output Files Host hook unavailable");e.on("before_tool_call",nativeOutputToolCallGate)}cleanupUploadToolResultCache().catch(t=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(t)}`)}),e.registerTool({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(t,r,i){const s=n?consumeNativeOutputTool(t):void 0,l=await executeUpload(r,agentGateway,i,s?(e,t)=>uploadNativeOutputFile(e,o.agentGatewayUrl,s,t,i,BEEOS_UPLOAD_REQUEST_TIMEOUT_MS):void 0,e.logger);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${t} ok=${l.ok}`),a({component:"upload-tool",domain:"tool",name:l.ok?"upload.success":"upload.failure",severity:l.ok?"info":"warn",payload:{toolCallId:t,ok:l.ok,fileCount:l.files?.length??0,error:l.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_UPLOAD_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_upload_file] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(l)}}),e.registerTool({name:BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,parameters:BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeDesktopScreenshot(r,agentGateway,o);return e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} ok=${n.ok}`),a({component:"desktop-screenshot-tool",domain:"tool",name:n.ok?"desktop_screenshot.success":"desktop_screenshot.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,fileCount:n.files?.length??0,error:n.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_desktop_screenshot] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(n)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,r){await handleFileStage(e,r,t.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,t){handleStatusRequest(e,t,{publicKey:agentKeys?.publicKey??null,pluginVersion:PLUGIN_VERSION})}}),e.registerTool({name:BEEOS_LIST_FILES_TOOL_NAME,description:BEEOS_LIST_FILES_TOOL_DESCRIPTION,parameters:BEEOS_LIST_FILES_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_list_files] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeListFiles(r,agentGateway,o);return a({component:"file-list-tool",domain:"tool",name:n.ok?"list_files.success":"list_files.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,fileCount:n.files?.length??0,error:n.error}}),n}}),e.registerTool({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeFetchFile(r,agentGateway,{signal:o,resolvePath:e.resolvePath});return a({component:"file-fetch-tool",domain:"tool",name:n.ok?"fetch_file.success":"fetch_file.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,size:n.size,error:n.error}}),n}})}function registerConnectorMcpProxy(e,t){e.registerHttpRoute({path:CONNECTOR_MCP_PROXY_PATH,auth:"plugin",async handler(t,r){await handleConnectorMcpRequest(t,r,{gateway:agentGateway,logger:e.logger})}})}function registerServices(e,t,r){const{cfg:o,writeObs:a,thirdPartyChannels:n}=t;if(sharedAutomationTurnPolicy.disable(),"function"==typeof e.on)try{e.on("before_tool_call",(e,t)=>sharedAutomationTurnPolicy.check(e.toolName,{sessionKey:t?.sessionKey,runId:t?.runId??e.runId}),{priority:100}),sharedAutomationTurnPolicy.enable()}catch{e.logger.warn?.("[beeos-claw] Automation Wake disabled: tool guard unavailable")}if("function"!=typeof e.on){if(o.messageBus.enabled)throw new Error("openclaw_before_message_write_hook_unavailable")}else registerModelCallObservationHooks((t,r)=>e.on(t,r),sharedModelCallObservationRouter),e.on("before_message_write",(t,r)=>{const o=t.sessionKey??r.sessionKey;if(!o)return void e.logger.debug?.("[before_message_write] ignored assistant write without sessionKey");sharedAssistantMessageCommitRouter.route(o,t.message)||e.logger.debug?.(`[before_message_write] no active IM commit target sessionKey=${o} active_targets=${sharedAssistantMessageCommitRouter.size()}`)}),e.on("after_tool_call",(t,r)=>{const o=r.sessionKey,a=t.toolCallId??r.toolCallId,n=t.toolName||r.toolName;if(!o||!a||!n)return void e.logger.debug?.(`[after_tool_call] ignored structured result without correlation sessionKey=${o??"missing"} toolCallId=${a??"missing"}`);observeToolCallForDelivery(t,o);sharedToolResultObservationRouter.route(o,{toolCallId:a,toolName:n,rawResult:t.result,isError:Boolean(t.error)})||e.logger.debug?.(`[after_tool_call] no active IM observation target sessionKey=${o} active_targets=${sharedToolResultObservationRouter.size()}`)});const i=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,s=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos");if(APPROVAL_V1_MS_ENABLED){if(!e.registerTrustedToolPolicy||!e.on)throw new Error("openclaw_trusted_approval_policy_unavailable");sharedApprovalJournal??=new FileApprovalJournal(join(s,"approval-v1")),sharedApprovalGate??=new ApprovalGate(sharedApprovalJournal,async(...e)=>{if(!sharedApprovalPublisher)throw new Error("approval_message_transport_unavailable");await sharedApprovalPublisher(...e)}),sharedApprovalPolicy??=new ApprovalTurnPolicy(sharedApprovalGate,[o.gateway.token].filter(Boolean));const t=e=>sharedApprovalPolicy.isManaged(e)||Boolean(e.sessionKey&&extractBeeosConversationIdFromSessionKey(e.sessionKey));e.registerTrustedToolPolicy({id:"beeos-approval-v1",description:"One-shot BeeOS MS execution approvals",evaluate:async(e,r)=>t(r)?sharedApprovalPolicy.evaluate(e,r):void 0}),e.on("before_tool_call",(e,r)=>t(r)?sharedApprovalPolicy.finalize(e,r):void 0,{priority:Number.MIN_SAFE_INTEGER})}const l=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(s,"inbound-execution-journal.v1.jsonl"));sharedMcpProjection??=new OpenClawNativeMcpProjection,!sharedMcpCredentialVault&&agentKeys&&i&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(s,"mcp-credential-vault.json"),i,agentKeys.privateKey));const c=pluginCloudRuntimeTarget(e);if(setClaimedCloudRuntimeInstanceId(c),c&&(!agentKeys||!agentGateway))throw new Error("Cloud runtime authority requires an agent identity and gateway transport");const u=sharedRuntimeAuthority?.cloudTargetInstanceId;if(u&&c&&u!==c)throw new Error("Cloud runtime authority target changed during process lifetime");if(sharedRuntimeAuthority&&!u&&c&&sharedRuntimeAuthority.bindCloudTarget(c),!sharedRuntimeAuthority&&agentKeys&&agentGateway&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:s,gateway:agentGateway,keys:agentKeys,targetInstanceId:c,logger:e.logger,getMSConnectionStatus:e=>sharedMSConnectionStatus.get(e)})),sharedGatewayClient??=new GatewayClient({url:o.gateway.url,token:o.gateway.token||"",clientId:o.gateway.clientId,openclawCanvasCompat:!!o.openclawCanvasCompat,retry:{baseMs:o.retry.baseMs,maxMs:o.retry.maxMs,maxAttempts:o.retry.maxAttempts}}),sharedRuntimeAgentCapabilities??={canvas:o.canvasEnabled,terminal:!1,webSsh:!1,fileSystem:!0,image:!0,audio:!1,mcp:!0,cron:!0,streaming:!0,pushNotifications:o.messageBus.enabled,...o.messageBus.enabled&&sharedAutomationTurnPolicy.isReady()&&agentGateway?{automationWake:!0}:{}},!sharedAgentProjection&&sharedRuntimeAuthority&&agentGateway){const t=sharedRuntimeAuthority;sharedAgentProjection=new AgentProjectionProduction({authority:t,stateFile:join(t.stateDirectory,"runtime-agent-projection.json"),journal:t.journal,identities:t.identities,source:new OpenClawAgentProjectionSource(()=>sharedGatewayClient),transport:new AgentGatewayHttpProjectionTransport({gateway:agentGateway,getRuntimeLeaseCredential:e=>{const r=t.authorityLease;if(!r||r.instanceId!==e.instanceId||r.leaseId!==e.leaseId||r.runtimeEpoch!==e.runtimeEpoch||r.handlerIdentity!==e.handlerIdentity)throw new Error("agent projection fenced by current runtime lease");return r.runtimeLeaseCredential},onAccepted:t=>{0!==t.size&&sharedAgentMappings.replace(t).catch(t=>{e.logger.warn?.("[agent-projection] mapping publication failed: "+(t instanceof Error?t.message:String(t)))})}}),capabilities:sharedRuntimeAgentCapabilities,logger:e.logger})}sharedRuntimeOwner??=new OpenClawRuntimeProcessOwner(sharedGatewayClient,sharedAgentProjection,e.logger);const d=sharedRuntimeOwner;sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main"}),e.logger,{onRecoveryRequired:t=>{scheduleProcessRuntimeRestart(t,e.logger)}});const g=sharedSessionMutationCoordinator;if(!sharedAcpServer){const t=sharedRuntimeAuthority&&agentGateway?new AgentGatewayTemplateOriginReporter({gateway:agentGateway}):void 0;sharedAcpServer=new ACPServer(o,e.logger,g,a,agentGateway??void 0,i,n,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpProjection,sharedMcpCredentialVault,{gateway:d.client,agentProjection:sharedAgentProjection,markAgentProjectionDirty:()=>sharedAgentProjection?.markDirty(),templateOriginReporter:t,agentMappings:sharedAgentMappings,agentCapabilities:sharedRuntimeAgentCapabilities,createRunOutputRouter:createPeerRunOutputRouterFactory(new MessageServiceRunOutputChannel({getClient:()=>sharedMessageClientOwner.current?.client??null,logger:e.logger,writeObs:a})),runExclusive:(t,r,o)=>sharedImHotPathDeferral.runExclusive(t,r,e.logger,o)})}const p=sharedAcpServer,m=()=>sharedAgentMappings.snapshot()?.values().next().value;r.current=p,sharedMcpNativeProjectionNudge.request({registrationMode:e.registrationMode,fingerprint:fingerprintMcpServers(t.openclawConfig),logger:e.logger});const h=sharedPromptRunStore,{enabled:y,principalId:v,a2aEnabled:f}=o.messageBus;let w;!c&&o.agentGatewayUrl&&agentKeys&&(w=createBeeosClawMessageTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const R=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),C=v||process.env.BEEOS_PRINCIPAL_ID||"",b=w?sharedMessageClientOwner.configure({tokenProvider:w,identityId:C,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&R?{runtimeDelivery:{scopedDeliveryKey:R,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null}}}}:{}}):void 0,S=c&&o.messageBus.serviceUrl&&sharedRuntimeAuthority?new NodeRuntimeDeliveryPort({serviceOrigin:async()=>o.messageBus.serviceUrl},{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t&&e.instanceId===c?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null},subscribeAuthority:e=>sharedRuntimeAuthority.subscribeAuthority(e)}):void 0;attachNativeCloudChat(e,o);const _=sharedRuntimeAuthority,E=o.messageBus.serviceUrl;b&&_&&E&&R?p.setCronConversationDelivery({deliver:async e=>{const t=_.authorityLease;if(!t)throw new Error("current runtime authority lease unavailable for cron delivery");const r=new MessageServiceCronDeliveryHttpAuthority({messageServiceUrl:E,scopedDeliveryKey:R,fetchAuthorized:(e,t)=>fetchRuntimeLeaseAttempt(e,t??{})});return await r.deliver({...e,runtimeLeaseCredential:t.runtimeLeaseCredential})}}):p.setCronConversationDelivery(void 0);const A=sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(s,"runtime-command-journal.json"),void 0,void 0,{onMaintenanceError:t=>e.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=threshold error=${t instanceof Error?t.message:String(t)}`)}),O=d.createRegistrationToken();e.registerService({id:"beeos-acp",async start(){const t=Date.now(),r=_pluginRegisteredAt?t-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${r}ms, bridge.url=${o.bridge.url||"(empty)"}`);const a=await createRuntimeServiceProductionCandidate({...agentGateway?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({gateway:agentGateway})}:{},onGrantJwksWarm:t=>{t.ready?e.logger.info?.("[beeos-claw] Gateway grant keyset loaded"):e.logger.warn?.(`[beeos-claw] Gateway grant keyset not ready yet (attempt ${t.attempt}): ${t.error instanceof Error?t.error.message:String(t.error)}`)},...b&&agentGateway&&R?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({gateway:agentGateway,messageService:b.nodeTransport,messageClient:b.client,configuredServiceUrl:o.messageBus.serviceUrl,scopedDeliveryKey:R})}:{},...S&&agentGateway&&o.messageBus.serviceUrl?{cloudTransportAdapter:new CloudRuntimeServiceTransportReadinessAdapter({gateway:agentGateway,configuredServiceUrl:o.messageBus.serviceUrl,runtimeDelivery:S,...sharedNativeCloudChat?{sessionNewConversation:sharedNativeCloudChat.sessionNewConversation,nativePrompt:{http:sharedNativeCloudChat.http,inputFiles:new NativeInputFilesHttpClient(o.agentGatewayUrl,()=>sharedRuntimeAuthority.authorityLease,(e,t)=>fetch(e,t)),runBoundary:new MessageServiceConversationRunBoundary({transport:{start:e=>S.startConversationRun(e),finish:e=>S.finishConversationRun(e)}}),host:{resolveNativePromptSessionKey:(e,t)=>p.resolveNativePromptSessionKey(e,t),prepareNativePromptModel:(e,t,r)=>p.prepareNativePromptModel(e,t,r),runtime:e.runtime,pluginConfig:o,logger:e.logger,promptRunStore:h,assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:g,abortTransport:{chatAbort:(e,t)=>p.chatAbort(e,t)},activeRunAuthority:p.getActiveRunAuthority(),waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{})}}}:{}})}:{},commandJournal:A,poisonJournal:new FileRuntimePoisonDeliveryJournal(join(s,"runtime-poison-deliveries.json")),onConsumerDeliveryError:t=>{const r=null!==t&&"object"==typeof t?t:{},o=e=>"string"==typeof e&&e.length>0&&e.length<=256&&!/[\u0000-\u001f\u007f]/.test(e)?JSON.stringify(e):JSON.stringify("unavailable"),a="string"==typeof r.code&&/^[A-Za-z0-9_.:-]{1,64}$/.test(r.code)?r.code:"unavailable",n="number"==typeof r.status&&Number.isInteger(r.status)&&r.status>=100&&r.status<=599?String(r.status):"unavailable";e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: operation_id=${o(r.operationId)} delivery_id=${o(r.deliveryId)} code=${a} status=${n}`)},onConsumerLeaseStarvation:({starvedForMs:t,recovered:r})=>{const o=Math.round(t/1e3);r?e.logger.info?.(`[runtime-service] runtime authority lease restored after ${o}s without delivery reads`):e.logger.warn?.(`[runtime-service] no runtime authority lease for ${o}s; delivery reads suspended, queued runtime operations (model switch, session control) will not be consumed`)},onConsumerRequestFailure:t=>e.logger.error?.(`[runtime-service] request failed operationId=${t.operationId} method=${t.method}: ${t.error instanceof Error?t.error.stack??t.error.message:String(t.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===a.status?a.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===a.status?a.resourceBindingContractRevision:void 0),p.setRuntimeRpcConsumerFactory("ready"===a.status?a.factory:void 0),"unavailable"===a.status?e.logger.warn?.("[runtime-service] capability fenced: "+a.blockers.map(e=>e.id).join(",")):a.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+a.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&agentGateway){const t=Date.now(),r=await agentGateway.bridge.config();if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-t}ms result=${r?.url??"null"}`),r)o.bridge.url=r.url,writeDiscoveryCache({bridge:{url:r.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${r.url}`);else{const t=readDiscoveryCache();t?.bridge?.url?(o.bridge.url=t.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${t.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await d.acquire(O);try{await p.start(o.bridge.url||void 0)}catch(e){throw await d.release(O),e}e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-t}ms)`)},async stop(){try{await d.release(O)}finally{await p.stop()}await A.checkpoint(),e.logger.info?.("[runtime-service] command journal checkpoint completed"),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(y&&void 0!==w&&w){const t=sharedMessageClientOwner.createRegistrationToken(),r=async(e,t)=>{const r=await w(e);if(!r.identityId||r.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:t}},o=(e,t,r)=>({getLocalAgentId:()=>t,resolveLocalAgentId:e=>e===r?t:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,t,r,o)=>{p.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>p.chatAbort(e,t)}),n=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async n=>{await sharedMessageClientOwner.acquire(t,async t=>{const i=await r(n.instanceId,n.runtimeEpoch),s=t.client;APPROVAL_V1_MS_ENABLED&&(sharedApprovalPublisher=async(e,t,r,o)=>{const a=sharedApprovalJournal.read(o.requestId),n=sharedRuntimeAuthority?.authorityLease;if(!a||!n||n.runtimeEpoch!==a.runtimeEpoch||n.instanceId!==i.principalId)throw new Error("approval_runtime_fenced");const l=await s.messages.send({conversationId:r,clientMessageId:t,idempotencyKey:t,type:e,content:{payload:toMessagePart(o),metadata:{delivery_principal:i.principalId,target_agent_id:a.platformAgentId,runtime_epoch:a.runtimeEpoch,owner_identity:a.ownerIdentity}}});if("outcome_unknown"===l.outcome||l.messageId!==t)throw new Error("approval_publication_not_confirmed")});const c={leaseId:n.leaseId,runtimeEpoch:n.runtimeEpoch};sharedMSConnectionStatus.bind(c);const u=new Map,d=new MessageProjectionInboundConsumer({client:s,bindings:()=>{const t=sharedRuntimeAuthority?.authorityLease;if(!t||t.instanceId!==i.principalId||t.runtimeEpoch!==i.runtimeEpoch)return[];const r=sharedAgentMappings.snapshot();return r?[...r.entries()].flatMap(([r,n])=>{if(!n.id||n.instanceId!==i.principalId)return[];let l=u.get(n.id);return l&&l.localAgentId===r||(l={localAgentId:r,inbound:createImInboundHandler({...APPROVAL_V1_MS_ENABLED?{approval:{gate:sharedApprovalGate,policy:sharedApprovalPolicy,runtimeEpoch:i.runtimeEpoch,platformAgentId:n.id,active:()=>{const e=sharedRuntimeAuthority?.authorityLease;return e?.runtimeEpoch===i.runtimeEpoch&&e?.instanceId===i.principalId}}}:{},automationTurnPolicy:sharedAutomationTurnPolicy,runtime:e.runtime,pluginConfig:e.pluginConfig,client:s,localServer:o(i,r,n.id),promptRunStore:h,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:g,logger:e.logger,writeObs:a,principalIdOverride:i.principalId,activeRunAuthority:p.getActiveRunAuthority(),applyTurnModel:(e,t)=>p.applyImTurnModel(e,t),restoreTurnModel:e=>p.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(n.id,l)),[{principalId:i.principalId,targetAgentId:n.id,runtimeEpoch:t.runtimeEpoch,inbound:l.inbound}]}):[]},executionJournal:l,logger:e.logger}),m=sharedAgentMappings.subscribe(()=>{sharedActiveMessageConsumer===d&&d.refresh()}),y=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===d&&d.refresh()})??(()=>{}),v=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==d)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===i.principalId&&e.runtimeEpoch===i.runtimeEpoch&&e.leaseId===n.leaseId&&e.handlerIdentity===n.handlerIdentity},reconnect:async()=>{if("failed"===s.getSnapshot().connection){await s.connect();try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${t instanceof Error?t.message:String(t)}`)}}}});let f=s.getSnapshot().connection;sharedMSConnectionStatus.setIfCurrent(c,f);const w=s.subscribe(()=>{const t=s.getSnapshot();t.connection!==f&&(f=t.connection,sharedMSConnectionStatus.setIfCurrent(c,t.connection),"connected"===t.connection?(v.notifyConnected(),e.logger.info?.(`[beeos-claw] connection transport=message_service_realtime state=connected localAgentId=${p.getLocalAgentId()} principalId=${i.principalId}`)):"failed"===t.connection?(e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=failed principalId=${i.principalId} recoveryError=${t.recoveryError??"unknown"}`),v.notifyFailed()):"disconnected"!==t.connection&&"reconnecting"!==t.connection||e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=${t.connection} principalId=${i.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=d,d.start();try{await s.connect()}catch(e){throw sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(c),v.dispose(),await d.stop(),m(),y(),w(),await s.disconnect().catch(()=>{}),e}try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${t instanceof Error?t.message:String(t)}`)}return async()=>{sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(c),v.dispose(),await d.stop(),y(),w(),await s.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(t)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){n?n.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(n?.stop())}})}else y?e.logger.warn?.("[beeos-claw] Message bus enabled but Agent Gateway token provider is unavailable — disabled"):e.logger.info?.(`[beeos-claw] Message bus disabled (enabled=${y})`);if(o.messageBus.enabled&&c&&!sharedNativeCloudChat&&e.logger.warn?.("[beeos-claw] Cloud message bus enabled but native composition unavailable (messageBus.serviceUrl or runtime authority missing) — disabled"),!1!==f&&agentGateway){const t=e=>p.getGatewaySessionKeyForToolCall(e),r=e=>p.getMentionsForToolCall(e),o=(e,t)=>{p.broadcastNotification(e,t)},a=new TaskHandleRegistry;registerA2ATools(e,{gateway:agentGateway,logger:e.logger},a,t,r,o,()=>m()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(agentGateway&&(registerAutomationTools(e,{gateway:agentGateway,logger:e.logger,getDefaultAgent:()=>{const e=m();return e?{id:e.id,instanceId:e.instanceId}:void 0},getCurrentConversationId:e=>{const t=p.getGatewaySessionKeyForToolCall(e);return t?extractBeeosConversationIdFromSessionKey(t):void 0}}),e.logger.info?.("[beeos-claw] Automation tools registered (create/create_webhook/capabilities/preflight/list/get/run/runs/get_run)")),o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const t=sharedCanvasState;if(agentGateway&&agentKeys){t.setLogger(e.logger);const r=()=>agentGateway.canvas.token(),a=a=>{const n=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,agentId:a.id,displayName:a.displayName,avatarUrl:a.avatarUrl,tokenProvider:r,onConnected:()=>p.flushPendingCanvasLinks(),onReconnect:()=>p.onRelayReconnected(),logger:e.logger});t.setRelayClient(n),t.setAgentId(a.id),p.wireRelayActionHandler(),n.connect(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${a.id}, name=${a.name??"none"})`)};e.registerService(createCanvasRelayService({getAgent:m,onceAgentReady:e=>sharedAgentMappings.onceReady(e),initRelay:a,stopRelay:()=>t.getRelayClient()?.disconnect(),logger:e.logger})),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const r={stateManager:t,logger:e.logger,writeObs:e=>a(e),getActiveSessionId:e=>p.getSessionIdForToolCall(e),getPlatformAgentId:e=>p.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>p.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>sharedAgentMappings.waitForSynchronization(),publishStaticHtml:createStaticCanvasHtmlPublisher(pluginCloudRuntimeTarget(e)?o.agentGatewayUrl:void 0)},i=new FormSchemaRegistry,s=buildCronSchemas(n);i.register(s.create),i.register(s.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(t,r,o)=>(p.preMapToolCallSession(t),e(t,r));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiToolExecutor(r))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(r))}),p.setCanvasState(t,{schemaRegistry:i,descriptorRegistry:l});const u=p.getFormBuilder();u&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(i),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:i,builder:u,logger:e.logger}))});const d=p.getResourceRenderer();if(d){generateActionTools(l,e,async(e,t)=>p.gatewayRequest(e,t),d,e.logger)}const g=buildToolRoutingHint(BEEOS_FILE_RESOURCE_ROUTING_RULE,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME),h=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,v=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,t)=>{if(t?.sessionKey){if(v.size>=y&&!v.has(t.sessionKey)){const e=v.keys().next().value;void 0!==e&&v.delete(e)}v.set(t.sessionKey,t.channelId),rememberDeliveryWorkspace(t.sessionKey,t.workspaceDir)}const r=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:t?.channelId});return t?.sessionKey||r?{appendSystemContext:buildAppendSystemContext({thirdParty:r,canvasSystemPrompt:`${CANVAS_PRESENTATION_GATE}\n\n${CANVAS_SYSTEM_PROMPT}`,toolRoutingHint:g})}:{appendSystemContext:g}}),e.logger.debug?.("[beeos-claw] Canvas system prompt hook registered: before_prompt_build")}catch{e.logger.debug?.("[beeos-claw] before_prompt_build hook not supported")}try{e.on("before_tool_call",(e,t)=>{if(t?.sessionKey&&p.setPendingToolCallSessionKey(t.sessionKey),!h.has(e.toolName))return;const r=t?.sessionKey?v.get(t.sessionKey):void 0,o=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:r}),a=canvasToolBlockReason({thirdParty:o,hasSession:Boolean(t?.sessionKey)});return a?{block:!0,blockReason:a}:void 0}),e.logger.debug?.("[beeos-claw] Canvas tool guard registered: before_tool_call")}catch{e.logger.debug?.("[beeos-claw] before_tool_call hook not supported")}}e.logger.info?.("[beeos-claw] Canvas tools registered (render_ui, close_ui, render_form + auto-action tools)")}else e.logger.info?.("[beeos-claw] Canvas disabled by config (canvasEnabled=false)");if(o.bridge.shell.enabled&&!0===o.legacyTerminalWsEnabled){const t=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:a});e.registerService({id:"beeos-terminal-ws",start(){t.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){t.stop(),e.logger.info?.("[beeos-claw] Terminal WS stopped")}})}else o.bridge.shell.enabled?e.logger.info?.("[beeos-claw] Legacy static-token Terminal WS disabled (default)"):e.logger.info?.("[beeos-claw] Terminal/shell disabled by config (bridge.shell.enabled=false)");if(t.openclawConfig){const r=mirrorOpenClawConfig(t.openclawConfig);r.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${r.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${r.reason}`)}}function pluginCloudRuntimeTarget(e){const t=e.pluginConfig?.cloudRuntimeInstanceId;return cloudRuntimeTargetInstanceId("string"==typeof t?t:void 0)}function attachNativeCloudChat(e,t){if(sharedNativeChatService)return e.registerService(sharedNativeChatService),sharedNativeCloudChat;const r=sharedRuntimeAuthority,o=t.messageBus.serviceUrl,a=sharedAcpServer,n=sharedSessionMutationCoordinator;if(!(r&&r.cloudTargetInstanceId&&o&&a&&n))return sharedNativeCloudChat;const i=sharedNativeCloudChat??createNativeCloudChatComposition({authority:nativeCloudChatAuthorityFromRuntimeAuthority(r),serviceUrl:o,logger:e.logger});if(sharedNativeCloudChat=i,!t.messageBus.enabled)return i;const s=i,l=r;let c;const u=new Map,d=new RuntimeAuthorityMessageBusLifecycle({authority:l,logger:e.logger,bus:{connect:async t=>{c?.(),u.clear(),c=s.adapter.listen({eventTypes:["message.created"]},r=>{const o=(r.content??{}).metadata??{},i="string"==typeof o.target_agent_id?o.target_agent_id:"",l=i?((t,r)=>{const o=sharedAgentMappings.snapshot();if(o)for(const[i,l]of o.entries()){if(l.id!==r)continue;if(l.instanceId!==t.instanceId)continue;const o=`${i}\0${l.id}`;let c=u.get(o);return c||(c={localAgentId:i,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:s.adapter,localServer:{getLocalAgentId:()=>i,resolveLocalAgentId:e=>e===l.id?i:void 0,getDefaultPlatformAgent:()=>({instanceId:t.instanceId}),ensureImInboundSession:(e,t,r,o)=>{a.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>a.chatAbort(e,t)},promptRunStore:sharedPromptRunStore,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:n,logger:e.logger,writeObs:sharedWriteObs,principalIdOverride:t.instanceId,activeRunAuthority:a.getActiveRunAuthority(),applyTurnModel:(e,t)=>a.applyImTurnModel(e,t),restoreTurnModel:e=>a.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(o,c)),c}})(t,i):void 0;if(!l)return void e.logger.warn?.(`[beeos-claw] native cloud chat dropped unresolvable target_agent_id=${i||"missing"} message_id=${r.id}`);("chat_cancel"===r.type?l.inbound.onChatCancel(r):l.inbound.onChatMessage(r)).catch(t=>{e.logger.error?.(`[beeos-claw] native cloud chat dispatch failed message_id=${r.id}: ${t instanceof Error?t.message:String(t)}`)})});try{await s.adapter.connect()}catch(e){throw c?.(),c=void 0,e}},disconnect:async()=>{c?.(),c=void 0,u.clear(),await s.adapter.disconnect()}}});return sharedNativeChatService={id:"beeos-native-cloud-chat",async start(){d.start()},async stop(){await d.stop()}},e.registerService(sharedNativeChatService),e.logger.info?.("[beeos-claw] native Cloud personal-chat composition registered"),i}const plugin={id:"beeos-claw",name:"beeos-claw",description:"BeeOS platform bridge plugin for OpenClaw. Provides file upload/download, ACP bridge, and observability.",version:PLUGIN_VERSION,register(e){if(_initializing)return;const t=pluginCloudRuntimeTarget(e),r=void 0!==t&&t!==sharedRuntimeAuthority?.cloudTargetInstanceId,o=planPluginRegistration(e.registrationMode,_fullRuntimeRegistered,r);if("skip"!==o){_initializing=!0;try{if(!hasRuntimeReplyApi(e.runtime))throw e.logger.error?.("[beeos-claw] FATAL: OpenClaw runtime.channel.reply.dispatchReplyFromConfig not exposed. Upgrade OpenClaw or revert beeos-claw."),new Error("openclaw_runtime_reply_api_unavailable");const t=(t,r)=>{registerUploadTools(e,t,r),registerConnectorMcpProxy(e,t),registerManagedConnectorTools(e,agentGateway),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)};if("capabilities"===o&&sharedPluginContext){if(cachedCapabilityTools.length>0){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool}),r=replayCachedPluginTools(r=>t.call(e,r),cachedCapabilityTools);return registerArouterLatencyRouting(e),registerArouterMediaProviders(e),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} tools_only count=${r}`)}const r={current:sharedAcpServer??null};return t(sharedPluginContext,r),registerServices(e,sharedPluginContext,r),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} capabilities_only`)}const r=initializePlugin(e);if(!r)return;const a={current:null};installUnhandledRejectionObserver(e,r.writeObs,a),ensureRegisterToolCache(e),cacheRuntimeRegistrations(e),cachedCapabilityTools.length=0,t(r,a),agentGateway&&(e.on?e.on("before_agent_finalize",fileDeliveryFinalizeDecision):e.logger.warn?.("[file-delivery] OpenClaw plugin hooks unavailable; finalization check disabled")),registerServices(e,r,a),sharedPluginContext=r,marksFullRuntimeRegistered(e.registrationMode,o)&&(_fullRuntimeRegistered=!0),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else if(!e.registrationMode||"full"===e.registrationMode){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool});replayCachedPluginTools(r=>t.call(e,r),cachedCapabilityTools),replayRuntimeRegistrations(e),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)}}};export default plugin;
1
+ import{harnessConnectorToolCaller}from"./connectors/harness-connector-mcp.js";import{consumeNativeOutputTool}from"./runtime/native-output-file-attempt.js";import{uploadNativeOutputFile}from"./upload/upload-file.js";import{nativeOutputToolCallGate}from"./upload/native-output-tool-hook.js";import{NativeInputFilesHttpClient}from"./runtime/native-input-files-http.js";import{fileDeliveryFinalizeDecision}from"./upload/finalize-hook.js";import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.js";import{createMcpNativeProjectionNudge,fingerprintMcpServers}from"./acp-gateway/mcp-native-projection-nudge.js";import{createImHotPathDeferral}from"./runtime/im-hot-path-deferral.js";import{SessionWriteGate}from"./acp-gateway/session-write-gate.js";import{OpenClawSessionWriteQuiescence}from"./runtime/openclaw-session-write-quiescence.js";import{SessionMutationCoordinator}from"./runtime/session-mutation-coordinator.js";import{scheduleProcessRuntimeRestart}from"./runtime/runtime-restart-scheduler.js";import{createImInboundHandler}from"./im-inbound-handler.js";import{AgentGatewayClient,NodeRuntimeDeliveryPort,agentIdentityFromKeyPair,loadAgentKeyPair,signAgentMessage}from"@beeos-ai/cloud-harness-sdk";import{MessageServiceConversationRunBoundary}from"./runtime/message-service-conversation-run-boundary.js";import{AutomationTurnPolicy}from"./automation/turn-policy.js";import{ApprovalGate}from"./approval/gate.js";import{FileApprovalJournal}from"./approval/journal.js";import{ApprovalTurnPolicy}from"./approval/turn-policy.js";import{toMessagePart}from"./message-client-types.js";import{registerAutomationTools}from"./automation/tools.js";import{extractBeeosConversationIdFromSessionKey}from"./runtime/openclaw-session-key-resolution.js";import{setOpenClawConfigSnapshot}from"./runtime/openclaw-session-model.js";import{BeeosClawMessageClientProcessOwner,createBeeosClawMessageTokenProvider}from"./message-client-composition.js";import{MessageProjectionInboundConsumer}from"./message-projection-inbound-consumer.js";import{MessageClientTerminalStateRecovery}from"./runtime/message-client-terminal-state-recovery.js";import{RuntimeAuthorityMessageBusLifecycle}from"./runtime/runtime-authority-message-bus-lifecycle.js";import{createNativeCloudChatComposition,nativeCloudChatAuthorityFromRuntimeAuthority}from"./runtime/native-cloud-chat-composition.js";import{MSConnectionStatusSnapshot}from"./runtime/ms-connection-status.js";import{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{completeA2ATask,registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,REQUEST_TIMEOUT_MS as BEEOS_UPLOAD_REQUEST_TIMEOUT_MS,executeUpload}from"./upload/tool.js";import{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,executeDesktopScreenshot}from"./upload/desktop-screenshot-tool.js";import{BEEOS_LIST_FILES_TOOL_NAME,BEEOS_LIST_FILES_TOOL_SCHEMA,BEEOS_LIST_FILES_TOOL_DESCRIPTION,executeListFiles}from"./files/list-tool.js";import{BEEOS_FETCH_FILE_TOOL_NAME,BEEOS_FETCH_FILE_TOOL_SCHEMA,BEEOS_FETCH_FILE_TOOL_DESCRIPTION,executeFetchFile}from"./files/fetch-tool.js";import{writeUploadToolResult,cleanupUploadToolResultCache}from"./upload/result-cache.js";import{handleFileStage}from"./upload/file-stage.js";import{handleStatusRequest}from"./status.js";import{ACPServer}from"./acp-server.js";import{GatewayClient}from"./gateway-client.js";import{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{setClaimedCloudRuntimeInstanceId,setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{deliverableFileExtractor}from"./upload/deliverable-extractor.js";import{observeToolCallForDelivery,rememberDeliveryWorkspace}from"./upload/delivery-observe.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{marksFullRuntimeRegistered,planPluginRegistration,replayCachedPluginTools,resolveCapabilityToolReplay}from"./plugin-registration-plan.js";import{buildAppendSystemContext,buildToolRoutingHint,canvasToolBlockReason}from"./prompt-system-context.js";import{CanvasStateManager}from"./canvas/state.js";import{createStaticCanvasHtmlPublisher}from"./canvas/static-html.js";import{CanvasRelayClient}from"./canvas/relay-client.js";import{createCanvasRelayService}from"./canvas/relay-service.js";import{RENDER_UI_TOOL_NAME,RENDER_UI_TOOL_DESCRIPTION,RENDER_UI_TOOL_SCHEMA,CLOSE_UI_TOOL_NAME,CLOSE_UI_TOOL_DESCRIPTION,CLOSE_UI_TOOL_SCHEMA,createRenderUiToolExecutor,createCloseUiHandler,CANVAS_PRESENTATION_GATE,CANVAS_SYSTEM_PROMPT}from"./canvas/tools.js";import{FormSchemaRegistry}from"./surface/form-schema-registry.js";import{buildCronSchemas}from"./surface/cron-schemas.js";import{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./surface/render-form-tool.js";import{ResourceDescriptorRegistry}from"./surface/resource-descriptor-registry.js";import{CRON_RESOURCE}from"./surface/cron-resource.js";import{generateActionTools}from"./surface/action-tool-generator.js";import{buildThirdPartyChannelSet,isThirdPartyChannel}from"./channel-detection.js";import{registerArouterMediaProviders}from"./media/index.js";import{homedir}from"node:os";import{join}from"node:path";import{RuntimeProductionAuthority,cloudRuntimeTargetInstanceId}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{OpenClawNativeMcpProjection}from"./acp-gateway/openclaw-native-mcp-projection.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,CloudRuntimeServiceTransportReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";import{fetchRuntimeLeaseAttempt}from"./runtime/message-service-runtime-authenticated-fetch.js";import{MessageServiceCronDeliveryHttpAuthority}from"./runtime/message-service-cron-delivery-http-authority.js";import{AgentMappingRegistry}from"./runtime/agent-mapping-registry.js";import{OpenClawRuntimeProcessOwner}from"./runtime/openclaw-runtime-process-owner.js";import{AgentGatewayHttpProjectionTransport,AgentGatewayTemplateOriginReporter,AgentProjectionProduction,OpenClawAgentProjectionSource}from"./runtime/agent-projection-production.js";import{MessageServiceRunOutputChannel}from"./runtime/message-service-run-output-channel.js";import{AssistantMessageCommitRouter}from"./runtime/assistant-message-commit-router.js";import{ToolResultObservationRouter}from"./runtime/tool-result-observation-router.js";import{ModelCallObservationRouter,registerModelCallObservationHooks}from"./runtime/model-call-observability.js";import{registerArouterLatencyRouting}from"./runtime/arouter-latency-routing.js";import{createPeerRunOutputRouterFactory}from"./runtime/run-output-composition.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,agentGateway=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore,sharedAutomationTurnPolicy=new AutomationTurnPolicy,APPROVAL_V1_MS_ENABLED="1"===process.env.BEEOS_APPROVAL_V1_MS;let sharedApprovalJournal,sharedApprovalGate,sharedApprovalPolicy,sharedApprovalPublisher,lastOpenclawConfig;const sharedMcpNativeProjectionNudge=createMcpNativeProjectionNudge({getActiveImRunCount:()=>sharedPromptRunStore.size(),nudge:()=>{sharedAcpServer?.nudgeMcpNativeProjection()}}),sharedImHotPathDeferral=createImHotPathDeferral({getActiveImRunCount:()=>sharedPromptRunStore.size()});sharedPromptRunStore.setOnBecameIdle(()=>{sharedMcpNativeProjectionNudge.flushIfIdle({fingerprint:fingerprintMcpServers(lastOpenclawConfig)}),sharedImHotPathDeferral.notifyIdle()});const sharedAssistantMessageCommitRouter=new AssistantMessageCommitRouter,sharedToolResultObservationRouter=new ToolResultObservationRouter,sharedModelCallObservationRouter=new ModelCallObservationRouter;let sharedSessionMutationCoordinator,sharedRuntimeAuthority,sharedNativeChatService,sharedNativeCloudChat,sharedWriteObs=()=>{};const sharedMSConnectionStatus=new MSConnectionStatusSnapshot,sharedAgentMappings=new AgentMappingRegistry;let sharedGatewayClient,sharedRuntimeOwner,sharedAgentProjection,sharedRuntimeAgentCapabilities,sharedMcpProjection,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0,_fullRuntimeRegistered=!1;const cachedCapabilityTools=[];let rawRegisterTool,wrappedRegisterTool;const cachedRuntimeServices=[],cachedRuntimeHooks=[];let rawRegisterService,wrappedRegisterService,rawOn,wrappedOn;function cacheRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService;if(rawRegisterService=t,wrappedRegisterService=r=>{cachedRuntimeServices.push(r),t.call(e,r)},e.registerService=wrappedRegisterService,cachedRuntimeServices.length=0,cachedRuntimeHooks.length=0,e.on){const t=e.on===wrappedOn?rawOn:e.on;rawOn=t,wrappedOn=(...r)=>{cachedRuntimeHooks.push(r),t.call(e,...r)},e.on=wrappedOn}}function replayRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService,r=e.on===wrappedOn?rawOn:e.on;for(const t of cachedRuntimeHooks)r.call(e,...t);for(const r of cachedRuntimeServices)t.call(e,r)}const ensureRegisterToolCache=e=>{const t=e.registerTool===wrappedRegisterTool?rawRegisterTool:e.registerTool;rawRegisterTool=t.bind(e),wrappedRegisterTool=e=>(cachedCapabilityTools.push(e),rawRegisterTool(e)),e.registerTool=wrappedRegisterTool};function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async t=>signAgentMessage(t,e.privateKey)}}let sharedPluginContext=null,unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,t,r){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",r=>{const o=r instanceof Error?r.message:String(r),a=r instanceof Error?r.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${a?`\n${a}`:""}`),t({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...a?{stack:a}:{}}})}),process.on("uncaughtException",r=>{const o=r instanceof Error?r.message:String(r);e.logger.error?.(`[beeos-claw] uncaughtException: ${r instanceof Error?r.stack??r.message:String(r)}`),t({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let t,r;try{t=e.runtime?.config?.loadConfig?.()}catch{}try{r=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:t})}catch(t){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${t instanceof Error?t.message:String(t)}`),null}const o=r.config,a=buildThirdPartyChannelSet(t);a.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...a].join(", ")}`);const n=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};n({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),n({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:r.sources,openclawConfigPath:r.openclawConfigPath}});for(const t of r.validation)n({component:"plugin",domain:"config",name:"config.validation",severity:t.severity,summary:t.message,error:{code:t.code,message:t.message,nextSteps:t.nextSteps}}),"error"===t.severity?e.logger.error?.(`[beeos-claw] ${t.message}`):e.logger.warn?.(`[beeos-claw] ${t.message}`);if(r.validation.some(e=>"error"===e.severity)&&e.logger.error?.("[beeos-claw] Plugin has configuration errors — some features may not work."),o.keyFile)try{agentKeys=loadAgentKeyPair(o.keyFile),agentGateway=o.agentGatewayUrl?new AgentGatewayClient({baseUrl:o.agentGatewayUrl,identity:agentIdentityFromKeyPair(agentKeys),onRetry:({method:t,path:r,attempt:o,delayMs:a,error:n})=>e.logger.warn?.(`[beeos-claw] Agent Gateway ${t} ${r} retry ${o} in ${a}ms: ${n instanceof Error?n.message:String(n)}`)}):null;const t=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${t})`)}catch(t){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${t}`),e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no key pair — signed requests disabled)`)}else e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no keyFile configured)`);return agentGateway&&(setUploadDeps({gateway:agentGateway,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),registerLocalFileExtractor(deliverableFileExtractor),e.logger.info?.("[beeos-claw] Upload deps + local file extractors registered")),lastOpenclawConfig=t,sharedWriteObs=n,setOpenClawConfigSnapshot(t),{cfg:o,writeObs:n,thirdPartyChannels:a,openclawConfig:t}}function registerUploadTools(e,t,r){const{cfg:o,writeObs:a}=t,n=Boolean(pluginCloudRuntimeTarget(e));if(n){if(!e.on)throw new Error("native output Files Host hook unavailable");e.on("before_tool_call",nativeOutputToolCallGate)}cleanupUploadToolResultCache().catch(t=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(t)}`)}),e.registerTool({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(t,r,i){const s=n?consumeNativeOutputTool(t):void 0,l=await executeUpload(r,agentGateway,i,s?(e,t)=>uploadNativeOutputFile(e,o.agentGatewayUrl,s,t,i,BEEOS_UPLOAD_REQUEST_TIMEOUT_MS):void 0,e.logger);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${t} ok=${l.ok}`),a({component:"upload-tool",domain:"tool",name:l.ok?"upload.success":"upload.failure",severity:l.ok?"info":"warn",payload:{toolCallId:t,ok:l.ok,fileCount:l.files?.length??0,error:l.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_UPLOAD_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_upload_file] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(l)}}),e.registerTool({name:BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,parameters:BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeDesktopScreenshot(r,agentGateway,o);return e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} ok=${n.ok}`),a({component:"desktop-screenshot-tool",domain:"tool",name:n.ok?"desktop_screenshot.success":"desktop_screenshot.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,fileCount:n.files?.length??0,error:n.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_desktop_screenshot] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(n)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,r){await handleFileStage(e,r,t.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,t){handleStatusRequest(e,t,{publicKey:agentKeys?.publicKey??null,pluginVersion:PLUGIN_VERSION})}}),e.registerTool({name:BEEOS_LIST_FILES_TOOL_NAME,description:BEEOS_LIST_FILES_TOOL_DESCRIPTION,parameters:BEEOS_LIST_FILES_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_list_files] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeListFiles(r,agentGateway,o);return a({component:"file-list-tool",domain:"tool",name:n.ok?"list_files.success":"list_files.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,fileCount:n.files?.length??0,error:n.error}}),n}}),e.registerTool({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeFetchFile(r,agentGateway,{signal:o,resolvePath:e.resolvePath});return a({component:"file-fetch-tool",domain:"tool",name:n.ok?"fetch_file.success":"fetch_file.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,size:n.size,error:n.error}}),n}})}function registerServices(e,t,r){const{cfg:o,writeObs:a,thirdPartyChannels:n}=t;if(sharedAutomationTurnPolicy.disable(),"function"==typeof e.on)try{e.on("before_tool_call",(e,t)=>sharedAutomationTurnPolicy.check(e.toolName,{sessionKey:t?.sessionKey,runId:t?.runId??e.runId}),{priority:100}),sharedAutomationTurnPolicy.enable()}catch{e.logger.warn?.("[beeos-claw] Automation Wake disabled: tool guard unavailable")}if("function"!=typeof e.on){if(o.messageBus.enabled)throw new Error("openclaw_before_message_write_hook_unavailable")}else registerModelCallObservationHooks((t,r)=>e.on(t,r),sharedModelCallObservationRouter),e.on("before_message_write",(t,r)=>{const o=t.sessionKey??r.sessionKey;if(!o)return void e.logger.debug?.("[before_message_write] ignored assistant write without sessionKey");sharedAssistantMessageCommitRouter.route(o,t.message)||e.logger.debug?.(`[before_message_write] no active IM commit target sessionKey=${o} active_targets=${sharedAssistantMessageCommitRouter.size()}`)}),e.on("after_tool_call",(t,r)=>{const o=r.sessionKey,a=t.toolCallId??r.toolCallId,n=t.toolName||r.toolName;if(!o||!a||!n)return void e.logger.debug?.(`[after_tool_call] ignored structured result without correlation sessionKey=${o??"missing"} toolCallId=${a??"missing"}`);observeToolCallForDelivery(t,o);sharedToolResultObservationRouter.route(o,{toolCallId:a,toolName:n,rawResult:t.result,isError:Boolean(t.error)})||e.logger.debug?.(`[after_tool_call] no active IM observation target sessionKey=${o} active_targets=${sharedToolResultObservationRouter.size()}`)});const i=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,s=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos");if(APPROVAL_V1_MS_ENABLED){if(!e.registerTrustedToolPolicy||!e.on)throw new Error("openclaw_trusted_approval_policy_unavailable");sharedApprovalJournal??=new FileApprovalJournal(join(s,"approval-v1")),sharedApprovalGate??=new ApprovalGate(sharedApprovalJournal,async(...e)=>{if(!sharedApprovalPublisher)throw new Error("approval_message_transport_unavailable");await sharedApprovalPublisher(...e)}),sharedApprovalPolicy??=new ApprovalTurnPolicy(sharedApprovalGate,[o.gateway.token].filter(Boolean));const t=e=>sharedApprovalPolicy.isManaged(e)||Boolean(e.sessionKey&&extractBeeosConversationIdFromSessionKey(e.sessionKey));e.registerTrustedToolPolicy({id:"beeos-approval-v1",description:"One-shot BeeOS MS execution approvals",evaluate:async(e,r)=>t(r)?sharedApprovalPolicy.evaluate(e,r):void 0}),e.on("before_tool_call",(e,r)=>t(r)?sharedApprovalPolicy.finalize(e,r):void 0,{priority:Number.MIN_SAFE_INTEGER})}const l=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(s,"inbound-execution-journal.v1.jsonl"));sharedMcpProjection??=new OpenClawNativeMcpProjection,!sharedMcpCredentialVault&&agentKeys&&i&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(s,"mcp-credential-vault.json"),i,agentKeys.privateKey));const c=pluginCloudRuntimeTarget(e);if(setClaimedCloudRuntimeInstanceId(c),c&&(!agentKeys||!agentGateway))throw new Error("Cloud runtime authority requires an agent identity and gateway transport");const u=sharedRuntimeAuthority?.cloudTargetInstanceId;if(u&&c&&u!==c)throw new Error("Cloud runtime authority target changed during process lifetime");if(sharedRuntimeAuthority&&!u&&c&&sharedRuntimeAuthority.bindCloudTarget(c),!sharedRuntimeAuthority&&agentKeys&&agentGateway&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:s,gateway:agentGateway,keys:agentKeys,targetInstanceId:c,logger:e.logger,getMSConnectionStatus:e=>sharedMSConnectionStatus.get(e)})),sharedGatewayClient??=new GatewayClient({url:o.gateway.url,token:o.gateway.token||"",clientId:o.gateway.clientId,openclawCanvasCompat:!!o.openclawCanvasCompat,retry:{baseMs:o.retry.baseMs,maxMs:o.retry.maxMs,maxAttempts:o.retry.maxAttempts}}),sharedRuntimeAgentCapabilities??={canvas:o.canvasEnabled,terminal:!1,webSsh:!1,fileSystem:!0,image:!0,audio:!1,mcp:!0,cron:!0,streaming:!0,pushNotifications:o.messageBus.enabled,...o.messageBus.enabled&&sharedAutomationTurnPolicy.isReady()&&agentGateway?{automationWake:!0}:{}},!sharedAgentProjection&&sharedRuntimeAuthority&&agentGateway){const t=sharedRuntimeAuthority;sharedAgentProjection=new AgentProjectionProduction({authority:t,stateFile:join(t.stateDirectory,"runtime-agent-projection.json"),journal:t.journal,identities:t.identities,source:new OpenClawAgentProjectionSource(()=>sharedGatewayClient),transport:new AgentGatewayHttpProjectionTransport({gateway:agentGateway,getRuntimeLeaseCredential:e=>{const r=t.authorityLease;if(!r||r.instanceId!==e.instanceId||r.leaseId!==e.leaseId||r.runtimeEpoch!==e.runtimeEpoch||r.handlerIdentity!==e.handlerIdentity)throw new Error("agent projection fenced by current runtime lease");return r.runtimeLeaseCredential},onAccepted:t=>{0!==t.size&&sharedAgentMappings.replace(t).catch(t=>{e.logger.warn?.("[agent-projection] mapping publication failed: "+(t instanceof Error?t.message:String(t)))})}}),capabilities:sharedRuntimeAgentCapabilities,logger:e.logger})}sharedRuntimeOwner??=new OpenClawRuntimeProcessOwner(sharedGatewayClient,sharedAgentProjection,e.logger);const d=sharedRuntimeOwner;sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main"}),e.logger,{onRecoveryRequired:t=>{scheduleProcessRuntimeRestart(t,e.logger)}});const g=sharedSessionMutationCoordinator;if(!sharedAcpServer){const t=sharedRuntimeAuthority&&agentGateway?new AgentGatewayTemplateOriginReporter({gateway:agentGateway}):void 0;sharedAcpServer=new ACPServer(o,e.logger,g,a,agentGateway??void 0,i,n,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpProjection,sharedMcpCredentialVault,{gateway:d.client,agentProjection:sharedAgentProjection,markAgentProjectionDirty:()=>sharedAgentProjection?.markDirty(),templateOriginReporter:t,agentMappings:sharedAgentMappings,agentCapabilities:sharedRuntimeAgentCapabilities,createRunOutputRouter:createPeerRunOutputRouterFactory(new MessageServiceRunOutputChannel({getClient:()=>sharedMessageClientOwner.current?.client??null,logger:e.logger,writeObs:a})),runExclusive:(t,r,o)=>sharedImHotPathDeferral.runExclusive(t,r,e.logger,o)})}const p=sharedAcpServer,m=()=>sharedAgentMappings.snapshot()?.values().next().value;r.current=p,sharedMcpNativeProjectionNudge.request({registrationMode:e.registrationMode,fingerprint:fingerprintMcpServers(t.openclawConfig),logger:e.logger});const h=sharedPromptRunStore,{enabled:y,principalId:v,a2aEnabled:f}=o.messageBus;let w;!c&&o.agentGatewayUrl&&agentKeys&&(w=createBeeosClawMessageTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const R=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),C=v||process.env.BEEOS_PRINCIPAL_ID||"",b=w?sharedMessageClientOwner.configure({tokenProvider:w,identityId:C,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&R?{runtimeDelivery:{scopedDeliveryKey:R,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null}}}}:{}}):void 0,S=c&&o.messageBus.serviceUrl&&sharedRuntimeAuthority?new NodeRuntimeDeliveryPort({serviceOrigin:async()=>o.messageBus.serviceUrl},{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t&&e.instanceId===c?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null},subscribeAuthority:e=>sharedRuntimeAuthority.subscribeAuthority(e)}):void 0;attachNativeCloudChat(e,o);const _=sharedRuntimeAuthority,E=o.messageBus.serviceUrl;b&&_&&E&&R?p.setCronConversationDelivery({deliver:async e=>{const t=_.authorityLease;if(!t)throw new Error("current runtime authority lease unavailable for cron delivery");const r=new MessageServiceCronDeliveryHttpAuthority({messageServiceUrl:E,scopedDeliveryKey:R,fetchAuthorized:(e,t)=>fetchRuntimeLeaseAttempt(e,t??{})});return await r.deliver({...e,runtimeLeaseCredential:t.runtimeLeaseCredential})}}):p.setCronConversationDelivery(void 0);const A=sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(s,"runtime-command-journal.json"),void 0,void 0,{onMaintenanceError:t=>e.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=threshold error=${t instanceof Error?t.message:String(t)}`)}),O=d.createRegistrationToken();e.registerService({id:"beeos-acp",async start(){const t=Date.now(),r=_pluginRegisteredAt?t-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${r}ms, bridge.url=${o.bridge.url||"(empty)"}`);const a=await createRuntimeServiceProductionCandidate({...agentGateway?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({gateway:agentGateway})}:{},onGrantJwksWarm:t=>{t.ready?e.logger.info?.("[beeos-claw] Gateway grant keyset loaded"):e.logger.warn?.(`[beeos-claw] Gateway grant keyset not ready yet (attempt ${t.attempt}): ${t.error instanceof Error?t.error.message:String(t.error)}`)},...b&&agentGateway&&R?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({gateway:agentGateway,messageService:b.nodeTransport,messageClient:b.client,configuredServiceUrl:o.messageBus.serviceUrl,scopedDeliveryKey:R})}:{},...S&&agentGateway&&o.messageBus.serviceUrl?{cloudTransportAdapter:new CloudRuntimeServiceTransportReadinessAdapter({gateway:agentGateway,configuredServiceUrl:o.messageBus.serviceUrl,runtimeDelivery:S,...sharedNativeCloudChat?{sessionNewConversation:sharedNativeCloudChat.sessionNewConversation,nativePrompt:{http:sharedNativeCloudChat.http,inputFiles:new NativeInputFilesHttpClient(o.agentGatewayUrl,()=>sharedRuntimeAuthority.authorityLease,(e,t)=>fetch(e,t)),runBoundary:new MessageServiceConversationRunBoundary({transport:{start:e=>S.startConversationRun(e),finish:e=>S.finishConversationRun(e)}}),host:{resolveNativePromptSessionKey:(e,t)=>p.resolveNativePromptSessionKey(e,t),prepareNativePromptModel:(e,t,r)=>p.prepareNativePromptModel(e,t,r),runtime:e.runtime,pluginConfig:o,logger:e.logger,promptRunStore:h,assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:g,abortTransport:{chatAbort:(e,t)=>p.chatAbort(e,t)},activeRunAuthority:p.getActiveRunAuthority(),waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{})}}}:{}})}:{},commandJournal:A,poisonJournal:new FileRuntimePoisonDeliveryJournal(join(s,"runtime-poison-deliveries.json")),onConsumerDeliveryError:t=>{const r=null!==t&&"object"==typeof t?t:{},o=e=>"string"==typeof e&&e.length>0&&e.length<=256&&!/[\u0000-\u001f\u007f]/.test(e)?JSON.stringify(e):JSON.stringify("unavailable"),a="string"==typeof r.code&&/^[A-Za-z0-9_.:-]{1,64}$/.test(r.code)?r.code:"unavailable",n="number"==typeof r.status&&Number.isInteger(r.status)&&r.status>=100&&r.status<=599?String(r.status):"unavailable";e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: operation_id=${o(r.operationId)} delivery_id=${o(r.deliveryId)} code=${a} status=${n}`)},onConsumerLeaseStarvation:({starvedForMs:t,recovered:r})=>{const o=Math.round(t/1e3);r?e.logger.info?.(`[runtime-service] runtime authority lease restored after ${o}s without delivery reads`):e.logger.warn?.(`[runtime-service] no runtime authority lease for ${o}s; delivery reads suspended, queued runtime operations (model switch, session control) will not be consumed`)},onConsumerRequestFailure:t=>e.logger.error?.(`[runtime-service] request failed operationId=${t.operationId} method=${t.method}: ${t.error instanceof Error?t.error.stack??t.error.message:String(t.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===a.status?a.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===a.status?a.resourceBindingContractRevision:void 0),p.setRuntimeRpcConsumerFactory("ready"===a.status?a.factory:void 0),"unavailable"===a.status?e.logger.warn?.("[runtime-service] capability fenced: "+a.blockers.map(e=>e.id).join(",")):a.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+a.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&agentGateway){const t=Date.now(),r=await agentGateway.bridge.config();if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-t}ms result=${r?.url??"null"}`),r)o.bridge.url=r.url,writeDiscoveryCache({bridge:{url:r.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${r.url}`);else{const t=readDiscoveryCache();t?.bridge?.url?(o.bridge.url=t.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${t.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await d.acquire(O);try{await p.start(o.bridge.url||void 0)}catch(e){throw await d.release(O),e}e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-t}ms)`)},async stop(){try{await d.release(O)}finally{await p.stop()}await A.checkpoint(),e.logger.info?.("[runtime-service] command journal checkpoint completed"),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(y&&void 0!==w&&w){const t=sharedMessageClientOwner.createRegistrationToken(),r=async(e,t)=>{const r=await w(e);if(!r.identityId||r.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:t}},o=(e,t,r)=>({getLocalAgentId:()=>t,resolveLocalAgentId:e=>e===r?t:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,t,r,o)=>{p.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>p.chatAbort(e,t)}),n=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async n=>{await sharedMessageClientOwner.acquire(t,async t=>{const i=await r(n.instanceId,n.runtimeEpoch),s=t.client;APPROVAL_V1_MS_ENABLED&&(sharedApprovalPublisher=async(e,t,r,o)=>{const a=sharedApprovalJournal.read(o.requestId),n=sharedRuntimeAuthority?.authorityLease;if(!a||!n||n.runtimeEpoch!==a.runtimeEpoch||n.instanceId!==i.principalId)throw new Error("approval_runtime_fenced");const l=await s.messages.send({conversationId:r,clientMessageId:t,idempotencyKey:t,type:e,content:{payload:toMessagePart(o),metadata:{delivery_principal:i.principalId,target_agent_id:a.platformAgentId,runtime_epoch:a.runtimeEpoch,owner_identity:a.ownerIdentity}}});if("outcome_unknown"===l.outcome||l.messageId!==t)throw new Error("approval_publication_not_confirmed")});const c={leaseId:n.leaseId,runtimeEpoch:n.runtimeEpoch};sharedMSConnectionStatus.bind(c);const u=new Map,d=new MessageProjectionInboundConsumer({client:s,bindings:()=>{const t=sharedRuntimeAuthority?.authorityLease;if(!t||t.instanceId!==i.principalId||t.runtimeEpoch!==i.runtimeEpoch)return[];const r=sharedAgentMappings.snapshot();return r?[...r.entries()].flatMap(([r,n])=>{if(!n.id||n.instanceId!==i.principalId)return[];let l=u.get(n.id);return l&&l.localAgentId===r||(l={localAgentId:r,inbound:createImInboundHandler({...APPROVAL_V1_MS_ENABLED?{approval:{gate:sharedApprovalGate,policy:sharedApprovalPolicy,runtimeEpoch:i.runtimeEpoch,platformAgentId:n.id,active:()=>{const e=sharedRuntimeAuthority?.authorityLease;return e?.runtimeEpoch===i.runtimeEpoch&&e?.instanceId===i.principalId}}}:{},automationTurnPolicy:sharedAutomationTurnPolicy,runtime:e.runtime,pluginConfig:e.pluginConfig,client:s,localServer:o(i,r,n.id),promptRunStore:h,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:g,logger:e.logger,writeObs:a,principalIdOverride:i.principalId,activeRunAuthority:p.getActiveRunAuthority(),applyTurnModel:(e,t)=>p.applyImTurnModel(e,t),restoreTurnModel:e=>p.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(n.id,l)),[{principalId:i.principalId,targetAgentId:n.id,runtimeEpoch:t.runtimeEpoch,inbound:l.inbound}]}):[]},executionJournal:l,logger:e.logger}),m=sharedAgentMappings.subscribe(()=>{sharedActiveMessageConsumer===d&&d.refresh()}),y=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===d&&d.refresh()})??(()=>{}),v=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==d)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===i.principalId&&e.runtimeEpoch===i.runtimeEpoch&&e.leaseId===n.leaseId&&e.handlerIdentity===n.handlerIdentity},reconnect:async()=>{if("failed"===s.getSnapshot().connection){await s.connect();try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${t instanceof Error?t.message:String(t)}`)}}}});let f=s.getSnapshot().connection;sharedMSConnectionStatus.setIfCurrent(c,f);const w=s.subscribe(()=>{const t=s.getSnapshot();t.connection!==f&&(f=t.connection,sharedMSConnectionStatus.setIfCurrent(c,t.connection),"connected"===t.connection?(v.notifyConnected(),e.logger.info?.(`[beeos-claw] connection transport=message_service_realtime state=connected localAgentId=${p.getLocalAgentId()} principalId=${i.principalId}`)):"failed"===t.connection?(e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=failed principalId=${i.principalId} recoveryError=${t.recoveryError??"unknown"}`),v.notifyFailed()):"disconnected"!==t.connection&&"reconnecting"!==t.connection||e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=${t.connection} principalId=${i.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=d,d.start();try{await s.connect()}catch(e){throw sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(c),v.dispose(),await d.stop(),m(),y(),w(),await s.disconnect().catch(()=>{}),e}try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${t instanceof Error?t.message:String(t)}`)}return async()=>{sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(c),v.dispose(),await d.stop(),y(),w(),await s.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(t)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){n?n.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(n?.stop())}})}else y?e.logger.warn?.("[beeos-claw] Message bus enabled but Agent Gateway token provider is unavailable — disabled"):e.logger.info?.(`[beeos-claw] Message bus disabled (enabled=${y})`);if(o.messageBus.enabled&&c&&!sharedNativeCloudChat&&e.logger.warn?.("[beeos-claw] Cloud message bus enabled but native composition unavailable (messageBus.serviceUrl or runtime authority missing) — disabled"),!1!==f&&agentGateway){const t=e=>p.getGatewaySessionKeyForToolCall(e),r=e=>p.getMentionsForToolCall(e),o=(e,t)=>{p.broadcastNotification(e,t)},a=new TaskHandleRegistry;registerA2ATools(e,{gateway:agentGateway,logger:e.logger},a,t,r,o,()=>m()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(agentGateway&&(registerAutomationTools(e,{gateway:agentGateway,callConnectorTool:harnessConnectorToolCaller(),logger:e.logger,getDefaultAgent:()=>{const e=m();return e?{id:e.id,instanceId:e.instanceId}:void 0},getCurrentConversationId:e=>{const t=p.getGatewaySessionKeyForToolCall(e);return t?extractBeeosConversationIdFromSessionKey(t):void 0}}),e.logger.info?.("[beeos-claw] Automation tools registered (create/create_webhook/capabilities/preflight/list/get/run/runs/get_run)")),o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const t=sharedCanvasState;if(agentGateway&&agentKeys){t.setLogger(e.logger);const r=()=>agentGateway.canvas.token(),a=a=>{const n=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,agentId:a.id,displayName:a.displayName,avatarUrl:a.avatarUrl,tokenProvider:r,onConnected:()=>p.flushPendingCanvasLinks(),onReconnect:()=>p.onRelayReconnected(),logger:e.logger});t.setRelayClient(n),t.setAgentId(a.id),p.wireRelayActionHandler(),n.connect(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${a.id}, name=${a.name??"none"})`)};e.registerService(createCanvasRelayService({getAgent:m,onceAgentReady:e=>sharedAgentMappings.onceReady(e),initRelay:a,stopRelay:()=>t.getRelayClient()?.disconnect(),logger:e.logger})),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const r={stateManager:t,logger:e.logger,writeObs:e=>a(e),getActiveSessionId:e=>p.getSessionIdForToolCall(e),getPlatformAgentId:e=>p.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>p.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>sharedAgentMappings.waitForSynchronization(),publishStaticHtml:createStaticCanvasHtmlPublisher(pluginCloudRuntimeTarget(e)?o.agentGatewayUrl:void 0)},i=new FormSchemaRegistry,s=buildCronSchemas(n);i.register(s.create),i.register(s.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(t,r,o)=>(p.preMapToolCallSession(t),e(t,r));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiToolExecutor(r))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(r))}),p.setCanvasState(t,{schemaRegistry:i,descriptorRegistry:l});const u=p.getFormBuilder();u&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(i),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:i,builder:u,logger:e.logger}))});const d=p.getResourceRenderer();if(d){generateActionTools(l,e,async(e,t)=>p.gatewayRequest(e,t),d,e.logger)}const g=buildToolRoutingHint(BEEOS_FILE_RESOURCE_ROUTING_RULE,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME),h=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,v=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,t)=>{if(t?.sessionKey){if(v.size>=y&&!v.has(t.sessionKey)){const e=v.keys().next().value;void 0!==e&&v.delete(e)}v.set(t.sessionKey,t.channelId),rememberDeliveryWorkspace(t.sessionKey,t.workspaceDir)}const r=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:t?.channelId});return t?.sessionKey||r?{appendSystemContext:buildAppendSystemContext({thirdParty:r,canvasSystemPrompt:`${CANVAS_PRESENTATION_GATE}\n\n${CANVAS_SYSTEM_PROMPT}`,toolRoutingHint:g})}:{appendSystemContext:g}}),e.logger.debug?.("[beeos-claw] Canvas system prompt hook registered: before_prompt_build")}catch{e.logger.debug?.("[beeos-claw] before_prompt_build hook not supported")}try{e.on("before_tool_call",(e,t)=>{if(t?.sessionKey&&p.setPendingToolCallSessionKey(t.sessionKey),!h.has(e.toolName))return;const r=t?.sessionKey?v.get(t.sessionKey):void 0,o=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:r}),a=canvasToolBlockReason({thirdParty:o,hasSession:Boolean(t?.sessionKey)});return a?{block:!0,blockReason:a}:void 0}),e.logger.debug?.("[beeos-claw] Canvas tool guard registered: before_tool_call")}catch{e.logger.debug?.("[beeos-claw] before_tool_call hook not supported")}}e.logger.info?.("[beeos-claw] Canvas tools registered (render_ui, close_ui, render_form + auto-action tools)")}else e.logger.info?.("[beeos-claw] Canvas disabled by config (canvasEnabled=false)");if(o.bridge.shell.enabled&&!0===o.legacyTerminalWsEnabled){const t=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:a});e.registerService({id:"beeos-terminal-ws",start(){t.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){t.stop(),e.logger.info?.("[beeos-claw] Terminal WS stopped")}})}else o.bridge.shell.enabled?e.logger.info?.("[beeos-claw] Legacy static-token Terminal WS disabled (default)"):e.logger.info?.("[beeos-claw] Terminal/shell disabled by config (bridge.shell.enabled=false)");if(t.openclawConfig){const r=mirrorOpenClawConfig(t.openclawConfig);r.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${r.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${r.reason}`)}}function pluginCloudRuntimeTarget(e){const t=e.pluginConfig?.cloudRuntimeInstanceId;return cloudRuntimeTargetInstanceId("string"==typeof t?t:void 0)}function attachNativeCloudChat(e,t){if(sharedNativeChatService)return e.registerService(sharedNativeChatService),sharedNativeCloudChat;const r=sharedRuntimeAuthority,o=t.messageBus.serviceUrl,a=sharedAcpServer,n=sharedSessionMutationCoordinator;if(!(r&&r.cloudTargetInstanceId&&o&&a&&n))return sharedNativeCloudChat;const i=sharedNativeCloudChat??createNativeCloudChatComposition({authority:nativeCloudChatAuthorityFromRuntimeAuthority(r),serviceUrl:o,logger:e.logger});if(sharedNativeCloudChat=i,!t.messageBus.enabled)return i;const s=i,l=r;let c;const u=new Map,d=new RuntimeAuthorityMessageBusLifecycle({authority:l,logger:e.logger,bus:{connect:async t=>{c?.(),u.clear(),c=s.adapter.listen({eventTypes:["message.created"]},r=>{const o=(r.content??{}).metadata??{},i="string"==typeof o.target_agent_id?o.target_agent_id:"",l=i?((t,r)=>{const o=sharedAgentMappings.snapshot();if(o)for(const[i,l]of o.entries()){if(l.id!==r)continue;if(l.instanceId!==t.instanceId)continue;const o=`${i}\0${l.id}`;let c=u.get(o);return c||(c={localAgentId:i,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:s.adapter,localServer:{getLocalAgentId:()=>i,resolveLocalAgentId:e=>e===l.id?i:void 0,getDefaultPlatformAgent:()=>({instanceId:t.instanceId}),ensureImInboundSession:(e,t,r,o)=>{a.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>a.chatAbort(e,t)},promptRunStore:sharedPromptRunStore,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:n,logger:e.logger,writeObs:sharedWriteObs,principalIdOverride:t.instanceId,activeRunAuthority:a.getActiveRunAuthority(),applyTurnModel:(e,t)=>a.applyImTurnModel(e,t),restoreTurnModel:e=>a.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(o,c)),c}})(t,i):void 0;if(!l)return void e.logger.warn?.(`[beeos-claw] native cloud chat dropped unresolvable target_agent_id=${i||"missing"} message_id=${r.id}`);("chat_cancel"===r.type?l.inbound.onChatCancel(r):l.inbound.onChatMessage(r)).catch(t=>{e.logger.error?.(`[beeos-claw] native cloud chat dispatch failed message_id=${r.id}: ${t instanceof Error?t.message:String(t)}`)})});try{await s.adapter.connect()}catch(e){throw c?.(),c=void 0,e}},disconnect:async()=>{c?.(),c=void 0,u.clear(),await s.adapter.disconnect()}}});return sharedNativeChatService={id:"beeos-native-cloud-chat",async start(){d.start()},async stop(){await d.stop()}},e.registerService(sharedNativeChatService),e.logger.info?.("[beeos-claw] native Cloud personal-chat composition registered"),i}const plugin={id:"beeos-claw",name:"beeos-claw",description:"BeeOS platform bridge plugin for OpenClaw. Provides file upload/download, ACP bridge, and observability.",version:PLUGIN_VERSION,register(e){if(_initializing)return;const t=pluginCloudRuntimeTarget(e),r=void 0!==t&&t!==sharedRuntimeAuthority?.cloudTargetInstanceId,o=planPluginRegistration(e.registrationMode,_fullRuntimeRegistered,r);if("skip"!==o){_initializing=!0;try{if(!hasRuntimeReplyApi(e.runtime))throw e.logger.error?.("[beeos-claw] FATAL: OpenClaw runtime.channel.reply.dispatchReplyFromConfig not exposed. Upgrade OpenClaw or revert beeos-claw."),new Error("openclaw_runtime_reply_api_unavailable");const t=(t,r)=>{registerUploadTools(e,t,r),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)};if("capabilities"===o&&sharedPluginContext){if(cachedCapabilityTools.length>0){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool}),r=replayCachedPluginTools(r=>t.call(e,r),cachedCapabilityTools);return registerArouterLatencyRouting(e),registerArouterMediaProviders(e),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} tools_only count=${r}`)}const r={current:sharedAcpServer??null};return t(sharedPluginContext,r),registerServices(e,sharedPluginContext,r),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} capabilities_only`)}const r=initializePlugin(e);if(!r)return;const a={current:null};installUnhandledRejectionObserver(e,r.writeObs,a),ensureRegisterToolCache(e),cacheRuntimeRegistrations(e),cachedCapabilityTools.length=0,t(r,a),agentGateway&&(e.on?e.on("before_agent_finalize",fileDeliveryFinalizeDecision):e.logger.warn?.("[file-delivery] OpenClaw plugin hooks unavailable; finalization check disabled")),registerServices(e,r,a),sharedPluginContext=r,marksFullRuntimeRegistered(e.registrationMode,o)&&(_fullRuntimeRegistered=!0),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else if(!e.registrationMode||"full"===e.registrationMode){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool});replayCachedPluginTools(r=>t.call(e,r),cachedCapabilityTools),replayRuntimeRegistrations(e),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)}}};export default plugin;
@@ -1 +1 @@
1
- import{TERMINAL_MAX_FRAME_BYTES,TERMINAL_SERVICE_PROTOCOL_VERSION}from"@beeos-ai/beeos-types/runtime";import{TerminalNotFoundError}from"./session-manager.js";import{getOrCreateRuntimeTerminalService}from"./runtime-terminal-service.js";import{TerminalAuthorityAdmission}from"./terminal-authority-admission.js";const DEFAULT_REPLAY_RETENTION_MS=3e5,DEFAULT_LEASE_RECOVERY_GRACE_MS=3e5;export class RuntimeTerminalOutboundRegistration{options;service;authorityAdmission;serviceGeneration;rings=new Map;ringBytes=new Map;droppedThrough=new Map;pending=[];pendingBytes=0;activeSend;activeFlush;flushes=new Set;connected=!1;handlerIdentity;draining=!1;stopped=!1;eventGeneration=0;transportEpoch=0;drainPromise;closePromise;replayExpiryTimers=new Map;constructor(e){this.options=e,this.service=e.service??getOrCreateRuntimeTerminalService(e.manager),this.authorityAdmission=new TerminalAuthorityAdmission(e.authorityJournal,e.authorityClock),this.serviceGeneration=this.service.setOutbound(this);const t=this.eventGeneration;e.client.on("connected",(...i)=>{if(!this.acceptsEvent(t))return;if(this.connected)return;this.transportEpoch++,this.activeFlush=void 0,this.serviceGeneration??=this.service.setOutbound(this);const n=i[0]?.handlerIdentity;n&&(this.handlerIdentity=n,this.service.closeParkedServiceSessions("runtime_lease_lost",n)),this.connected=!0,this.publishAvailability(!0),this.kickFlush(),e.logger?.info?.("[terminal-service] outbound registration connected")}),e.client.on("disconnected",()=>{this.acceptsEvent(t)&&this.invalidateConnection("transport")}),e.client.on("message",(...e)=>{if(!this.acceptsEvent(t))return;const i=this.serviceGeneration,n=this.transportEpoch;if(!i||!this.acceptsTransport(n,i))return;const r=e[0],s="string"==typeof r?r:Buffer.from(r).toString("utf8");this.handleWire(s,i,n)}),e.client.on("error",(...i)=>{this.acceptsEvent(t)&&e.logger?.warn?.("[terminal-service] outbound registration error",i[0])}),e.client.on("authorityLost",(...i)=>{if(this.acceptsEvent(t)){if(!0===i[0]?.recoverable)return this.invalidateConnection("park"),void e.logger?.warn?.("[terminal-service] runtime lease lost; Service terminals parked for recovery");this.invalidateConnection("fence"),e.logger?.warn?.("[terminal-service] runtime lease lost; Service terminals fenced")}}),e.client.on("transportEpochChanged",()=>{this.acceptsEvent(t)&&(this.invalidateConnection("park"),e.logger?.info?.("[terminal-service] runtime lease rotated; prior Terminal epoch parked for resume"))})}async start(){if(this.stopped)throw new Error("terminal outbound registration is stopped");await this.options.client.connect()}isAvailable(){return this.connected&&!this.draining&&!this.stopped}send(e){if(this.stopped)return!1;const t=JSON.stringify(e),i=Buffer.byteLength(t);return this.remember(e,t,i),!this.connected||(this.enqueueWithOutputBackpressure({clientId:e.clientId,terminalId:e.terminalId,frame:e,wire:t,bytes:i}),this.kickFlush(),!0)}resume(e,t,i){const n=this.transportEpoch;if(!this.acceptsConnection(n))throw new Error("terminal outbound registration is disconnected");const r=BigInt(i),s=r<(this.droppedThrough.get(t)??0n),a=[];let o=-1n;for(const i of this.rings.get(t)??[]){if(i.frame.clientId!==e)throw new Error("terminal resume ownership mismatch");const n=BigInt(i.frame.sequence);if(n<=o)throw new Error("terminal replay sequence is not monotonic");o=n,n<=r||a.push({clientId:e,terminalId:t,frame:i.frame,wire:i.wire,bytes:i.bytes})}if(!this.acceptsConnection(n))throw new Error("terminal outbound registration epoch changed");for(const e of a)this.enqueueWithOutputBackpressure(e);return this.acknowledgeReplay(t,r),this.kickFlush(),{gap:s}}rebindResumeClient(e,t,i){if(e===t)return;const n=this.rings.get(i);if(n?.some(t=>t.frame.clientId!==e))throw new Error("terminal resume ownership mismatch");if(n){let e=0;const r=n.map(i=>{const n=Object.freeze({...i.frame,clientId:t}),r=JSON.stringify(n),s=Buffer.byteLength(r);return e+=s,{frame:n,wire:r,bytes:s}});this.rings.set(i,r),this.ringBytes.set(i,e)}for(let n=0;n<this.pending.length;n++){const r=this.pending[n];if(r.terminalId!==i||r.clientId!==e)continue;const s={...r.frame,clientId:t},a=JSON.stringify(s),o=Buffer.byteLength(a);this.pendingBytes+=o-r.bytes,this.pending[n]={clientId:t,terminalId:i,frame:s,wire:a,bytes:o}}if(this.activeSend?.item.terminalId===i&&this.activeSend.item.clientId===e){const e=this.activeSend.item,n={...e.frame,clientId:t},r=JSON.stringify(n),s=Buffer.byteLength(r);this.activeSend.counted&&(this.pendingBytes+=s-e.bytes),this.activeSend={item:{clientId:t,terminalId:i,frame:n,wire:r,bytes:s},counted:this.activeSend.counted}}}forgetTerminal(e,t){this.prepareForgetTerminal(e,t)()}prepareForgetTerminal(e,t){const i=this.rings.get(t),n=new Set(this.pending.filter(e=>e.terminalId===t)),r=this.activeSend?.item.terminalId===t&&this.activeSend.counted?this.activeSend:void 0;if(i?.some(t=>t.frame.clientId!==e)||[...n].some(t=>t.clientId!==e)||r&&r.item.clientId!==e)throw new Error("terminal forget ownership mismatch");const s=this.replayExpiryTimers.get(t);let a=!1;return()=>{if(a)return;a=!0,s&&this.replayExpiryTimers.get(t)===s&&(clearTimeout(s),this.replayExpiryTimers.delete(t)),i&&this.rings.get(t)===i&&(this.rings.delete(t),this.ringBytes.delete(t),this.droppedThrough.delete(t));let e=0;for(const t of this.pending)n.has(t)?this.pendingBytes-=t.bytes:this.pending[e++]=t;this.pending.length=e,r&&this.activeSend===r&&r.counted&&(r.counted=!1,this.pendingBytes-=r.item.bytes),this.pendingBytes=Math.max(0,this.pendingBytes)}}startTerminalReplayExpiry(e,t){if((this.rings.get(t)??[]).some(t=>t.frame.clientId!==e))throw new Error("terminal replay expiry ownership mismatch");this.scheduleReplayExpiry(e,t)}drain(e){return this.drainPromise??=this.drainOnce(e),this.drainPromise}async drainOnce(e){this.draining=!0,this.stopped=!0,this.eventGeneration++;const t=[...this.flushes];this.invalidateConnection("fence");const i=await waitBounded(this.options.manager.drain(e.timeoutMs,e.terminateAfterTimeout),e.timeoutMs,e.signal),n=i===interrupted?"terminated":i;return i!==interrupted&&"terminated"===n&&e.terminateAfterTimeout&&await waitBounded(this.options.manager.drain(Math.min(1e3,Math.max(50,e.timeoutMs)),!1),Math.min(1e3,Math.max(50,e.timeoutMs)),e.signal),await waitBounded(Promise.allSettled(t),e.timeoutMs,e.signal),await waitBounded(this.closeClientOnce(),e.timeoutMs,e.signal),this.clearReplayState(),n}acceptsEvent(e){return!this.stopped&&e===this.eventGeneration}async handleWire(e,t,i){if(!this.acceptsTransport(i,t))return;if(Buffer.byteLength(e)>TERMINAL_MAX_FRAME_BYTES)return void this.options.logger?.warn?.("[terminal-service] oversized client frame rejected");let n,r;try{n=JSON.parse(e)}catch{return void this.options.logger?.warn?.("[terminal-service] invalid client JSON")}try{r=await this.authorityAdmission.admit(n),await this.service.handleClientFrame(r.frame,t,r.admission)}catch(e){if(this.acceptsTransport(i,t)){r&&this.sendRejectedFrame(r.frame,e);const t=e instanceof Error?e.message:String(e);this.options.logger?.warn?.(`[terminal-service] client frame rejected: ${t}`,e)}}}sendRejectedFrame(e,t){const i=(t instanceof Error?t.message:String(t)).toLowerCase(),n=t instanceof TerminalNotFoundError||i.includes("not found")?"TERMINAL_NOT_FOUND":i.includes("quota")?"TERMINAL_QUOTA_EXCEEDED":i.includes("unauthorized")||i.includes("authority")?"UNAUTHORIZED_TARGET":"TERMINAL_IO_ERROR",r=this.rings.get(e.terminalId),s="TERMINAL_NOT_FOUND"!==n&&this.options.manager.getSession(e.terminalId)?.sessionId===e.clientId&&(!r||r.every(t=>t.frame.clientId===e.clientId)),a=s?this.options.manager.getSessionIncarnation(e.terminalId):void 0,o=s||"terminal.resume"!==e.type?a?BigInt(this.options.manager.nextServerSequence(e.terminalId,a)):1n:BigInt(e.lastServerSequence)+1n,c={protocolVersion:TERMINAL_SERVICE_PROTOCOL_VERSION,type:"terminal.error",clientId:e.clientId,terminalId:e.terminalId,sequence:String(o),code:n,message:n,recoverable:"TERMINAL_IO_ERROR"===n||"TERMINAL_QUOTA_EXCEEDED"===n};if(!s){const t=JSON.stringify(c);return this.enqueueWithOutputBackpressure({clientId:e.clientId,terminalId:e.terminalId,frame:c,wire:t,bytes:Buffer.byteLength(t)}),void this.kickFlush()}this.send(c)}remember(e,t,i){const n=this.rings.get(e.terminalId)??[];n.push({frame:Object.freeze({...e}),wire:t,bytes:i});let r=(this.ringBytes.get(e.terminalId)??0)+i;const s=this.options.maxBufferedFramesPerTerminal??512,a=this.options.maxBufferedBytesPerTerminal??1048576;for(;n.length>s||r>a;){const t=n.shift();if(!t)break;r-=t.bytes,this.droppedThrough.set(e.terminalId,BigInt(t.frame.sequence))}this.rings.set(e.terminalId,n),this.ringBytes.set(e.terminalId,r),"terminal.exit"===e.type&&this.scheduleReplayExpiry(e.clientId,e.terminalId)}enqueueWithOutputBackpressure(e){const t=this.options.maxPendingSendBytes??1048576;if(this.pendingBytes+e.bytes<=t)return this.pending.push(e),void(this.pendingBytes+=e.bytes);if("terminal.output"===e.frame.type){if(this.hasPendingTruncation(e.terminalId))return;const i=this.toTruncationMarker(e);return this.compactPendingOutput(i.bytes,t),void(this.hasPendingTruncation(e.terminalId)||(this.pending.push(i),this.pendingBytes+=i.bytes))}this.compactPendingOutput(e.bytes,t),this.pending.push(e),this.pendingBytes+=e.bytes}compactPendingOutput(e,t){for(;this.pendingBytes+e>t;){const e=this.pending.findIndex(e=>"terminal.output"===e.frame.type&&!0!==e.frame.truncated);if(e<0)return;const t=this.pending[e];if(this.hasPendingTruncation(t.terminalId,t)){this.pending.splice(e,1),this.pendingBytes-=t.bytes;continue}const i=this.toTruncationMarker(t);this.pending[e]=i,this.pendingBytes+=i.bytes-t.bytes}}hasPendingTruncation(e,t){return this.activeSend?.item!==t&&this.activeSend?.item.terminalId===e&&"terminal.output"===this.activeSend.item.frame.type&&!0===this.activeSend.item.frame.truncated||this.pending.some(i=>i!==t&&i.terminalId===e&&"terminal.output"===i.frame.type&&!0===i.frame.truncated)}toTruncationMarker(e){if("terminal.output"!==e.frame.type)throw new Error("only terminal output can be truncated");const t={...e.frame,data:"",encoding:"base64",truncated:!0},i=JSON.stringify(t);return{...e,frame:t,wire:i,bytes:Buffer.byteLength(i)}}async flush(e){for(;this.acceptsConnection(e)&&this.pending.length>0;){const t=this.pending.shift(),i={item:t,counted:!0};this.activeSend=i;try{await this.options.client.send(t.wire)}catch{return void(this.transportEpoch===e&&this.invalidateConnection("transport"))}if(!this.acceptsConnection(e))return;this.activeSend===i&&(i.counted&&(this.pendingBytes-=t.bytes),this.activeSend=void 0)}}kickFlush(){if(this.activeFlush||!this.connected||0===this.pending.length)return;const e=this.transportEpoch,t=this.flush(e).finally(()=>{this.flushes.delete(t),this.activeFlush?.promise===t&&(this.activeFlush=void 0,this.acceptsConnection(e)&&this.kickFlush())});this.activeFlush={epoch:e,promise:t},this.flushes.add(t)}acceptsConnection(e){return this.connected&&!this.stopped&&e===this.transportEpoch}acceptsTransport(e,t){return this.acceptsEvent(this.eventGeneration)&&this.acceptsConnection(e)&&this.serviceGeneration===t}invalidateConnection(e){const t=this.connected;this.transportEpoch++,this.connected=!1,t&&this.publishAvailability(!1),this.activeFlush=void 0,this.activeSend=void 0,this.flushes.clear(),this.pending.length=0,this.pendingBytes=0;const i=this.serviceGeneration;switch(e){case"transport":return;case"park":i&&this.service.parkServiceSessions(i,this.handlerIdentity,this.options.leaseRecoveryGraceMs??3e5);break;case"fence":this.service.closeParkedServiceSessions("runtime_lease_lost"),i&&this.service.fenceServiceSessions("runtime_lease_lost",i);break;default:throw new Error(`unhandled connection invalidation ${String(e)}`)}i&&(this.service.clearOutbound(this,i),this.serviceGeneration===i&&(this.serviceGeneration=void 0)),this.clearReplayState()}publishAvailability(e){try{this.options.onAvailabilityChange?.(e)}catch{}}clearReplayState(){for(const e of this.replayExpiryTimers.values())clearTimeout(e);this.replayExpiryTimers.clear(),this.rings.clear(),this.ringBytes.clear(),this.droppedThrough.clear()}acknowledgeReplay(e,t){const i=this.rings.get(e);if(!i||0===i.length)return;let n=0,r=this.droppedThrough.get(e)??0n,s=0;for(;s<i.length;){const e=i[s],a=BigInt(e.frame.sequence);if(a>t)break;n+=e.bytes,a>r&&(r=a),s++}0!==s&&(i.splice(0,s),this.ringBytes.set(e,Math.max(0,(this.ringBytes.get(e)??0)-n)),this.droppedThrough.set(e,r))}scheduleReplayExpiry(e,t){this.clearReplayExpiry(t);const i=this.serviceGeneration;if(!i)return;const n=setTimeout(()=>{if(this.replayExpiryTimers.get(t)===n){this.replayExpiryTimers.delete(t);try{this.service.expireServiceTerminalReplay(e,t,i)}catch(e){this.options.logger?.warn?.("[terminal-service] replay expiry failed",e)}}},Math.max(0,this.options.replayRetentionMs??3e5));n.unref?.(),this.replayExpiryTimers.set(t,n)}clearReplayExpiry(e){const t=this.replayExpiryTimers.get(e);t&&clearTimeout(t),this.replayExpiryTimers.delete(e)}closeClientOnce(){return this.closePromise??=this.options.client.close(!0),this.closePromise}}const interrupted=Symbol("interrupted");async function waitBounded(e,t,i){return i?.aborted?(e.catch(()=>{}),interrupted):await new Promise((n,r)=>{let s=!1;const a=e=>{s||(s=!0,clearTimeout(c),i?.removeEventListener("abort",o),n(e))},o=()=>a(interrupted),c=setTimeout(()=>a(interrupted),Math.max(0,t));c.unref?.(),i?.addEventListener("abort",o,{once:!0}),e.then(e=>a(e),e=>{s||(s=!0,clearTimeout(c),i?.removeEventListener("abort",o),r(e))})})}
1
+ import{TERMINAL_MAX_FRAME_BYTES,TERMINAL_SERVICE_PROTOCOL_VERSION}from"@beeos-ai/beeos-types/runtime";import{TerminalNotFoundError}from"./session-manager.js";import{getOrCreateRuntimeTerminalService}from"./runtime-terminal-service.js";import{TerminalAuthorityAdmission}from"./terminal-authority-admission.js";const DEFAULT_REPLAY_RETENTION_MS=3e5,DEFAULT_LEASE_RECOVERY_GRACE_MS=3e5;export class RuntimeTerminalOutboundRegistration{options;service;authorityAdmission;serviceGeneration;rings=new Map;ringBytes=new Map;droppedThrough=new Map;pending=[];pendingBytes=0;activeSend;activeFlush;flushes=new Set;connected=!1;handlerIdentity;draining=!1;stopped=!1;eventGeneration=0;transportEpoch=0;drainPromise;closePromise;replayExpiryTimers=new Map;constructor(e){this.options=e,this.service=e.service??getOrCreateRuntimeTerminalService(e.manager),this.authorityAdmission=new TerminalAuthorityAdmission(e.authorityJournal,e.authorityClock),this.serviceGeneration=this.service.setOutbound(this);const t=this.eventGeneration;e.client.on("connected",(...i)=>{if(!this.acceptsEvent(t))return;if(this.connected)return;this.transportEpoch++,this.activeFlush=void 0,this.serviceGeneration??=this.service.setOutbound(this);const n=i[0]?.handlerIdentity;n&&(this.handlerIdentity=n,this.service.closeParkedServiceSessions("runtime_lease_lost",n)),this.connected=!0,this.publishAvailability(!0),this.kickFlush(),e.logger?.info?.("[terminal-service] outbound registration connected")}),e.client.on("disconnected",()=>{this.acceptsEvent(t)&&this.invalidateConnection("transport")}),e.client.on("message",(...e)=>{if(!this.acceptsEvent(t))return;const i=this.serviceGeneration,n=this.transportEpoch;if(!i||!this.acceptsTransport(n,i))return;const r=e[0],s="string"==typeof r?r:Buffer.from(r).toString("utf8");this.handleWire(s,i,n)}),e.client.on("error",(...i)=>{this.acceptsEvent(t)&&e.logger?.warn?.("[terminal-service] outbound registration error",i[0])}),e.client.on("authorityLost",(...i)=>{if(this.acceptsEvent(t)){if(!0===i[0]?.recoverable)return this.invalidateConnection("park"),void e.logger?.warn?.("[terminal-service] runtime lease lost; Service terminals parked for recovery");this.invalidateConnection("fence"),e.logger?.warn?.("[terminal-service] runtime lease lost; Service terminals fenced")}}),e.client.on("transportEpochChanged",()=>{this.acceptsEvent(t)&&(this.invalidateConnection("park"),e.logger?.info?.("[terminal-service] runtime lease rotated; prior Terminal epoch parked for resume"))})}async start(){if(this.stopped)throw new Error("terminal outbound registration is stopped");await this.options.client.connect()}isAvailable(){return this.connected&&!this.draining&&!this.stopped}send(e){if(this.stopped)return!1;const t=JSON.stringify(e),i=Buffer.byteLength(t);return this.remember(e,t,i),!this.connected||(this.enqueueWithOutputBackpressure({clientId:e.clientId,terminalId:e.terminalId,frame:e,wire:t,bytes:i}),this.kickFlush(),!0)}resume(e,t,i){const n=this.transportEpoch;if(!this.acceptsConnection(n))throw new Error("terminal outbound registration is disconnected");const r=BigInt(i),s=r<(this.droppedThrough.get(t)??0n),a=[];let o=-1n;for(const i of this.rings.get(t)??[]){if(i.frame.clientId!==e)throw new Error("terminal resume ownership mismatch");const n=BigInt(i.frame.sequence);if(n<=o)throw new Error("terminal replay sequence is not monotonic");o=n,n<=r||a.push({clientId:e,terminalId:t,frame:i.frame,wire:i.wire,bytes:i.bytes})}if(!this.acceptsConnection(n))throw new Error("terminal outbound registration epoch changed");for(const e of a)this.enqueueWithOutputBackpressure(e);return this.kickFlush(),{gap:s}}rebindResumeClient(e,t,i){if(e===t)return;const n=this.rings.get(i);if(n?.some(t=>t.frame.clientId!==e))throw new Error("terminal resume ownership mismatch");if(n){let e=0;const r=n.map(i=>{const n=Object.freeze({...i.frame,clientId:t}),r=JSON.stringify(n),s=Buffer.byteLength(r);return e+=s,{frame:n,wire:r,bytes:s}});this.rings.set(i,r),this.ringBytes.set(i,e)}for(let n=0;n<this.pending.length;n++){const r=this.pending[n];if(r.terminalId!==i||r.clientId!==e)continue;const s={...r.frame,clientId:t},a=JSON.stringify(s),o=Buffer.byteLength(a);this.pendingBytes+=o-r.bytes,this.pending[n]={clientId:t,terminalId:i,frame:s,wire:a,bytes:o}}if(this.activeSend?.item.terminalId===i&&this.activeSend.item.clientId===e){const e=this.activeSend.item,n={...e.frame,clientId:t},r=JSON.stringify(n),s=Buffer.byteLength(r);this.activeSend.counted&&(this.pendingBytes+=s-e.bytes),this.activeSend={item:{clientId:t,terminalId:i,frame:n,wire:r,bytes:s},counted:this.activeSend.counted}}}forgetTerminal(e,t){this.prepareForgetTerminal(e,t)()}prepareForgetTerminal(e,t){const i=this.rings.get(t),n=new Set(this.pending.filter(e=>e.terminalId===t)),r=this.activeSend?.item.terminalId===t&&this.activeSend.counted?this.activeSend:void 0;if(i?.some(t=>t.frame.clientId!==e)||[...n].some(t=>t.clientId!==e)||r&&r.item.clientId!==e)throw new Error("terminal forget ownership mismatch");const s=this.replayExpiryTimers.get(t);let a=!1;return()=>{if(a)return;a=!0,s&&this.replayExpiryTimers.get(t)===s&&(clearTimeout(s),this.replayExpiryTimers.delete(t)),i&&this.rings.get(t)===i&&(this.rings.delete(t),this.ringBytes.delete(t),this.droppedThrough.delete(t));let e=0;for(const t of this.pending)n.has(t)?this.pendingBytes-=t.bytes:this.pending[e++]=t;this.pending.length=e,r&&this.activeSend===r&&r.counted&&(r.counted=!1,this.pendingBytes-=r.item.bytes),this.pendingBytes=Math.max(0,this.pendingBytes)}}startTerminalReplayExpiry(e,t){if((this.rings.get(t)??[]).some(t=>t.frame.clientId!==e))throw new Error("terminal replay expiry ownership mismatch");this.scheduleReplayExpiry(e,t)}drain(e){return this.drainPromise??=this.drainOnce(e),this.drainPromise}async drainOnce(e){this.draining=!0,this.stopped=!0,this.eventGeneration++;const t=[...this.flushes];this.invalidateConnection("fence");const i=await waitBounded(this.options.manager.drain(e.timeoutMs,e.terminateAfterTimeout),e.timeoutMs,e.signal),n=i===interrupted?"terminated":i;return i!==interrupted&&"terminated"===n&&e.terminateAfterTimeout&&await waitBounded(this.options.manager.drain(Math.min(1e3,Math.max(50,e.timeoutMs)),!1),Math.min(1e3,Math.max(50,e.timeoutMs)),e.signal),await waitBounded(Promise.allSettled(t),e.timeoutMs,e.signal),await waitBounded(this.closeClientOnce(),e.timeoutMs,e.signal),this.clearReplayState(),n}acceptsEvent(e){return!this.stopped&&e===this.eventGeneration}async handleWire(e,t,i){if(!this.acceptsTransport(i,t))return;if(Buffer.byteLength(e)>TERMINAL_MAX_FRAME_BYTES)return void this.options.logger?.warn?.("[terminal-service] oversized client frame rejected");let n,r;try{n=JSON.parse(e)}catch{return void this.options.logger?.warn?.("[terminal-service] invalid client JSON")}try{r=await this.authorityAdmission.admit(n),await this.service.handleClientFrame(r.frame,t,r.admission)}catch(e){if(this.acceptsTransport(i,t)){r&&this.sendRejectedFrame(r.frame,e);const t=e instanceof Error?e.message:String(e);this.options.logger?.warn?.(`[terminal-service] client frame rejected: ${t}`,e)}}}sendRejectedFrame(e,t){const i=(t instanceof Error?t.message:String(t)).toLowerCase(),n=t instanceof TerminalNotFoundError||i.includes("not found")?"TERMINAL_NOT_FOUND":i.includes("quota")?"TERMINAL_QUOTA_EXCEEDED":i.includes("unauthorized")||i.includes("authority")?"UNAUTHORIZED_TARGET":"TERMINAL_IO_ERROR",r=this.rings.get(e.terminalId),s="TERMINAL_NOT_FOUND"!==n&&this.options.manager.getSession(e.terminalId)?.sessionId===e.clientId&&(!r||r.every(t=>t.frame.clientId===e.clientId)),a=s?this.options.manager.getSessionIncarnation(e.terminalId):void 0,o=s||"terminal.resume"!==e.type?a?BigInt(this.options.manager.nextServerSequence(e.terminalId,a)):1n:BigInt(e.lastServerSequence)+1n,c={protocolVersion:TERMINAL_SERVICE_PROTOCOL_VERSION,type:"terminal.error",clientId:e.clientId,terminalId:e.terminalId,sequence:String(o),code:n,message:n,recoverable:"TERMINAL_IO_ERROR"===n||"TERMINAL_QUOTA_EXCEEDED"===n};if(!s){const t=JSON.stringify(c);return this.enqueueWithOutputBackpressure({clientId:e.clientId,terminalId:e.terminalId,frame:c,wire:t,bytes:Buffer.byteLength(t)}),void this.kickFlush()}this.send(c)}remember(e,t,i){const n=this.rings.get(e.terminalId)??[];n.push({frame:Object.freeze({...e}),wire:t,bytes:i});let r=(this.ringBytes.get(e.terminalId)??0)+i;const s=this.options.maxBufferedFramesPerTerminal??512,a=this.options.maxBufferedBytesPerTerminal??1048576;for(;n.length>s||r>a;){const t=n.shift();if(!t)break;r-=t.bytes,this.droppedThrough.set(e.terminalId,BigInt(t.frame.sequence))}this.rings.set(e.terminalId,n),this.ringBytes.set(e.terminalId,r),"terminal.exit"===e.type&&this.scheduleReplayExpiry(e.clientId,e.terminalId)}enqueueWithOutputBackpressure(e){const t=this.options.maxPendingSendBytes??1048576;if(this.pendingBytes+e.bytes<=t)return this.pending.push(e),void(this.pendingBytes+=e.bytes);if("terminal.output"===e.frame.type){if(this.hasPendingTruncation(e.terminalId))return;const i=this.toTruncationMarker(e);return this.compactPendingOutput(i.bytes,t),void(this.hasPendingTruncation(e.terminalId)||(this.pending.push(i),this.pendingBytes+=i.bytes))}this.compactPendingOutput(e.bytes,t),this.pending.push(e),this.pendingBytes+=e.bytes}compactPendingOutput(e,t){for(;this.pendingBytes+e>t;){const e=this.pending.findIndex(e=>"terminal.output"===e.frame.type&&!0!==e.frame.truncated);if(e<0)return;const t=this.pending[e];if(this.hasPendingTruncation(t.terminalId,t)){this.pending.splice(e,1),this.pendingBytes-=t.bytes;continue}const i=this.toTruncationMarker(t);this.pending[e]=i,this.pendingBytes+=i.bytes-t.bytes}}hasPendingTruncation(e,t){return this.activeSend?.item!==t&&this.activeSend?.item.terminalId===e&&"terminal.output"===this.activeSend.item.frame.type&&!0===this.activeSend.item.frame.truncated||this.pending.some(i=>i!==t&&i.terminalId===e&&"terminal.output"===i.frame.type&&!0===i.frame.truncated)}toTruncationMarker(e){if("terminal.output"!==e.frame.type)throw new Error("only terminal output can be truncated");const t={...e.frame,data:"",encoding:"base64",truncated:!0},i=JSON.stringify(t);return{...e,frame:t,wire:i,bytes:Buffer.byteLength(i)}}async flush(e){for(;this.acceptsConnection(e)&&this.pending.length>0;){const t=this.pending.shift(),i={item:t,counted:!0};this.activeSend=i;try{await this.options.client.send(t.wire)}catch{return void(this.transportEpoch===e&&this.invalidateConnection("transport"))}if(!this.acceptsConnection(e))return;this.activeSend===i&&(i.counted&&(this.pendingBytes-=t.bytes),this.activeSend=void 0)}}kickFlush(){if(this.activeFlush||!this.connected||0===this.pending.length)return;const e=this.transportEpoch,t=this.flush(e).finally(()=>{this.flushes.delete(t),this.activeFlush?.promise===t&&(this.activeFlush=void 0,this.acceptsConnection(e)&&this.kickFlush())});this.activeFlush={epoch:e,promise:t},this.flushes.add(t)}acceptsConnection(e){return this.connected&&!this.stopped&&e===this.transportEpoch}acceptsTransport(e,t){return this.acceptsEvent(this.eventGeneration)&&this.acceptsConnection(e)&&this.serviceGeneration===t}invalidateConnection(e){const t=this.connected;this.transportEpoch++,this.connected=!1,t&&this.publishAvailability(!1),this.activeFlush=void 0,this.activeSend=void 0,this.flushes.clear(),this.pending.length=0,this.pendingBytes=0;const i=this.serviceGeneration;switch(e){case"transport":return;case"park":i&&this.service.parkServiceSessions(i,this.handlerIdentity,this.options.leaseRecoveryGraceMs??3e5);break;case"fence":this.service.closeParkedServiceSessions("runtime_lease_lost"),i&&this.service.fenceServiceSessions("runtime_lease_lost",i);break;default:throw new Error(`unhandled connection invalidation ${String(e)}`)}i&&(this.service.clearOutbound(this,i),this.serviceGeneration===i&&(this.serviceGeneration=void 0)),this.clearReplayState()}publishAvailability(e){try{this.options.onAvailabilityChange?.(e)}catch{}}clearReplayState(){for(const e of this.replayExpiryTimers.values())clearTimeout(e);this.replayExpiryTimers.clear(),this.rings.clear(),this.ringBytes.clear(),this.droppedThrough.clear()}scheduleReplayExpiry(e,t){this.clearReplayExpiry(t);const i=this.serviceGeneration;if(!i)return;const n=setTimeout(()=>{if(this.replayExpiryTimers.get(t)===n){this.replayExpiryTimers.delete(t);try{this.service.expireServiceTerminalReplay(e,t,i)}catch(e){this.options.logger?.warn?.("[terminal-service] replay expiry failed",e)}}},Math.max(0,this.options.replayRetentionMs??3e5));n.unref?.(),this.replayExpiryTimers.set(t,n)}clearReplayExpiry(e){const t=this.replayExpiryTimers.get(e);t&&clearTimeout(t),this.replayExpiryTimers.delete(e)}closeClientOnce(){return this.closePromise??=this.options.client.close(!0),this.closePromise}}const interrupted=Symbol("interrupted");async function waitBounded(e,t,i){return i?.aborted?(e.catch(()=>{}),interrupted):await new Promise((n,r)=>{let s=!1;const a=e=>{s||(s=!0,clearTimeout(c),i?.removeEventListener("abort",o),n(e))},o=()=>a(interrupted),c=setTimeout(()=>a(interrupted),Math.max(0,t));c.unref?.(),i?.addEventListener("abort",o,{once:!0}),e.then(e=>a(e),e=>{s||(s=!0,clearTimeout(c),i?.removeEventListener("abort",o),r(e))})})}
@@ -1 +1 @@
1
- import{randomUUID}from"node:crypto";import{assertTerminalClientFrame}from"./runtime-terminal-service.js";import{systemTerminalAuthorityClock,verifyTerminalAuthority}from"./terminal-authority-contract.js";import{InMemoryTerminalAuthorityJournal}from"./terminal-authority-journal.js";export class TerminalAuthorityAdmission{journal;clock;constructor(r=new InMemoryTerminalAuthorityJournal,e=systemTerminalAuthorityClock){this.journal=r,this.clock=e}async admit(r){if(!isRecord(r))throw new Error("invalid terminal client frame");const e=verifyTerminalAuthority(r.terminalAuthority,this.clock);if(r.clientId!==e.clientId)throw new Error("terminal authority client mismatch");if("terminal.open"===r.type||"terminal.create"===r.type){if(e.resumeTerminalId)throw new Error("terminal resume requires terminal.resume");if(""!==r.terminalId)throw new Error("new terminal must be runtime allocated");assertTerminalClientFrame({...r,terminalId:VALIDATION_TERMINAL_ID});const t=await this.journal.bindNew(e,randomUUID());return{frame:{...r,terminalId:t.binding.terminalId},admission:{recovered:t.recovered}}}assertTerminalClientFrame(r);const t=r.terminalId;if("terminal.resume"===r.type){if(!e.resumeTerminalId||e.resumeTerminalId!==t)throw new Error("terminal resume id mismatch");return await this.journal.resume(e),{frame:r,admission:{recovered:!0}}}return await this.journal.assertBound(t,e),{frame:r,admission:{recovered:!1}}}}const VALIDATION_TERMINAL_ID="018f0000-0000-7000-8000-0000000000f0";function isRecord(r){return null!==r&&"object"==typeof r&&!Array.isArray(r)}
1
+ import{randomUUID}from"node:crypto";import{assertTerminalClientFrame}from"./runtime-terminal-service.js";import{systemTerminalAuthorityClock,verifyTerminalAuthority}from"./terminal-authority-contract.js";import{InMemoryTerminalAuthorityJournal}from"./terminal-authority-journal.js";export class TerminalAuthorityAdmission{journal;clock;constructor(r=new InMemoryTerminalAuthorityJournal,e=systemTerminalAuthorityClock){this.journal=r,this.clock=e}async admit(r){if(!isRecord(r))throw new Error("invalid terminal client frame");const e="terminal.open"===r.type||"terminal.create"===r.type,t=e||"terminal.resume"===r.type?"establish":"bound",i=verifyTerminalAuthority(r.terminalAuthority,this.clock,t);if(r.clientId!==i.clientId)throw new Error("terminal authority client mismatch");if(e){if(i.resumeTerminalId)throw new Error("terminal resume requires terminal.resume");if(""!==r.terminalId)throw new Error("new terminal must be runtime allocated");assertTerminalClientFrame({...r,terminalId:VALIDATION_TERMINAL_ID});const e=await this.journal.bindNew(i,randomUUID());return{frame:{...r,terminalId:e.binding.terminalId},admission:{recovered:e.recovered}}}assertTerminalClientFrame(r);const n=r.terminalId;if("terminal.resume"===r.type){if(!i.resumeTerminalId||i.resumeTerminalId!==n)throw new Error("terminal resume id mismatch");return await this.journal.resume(i),{frame:r,admission:{recovered:!0}}}return await this.journal.assertBound(n,i),{frame:r,admission:{recovered:!1}}}}const VALIDATION_TERMINAL_ID="018f0000-0000-7000-8000-0000000000f0";function isRecord(r){return null!==r&&"object"==typeof r&&!Array.isArray(r)}
@@ -1 +1 @@
1
- import{createHash}from"node:crypto";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";export const TERMINAL_AUTHORITY_SCHEMA_VERSION=1;export const TERMINAL_AUTHORITY_CONTRACT_REVISION="beeos.terminal-authority.v1";export const TERMINAL_AUTHORITY_SCHEMA_HASH="e1e1acbf9d3c7a8ee2377e7224d327b1a136069de7024c71e229702e997cdcea";export const TERMINAL_AUTHORITY_CONTRACT_DIGEST="88eaec1ec16ab48462c81b58a6c65920ba721e9f7adf074f6467373075950c8f";export const TERMINAL_AUTHORITY_CANONICALIZATION_REVISION="rfc8785-jcs";export const TERMINAL_AUTHORITY_HASH_PREIMAGE_RULE="JCS(authority with ticketProof and authorityHash omitted)";export const TERMINAL_AUTHORITY_CLOCK_SKEW_MS=5e3;export const TERMINAL_AUTHORITY_MAX_LIFETIME_MS=6e4;const HEX_256=/^[0-9a-f]{64}$/,RFC3339_NANO=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$/,NANOS_PER_MILLISECOND=1000000n,REQUIRED_KEYS=["schemaVersion","contractRevision","schemaHash","userId","instanceId","platformAgentId","clientId","ticketId","ticketProof","ticketProofHash","issuedAt","expiresAt","scopeHash","authorityHash"],AUTHORITY_KEYS=new Set([...REQUIRED_KEYS,"conversationId","resumeTerminalId"]);export const systemTerminalAuthorityClock=Object.freeze({now:()=>new Date});export const terminalAuthorityJcsPort=Object.freeze({revision:"rfc8785-jcs",canonicalize:t=>canonicalizeJcs(t),hash:t=>sha256(canonicalizeJcs(t))});export function verifyTerminalAuthorityGolden(t){if("beeos.terminal-authority.v1.golden"!==t.format||"rfc8785-jcs"!==t.canonicalization||"sha256"!==t.hashAlgorithm||t.contractDigest!==TERMINAL_AUTHORITY_CONTRACT_DIGEST||1!==t.contract.schemaVersion||"beeos.terminal-authority.v1"!==t.contract.contractRevision||t.contract.schemaHash!==TERMINAL_AUTHORITY_SCHEMA_HASH||t.contract.authorityHashPreimageRule!==TERMINAL_AUTHORITY_HASH_PREIMAGE_RULE||sha256(t.contract.schemaCanonicalJson)!==TERMINAL_AUTHORITY_SCHEMA_HASH||terminalAuthorityJcsPort.hash(t.contract)!==t.contractDigest||0===t.fixtures.length)throw new Error("terminal authority JCS golden contract mismatch");for(const e of t.fixtures){const t=authorityHashPreimage(e.authority);if(terminalAuthorityJcsPort.canonicalize(JSON.parse(e.authorityHashPreimageJson))!==t||t!==e.authorityCanonicalJson||sha256(t)!==e.authorityHash||e.authorityHash!==e.authority.authorityHash)throw new Error(`terminal authority JCS golden fixture mismatch: ${e.name}`)}}export function verifyTerminalAuthority(t,e=systemTerminalAuthorityClock){if(!isPlainObject(t)||Object.keys(t).some(t=>!AUTHORITY_KEYS.has(t))||REQUIRED_KEYS.some(e=>!(e in t)))throw new Error("terminal authority schema mismatch");const r=t;if(1!==r.schemaVersion||"beeos.terminal-authority.v1"!==r.contractRevision||r.schemaHash!==TERMINAL_AUTHORITY_SCHEMA_HASH)throw new Error("terminal authority contract mismatch");const i=requireString(r.userId,256,"userId"),o=requireString(r.instanceId,128,"instanceId"),n=requireString(r.platformAgentId,128,"platformAgentId"),a=optionalString(r.conversationId,128,"conversationId"),s=requireString(r.clientId,128,"clientId"),c=requireString(r.ticketId,128,"ticketId"),h=requireString(r.ticketProof,8192,"ticketProof"),u=requireDigest(r.ticketProofHash,"ticketProofHash"),m=requireTimestamp(r.issuedAt,"issuedAt"),I=requireTimestamp(r.expiresAt,"expiresAt"),l=optionalString(r.resumeTerminalId,128,"resumeTerminalId"),d=requireDigest(r.scopeHash,"scopeHash"),A=requireDigest(r.authorityHash,"authorityHash"),f=timestampNanos(m),T=timestampNanos(I),H=e.now().getTime();if(!Number.isFinite(H))throw new Error("terminal authority clock is invalid");const E=1000000n*BigInt(Math.trunc(H));if(T<=f)throw new Error("terminal authority time range is invalid");if(T-f>1000000n*BigInt(6e4))throw new Error("terminal authority lifetime exceeds maximum");if(f>E+1000000n*BigInt(5e3))throw new Error("terminal authority issue time is in the future");if(T<=E)throw new Error("terminal authority has expired");if(sha256(h)!==u)throw new Error("terminal authority ticket proof mismatch");const y=authorityHashPreimage(r);if(sha256(y)!==A)throw new Error("terminal authority integrity mismatch");return Object.freeze({schemaVersion:1,contractRevision:"beeos.terminal-authority.v1",schemaHash:TERMINAL_AUTHORITY_SCHEMA_HASH,userId:i,instanceId:o,platformAgentId:n,conversationId:a,clientId:s,ticketId:c,issuedAt:m,expiresAt:I,resumeTerminalId:l,scopeHash:d,authorityHash:A,terminalBindingHash:sha256(["terminal-binding-v1",i,o,n,a,s,c].join("\0"))})}export function authorityHashPreimage(t){const e=t,r={schemaVersion:e.schemaVersion,contractRevision:e.contractRevision,schemaHash:e.schemaHash,userId:e.userId,instanceId:e.instanceId,platformAgentId:e.platformAgentId,...e.conversationId?{conversationId:e.conversationId}:{},clientId:e.clientId,ticketId:e.ticketId,ticketProofHash:e.ticketProofHash,issuedAt:e.issuedAt,expiresAt:e.expiresAt,...e.resumeTerminalId?{resumeTerminalId:e.resumeTerminalId}:{},scopeHash:e.scopeHash};return terminalAuthorityJcsPort.canonicalize(r)}export const sha256=t=>createHash("sha256").update(t,"utf8").digest("hex");function requireString(t,e,r){if("string"!=typeof t||t.length<1||t.length>e||hasLoneSurrogate(t))throw new Error(`terminal authority ${r} is invalid`);return t}function optionalString(t,e,r){if(void 0===t)return"";if("string"!=typeof t||t.length>e||hasLoneSurrogate(t))throw new Error(`terminal authority ${r} is invalid`);return t}function requireDigest(t,e){if("string"!=typeof t||!HEX_256.test(t))throw new Error(`terminal authority ${e} is invalid`);return t}function requireTimestamp(t,e){if("string"!=typeof t||!RFC3339_NANO.test(t)||!Number.isFinite(Date.parse(t)))throw new Error(`terminal authority ${e} is invalid`);return t}function timestampNanos(t){const e=RFC3339_NANO.exec(t);if(!e)throw new Error("terminal authority timestamp is invalid");const r=Date.parse(`${e[1]}${e[3]}`),i=BigInt((e[2]??"").padEnd(9,"0"));return 1000000n*BigInt(r)+i}function isPlainObject(t){return null!==t&&"object"==typeof t&&!Array.isArray(t)&&(Object.getPrototypeOf(t)===Object.prototype||null===Object.getPrototypeOf(t))}function hasLoneSurrogate(t){for(let e=0;e<t.length;e++){const r=t.charCodeAt(e);if(r>=55296&&r<=56319){if(++e>=t.length||t.charCodeAt(e)<56320||t.charCodeAt(e)>57343)return!0}else if(r>=56320&&r<=57343)return!0}return!1}
1
+ import{createHash}from"node:crypto";import{canonicalizeJcs}from"@beeos-ai/beeos-types/runtime";export const TERMINAL_AUTHORITY_SCHEMA_VERSION=1;export const TERMINAL_AUTHORITY_CONTRACT_REVISION="beeos.terminal-authority.v1";export const TERMINAL_AUTHORITY_SCHEMA_HASH="e1e1acbf9d3c7a8ee2377e7224d327b1a136069de7024c71e229702e997cdcea";export const TERMINAL_AUTHORITY_CONTRACT_DIGEST="88eaec1ec16ab48462c81b58a6c65920ba721e9f7adf074f6467373075950c8f";export const TERMINAL_AUTHORITY_CANONICALIZATION_REVISION="rfc8785-jcs";export const TERMINAL_AUTHORITY_HASH_PREIMAGE_RULE="JCS(authority with ticketProof and authorityHash omitted)";export const TERMINAL_AUTHORITY_CLOCK_SKEW_MS=5e3;export const TERMINAL_AUTHORITY_MAX_LIFETIME_MS=6e4;const HEX_256=/^[0-9a-f]{64}$/,RFC3339_NANO=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$/,NANOS_PER_MILLISECOND=1000000n,REQUIRED_KEYS=["schemaVersion","contractRevision","schemaHash","userId","instanceId","platformAgentId","clientId","ticketId","ticketProof","ticketProofHash","issuedAt","expiresAt","scopeHash","authorityHash"],AUTHORITY_KEYS=new Set([...REQUIRED_KEYS,"conversationId","resumeTerminalId"]);export const systemTerminalAuthorityClock=Object.freeze({now:()=>new Date});export const terminalAuthorityJcsPort=Object.freeze({revision:"rfc8785-jcs",canonicalize:t=>canonicalizeJcs(t),hash:t=>sha256(canonicalizeJcs(t))});export function verifyTerminalAuthorityGolden(t){if("beeos.terminal-authority.v1.golden"!==t.format||"rfc8785-jcs"!==t.canonicalization||"sha256"!==t.hashAlgorithm||t.contractDigest!==TERMINAL_AUTHORITY_CONTRACT_DIGEST||1!==t.contract.schemaVersion||"beeos.terminal-authority.v1"!==t.contract.contractRevision||t.contract.schemaHash!==TERMINAL_AUTHORITY_SCHEMA_HASH||t.contract.authorityHashPreimageRule!==TERMINAL_AUTHORITY_HASH_PREIMAGE_RULE||sha256(t.contract.schemaCanonicalJson)!==TERMINAL_AUTHORITY_SCHEMA_HASH||terminalAuthorityJcsPort.hash(t.contract)!==t.contractDigest||0===t.fixtures.length)throw new Error("terminal authority JCS golden contract mismatch");for(const e of t.fixtures){const t=authorityHashPreimage(e.authority);if(terminalAuthorityJcsPort.canonicalize(JSON.parse(e.authorityHashPreimageJson))!==t||t!==e.authorityCanonicalJson||sha256(t)!==e.authorityHash||e.authorityHash!==e.authority.authorityHash)throw new Error(`terminal authority JCS golden fixture mismatch: ${e.name}`)}}export function verifyTerminalAuthority(t,e=systemTerminalAuthorityClock,r="establish"){if(!isPlainObject(t)||Object.keys(t).some(t=>!AUTHORITY_KEYS.has(t))||REQUIRED_KEYS.some(e=>!(e in t)))throw new Error("terminal authority schema mismatch");const i=t;if(1!==i.schemaVersion||"beeos.terminal-authority.v1"!==i.contractRevision||i.schemaHash!==TERMINAL_AUTHORITY_SCHEMA_HASH)throw new Error("terminal authority contract mismatch");const o=requireString(i.userId,256,"userId"),n=requireString(i.instanceId,128,"instanceId"),a=requireString(i.platformAgentId,128,"platformAgentId"),s=optionalString(i.conversationId,128,"conversationId"),c=requireString(i.clientId,128,"clientId"),h=requireString(i.ticketId,128,"ticketId"),u=requireString(i.ticketProof,8192,"ticketProof"),m=requireDigest(i.ticketProofHash,"ticketProofHash"),I=requireTimestamp(i.issuedAt,"issuedAt"),l=requireTimestamp(i.expiresAt,"expiresAt"),d=optionalString(i.resumeTerminalId,128,"resumeTerminalId"),A=requireDigest(i.scopeHash,"scopeHash"),f=requireDigest(i.authorityHash,"authorityHash"),T=timestampNanos(I),H=timestampNanos(l),E=e.now().getTime();if(!Number.isFinite(E))throw new Error("terminal authority clock is invalid");const y=1000000n*BigInt(Math.trunc(E));if(H<=T)throw new Error("terminal authority time range is invalid");if(H-T>1000000n*BigInt(6e4))throw new Error("terminal authority lifetime exceeds maximum");if(T>y+1000000n*BigInt(5e3))throw new Error("terminal authority issue time is in the future");if("establish"===r&&H<=y)throw new Error("terminal authority has expired");if(sha256(u)!==m)throw new Error("terminal authority ticket proof mismatch");const p=authorityHashPreimage(i);if(sha256(p)!==f)throw new Error("terminal authority integrity mismatch");return Object.freeze({schemaVersion:1,contractRevision:"beeos.terminal-authority.v1",schemaHash:TERMINAL_AUTHORITY_SCHEMA_HASH,userId:o,instanceId:n,platformAgentId:a,conversationId:s,clientId:c,ticketId:h,issuedAt:I,expiresAt:l,resumeTerminalId:d,scopeHash:A,authorityHash:f,terminalBindingHash:sha256(["terminal-binding-v1",o,n,a,s,c,h].join("\0"))})}export function authorityHashPreimage(t){const e=t,r={schemaVersion:e.schemaVersion,contractRevision:e.contractRevision,schemaHash:e.schemaHash,userId:e.userId,instanceId:e.instanceId,platformAgentId:e.platformAgentId,...e.conversationId?{conversationId:e.conversationId}:{},clientId:e.clientId,ticketId:e.ticketId,ticketProofHash:e.ticketProofHash,issuedAt:e.issuedAt,expiresAt:e.expiresAt,...e.resumeTerminalId?{resumeTerminalId:e.resumeTerminalId}:{},scopeHash:e.scopeHash};return terminalAuthorityJcsPort.canonicalize(r)}export const sha256=t=>createHash("sha256").update(t,"utf8").digest("hex");function requireString(t,e,r){if("string"!=typeof t||t.length<1||t.length>e||hasLoneSurrogate(t))throw new Error(`terminal authority ${r} is invalid`);return t}function optionalString(t,e,r){if(void 0===t)return"";if("string"!=typeof t||t.length>e||hasLoneSurrogate(t))throw new Error(`terminal authority ${r} is invalid`);return t}function requireDigest(t,e){if("string"!=typeof t||!HEX_256.test(t))throw new Error(`terminal authority ${e} is invalid`);return t}function requireTimestamp(t,e){if("string"!=typeof t||!RFC3339_NANO.test(t)||!Number.isFinite(Date.parse(t)))throw new Error(`terminal authority ${e} is invalid`);return t}function timestampNanos(t){const e=RFC3339_NANO.exec(t);if(!e)throw new Error("terminal authority timestamp is invalid");const r=Date.parse(`${e[1]}${e[3]}`),i=BigInt((e[2]??"").padEnd(9,"0"));return 1000000n*BigInt(r)+i}function isPlainObject(t){return null!==t&&"object"==typeof t&&!Array.isArray(t)&&(Object.getPrototypeOf(t)===Object.prototype||null===Object.getPrototypeOf(t))}function hasLoneSurrogate(t){for(let e=0;e<t.length;e++){const r=t.charCodeAt(e);if(r>=55296&&r<=56319){if(++e>=t.length||t.charCodeAt(e)<56320||t.charCodeAt(e)>57343)return!0}else if(r>=56320&&r<=57343)return!0}return!1}
@@ -30,11 +30,7 @@
30
30
  "beeos_automation_get_run",
31
31
  "cron_toggle",
32
32
  "cron_run",
33
- "cron_delete",
34
- "list_connectors",
35
- "search_actions",
36
- "get_action_guide",
37
- "execute_action"
33
+ "cron_delete"
38
34
  ],
39
35
  "imageGenerationProviders": [
40
36
  "arouter"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.6.66-cloud.5",
3
+ "version": "0.6.66-cloud.6",
4
4
  "description": "OpenClaw plugin that bridges the BeeOS platform with the local OpenClaw Gateway, providing file transfer, ACP bridge, and observability.",
5
5
  "license": "MIT",
6
6
  "author": "BeeOS <dev@beeos.ai>",
@@ -88,5 +88,5 @@
88
88
  "fast-uri": ">=3.1.4",
89
89
  "brace-expansion": ">=5.0.9"
90
90
  },
91
- "gitHead": "2e2d94b544e224a005f81c54bf4ef728a730060c"
91
+ "gitHead": "9d9f39bbe34ba2159b23e4873aba08e42deed5b6"
92
92
  }
@@ -1 +0,0 @@
1
- const CONNECTOR_TOOL_NAMES=["list_connectors","search_actions","get_action_guide","execute_action"],objectSchema=(t,e)=>({type:"object",additionalProperties:!1,properties:t,...e&&e.length>0?{required:[...e]}:{}}),TOOLS={list_connectors:{description:"List the connectors enabled for this OpenClaw instance.",parameters:objectSchema({})},search_actions:{description:"Search actions exposed by enabled connectors.",parameters:objectSchema({query:{type:"string"},connectorId:{type:"string"},limit:{type:"integer"}})},get_action_guide:{description:"Get the input and output schema for one connector action.",parameters:objectSchema({actionId:{type:"string"}},["actionId"])},execute_action:{description:"Execute one connector action using the credential bound to this instance. For the Weather connector, actionId is wttr.get_weather and input is an object with location.",parameters:objectSchema({actionId:{type:"string"},input:{type:"object"}},["actionId","input"])}};function argumentsOf(t){if(null==t)return{};if("object"!=typeof t||Array.isArray(t))throw new Error("connector tool arguments must be an object");return t}function textFromContent(t){if(!Array.isArray(t))return;const e=t.flatMap(t=>{if(!t||"object"!=typeof t||!("text"in t))return[];const e=t.text;return"string"==typeof e?[e]:[]});return e.length>0?e.join("\n"):void 0}export function readableConnectorResult(t){if(!t||"object"!=typeof t)return{content:JSON.stringify(t)};const e=t;if(void 0!==e.error&&null!==e.error){const t=e.error,n=t&&"object"==typeof t&&"message"in t?String(t.message):JSON.stringify(t);throw new Error(n)}const n="result"in e?e.result:t;if(n&&"object"==typeof n){const t=n;if(!0===t.isError)throw new Error(textFromContent(t.content)||"connector tool failed");if(void 0!==t.structuredContent)return{content:JSON.stringify(t.structuredContent)};const e=textFromContent(t.content);if(void 0!==e)return{content:e}}return{content:"string"==typeof n?n:JSON.stringify(n)}}async function callConnectorTool(t,e,n,o){return readableConnectorResult(await t.connectors.callJson({jsonrpc:"2.0",id:e,method:"tools/call",params:{name:e,arguments:"list_connectors"===e?{}:argumentsOf(n)}},o?{signal:o}:void 0))}export function registerManagedConnectorTools(t,e){if(e)for(const n of CONNECTOR_TOOL_NAMES){const o=TOOLS[n];t.registerTool({name:n,description:o.description,parameters:o.parameters,execute:(t,o,r)=>callConnectorTool(e,n,o,r)})}}
@@ -1 +0,0 @@
1
- export const CONNECTOR_MCP_PROXY_PATH="/beeos/connectors/mcp";export const CONNECTOR_MCP_MAX_BODY_BYTES=262144;class RequestBodyTooLargeError extends Error{}export function isLoopbackAddress(e){return"127.0.0.1"===e||"::1"===e||"::ffff:127.0.0.1"===e}export function isLoopbackRequest(e){return isLoopbackAddress(e.socket.remoteAddress)}export function readBoundedRawBody(e,o=262144){return new Promise((r,t)=>{const n=[];let s=0,a=!1;const d=()=>{e.off("data",u),e.off("end",i),e.off("error",f),e.off("aborted",p)},c=e=>{a||(a=!0,d(),t(e))},u=r=>{const t=Buffer.isBuffer(r)?r:Buffer.from(r);if(s+=t.byteLength,s>o)return d(),e.resume(),void c(new RequestBodyTooLargeError("connector MCP request body is too large"));n.push(t)},i=()=>{a||(a=!0,d(),r(Buffer.concat(n,s)))},f=e=>c(e),p=()=>c(new Error("connector MCP request was aborted"));e.on("data",u),e.on("end",i),e.on("error",f),e.on("aborted",p)})}function writeTextResponse(e,o,r){e.statusCode=o,e.setHeader("Content-Type","text/plain; charset=utf-8"),e.end(r)}function copyRequestHeader(e,o,r){const t=e.headers[r.toLowerCase()];"string"==typeof t?o.set(r,t):Array.isArray(t)&&o.set(r,t.join(", "))}export async function handleConnectorMcpRequest(e,o,r){if(!isLoopbackRequest(e))return e.resume(),void writeTextResponse(o,403,"loopback access required");if("POST"!==e.method)return e.resume(),o.setHeader("Allow","POST"),void writeTextResponse(o,405,"method not allowed");if(e.url?.includes("?"))return e.resume(),void writeTextResponse(o,400,"query parameters are not supported");if(!r.gateway)return e.resume(),void writeTextResponse(o,503,"connector MCP proxy is not configured");let t;try{t=await readBoundedRawBody(e)}catch(e){return e instanceof RequestBodyTooLargeError?void writeTextResponse(o,413,"request body too large"):(r.logger?.warn?.(`[connector-mcp] failed to read request: ${String(e)}`),void(o.writableEnded||writeTextResponse(o,400,"invalid request body")))}const n=new Headers;copyRequestHeader(e,n,"Content-Type"),copyRequestHeader(e,n,"Accept"),copyRequestHeader(e,n,"MCP-Protocol-Version");try{const e=await r.gateway.connectors.mcp({method:"POST",headers:n,body:new Uint8Array(t)}),s=Buffer.from(await e.arrayBuffer());o.statusCode=e.status;const a=e.headers.get("content-type");a&&o.setHeader("Content-Type",a),o.end(s)}catch(e){r.logger?.warn?.(`[connector-mcp] upstream request failed: ${String(e)}`),o.writableEnded||writeTextResponse(o,502,"connector MCP upstream unavailable")}}