beeos-claw 0.3.1 → 0.3.3-staging.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +52 -5
  2. package/dist/acp-gateway/assistant-mq-lifecycle.test.js +1 -1
  3. package/dist/acp-gateway/bridge-core.js +1 -1
  4. package/dist/acp-gateway/gateway-events-cron-backfill.test.js +1 -0
  5. package/dist/acp-gateway/gateway-events-heartbeat.test.js +1 -1
  6. package/dist/acp-gateway/gateway-events.js +1 -1
  7. package/dist/acp-gateway/mcp-service.js +1 -0
  8. package/dist/acp-gateway/mcp-service.test.js +1 -0
  9. package/dist/acp-gateway/pending-user-turn-updates.test.js +1 -0
  10. package/dist/acp-gateway/session-load-inflight-user.test.js +1 -0
  11. package/dist/acp-gateway/session-load.test.js +1 -0
  12. package/dist/acp-gateway/session-state.js +1 -1
  13. package/dist/acp-gateway/session-state.test.js +1 -1
  14. package/dist/acp-gateway/transport.js +1 -1
  15. package/dist/acp-gateway/transport.test.js +1 -1
  16. package/dist/acp-gateway/types.js +1 -1
  17. package/dist/acp-server.js +1 -1
  18. package/dist/auto-reply-tokens.js +1 -0
  19. package/dist/auto-reply-tokens.test.js +1 -0
  20. package/dist/config.js +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/message-filter.js +1 -1
  23. package/dist/message-filter.test.js +1 -1
  24. package/dist/messaging/chat-envelope.js +1 -0
  25. package/dist/messaging/chat-envelope.test.js +1 -0
  26. package/dist/messaging/message-sdk.js +1 -1
  27. package/dist/openclaw-cli.js +1 -0
  28. package/dist/status.js +1 -0
  29. package/dist/surface/cron-resource.js +1 -1
  30. package/dist/surface/cron-schemas.js +1 -1
  31. package/dist/surface/index.js +1 -1
  32. package/dist/utils/mq.js +1 -1
  33. package/openclaw.plugin.json +0 -4
  34. package/package.json +2 -2
  35. package/dist/acp-gateway/session-load-concurrency.test.js +0 -1
@@ -1 +1 @@
1
- const SHARED_FIELDS=[{name:"name",label:"Task Name",inputType:"text",required:!0,placeholder:"e.g. daily-report",apiPath:"name"},{name:"description",label:"Description",inputType:"textarea",placeholder:"What does this task do?",apiPath:"description"},{name:"enabled",label:"Enabled",inputType:"toggle",defaultValue:!0,apiPath:"enabled"},{name:"scheduleKind",label:"Schedule Type",inputType:"select",required:!0,options:[{label:"Interval (every N ms)",value:"every"},{label:"Cron Expression",value:"cron"},{label:"Specific Time",value:"at"}],apiPath:"schedule.kind"},{name:"everyMs",label:"Interval (ms)",inputType:"number",placeholder:"3600000 = 1 hour",validation:{min:1e3},apiPath:"schedule.everyMs"},{name:"cronExpr",label:"Cron Expression",inputType:"text",placeholder:"e.g. 0 9 * * *",apiPath:"schedule.expr"},{name:"at",label:"Run At (ISO 8601)",inputType:"text",placeholder:"e.g. 2026-04-01T09:00:00Z",apiPath:"schedule.at"},{name:"tz",label:"Timezone",inputType:"text",placeholder:"e.g. Asia/Shanghai (optional)",apiPath:"schedule.tz"},{name:"message",label:"Agent Message",inputType:"textarea",required:!0,placeholder:"What should the agent do when this task fires?",apiPath:"payload.message"}];function cronTransformPayload(e){const a={};void 0!==e.name&&(a.name=e.name),void 0!==e.description&&(a.description=e.description),void 0!==e.enabled&&(a.enabled=e.enabled);const t=e.scheduleKind;if(t){const n={kind:t};"every"===t&&e.everyMs&&(n.everyMs=Number(e.everyMs)),"cron"===t&&e.cronExpr&&(n.expr=e.cronExpr),"at"===t&&e.at&&(n.at=e.at),e.tz&&(n.tz=e.tz),a.schedule=n}const n=e.message;if(void 0!==n){const t="isolated"===e.sessionTarget;a.payload=t?{kind:"agentTurn",message:String(n)}:{kind:"systemEvent",text:String(n)}}return a}function cronCreateTransform(e){const a=cronTransformPayload(e);return a.name||(a.name="Untitled"),void 0===a.enabled&&(a.enabled=!0),a.schedule||(a.schedule={kind:"every",everyMs:36e5}),a.sessionTarget="main",a.wakeMode="now",a.payload||(a.payload={kind:"systemEvent",text:""}),a}export const CRON_CREATE_SCHEMA={domain:"cron",operation:"create",title:"Create Scheduled Task",description:"Add a new recurring or one-time agent task.",fields:SHARED_FIELDS,submitLabel:"Create",targetRpc:"cron.add",transformPayload:cronCreateTransform};export const CRON_UPDATE_SCHEMA={domain:"cron",operation:"update",title:"Edit Scheduled Task",description:"Modify an existing scheduled task.",fields:SHARED_FIELDS,submitLabel:"Update",targetRpc:"cron.update",transformPayload:cronTransformPayload};
1
+ function buildSharedFields(e){const a=[{name:"name",label:"Task Name",inputType:"text",required:!0,placeholder:"e.g. daily-report",apiPath:"name"},{name:"description",label:"Description",inputType:"textarea",placeholder:"What does this task do?",apiPath:"description"},{name:"enabled",label:"Enabled",inputType:"toggle",defaultValue:!0,apiPath:"enabled"},{name:"sessionTarget",label:"Execution Mode",inputType:"select",required:!0,defaultValue:"isolated",options:[{label:"Independent (isolated)",value:"isolated"},{label:"Main session",value:"main"}]},{name:"deliveryMode",label:"Result Delivery",inputType:"select",required:!0,defaultValue:"internal",options:[{label:"Internal (BeeOS IM channel)",value:"internal"},...e.length>0?[{label:"Channel (Telegram/Discord/…)",value:"announce"}]:[],{label:"Webhook",value:"webhook"},{label:"None (log only)",value:"none"}]}];return e.length>0&&a.push({name:"deliveryChannel",label:"Delivery Channel",inputType:"select",options:e}),a.push({name:"webhookUrl",label:"Webhook URL",inputType:"url",placeholder:"https://example.com/webhook"},{name:"scheduleKind",label:"Schedule Type",inputType:"select",required:!0,options:[{label:"Interval (every N ms)",value:"every"},{label:"Cron Expression",value:"cron"},{label:"Specific Time",value:"at"}],apiPath:"schedule.kind"},{name:"everyMs",label:"Interval (ms)",inputType:"number",placeholder:"3600000 = 1 hour",validation:{min:1e3},apiPath:"schedule.everyMs"},{name:"cronExpr",label:"Cron Expression",inputType:"text",placeholder:"e.g. 0 9 * * *",apiPath:"schedule.expr"},{name:"at",label:"Run At (ISO 8601)",inputType:"text",placeholder:"e.g. 2026-04-01T09:00:00Z",apiPath:"schedule.at"},{name:"tz",label:"Timezone",inputType:"text",placeholder:"e.g. Asia/Shanghai (optional)",apiPath:"schedule.tz"},{name:"message",label:"Agent Message",inputType:"textarea",required:!0,placeholder:"What should the agent do when this task fires?",apiPath:"payload.message"}),a}function cronTransformPayload(e){const a={};void 0!==e.name&&(a.name=e.name),void 0!==e.description&&(a.description=e.description),void 0!==e.enabled&&(a.enabled=e.enabled);const n=e.scheduleKind;if(n){const l={kind:n};"every"===n&&e.everyMs&&(l.everyMs=Number(e.everyMs)),"cron"===n&&e.cronExpr&&(l.expr=e.cronExpr),"at"===n&&e.at&&(l.at=e.at),e.tz&&(l.tz=e.tz),a.schedule=l}const l=e.deliveryMode??"internal",t=e.sessionTarget??"isolated",o=e.message;switch(l){case"internal":a.sessionTarget="isolated",a.delivery={mode:"none"},a._beeos_internal=!0,void 0!==o&&(a.payload={kind:"agentTurn",message:String(o)});break;case"announce":a.sessionTarget="isolated",a.delivery={mode:"announce",...e.deliveryChannel?{channel:e.deliveryChannel}:{}},void 0!==o&&(a.payload={kind:"agentTurn",message:String(o)});break;case"webhook":a.sessionTarget="isolated",a.delivery={mode:"webhook",...e.webhookUrl?{to:e.webhookUrl}:{}},void 0!==o&&(a.payload={kind:"agentTurn",message:String(o)});break;default:if(a.sessionTarget=t,a.delivery={mode:"none"},void 0!==o){const e="isolated"===t;a.payload=e?{kind:"agentTurn",message:String(o)}:{kind:"systemEvent",text:String(o)}}}return a}function cronCreateTransform(e){const a=cronTransformPayload(e);return a.name||(a.name="Untitled"),void 0===a.enabled&&(a.enabled=!0),a.schedule||(a.schedule={kind:"every",everyMs:36e5}),a.sessionTarget||(a.sessionTarget="isolated"),a.wakeMode="now",a.payload||(a.payload={kind:"agentTurn",message:""}),a.delivery||(a.delivery={mode:"none"}),void 0===a._beeos_internal&&(a._beeos_internal=!0),a}export function buildCronSchemas(e){const a=buildSharedFields([...e].map(e=>({label:e.charAt(0).toUpperCase()+e.slice(1),value:e})));return{create:{domain:"cron",operation:"create",title:"Create Scheduled Task",description:"Add a new recurring or one-time agent task.",fields:a,submitLabel:"Create",targetRpc:"cron.add",transformPayload:cronCreateTransform},update:{domain:"cron",operation:"update",title:"Edit Scheduled Task",description:"Modify an existing scheduled task.",fields:a,submitLabel:"Update",targetRpc:"cron.update",transformPayload:cronTransformPayload}}}
@@ -1 +1 @@
1
- export{FormSchemaRegistry}from"./form-schema-registry.js";export{FormSurfaceBuilder}from"./form-surface-builder.js";export{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./render-form-tool.js";export{ResourceDescriptorRegistry}from"./resource-descriptor-registry.js";export{ResourceSurfaceRenderer}from"./resource-surface-renderer.js";export{generateActionTools}from"./action-tool-generator.js";export{CRON_CREATE_SCHEMA,CRON_UPDATE_SCHEMA}from"./cron-schemas.js";export{CRON_RESOURCE}from"./cron-resource.js";
1
+ export{FormSchemaRegistry}from"./form-schema-registry.js";export{FormSurfaceBuilder}from"./form-surface-builder.js";export{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./render-form-tool.js";export{ResourceDescriptorRegistry}from"./resource-descriptor-registry.js";export{ResourceSurfaceRenderer}from"./resource-surface-renderer.js";export{generateActionTools}from"./action-tool-generator.js";export{buildCronSchemas}from"./cron-schemas.js";export{CRON_RESOURCE}from"./cron-resource.js";
package/dist/utils/mq.js CHANGED
@@ -1 +1 @@
1
- export class MessageQueue{messages=[];waiters=[];_closed=!1;get closed(){return this._closed}push(s){if(this._closed)return;this.messages.push(s);const e=this.waiters;this.waiters=[],e.forEach(s=>s())}async read(s){return this._closed?null:s<this.messages.length?this.messages.slice(s):new Promise(e=>{this.waiters.push(()=>{this._closed?e(null):e(this.messages.slice(s))})})}peek(s){return this._closed||s>=this.messages.length?[]:this.messages.slice(s)}close(){this._closed=!0;const s=this.waiters;this.waiters=[],s.forEach(s=>s())}}
1
+ export class MessageQueue{messages=[];_closed=!1;get closed(){return this._closed}push(s){this._closed||this.messages.push(s)}peek(s){return this._closed||s>=this.messages.length?[]:this.messages.slice(s)}close(){this._closed=!0}}
@@ -53,10 +53,6 @@
53
53
  "promptTimeoutMs": {
54
54
  "type": "number",
55
55
  "description": "Timeout for LLM prompt responses in milliseconds"
56
- },
57
- "historyPendingTimeoutMs": {
58
- "type": "number",
59
- "description": "Timeout for history replay pending state in milliseconds"
60
56
  }
61
57
  }
62
58
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.3.1",
3
+ "version": "0.3.3-staging.0",
4
4
  "description": "OpenClaw plugin that bridges the BeeOS platform with the local OpenClaw Gateway, providing file transfer, ACP bridge, and observability.",
5
5
  "license": "MIT",
6
6
  "author": "BeeOS <dev@beeos.ai>",
@@ -38,7 +38,7 @@
38
38
  "test:watch": "vitest"
39
39
  },
40
40
  "dependencies": {
41
- "@beeos-ai/beeos-types": "^0.1.0-beta.4",
41
+ "@beeos-ai/beeos-types": "^1.0.0",
42
42
  "@beeos-ai/bridge-client": "^0.1.0",
43
43
  "adm-zip": "^0.5.17",
44
44
  "centrifuge": "^5.5.3",
@@ -1 +0,0 @@
1
- import{describe,it,expect,vi,beforeEach}from"vitest";import{AcpGatewayBridgeCore}from"./bridge-core.js";import{AcpGatewaySessionState}from"./session-state.js";import{AcpTransport}from"./transport.js";import{MessageQueue}from"../utils/mq.js";function makeLogger(){return{info:vi.fn(),warn:vi.fn(),debug:vi.fn(),error:vi.fn()}}function makeConfig(){return{agentGatewayUrl:"http://localhost:0",keyFile:"/tmp/key",bridge:{url:"",service:"bridge",shell:{enabled:!1}},gateway:{url:"",token:"",protocol:1,clientId:"c",agentId:"main"},retry:{baseMs:100,maxMs:1e3,maxAttempts:0},log:{enabled:!1,verbose:!1,dir:"/tmp"},promptTimeoutMs:6e4,terminalWsPort:0,terminalWsAllowedOrigins:[],streamIdleTimeoutMs:6e4,streamStaleTimeoutMs:6e4,loadReplayIdleTimeoutMs:10,cronFlushTimeoutMs:5e3,cronSignalWindowMs:5e3,canvasRelayUrl:"",canvasEnabled:!1,openclawCanvasCompat:!1,messageBus:{enabled:!1,serviceUrl:"",url:"",principalId:"",a2aEnabled:!1}}}function buildCore(){const e=makeLogger(),s=vi.fn(),o=new AcpGatewaySessionState(e),t=vi.fn(),a=new AcpTransport(t,s);return{core:new AcpGatewayBridgeCore({state:o,transport:a,config:makeConfig(),logger:e,writeObs:s,getGateway:()=>null,instanceId:"test-instance"}),state:o,transport:a,logger:e,writeObs:s,sendBridgeMessage:t}}function registerOpenMqSession(e,s,o="session:test-1"){const t={sessionId:o,gatewaySessionKey:`agent:main:${o}`,agentId:"main",createdAt:Date.now(),chatReplayDedupKeys:new Set,assistantMq:new MessageQueue,promptDone:!0};return s.sessions.set(t.sessionId,t),s.sessionsByGatewayKey.set(t.gatewaySessionKey,t),t}async function callSessionLoad(e,s,o){const t={jsonrpc:"2.0",id:s,method:"session/load",params:{sessionId:o}};await e.handleSessionLoad(t)}describe("handleSessionLoad — concurrent load serialization (Bug-AW)",()=>{let e;beforeEach(()=>{e=buildCore()}),it("holds the per-session lock across the full replay lifecycle (no overlap)",async()=>{const s=registerOpenMqSession(e.core,e.state),o=e.core._loadSessionLock,t=vi.spyOn(e.core,"replayCurrentAssistantStream"),a=callSessionLoad(e.core,1,s.sessionId),n=callSessionLoad(e.core,2,s.sessionId);await Promise.resolve(),expect(o.has(s.sessionId)).toBe(!0),await a,await n;const i=e.sendBridgeMessage.mock.calls.filter(e=>void 0!==e[0]?.result);expect(i).toHaveLength(2),expect(i.map(e=>e[0].id).sort()).toEqual([1,2]),expect(t).toHaveBeenCalledTimes(2);const r=[],c=[];t.mockRestore(),vi.spyOn(e.core,"replayCurrentAssistantStream").mockImplementation(async function(...e){const s=Date.now();r.push(s),await new Promise(e=>setTimeout(e,30)),c.push(Date.now())}),e.sendBridgeMessage.mockClear();const l=callSessionLoad(e.core,3,s.sessionId),d=callSessionLoad(e.core,4,s.sessionId);await Promise.all([l,d]),expect(r).toHaveLength(2),expect(c).toHaveLength(2),expect(r[1]).toBeGreaterThanOrEqual(c[0])}),it("releases the lock once replay has finished so later loads can proceed",async()=>{const s=registerOpenMqSession(e.core,e.state),o=e.core._loadSessionLock;await callSessionLoad(e.core,1,s.sessionId),expect(o.has(s.sessionId)).toBe(!1),e.sendBridgeMessage.mockClear(),await callSessionLoad(e.core,2,s.sessionId);const t=e.sendBridgeMessage.mock.calls.filter(e=>void 0!==e[0]?.result);expect(t).toHaveLength(1),expect(t[0][0].id).toBe(2),expect(o.has(s.sessionId)).toBe(!1)}),it("does not deadlock when assistantMq is closed (no replay branch)",async()=>{const s=registerOpenMqSession(e.core,e.state,"session:closed");s.assistantMq.close(),await callSessionLoad(e.core,1,s.sessionId);const o=e.core._loadSessionLock;expect(o.has(s.sessionId)).toBe(!1);const t=e.sendBridgeMessage.mock.calls.filter(e=>void 0!==e[0]?.result);expect(t).toHaveLength(1)})});