aws-runtime-bridge 1.9.162 → 1.9.169

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 (123) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +31 -3
  3. package/dist/adapter/AcodeSdkAdapter.js +4 -9
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
  5. package/dist/adapter/ClaudeSdkAdapter.js +3 -3
  6. package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
  7. package/dist/adapter/CodexSdkAdapter.js +3 -3
  8. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  9. package/dist/adapter/OpencodeSdkAdapter.js +3 -3
  10. package/dist/adapter/prompts.d.ts +1 -1
  11. package/dist/adapter/prompts.js +1 -1
  12. package/dist/adapter/types.d.ts +41 -4
  13. package/dist/adapter/types.js +1 -1
  14. package/dist/browser/frame-encode.d.ts +25 -0
  15. package/dist/browser/frame-encode.js +2 -0
  16. package/dist/browser/screencast-differ.d.ts +2 -3
  17. package/dist/browser/screencast-differ.js +1 -1
  18. package/dist/browser/screencast-manager.js +1 -1
  19. package/dist/browser/types.d.ts +5 -1
  20. package/dist/browser/types.js +1 -1
  21. package/dist/desktop/desktop-mcp-client.js +2 -2
  22. package/dist/routes/background-tasks.js +3 -3
  23. package/dist/routes/capabilities.js +1 -1
  24. package/dist/routes/dashboard.d.ts +2 -0
  25. package/dist/routes/dashboard.js +4 -4
  26. package/dist/routes/git.js +22 -22
  27. package/dist/routes/instance.js +1 -1
  28. package/dist/routes/launch.js +10 -10
  29. package/dist/routes/mcp-extra.js +2 -2
  30. package/dist/routes/mcp.d.ts +4 -0
  31. package/dist/routes/mcp.js +1 -1
  32. package/dist/routes/plugins.js +1 -1
  33. package/dist/routes/pty.d.ts +11 -3
  34. package/dist/routes/pty.js +3 -3
  35. package/dist/routes/runtime-binding.js +1 -1
  36. package/dist/routes/sessions.js +1 -1
  37. package/dist/routes/skills.js +1 -1
  38. package/dist/routes/sub-agents.js +8 -8
  39. package/dist/routes/terminal.d.ts +16 -2
  40. package/dist/routes/terminal.js +34 -36
  41. package/dist/services/agent-process-manager.js +1 -1
  42. package/dist/services/agent-pty-manager.js +4 -4
  43. package/dist/services/aws-client-agent-mcp.js +2 -2
  44. package/dist/services/capability-config.d.ts +8 -0
  45. package/dist/services/capability-config.js +2 -2
  46. package/dist/services/desktop-mcp-manager.d.ts +3 -1
  47. package/dist/services/desktop-mcp-manager.js +1 -1
  48. package/dist/services/instance-ai-config-service.js +1 -1
  49. package/dist/services/instance-features.d.ts +10 -0
  50. package/dist/services/instance-features.js +1 -1
  51. package/dist/services/instance-init-service.js +1 -1
  52. package/dist/services/launch-manager.d.ts +9 -1
  53. package/dist/services/launch-manager.js +6 -6
  54. package/dist/services/launch-metrics.d.ts +1 -1
  55. package/dist/services/launch-metrics.js +4 -3
  56. package/dist/services/mcp-deploy.d.ts +4 -0
  57. package/dist/services/mcp-env-injector.d.ts +12 -0
  58. package/dist/services/mcp-env-injector.js +2 -0
  59. package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
  60. package/dist/services/mcp-launch-binding-queue.js +1 -1
  61. package/dist/services/orphan-monitor.js +1 -1
  62. package/dist/services/panel-env.d.ts +6 -2
  63. package/dist/services/panel-env.js +1 -1
  64. package/dist/services/plugin-manager.js +9 -9
  65. package/dist/services/process-detector.d.ts +23 -3
  66. package/dist/services/process-detector.js +13 -13
  67. package/dist/services/runtime-resources-snapshot.d.ts +3 -0
  68. package/dist/services/runtime-resources-snapshot.js +3 -0
  69. package/dist/services/session-output.d.ts +13 -0
  70. package/dist/services/session-output.js +4 -4
  71. package/dist/services/tunnel-client.js +1 -1
  72. package/dist/services/workspace-files.js +1 -1
  73. package/dist/types.d.ts +4 -0
  74. package/dist/utils/env-safety.d.ts +15 -0
  75. package/dist/utils/env-safety.js +2 -0
  76. package/dist/utils/lifecycle-log.d.ts +2 -0
  77. package/dist/utils/lifecycle-log.js +3 -0
  78. package/dist/utils/mcp-utils.js +1 -1
  79. package/package/acode/dist/background-command-manager.js +4 -4
  80. package/package/acode/dist/built-in-file-tools.d.ts +13 -0
  81. package/package/acode/dist/built-in-file-tools.js +2 -2
  82. package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
  83. package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
  84. package/package/acode/dist/compaction.d.ts +10 -0
  85. package/package/acode/dist/compaction.js +6 -6
  86. package/package/acode/dist/context-overflow.js +1 -1
  87. package/package/acode/dist/index.d.ts +1 -0
  88. package/package/acode/dist/index.js +1 -1
  89. package/package/acode/dist/mcpToolNames.d.ts +4 -0
  90. package/package/acode/dist/mcpToolNames.js +1 -1
  91. package/package/acode/dist/runtime-environment.d.ts +2 -0
  92. package/package/acode/dist/runtime-environment.js +3 -2
  93. package/package/acode/dist/runtime.d.ts +68 -8
  94. package/package/acode/dist/runtime.js +28 -27
  95. package/package/acode/dist/sub-agent-manager.js +1 -1
  96. package/package/acode/dist/tool-allocation.js +1 -1
  97. package/package/acode/dist/tool-group-manager.d.ts +12 -0
  98. package/package/acode/dist/tool-group-manager.js +8 -4
  99. package/package/acode/dist/types.d.ts +8 -0
  100. package/package/acode/package.json +1 -1
  101. package/package/aws-client-agent-mcp/README.md +1 -0
  102. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +22 -8
  103. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  104. package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
  105. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  106. package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
  107. package/package/aws-client-agent-mcp/dist/logger.js +2 -2
  108. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +19 -2
  109. package/package/aws-client-agent-mcp/dist/mcp-server.js +18 -18
  110. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +15 -4
  111. package/package/aws-client-agent-mcp/dist/mcp-tools.js +79 -29
  112. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
  113. package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
  114. package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
  115. package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +15 -0
  116. package/package/aws-client-agent-mcp/dist/office/office-workspace.js +1 -1
  117. package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
  118. package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
  119. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  120. package/package/aws-client-agent-mcp/dist/types.d.ts +52 -1
  121. package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
  122. package/package/aws-client-agent-mcp/package.json +1 -1
  123. package/package.json +1 -1
@@ -151,6 +151,8 @@ export interface MemoryStorePort {
151
151
  }
152
152
  export declare class MemoryStore implements MemoryStorePort {
153
153
  private readonly storePath;
154
+
155
+ private readonly domainJsonCache;
154
156
  constructor(storePath: string);
155
157
  private nowIso;
156
158
  private normalizeUri;
@@ -1,4 +1,4 @@
1
- const E=["recently_memory","agent_memory","project_memory","session_context"],h=["recently_memory","agent_memory"],C=64,R=32,Y=128,$=64,P=1024;function L(_){const e=String(_||"").trim().replace(/\\/g,"/");if(!e)return e;const r=e.startsWith("@/")?e.substring(1):e;return r.startsWith("./")?r:`./${r.replace(/^\/+/,"")}`}class T extends Error{details;constructor(e,r){super(e),this.name="MemoryCapacityError",this.details=r}}const b=/^([a-zA-Z_][a-zA-Z0-9_]*):\/\/(.*)$/,g="local",S=50,x=10;function D(_){const e=(_||"").trim();return e?e.split("|").map(r=>r.trim()).filter(Boolean).map(r=>r.split(/\s+/).filter(Boolean)):[]}function O(_,e){return _.length===0?!1:_.some(r=>r.every(i=>e.includes(i)))}class p{storePath;constructor(e){this.storePath=e}nowIso(){return new Date().toISOString()}normalizeUri(e){const r=String(e||"").trim(),i=b.exec(r);if(!i)throw new Error(`Invalid memory uri: ${e}`);const o=i[1],t=i[2];if(!o||!t)throw new Error(`Invalid memory uri: ${e}`);const n=o.toLowerCase(),c=t.replace(/^\/+|\/+$/g,"");if(!c)throw new Error(`Invalid memory uri path: ${e}`);return{uri:`${n}://${c}`,domain:n,path:c}}normalizeMemoryType(e,r=E){const i=String(e||"").trim();if(!r.includes(i))throw new Error(`Invalid memory_type: ${e}`);return i}ensureTypeMatch(e,r){if(r&&e.memory_type!==r)throw new Error(`Memory type mismatch: expected ${r}, actual ${e.memory_type}`)}async ensureStoreDir(){const{mkdir:e}=await import("node:fs/promises");await e(this.storePath,{recursive:!0})}async loadMemoryFile(e){const{readFile:r}=await import("node:fs/promises");try{const i=await r(e,"utf-8"),o=JSON.parse(i),t=o.by_uri&&typeof o.by_uri=="object"?o.by_uri:{},n={};for(const[c,a]of Object.entries(t)){const s=this.normalizeMemoryType(a.memory_type||"project_memory"),d=this.normalizeUri(a.uri||c),m=a;let l=m.memory_status;l||(m.update_status==="updating"?l="updating":m.recall_status==="recalling"?l="recalling":l="normal");const u={...a};delete u.update_status,delete u.recall_status,n[d.uri]={...u,uri:d.uri,domain:d.domain,path:d.path,memory_type:s,memory_status:l}}return{by_uri:n}}catch{return{by_uri:{}}}}async loadData(){const{readdir:e}=await import("node:fs/promises"),r=await import("node:path");try{const i=await e(this.storePath,{withFileTypes:!0}),o={by_uri:{}};for(const t of i){if(!t.isFile()||!t.name.endsWith(".json"))continue;const n=await this.loadMemoryFile(r.join(this.storePath,t.name));Object.assign(o.by_uri,n.by_uri)}return o}catch{return{by_uri:{}}}}async writeJsonAtomically(e,r){const{rename:i,rm:o,writeFile:t}=await import("node:fs/promises"),n=`${e}.${process.pid}.${Date.now()}.tmp`;try{await t(n,JSON.stringify(r,null,2),"utf-8"),await i(n,e)}catch(c){throw await o(n,{force:!0}),c}}async saveData(e){const{readdir:r,rm:i}=await import("node:fs/promises"),o=await import("node:path");await this.ensureStoreDir();const t=new Map;for(const a of Object.values(e.by_uri)){const s=t.get(a.domain)??{by_uri:{}};s.by_uri[a.uri]=a,t.set(a.domain,s)}for(const[a,s]of t.entries())await this.writeJsonAtomically(o.join(this.storePath,`${a}.json`),s);const n=new Set([...t.keys()].map(a=>`${a}.json`)),c=await r(this.storePath,{withFileTypes:!0});for(const a of c)a.isFile()&&a.name.endsWith(".json")&&!n.has(a.name)&&await i(o.join(this.storePath,a.name),{force:!0})}createEmptyStats(){return{total:0,listable:{count:0,limit:64,hardLimit:128,exceeded:!1,hardExceeded:!1},by_type:{recently_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},agent_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},project_memory:{count:0,limit:null,hardLimit:null,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}},session_context:{count:0,limit:null,hardLimit:1024,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}}}}}calculateStats(e){const r=this.createEmptyStats();for(const i of Object.values(e.by_uri)){r.total+=1;const o=r.by_type[i.memory_type];o.count+=1;const t=a=>h.includes(a)?32:null,n=a=>h.includes(a)?64:a==="session_context"?1024:null,c=o.by_domain[i.domain]??{count:0,limit:t(i.memory_type),hardLimit:n(i.memory_type),exceeded:!1,hardExceeded:!1};c.count+=1,o.by_domain[i.domain]=c,h.includes(i.memory_type)&&(r.listable.count+=1)}r.listable.exceeded=r.listable.count>r.listable.limit,r.listable.hardExceeded=r.listable.count>=r.listable.hardLimit;for(const i of E){const o=r.by_type[i];o.domainCount=Object.keys(o.by_domain).length,o.limit!==null&&o.hardLimit!==null&&(o.exceeded=o.domainCount>o.limit,o.hardExceeded=o.domainCount>=o.hardLimit);for(const t of Object.values(o.by_domain))t.limit!==null&&t.hardLimit!==null&&(t.exceeded=t.count>t.limit,t.hardExceeded=t.count>=t.hardLimit)}return r}generateId(e){return`${e.replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}_${Date.now().toString(36)}`}ensureListableMemoryCapacity(e,r,i){if(!h.includes(r))return;const t=this.calculateStats(e).by_type[r],n=t.by_domain[i.domain];if(!n&&t.domainCount>=64)throw new T(`Cannot create ${r}: hard domain type limit 64 reached. Please delete an existing ${r} domain type before creating a new ${r}.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,limit:64,current:t.domainCount,recommended_actions:[`list_memories({ memory_type: '${r}' })`,`delete_memory({ uri, memory_type: '${r}' })`]});if(n&&n.count>=64)throw new T(`Cannot create ${r}: hard memory limit 64 reached under domain ${i.domain}. Please delete or archive existing ${i.domain}://${r} memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,domain:i.domain,limit:64,current:n.count,recommended_actions:[`list_memories({ memory_type: '${r}' })`,`delete_memory({ uri, memory_type: '${r}' })`]})}ensureSessionContextCapacity(e,r,i){if(r!=="session_context")return;const o=Object.values(e.by_uri).filter(t=>t.memory_type==="session_context"&&t.domain===i.domain).length;if(o>=1024)throw new T(`Cannot create session_context: hard limit 1024 reached under domain ${i.domain}. Please delete existing session_context memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,domain:i.domain,limit:1024,current:o,recommended_actions:["list_memories({ memory_type: 'session_context' })","delete_memory({ uri, memory_type: 'session_context' })"]})}async getStats(){const e=await this.loadData();return this.calculateStats(e)}static calcAgentMemoryExpiresAt(){return new Date(Date.now()+432e5).toISOString()}static isExpirableType(e){return e==="agent_memory"||e==="recently_memory"}async createMemory(e){const r=this.normalizeMemoryType(e.memory_type),i=this.normalizeUri(e.uri),o=await this.loadData();if(o.by_uri[i.uri])throw new Error(`Memory already exists: ${i.uri}`);this.ensureListableMemoryCapacity(o,r,i),this.ensureSessionContextCapacity(o,r,i);const t=this.nowIso(),n={id:this.generateId(i.uri),uri:i.uri,domain:i.domain,path:i.path,title:e.title||void 0,content:String(e.content||""),memory_type:r,createdAt:t,updatedAt:t,version:1,keywords:e.keywords,bound_files:e.bound_files,file_md5_map:e.file_md5_map||void 0,updating_agent_id:void 0,last_check_time:e.last_check_time||void 0,expiresAt:e.expiresAt||(p.isExpirableType(r)?p.calcAgentMemoryExpiresAt():void 0),memory_status:"normal"};return o.by_uri[i.uri]=n,await this.saveData(o),n}async readMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,t=(await this.loadData()).by_uri[r.uri]??null;return t?(this.ensureTypeMatch(t,i),t):null}async updateMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),t=o.by_uri[r.uri];if(!t)throw new Error(`Memory not found: ${r.uri}`);this.ensureTypeMatch(t,i);let n=t.content;if(typeof e.old_string=="string"&&typeof e.new_string=="string"){const m=e.old_string;if(!m)throw new Error("old_string cannot be empty when replacing");const l=n.split(m).length-1;if(l===0)throw new Error("old_string not found in memory content");if(l>1)throw new Error("old_string appears multiple times; replace is ambiguous");n=n.replace(m,e.new_string)}typeof e.append=="string"&&e.append.length>0&&(n=`${n}${e.append}`);const c=n!==t.content||typeof e.title=="string"&&e.title!==t.title,a=this.nowIso();let s=t.expiresAt;if(p.isExpirableType(t.memory_type))if(t.memory_type==="recently_memory")s=new Date(Date.now()+24*60*60*1e3).toISOString();else{const m=t.expiresAt?new Date(t.expiresAt):null,l=t.updatedAt?new Date(t.updatedAt):null,u=m&&l&&!isNaN(l.getTime())?Math.max(12*60*60*1e3,m.getTime()-l.getTime()):12*60*60*1e3;s=new Date(Date.now()+u*2).toISOString()}e.expiresAt!==void 0&&(s=e.expiresAt);const d={...t,content:n,title:e.title!==void 0?e.title:t.title,updatedAt:a,version:t.version+1,keywords:e.keywords!==void 0?e.keywords:t.keywords,bound_files:e.bound_files!==void 0?e.bound_files:t.bound_files,file_md5_map:e.file_md5_map!==void 0?e.file_md5_map:e.bound_files!==void 0?void 0:t.file_md5_map,memory_status:e.memory_status!==void 0?e.memory_status:t.memory_status==="updating"?"normal":t.memory_status||"normal",updating_agent_id:e.memory_status!==void 0?e.updating_agent_id||void 0:t.memory_status==="updating"?void 0:t.updating_agent_id,last_check_time:e.last_check_time!==void 0?e.last_check_time:t.last_check_time,expiresAt:s};return o.by_uri[r.uri]=d,await this.saveData(o),d}async deleteMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),t=o.by_uri[r.uri];return t?(this.ensureTypeMatch(t,i),delete o.by_uri[r.uri],await this.saveData(o),!0):!1}async listExpiredRecentlyMemories(){const e=await this.loadData(),r=new Date,i=[];for(const o of Object.values(e.by_uri))o.memory_type!=="agent_memory"&&o.memory_type!=="recently_memory"||o.expiresAt&&(new Date(o.expiresAt)>r||o.memory_status==="recalling"&&o.updating_agent_id!==g||i.push(o));return i.sort((o,t)=>o.expiresAt.localeCompare(t.expiresAt))}async searchMemory(e){const r=await this.loadData(),o=String(e.query||"").trim().toLowerCase(),t=e.memory_type?this.normalizeMemoryType(e.memory_type):void 0,n=typeof e.limit=="number"&&e.limit>0?e.limit:10,c=e.keywords?.map(l=>l.toLowerCase()),a=e.keyword_mode==="all"?"all":"any",s=D(o);if(s.length===0&&(!c||c.length===0))return{query:o,results:[]};const d=new Set,m=[];for(const l of Object.values(r.by_uri)){if(t&&l.memory_type!==t||d.has(l.id))continue;let u=0;if(c&&c.length>0&&l.keywords){const f=l.keywords.map(y=>y.toLowerCase());if(a==="all"){if(c.every(w=>f.includes(w)))u+=10*c.length;else if(s.length===0)continue}else for(const y of c)f.includes(y)&&(u+=10)}if(s.length>0){const f=`${l.uri}
2
- ${l.title||""}
3
- ${l.content}`.toLowerCase();if(!O(s,f)&&u===0)continue;for(const y of s){const w=y.filter(M=>f.includes(M)).length;if(w>0){const M=l.uri.toLowerCase(),I=y.filter(A=>M.includes(A)).length;u+=w+I}}}u!==0&&(d.add(l.id),m.push({score:u,record:l}))}return m.sort((l,u)=>u.score!==l.score?u.score-l.score:u.record.updatedAt.localeCompare(l.record.updatedAt)),{query:o,results:m.slice(0,n).map(l=>l.record)}}async listByType(e){const r=e==="session_context"||e==="project_memory"?E:h,i=this.normalizeMemoryType(e,r),o=await this.loadData(),t=new Set,n=[];for(const c of Object.values(o.by_uri))c.memory_type===i&&(t.has(c.id)||(t.add(c.id),n.push(c)));return n.sort((c,a)=>a.updatedAt.localeCompare(c.updatedAt)),n}async listByFile(e,r){const i=await this.loadData(),o=typeof r=="object"&&r!==null?r.memory_type:r,t=o?this.normalizeMemoryType(o):void 0,n=L(e),c=new Set,a=[];for(const s of Object.values(i.by_uri))t&&s.memory_type!==t||c.has(s.id)||s.bound_files&&s.bound_files.length>0&&s.bound_files.some(m=>L(m)===n)&&(c.add(s.id),a.push(s));return a.sort((s,d)=>d.updatedAt.localeCompare(s.updatedAt)),a}async markExpiredMemoriesRecalling(e){const r=await this.listExpiredRecentlyMemories();if(r.length===0)return{marked:0,uris:[]};const i=r.filter(s=>s.memory_status!=="recalling"),o=e?i.filter(s=>e.includes(s.uri)):i.slice(0,S);if(o.length===0){const s=r.filter(d=>d.memory_status==="recalling").map(d=>d.uri);return{marked:s.length,uris:s}}const t=await this.loadData(),n=this.nowIso(),c=new Date(Date.now()+x*60*1e3).toISOString(),a=[];for(const s of o){const d=t.by_uri[s.uri];d&&(d.memory_status="recalling",d.updating_agent_id=g,d.lease_expires_at=c,d.updatedAt=n,d.version=(d.version||1)+1,a.push(s.uri))}return a.length>0&&await this.saveData(t),{marked:a.length,uris:a}}async clearRecallingExpiredMemories(e){const r=await this.loadData(),i=new Date,o=[];for(const t of Object.values(r.by_uri))p.isExpirableType(t.memory_type)&&t.memory_status==="recalling"&&t.updating_agent_id===g&&t.expiresAt&&(new Date(t.expiresAt)>i||o.push(t.uri));if(e){const t=new Set(e),n=o.filter(c=>t.has(c));o.length=0,o.push(...n)}if(o.length===0)return{deleted:0,uris:[]};for(const t of o)delete r.by_uri[t];return await this.saveData(r),{deleted:o.length,uris:o}}async claimMemoryUpdate(e,r,i){throw new Error("claimMemoryUpdate not supported in local MemoryStore")}async renewMemoryLease(e){throw new Error("renewMemoryLease not supported in local MemoryStore")}async releaseMemoryClaim(e){throw new Error("releaseMemoryClaim not supported in local MemoryStore")}async releaseAllMemoryClaims(){throw new Error("releaseAllMemoryClaims not supported in local MemoryStore")}async getMyClaimedUris(){throw new Error("getMyClaimedUris not supported in local MemoryStore")}}export{T as MemoryCapacityError,p as MemoryStore,L as normalizeBoundFilePath};
1
+ const E=["recently_memory","agent_memory","project_memory","session_context"],h=["recently_memory","agent_memory"],C=64,R=32,Y=128,$=64,P=1024;function L(y){const e=String(y||"").trim().replace(/\\/g,"/");if(!e)return e;const t=e.startsWith("@/")?e.substring(1):e;return t.startsWith("./")?t:`./${t.replace(/^\/+/,"")}`}class T extends Error{details;constructor(e,t){super(e),this.name="MemoryCapacityError",this.details=t}}const b=/^([a-zA-Z_][a-zA-Z0-9_]*):\/\/(.*)$/,g="local",S=50,x=10;function D(y){const e=(y||"").trim();return e?e.split("|").map(t=>t.trim()).filter(Boolean).map(t=>t.split(/\s+/).filter(Boolean)):[]}function O(y,e){return y.length===0?!1:y.some(t=>t.every(i=>e.includes(i)))}class p{storePath;domainJsonCache=new Map;constructor(e){this.storePath=e}nowIso(){return new Date().toISOString()}normalizeUri(e){const t=String(e||"").trim(),i=b.exec(t);if(!i)throw new Error(`Invalid memory uri: ${e}`);const o=i[1],r=i[2];if(!o||!r)throw new Error(`Invalid memory uri: ${e}`);const a=o.toLowerCase(),s=r.replace(/^\/+|\/+$/g,"");if(!s)throw new Error(`Invalid memory uri path: ${e}`);return{uri:`${a}://${s}`,domain:a,path:s}}normalizeMemoryType(e,t=E){const i=String(e||"").trim();if(!t.includes(i))throw new Error(`Invalid memory_type: ${e}`);return i}ensureTypeMatch(e,t){if(t&&e.memory_type!==t)throw new Error(`Memory type mismatch: expected ${t}, actual ${e.memory_type}`)}async ensureStoreDir(){const{mkdir:e}=await import("node:fs/promises");await e(this.storePath,{recursive:!0})}async loadMemoryFile(e){const{readFile:t}=await import("node:fs/promises");try{const i=await t(e,"utf-8"),o=JSON.parse(i),r=o.by_uri&&typeof o.by_uri=="object"?o.by_uri:{},a={};for(const[s,d]of Object.entries(r)){const n=this.normalizeMemoryType(d.memory_type||"project_memory"),l=this.normalizeUri(d.uri||s),m=d;let c=m.memory_status;c||(m.update_status==="updating"?c="updating":m.recall_status==="recalling"?c="recalling":c="normal");const u={...d};delete u.update_status,delete u.recall_status,a[l.uri]={...u,uri:l.uri,domain:l.domain,path:l.path,memory_type:n,memory_status:c}}return{by_uri:a}}catch{return{by_uri:{}}}}async loadData(){const{readdir:e}=await import("node:fs/promises"),t=await import("node:path");try{const i=await e(this.storePath,{withFileTypes:!0}),o={by_uri:{}};for(const r of i){if(!r.isFile()||!r.name.endsWith(".json"))continue;const a=await this.loadMemoryFile(t.join(this.storePath,r.name));Object.assign(o.by_uri,a.by_uri)}return o}catch{return{by_uri:{}}}}async writeJsonAtomically(e,t,i=JSON.stringify(t,null,2)){const{rename:o,rm:r,writeFile:a}=await import("node:fs/promises"),s=`${e}.${process.pid}.${Date.now()}.tmp`;try{await a(s,i,"utf-8"),await o(s,e)}catch(d){throw await r(s,{force:!0}),d}}async saveData(e){const{readFile:t,readdir:i,rm:o}=await import("node:fs/promises"),r=await import("node:path");await this.ensureStoreDir();const a=new Map;for(const n of Object.values(e.by_uri)){const l=a.get(n.domain)??{by_uri:{}};l.by_uri[n.uri]=n,a.set(n.domain,l)}for(const[n,l]of a.entries()){const m=r.join(this.storePath,`${n}.json`),c=JSON.stringify(l,null,2);if(this.domainJsonCache.get(m)===c)continue;let _;try{_=await t(m,"utf-8")}catch{_=void 0}if(_===c){this.domainJsonCache.set(m,c);continue}await this.writeJsonAtomically(m,l,c),this.domainJsonCache.set(m,c)}const s=new Set([...a.keys()].map(n=>`${n}.json`)),d=await i(this.storePath,{withFileTypes:!0});for(const n of d)if(n.isFile()&&n.name.endsWith(".json")&&!s.has(n.name)){const l=r.join(this.storePath,n.name);await o(l,{force:!0}),this.domainJsonCache.delete(l)}}createEmptyStats(){return{total:0,listable:{count:0,limit:64,hardLimit:128,exceeded:!1,hardExceeded:!1},by_type:{recently_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},agent_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},project_memory:{count:0,limit:null,hardLimit:null,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}},session_context:{count:0,limit:null,hardLimit:1024,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}}}}}calculateStats(e){const t=this.createEmptyStats();for(const i of Object.values(e.by_uri)){t.total+=1;const o=t.by_type[i.memory_type];o.count+=1;const r=d=>h.includes(d)?32:null,a=d=>h.includes(d)?64:d==="session_context"?1024:null,s=o.by_domain[i.domain]??{count:0,limit:r(i.memory_type),hardLimit:a(i.memory_type),exceeded:!1,hardExceeded:!1};s.count+=1,o.by_domain[i.domain]=s,h.includes(i.memory_type)&&(t.listable.count+=1)}t.listable.exceeded=t.listable.count>t.listable.limit,t.listable.hardExceeded=t.listable.count>=t.listable.hardLimit;for(const i of E){const o=t.by_type[i];o.domainCount=Object.keys(o.by_domain).length,o.limit!==null&&o.hardLimit!==null&&(o.exceeded=o.domainCount>o.limit,o.hardExceeded=o.domainCount>=o.hardLimit);for(const r of Object.values(o.by_domain))r.limit!==null&&r.hardLimit!==null&&(r.exceeded=r.count>r.limit,r.hardExceeded=r.count>=r.hardLimit)}return t}generateId(e){return`${e.replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}_${Date.now().toString(36)}`}ensureListableMemoryCapacity(e,t,i){if(!h.includes(t))return;const r=this.calculateStats(e).by_type[t],a=r.by_domain[i.domain];if(!a&&r.domainCount>=64)throw new T(`Cannot create ${t}: hard domain type limit 64 reached. Please delete an existing ${t} domain type before creating a new ${t}.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,limit:64,current:r.domainCount,recommended_actions:[`list_memories({ memory_type: '${t}' })`,`delete_memory({ uri, memory_type: '${t}' })`]});if(a&&a.count>=64)throw new T(`Cannot create ${t}: hard memory limit 64 reached under domain ${i.domain}. Please delete or archive existing ${i.domain}://${t} memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,domain:i.domain,limit:64,current:a.count,recommended_actions:[`list_memories({ memory_type: '${t}' })`,`delete_memory({ uri, memory_type: '${t}' })`]})}ensureSessionContextCapacity(e,t,i){if(t!=="session_context")return;const o=Object.values(e.by_uri).filter(r=>r.memory_type==="session_context"&&r.domain===i.domain).length;if(o>=1024)throw new T(`Cannot create session_context: hard limit 1024 reached under domain ${i.domain}. Please delete existing session_context memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,domain:i.domain,limit:1024,current:o,recommended_actions:["list_memories({ memory_type: 'session_context' })","delete_memory({ uri, memory_type: 'session_context' })"]})}async getStats(){const e=await this.loadData();return this.calculateStats(e)}static calcAgentMemoryExpiresAt(){return new Date(Date.now()+432e5).toISOString()}static isExpirableType(e){return e==="agent_memory"||e==="recently_memory"}async createMemory(e){const t=this.normalizeMemoryType(e.memory_type),i=this.normalizeUri(e.uri),o=await this.loadData();if(o.by_uri[i.uri])throw new Error(`Memory already exists: ${i.uri}`);this.ensureListableMemoryCapacity(o,t,i),this.ensureSessionContextCapacity(o,t,i);const r=this.nowIso(),a={id:this.generateId(i.uri),uri:i.uri,domain:i.domain,path:i.path,title:e.title||void 0,content:String(e.content||""),memory_type:t,createdAt:r,updatedAt:r,version:1,keywords:e.keywords,bound_files:e.bound_files,file_md5_map:e.file_md5_map||void 0,updating_agent_id:void 0,last_check_time:e.last_check_time||void 0,expiresAt:e.expiresAt||(p.isExpirableType(t)?p.calcAgentMemoryExpiresAt():void 0),memory_status:"normal"};return o.by_uri[i.uri]=a,await this.saveData(o),a}async readMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,r=(await this.loadData()).by_uri[t.uri]??null;return r?(this.ensureTypeMatch(r,i),r):null}async updateMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),r=o.by_uri[t.uri];if(!r)throw new Error(`Memory not found: ${t.uri}`);this.ensureTypeMatch(r,i);let a=r.content;if(typeof e.old_string=="string"&&typeof e.new_string=="string"){const m=e.old_string;if(!m)throw new Error("old_string cannot be empty when replacing");const c=a.split(m).length-1;if(c===0)throw new Error("old_string not found in memory content");if(c>1)throw new Error("old_string appears multiple times; replace is ambiguous");a=a.replace(m,e.new_string)}typeof e.append=="string"&&e.append.length>0&&(a=`${a}${e.append}`);const s=a!==r.content||typeof e.title=="string"&&e.title!==r.title,d=this.nowIso();let n=r.expiresAt;if(p.isExpirableType(r.memory_type))if(r.memory_type==="recently_memory")n=new Date(Date.now()+24*60*60*1e3).toISOString();else{const m=r.expiresAt?new Date(r.expiresAt):null,c=r.updatedAt?new Date(r.updatedAt):null,u=m&&c&&!isNaN(c.getTime())?Math.max(12*60*60*1e3,m.getTime()-c.getTime()):12*60*60*1e3;n=new Date(Date.now()+u*2).toISOString()}e.expiresAt!==void 0&&(n=e.expiresAt);const l={...r,content:a,title:e.title!==void 0?e.title:r.title,updatedAt:d,version:r.version+1,keywords:e.keywords!==void 0?e.keywords:r.keywords,bound_files:e.bound_files!==void 0?e.bound_files:r.bound_files,file_md5_map:e.file_md5_map!==void 0?e.file_md5_map:e.bound_files!==void 0?void 0:r.file_md5_map,memory_status:e.memory_status!==void 0?e.memory_status:r.memory_status==="updating"?"normal":r.memory_status||"normal",updating_agent_id:e.memory_status!==void 0?e.updating_agent_id||void 0:r.memory_status==="updating"?void 0:r.updating_agent_id,last_check_time:e.last_check_time!==void 0?e.last_check_time:r.last_check_time,expiresAt:n};return o.by_uri[t.uri]=l,await this.saveData(o),l}async deleteMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),r=o.by_uri[t.uri];return r?(this.ensureTypeMatch(r,i),delete o.by_uri[t.uri],await this.saveData(o),!0):!1}async listExpiredRecentlyMemories(){const e=await this.loadData(),t=new Date,i=[];for(const o of Object.values(e.by_uri))o.memory_type!=="agent_memory"&&o.memory_type!=="recently_memory"||o.expiresAt&&(new Date(o.expiresAt)>t||o.memory_status==="recalling"&&o.updating_agent_id!==g||i.push(o));return i.sort((o,r)=>o.expiresAt.localeCompare(r.expiresAt))}async searchMemory(e){const t=await this.loadData(),o=String(e.query||"").trim().toLowerCase(),r=e.memory_type?this.normalizeMemoryType(e.memory_type):void 0,a=typeof e.limit=="number"&&e.limit>0?e.limit:10,s=e.keywords?.map(c=>c.toLowerCase()),d=e.keyword_mode==="all"?"all":"any",n=D(o);if(n.length===0&&(!s||s.length===0))return{query:o,results:[]};const l=new Set,m=[];for(const c of Object.values(t.by_uri)){if(r&&c.memory_type!==r||l.has(c.id))continue;let u=0;if(s&&s.length>0&&c.keywords){const _=c.keywords.map(f=>f.toLowerCase());if(d==="all"){if(s.every(w=>_.includes(w)))u+=10*s.length;else if(n.length===0)continue}else for(const f of s)_.includes(f)&&(u+=10)}if(n.length>0){const _=`${c.uri}
2
+ ${c.title||""}
3
+ ${c.content}`.toLowerCase();if(!O(n,_)&&u===0)continue;for(const f of n){const w=f.filter(M=>_.includes(M)).length;if(w>0){const M=c.uri.toLowerCase(),I=f.filter(A=>M.includes(A)).length;u+=w+I}}}u!==0&&(l.add(c.id),m.push({score:u,record:c}))}return m.sort((c,u)=>u.score!==c.score?u.score-c.score:u.record.updatedAt.localeCompare(c.record.updatedAt)),{query:o,results:m.slice(0,a).map(c=>c.record)}}async listByType(e){const t=e==="session_context"||e==="project_memory"?E:h,i=this.normalizeMemoryType(e,t),o=await this.loadData(),r=new Set,a=[];for(const s of Object.values(o.by_uri))s.memory_type===i&&(r.has(s.id)||(r.add(s.id),a.push(s)));return a.sort((s,d)=>d.updatedAt.localeCompare(s.updatedAt)),a}async listByFile(e,t){const i=await this.loadData(),o=typeof t=="object"&&t!==null?t.memory_type:t,r=o?this.normalizeMemoryType(o):void 0,a=L(e),s=new Set,d=[];for(const n of Object.values(i.by_uri))r&&n.memory_type!==r||s.has(n.id)||n.bound_files&&n.bound_files.length>0&&n.bound_files.some(m=>L(m)===a)&&(s.add(n.id),d.push(n));return d.sort((n,l)=>l.updatedAt.localeCompare(n.updatedAt)),d}async markExpiredMemoriesRecalling(e){const t=await this.listExpiredRecentlyMemories();if(t.length===0)return{marked:0,uris:[]};const i=t.filter(n=>n.memory_status!=="recalling"),o=e?i.filter(n=>e.includes(n.uri)):i.slice(0,S);if(o.length===0){const n=t.filter(l=>l.memory_status==="recalling").map(l=>l.uri);return{marked:n.length,uris:n}}const r=await this.loadData(),a=this.nowIso(),s=new Date(Date.now()+x*60*1e3).toISOString(),d=[];for(const n of o){const l=r.by_uri[n.uri];l&&(l.memory_status="recalling",l.updating_agent_id=g,l.lease_expires_at=s,l.updatedAt=a,l.version=(l.version||1)+1,d.push(n.uri))}return d.length>0&&await this.saveData(r),{marked:d.length,uris:d}}async clearRecallingExpiredMemories(e){const t=await this.loadData(),i=new Date,o=[];for(const r of Object.values(t.by_uri))p.isExpirableType(r.memory_type)&&r.memory_status==="recalling"&&r.updating_agent_id===g&&r.expiresAt&&(new Date(r.expiresAt)>i||o.push(r.uri));if(e){const r=new Set(e),a=o.filter(s=>r.has(s));o.length=0,o.push(...a)}if(o.length===0)return{deleted:0,uris:[]};for(const r of o)delete t.by_uri[r];return await this.saveData(t),{deleted:o.length,uris:o}}async claimMemoryUpdate(e,t,i){throw new Error("claimMemoryUpdate not supported in local MemoryStore")}async renewMemoryLease(e){throw new Error("renewMemoryLease not supported in local MemoryStore")}async releaseMemoryClaim(e){throw new Error("releaseMemoryClaim not supported in local MemoryStore")}async releaseAllMemoryClaims(){throw new Error("releaseAllMemoryClaims not supported in local MemoryStore")}async getMyClaimedUris(){throw new Error("getMyClaimedUris not supported in local MemoryStore")}}export{T as MemoryCapacityError,p as MemoryStore,L as normalizeBoundFilePath};
4
4
 
@@ -1,2 +1,2 @@
1
- import{logger as r}from"./logger.js";import{meetingDebugFingerprint as h,meetingDebugFingerprints as c,meetingDebugLog as f}from"./meeting-debug-log.js";const u=500;function a(n){if(n.msgId===void 0||n.msgId===null)return;const e=n.channel;if(e==="meeting")return`meeting:${n.msgId}`;if(e==="meeting_invite")return`meeting_invite:${n.msgId}`;if(e==="notification")return`notification:${n.msgId}`;if(typeof n.msgId=="number"){const s=n.roomId;return`group:${typeof s=="string"?s:""}:${n.msgId}`}return n.msgId}class M{buffer=[];resolvers=[];onMessageArrived=null;isPolling=!1;seenMsgIds=new Map;setOnMessageArrived(e){this.onMessageArrived=e}setIsPolling(e){this.isPolling=e}markSeen(e){const s=a(e);s!==void 0&&(this.seenMsgIds.set(s,Date.now()),this.cleanupSeenMsgIds())}isDuplicate(e){const s=a(e);return s===void 0?!1:this.seenMsgIds.has(s)?!0:(this.seenMsgIds.set(s,Date.now()),this.cleanupSeenMsgIds(),!1)}cleanupSeenMsgIds(){if(this.seenMsgIds.size<=u)return;let e=0;const s=this.seenMsgIds.size-u;for(const t of this.seenMsgIds.keys()){if(e>=s)break;this.seenMsgIds.delete(t),e++}}push(e){if(this.isDuplicate(e)){r.info(`[MessageBuffer] \u5FFD\u7565\u91CD\u590D\u6D88\u606F\uFF0CmsgId: ${e.msgId}`);const s=e.channel;(s==="meeting"||s==="meeting_invite")&&f("buffer.push.duplicate-blocked",`${h(e)} content=${String(e.content??"").slice(0,120)}`);return}this.buffer.push(e),r.info(`[MessageBuffer] \u6D88\u606F\u5165\u7F13\u51B2\u533A\uFF0C\u5F53\u524D\u6570\u91CF: ${this.buffer.length}`);{const s=e.channel;(s==="meeting"||s==="meeting_invite")&&f("buffer.push.enqueued",`${h(e)} content=${String(e.content??"").slice(0,120)}`)}this.isPolling&&this.onMessageArrived&&(r.info("[MessageBuffer] \u68C0\u6D4B\u5230 poll \u7B49\u5F85\u4E2D\uFF0C\u89E6\u53D1\u6D88\u606F\u5230\u8FBE\u56DE\u8C03"),this.onMessageArrived()),this.tryDispatch()}setProfileMessage(e){r.info(`[MessageBuffer] \u6536\u5230 Profile \u63A8\u9001\uFF0CdisplayName: ${e.displayName}\u3002\u8EAB\u4EFD\u4FE1\u606F\u8BF7\u901A\u8FC7 get_profile \u83B7\u53D6\u3002`)}removeProfileMessage(){r.info("[MessageBuffer] removeProfileMessage \u88AB\u8C03\u7528\uFF0C\u5F53\u524D\u65E0\u9700\u79FB\u9664\u672A\u8BFB\u8EAB\u4EFD\u6D88\u606F")}hasProfileMessage(){return!1}wakeUpWaiters(){if(f("buffer.wakeUpWaiters",`bufferSize=${this.buffer.length} waiters=${this.resolvers.length}`),this.tryDispatch(),this.buffer.length===0&&this.resolvers.length>0){const e=this.resolvers.shift();e&&(this.updatePollingState(),r.info("[MessageBuffer] wakeUpWaiters: \u5524\u9192 poll \u8D70 hydrate \u91CD\u67E5"),e({directMessages:[],groupMessages:[]}))}}getProfileMessage(){return null}updatePollingState(){this.isPolling=this.resolvers.length>0}poll(e){if(r.info(`[MessageBuffer] poll() \u88AB\u8C03\u7528\uFF0Cbuffer: ${this.buffer.length}${e?`\uFF0C\u8D85\u65F6: ${e}ms`:""}`),this.buffer.length>0){const s=this.consumeAll();return r.info(`[MessageBuffer] poll \u7ACB\u5373\u8FD4\u56DE\uFF0C\u79C1\u804A: ${s.directMessages.length}\uFF0C\u7FA4\u804A: ${s.groupMessages.length}`),Promise.resolve(s)}return this.resolvers.length===0&&(this.isPolling=!0),new Promise(s=>{let t=null,i=!1;const o=l=>{if(i)return;i=!0;const g=this.resolvers.indexOf(o);g>-1&&this.resolvers.splice(g,1),t&&(clearTimeout(t),t=null),this.updatePollingState(),r.info(`[MessageBuffer] poll \u6536\u5230\u6D88\u606F\uFF0C\u79C1\u804A: ${l.directMessages.length}\uFF0C\u7FA4\u804A: ${l.groupMessages.length}`),s(l)};this.resolvers.push(o),this.tryDispatch(),e&&e>0&&(t=setTimeout(()=>{if(i)return;i=!0;const l=this.resolvers.indexOf(o);l>-1&&this.resolvers.splice(l,1),this.updatePollingState(),r.info(`[MessageBuffer] poll \u8D85\u65F6\uFF08${e}ms\uFF09\uFF0C\u8FD4\u56DE\u7A7A\u6D88\u606F`),s({directMessages:[],groupMessages:[]})},e))})}get(){if(this.buffer.length>0){const e=this.consumeAll();return r.info(`[MessageBuffer] get \u8FD4\u56DE\u6D88\u606F\uFF0C\u79C1\u804A: ${e.directMessages.length}\uFF0C\u7FA4\u804A: ${e.groupMessages.length}`),e}return{directMessages:[],groupMessages:[]}}takeForceDirectMessages(){const e=[],s=[];for(const t of this.buffer)this.isDirectMessage(t)&&t.force===!0?(this.markSeen(t),e.push(t)):s.push(t);return this.buffer=s,e.length>0&&(r.info(`[MessageBuffer] takeForceDirectMessages \u53D6\u8D70\u5F3A\u5236\u79C1\u4FE1 ${e.length} \u6761\uFF0C\u5269\u4F59 ${s.length} \u6761`),this.tryDispatch()),{directMessages:e,groupMessages:[]}}requeue(e){const s=[...e.directMessages,...e.groupMessages];s.length!==0&&(this.buffer.unshift(...s),r.info(`[MessageBuffer] requeue \u56DE\u6EDA\u672A\u4EA4\u4ED8\u6D88\u606F ${s.length} \u6761\uFF08\u79C1\u804A ${e.directMessages.length}\uFF0C\u7FA4\u804A ${e.groupMessages.length}\uFF09\uFF0C\u5F53\u524D\u6570\u91CF: ${this.buffer.length}`),this.tryDispatch())}size(){return this.buffer.length}clear(){this.buffer=[];for(const e of this.resolvers)e({directMessages:[],groupMessages:[]});this.resolvers=[],this.isPolling=!1,this.seenMsgIds.clear()}tryDispatch(){for(;this.resolvers.length>0&&this.buffer.length>0;){const e=this.resolvers.shift();if(e){const s=this.consumeAll();e(s)}}this.updatePollingState()}consumeAll(){const e=[],s=[];for(;this.buffer.length>0;){const i=this.buffer.shift();i&&(this.markSeen(i),this.isDirectMessage(i)?e.push(i):s.push(i))}const t=e.filter(i=>i.channel==="meeting"||i.channel==="meeting_invite");return t.length>0&&f("buffer.consumeAll",`consumed=${c(t)} dm=${e.length} gm=${s.length}`),{directMessages:e,groupMessages:s}}isDirectMessage(e){const s=e.channel;return s==="meeting"||s==="meeting_invite"?!0:typeof e.msgId=="string"}}export{M as MessageBuffer};
1
+ import{logger as r}from"./logger.js";import{meetingDebugFingerprint as h,meetingDebugFingerprints as c,meetingDebugLog as f}from"./meeting-debug-log.js";const u=500;function a(n){if(n.msgId===void 0||n.msgId===null)return;const e=n.channel;if(e==="meeting")return`meeting:${n.msgId}`;if(e==="meeting_invite")return`meeting_invite:${n.msgId}`;if(e==="notification")return`notification:${n.msgId}`;if(typeof n.msgId=="number"){const s=n.roomId;return`group:${typeof s=="string"?s:""}:${n.msgId}`}return n.msgId}class M{buffer=[];resolvers=[];onMessageArrived=null;isPolling=!1;seenMsgIds=new Map;setOnMessageArrived(e){this.onMessageArrived=e}setIsPolling(e){this.isPolling=e}markSeen(e){const s=a(e);s!==void 0&&(this.seenMsgIds.set(s,Date.now()),this.cleanupSeenMsgIds())}isDuplicate(e){const s=a(e);return s===void 0?!1:this.seenMsgIds.has(s)?!0:(this.seenMsgIds.set(s,Date.now()),this.cleanupSeenMsgIds(),!1)}cleanupSeenMsgIds(){if(this.seenMsgIds.size<=u)return;let e=0;const s=this.seenMsgIds.size-u;for(const t of this.seenMsgIds.keys()){if(e>=s)break;this.seenMsgIds.delete(t),e++}}push(e){if(this.isDuplicate(e)){r.info(`[MessageBuffer] \u5FFD\u7565\u91CD\u590D\u6D88\u606F\uFF0CmsgId: ${e.msgId}`);const s=e.channel;(s==="meeting"||s==="meeting_invite")&&f("buffer.push.duplicate-blocked",`${h(e)} content=${String(e.content??"").slice(0,120)}`);return}this.buffer.push(e),r.debug(`[MessageBuffer] \u6D88\u606F\u5165\u7F13\u51B2\u533A\uFF0C\u5F53\u524D\u6570\u91CF: ${this.buffer.length}`);{const s=e.channel;(s==="meeting"||s==="meeting_invite")&&f("buffer.push.enqueued",`${h(e)} content=${String(e.content??"").slice(0,120)}`)}this.isPolling&&this.onMessageArrived&&(r.debug("[MessageBuffer] \u68C0\u6D4B\u5230 poll \u7B49\u5F85\u4E2D\uFF0C\u89E6\u53D1\u6D88\u606F\u5230\u8FBE\u56DE\u8C03"),this.onMessageArrived()),this.tryDispatch()}setProfileMessage(e){r.info(`[MessageBuffer] \u6536\u5230 Profile \u63A8\u9001\uFF0CdisplayName: ${e.displayName}\u3002\u8EAB\u4EFD\u4FE1\u606F\u8BF7\u901A\u8FC7 get_profile \u83B7\u53D6\u3002`)}removeProfileMessage(){r.info("[MessageBuffer] removeProfileMessage \u88AB\u8C03\u7528\uFF0C\u5F53\u524D\u65E0\u9700\u79FB\u9664\u672A\u8BFB\u8EAB\u4EFD\u6D88\u606F")}hasProfileMessage(){return!1}wakeUpWaiters(){if(f("buffer.wakeUpWaiters",`bufferSize=${this.buffer.length} waiters=${this.resolvers.length}`),this.tryDispatch(),this.buffer.length===0&&this.resolvers.length>0){const e=this.resolvers.shift();e&&(this.updatePollingState(),r.info("[MessageBuffer] wakeUpWaiters: \u5524\u9192 poll \u8D70 hydrate \u91CD\u67E5"),e({directMessages:[],groupMessages:[]}))}}getProfileMessage(){return null}updatePollingState(){this.isPolling=this.resolvers.length>0}poll(e){if(r.debug(`[MessageBuffer] poll() \u88AB\u8C03\u7528\uFF0Cbuffer: ${this.buffer.length}${e?`\uFF0C\u8D85\u65F6: ${e}ms`:""}`),this.buffer.length>0){const s=this.consumeAll();return r.info(`[MessageBuffer] poll \u7ACB\u5373\u8FD4\u56DE\uFF0C\u79C1\u804A: ${s.directMessages.length}\uFF0C\u7FA4\u804A: ${s.groupMessages.length}`),Promise.resolve(s)}return this.resolvers.length===0&&(this.isPolling=!0),new Promise(s=>{let t=null,i=!1;const g=l=>{if(i)return;i=!0;const o=this.resolvers.indexOf(g);o>-1&&this.resolvers.splice(o,1),t&&(clearTimeout(t),t=null),this.updatePollingState(),r.info(`[MessageBuffer] poll \u6536\u5230\u6D88\u606F\uFF0C\u79C1\u804A: ${l.directMessages.length}\uFF0C\u7FA4\u804A: ${l.groupMessages.length}`),s(l)};this.resolvers.push(g),this.tryDispatch(),e&&e>0&&(t=setTimeout(()=>{if(i)return;i=!0;const l=this.resolvers.indexOf(g);l>-1&&this.resolvers.splice(l,1),this.updatePollingState(),r.info(`[MessageBuffer] poll \u8D85\u65F6\uFF08${e}ms\uFF09\uFF0C\u8FD4\u56DE\u7A7A\u6D88\u606F`),s({directMessages:[],groupMessages:[]})},e))})}get(){if(this.buffer.length>0){const e=this.consumeAll();return r.info(`[MessageBuffer] get \u8FD4\u56DE\u6D88\u606F\uFF0C\u79C1\u804A: ${e.directMessages.length}\uFF0C\u7FA4\u804A: ${e.groupMessages.length}`),e}return{directMessages:[],groupMessages:[]}}takeForceDirectMessages(){const e=[],s=[];for(const t of this.buffer)this.isDirectMessage(t)&&t.force===!0?(this.markSeen(t),e.push(t)):s.push(t);return this.buffer=s,e.length>0&&(r.info(`[MessageBuffer] takeForceDirectMessages \u53D6\u8D70\u5F3A\u5236\u79C1\u4FE1 ${e.length} \u6761\uFF0C\u5269\u4F59 ${s.length} \u6761`),this.tryDispatch()),{directMessages:e,groupMessages:[]}}requeue(e){const s=[...e.directMessages,...e.groupMessages];s.length!==0&&(this.buffer.unshift(...s),r.info(`[MessageBuffer] requeue \u56DE\u6EDA\u672A\u4EA4\u4ED8\u6D88\u606F ${s.length} \u6761\uFF08\u79C1\u804A ${e.directMessages.length}\uFF0C\u7FA4\u804A ${e.groupMessages.length}\uFF09\uFF0C\u5F53\u524D\u6570\u91CF: ${this.buffer.length}`),this.tryDispatch())}size(){return this.buffer.length}clear(){this.buffer=[];for(const e of this.resolvers)e({directMessages:[],groupMessages:[]});this.resolvers=[],this.isPolling=!1,this.seenMsgIds.clear()}tryDispatch(){for(;this.resolvers.length>0&&this.buffer.length>0;){const e=this.resolvers.shift();if(e){const s=this.consumeAll();e(s)}}this.updatePollingState()}consumeAll(){const e=[],s=[];for(;this.buffer.length>0;){const i=this.buffer.shift();i&&(this.markSeen(i),this.isDirectMessage(i)?e.push(i):s.push(i))}const t=e.filter(i=>i.channel==="meeting"||i.channel==="meeting_invite");return t.length>0&&f("buffer.consumeAll",`consumed=${c(t)} dm=${e.length} gm=${s.length}`),{directMessages:e,groupMessages:s}}isDirectMessage(e){const s=e.channel;return s==="meeting"||s==="meeting_invite"?!0:typeof e.msgId=="string"}}export{M as MessageBuffer};
2
2
 
@@ -2,6 +2,10 @@
2
2
 
3
3
  export declare function officeKindOf(filePath: string): "docx" | "xlsx" | "pptx" | null;
4
4
 
5
+ export declare function isLegacyOfficeExt(filePath: string): boolean;
6
+
7
+ export declare function modernOfficeFileName(filePath: string): string;
8
+
5
9
  export declare function officeWorkspaceRoot(): string;
6
10
 
7
11
  export declare function resolveOfficeFile(rawFile: string, workspaceRoot?: string): string;
@@ -19,7 +23,18 @@ export interface PackedOfficeFile {
19
23
 
20
24
  export declare function packOfficeFile(rawFile: string, workspaceRoot?: string): PackedOfficeFile;
21
25
 
26
+ export declare const OFFICE_BACKUP_KEEP = 5;
27
+
28
+ export declare function backupOfficeFile(absolutePath: string, keep?: number): string | null;
29
+
22
30
  export declare function writeOfficeFileAtomic(rawFile: string, fileBase64: string, workspaceRoot?: string): {
23
31
  absolutePath: string;
24
32
  sizeKb: number;
33
+ backupPath: string | null;
34
+ };
35
+
36
+ export declare function writeOfficeFileAtomicAs(rawFile: string, targetName: string, fileBase64: string, workspaceRoot?: string): {
37
+ absolutePath: string;
38
+ sizeKb: number;
39
+ backupPath: string | null;
25
40
  };
@@ -1,2 +1,2 @@
1
- import i from"node:fs";import o from"node:path";const h={".docx":"docx",".docm":"docx",".xlsx":"xlsx",".xlsm":"xlsx",".pptx":"pptx",".pptm":"pptx"};function x(t){return h[o.extname(t).toLowerCase()]??null}function p(){return o.resolve(process.env.AWS_WORKSPACE_PATH||process.cwd())}function l(t,s=p()){const e=t.trim();if(!e)throw new Error("file \u4E0D\u80FD\u4E3A\u7A7A");return o.resolve(s,e)}const m=16*1024*1024;function E(t,s=p()){const e=l(t,s),n=o.basename(e);if(!x(e))throw new Error(`\u4E0D\u652F\u6301\u7684\u6587\u6863\u7C7B\u578B: ${t}\uFF08\u4EC5\u652F\u6301 .docx/.docm\u3001.xlsx/.xlsm\u3001.pptx/.pptm\uFF09`);let r;try{r=i.statSync(e)}catch{throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${t}\uFF08\u89E3\u6790\u4E3A ${e}\uFF09`)}if(!r.isFile())throw new Error(`\u4E0D\u662F\u666E\u901A\u6587\u4EF6: ${t}`);if(r.size>m)throw new Error(`\u6587\u4EF6\u8FC7\u5927\uFF08\u4E0A\u9650 ${Math.floor(m/1024/1024)}MB\uFF09: ${t}`);const c=i.readFileSync(e);return{absolutePath:e,fileName:n,fileBase64:c.toString("base64"),sizeKb:Math.ceil(c.length/1024)}}function d(t,s,e=p()){const n=l(t,e),r=typeof s=="string"?s.trim():"";if(!r)throw new Error("\u8FD4\u56DE\u7684\u6587\u4EF6\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u5DF2\u653E\u5F03\u5199\u56DE");if(!/^[A-Za-z0-9+/]+={0,2}$/.test(r)||r.length%4!==0)throw new Error("\u8FD4\u56DE\u7684 fileBase64 \u4E0D\u662F\u5408\u6CD5 Base64 \u5185\u5BB9");const c=Buffer.from(r,"base64");if(c.length===0)throw new Error("\u8FD4\u56DE\u7684\u6587\u4EF6\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u5DF2\u653E\u5F03\u5199\u56DE");i.mkdirSync(o.dirname(n),{recursive:!0});const f=o.join(o.dirname(n),`.${o.basename(n)}.${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}.tmp`);i.writeFileSync(f,c);try{i.renameSync(f,n)}catch(a){try{i.rmSync(f,{force:!0})}catch{}throw new Error(`\u5199\u56DE\u5931\u8D25\uFF08\u6587\u4EF6\u53EF\u80FD\u6B63\u88AB\u5176\u4ED6\u7A0B\u5E8F\u5360\u7528\uFF09: ${t} - ${a instanceof Error?a.message:String(a)}`)}return{absolutePath:n,sizeKb:Math.ceil(c.length/1024)}}export{x as officeKindOf,p as officeWorkspaceRoot,E as packOfficeFile,l as resolveOfficeFile,d as writeOfficeFileAtomic};
1
+ import f from"node:fs";import o from"node:path";const h={".docx":"docx",".docm":"docx",".xlsx":"xlsx",".xlsm":"xlsx",".pptx":"pptx",".pptm":"pptx"},u={".doc":"docx",".xls":"xlsx",".ppt":"pptx"};function E(t){const e=o.extname(t).toLowerCase();return h[e]??u[e]??null}function F(t){return u[o.extname(t).toLowerCase()]!==void 0}function B(t){const e=o.extname(t).toLowerCase(),r=u[e];return r?t.slice(0,t.length-e.length)+"."+r:t}function a(){return o.resolve(process.env.AWS_WORKSPACE_PATH||process.cwd())}function x(t,e=a()){const r=t.trim();if(!r)throw new Error("file \u4E0D\u80FD\u4E3A\u7A7A");return o.resolve(e,r)}const m=16*1024*1024;function k(t,e=a()){const r=x(t,e),n=o.basename(r);if(!E(r))throw new Error(`\u4E0D\u652F\u6301\u7684\u6587\u6863\u7C7B\u578B: ${t}\uFF08\u4EC5\u652F\u6301 .docx/.docm\u3001.xlsx/.xlsm\u3001.pptx/.pptm\uFF0C\u4EE5\u53CA\u65E7\u7248 .doc/.xls/.ppt\uFF09`);let c;try{c=f.statSync(r)}catch{throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${t}\uFF08\u89E3\u6790\u4E3A ${r}\uFF09`)}if(!c.isFile())throw new Error(`\u4E0D\u662F\u666E\u901A\u6587\u4EF6: ${t}`);if(c.size>m)throw new Error(`\u6587\u4EF6\u8FC7\u5927\uFF08\u4E0A\u9650 ${Math.floor(m/1024/1024)}MB\uFF09: ${t}`);const i=f.readFileSync(r);return{absolutePath:r,fileName:n,fileBase64:i.toString("base64"),sizeKb:Math.ceil(i.length/1024)}}const y=5,l="-backup-";function S(t,e){return new RegExp(`^${$(t)}${l}\\d{8}-\\d{6}${$(e)}$`)}function $(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function d(t=new Date){const e=r=>String(r).padStart(2,"0");return`${t.getFullYear()}${e(t.getMonth()+1)}${e(t.getDate())}-${e(t.getHours())}${e(t.getMinutes())}${e(t.getSeconds())}`}function g(t,e=y){try{if(!f.existsSync(t)||!f.statSync(t).isFile())return null;const r=o.dirname(t),n=o.extname(t),c=o.basename(t,n);let s=o.join(r,`${c}${l}${d()}${n}`),p=1;for(;f.existsSync(s);)s=o.join(r,`${c}${l}${d()}-${p++}${n}`);return f.copyFileSync(t,s),A(r,c,n,e),s}catch{return null}}function A(t,e,r,n){if(!(n<=0))try{const c=S(e,r),i=f.readdirSync(t).filter(s=>c.test(s)).sort();for(;i.length>n;){const s=i.shift();s&&f.rmSync(o.join(t,s),{force:!0})}}catch{}}function C(t,e,r=a()){const n=x(t,r),c=g(n);return{...w(n,e,t),backupPath:c}}function K(t,e,r,n=a()){const c=x(t,n),i=o.basename(e);if(!i||i==="."||i==="..")throw new Error(`\u53E6\u5B58\u76EE\u6807\u6587\u4EF6\u540D\u4E0D\u5408\u6CD5: ${e}`);const s=o.join(o.dirname(c),i),p=g(s);return{...w(s,r,t),backupPath:p}}function w(t,e,r){const n=typeof e=="string"?e.trim():"";if(!n)throw new Error("\u8FD4\u56DE\u7684\u6587\u4EF6\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u5DF2\u653E\u5F03\u5199\u56DE");if(!/^[A-Za-z0-9+/]+={0,2}$/.test(n)||n.length%4!==0)throw new Error("\u8FD4\u56DE\u7684 fileBase64 \u4E0D\u662F\u5408\u6CD5 Base64 \u5185\u5BB9");const c=Buffer.from(n,"base64");if(c.length===0)throw new Error("\u8FD4\u56DE\u7684\u6587\u4EF6\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u5DF2\u653E\u5F03\u5199\u56DE");f.mkdirSync(o.dirname(t),{recursive:!0});const i=o.join(o.dirname(t),`.${o.basename(t)}.${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}.tmp`);f.writeFileSync(i,c);try{f.renameSync(i,t)}catch(s){try{f.rmSync(i,{force:!0})}catch{}throw new Error(`\u5199\u56DE\u5931\u8D25\uFF08\u6587\u4EF6\u53EF\u80FD\u6B63\u88AB\u5176\u4ED6\u7A0B\u5E8F\u5360\u7528\uFF09: ${r} - ${s instanceof Error?s.message:String(s)}`)}return{absolutePath:t,sizeKb:Math.ceil(c.length/1024)}}export{y as OFFICE_BACKUP_KEEP,g as backupOfficeFile,F as isLegacyOfficeExt,B as modernOfficeFileName,E as officeKindOf,a as officeWorkspaceRoot,k as packOfficeFile,x as resolveOfficeFile,C as writeOfficeFileAtomic,K as writeOfficeFileAtomicAs};
2
2
 
@@ -1,4 +1,4 @@
1
- import{EventEmitter as _}from"node:events";import{logger as h}from"./logger.js";const d="[temp clipboard paste file]",g=/[A-Z]:(?:\\\\|\\)[^\r\n"'`]*?(?:\\\\|\\)mini-term-clipboard(?:\\\\|\\)paste-\d+\.txt/gi,A=/\/[^\r\n"'`]*?\/mini-term-clipboard\/paste-\d+\.txt/gi,S=/mini-term-clipboard[\\/]paste-\d+\.txt/gi,w=new Set(["aws-mcp","agents-work-studio"]),m=500;function p(s){return s.replace(g,d).replace(A,d).replace(S,d)}const y=/^(password|passwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|authorization|credential)/i;function f(s,e=0){if(e>8)return s;if(Array.isArray(s))return s.map(t=>f(t,e+1));if(s!==null&&typeof s=="object"){const t={};for(const[r,i]of Object.entries(s))typeof i=="string"&&y.test(r)?t[r]="[redacted]":t[r]=f(i,e+1);return t}return s}class u extends _{config;currentStatus="stopped";currentAction=null;constructor(e){super(),this.config=e}reportStarting(){this.updateStatus("starting")}reportRunning(){this.updateStatus("running")}reportWaitingInput(){this.updateStatus("waiting_input"),this.clearAction()}reportThinking(){this.updateStatus("thinking"),this.clearAction()}reportStopped(){this.updateStatus("stopped"),this.clearAction()}reportError(){this.updateStatus("error"),this.clearAction()}reportToolUse(e,t){const r=this.parseToolAction(e,t);this.updateStatus("tool_using",r.type,r.label,r.detail,void 0,this.formatToolInput(t))}reportToolResult(e){this.updateStatus("tool_using",this.currentAction?.type,this.currentAction?.label,this.currentAction?.detail,this.formatToolResult(e),this.currentAction?.input)}reportToolError(e){const t=e instanceof Error?e.message:String(e);this.updateStatus("error",this.currentAction?.type,this.currentAction?.label||"Tool call failed",this.currentAction?.detail,t,this.currentAction?.input),this.clearAction()}static KNOWN_MCP_TOOLS={get_colleague:"aws-mcp",get_group_rooms:"aws-mcp",get_profile:"aws-mcp",hire_colleague:"aws-mcp",send_group:"aws-mcp",send_private:"aws-mcp",poll_message:"aws-mcp",get_message:"aws-mcp",get_dm_history:"aws-mcp",get_group_history:"aws-mcp",my_task:"aws-mcp",create_task_instance_comment:"aws-mcp",submit_task_result:"aws-mcp",start_task_rollback:"aws-mcp",finish_task_rollback:"aws-mcp",reject_task:"aws-mcp",terminate_task:"aws-mcp",create_memory:"aws-mcp",read_memory:"aws-mcp",update_memory:"aws-mcp",delete_memory:"aws-mcp",search_memory:"aws-mcp",list_memories:"aws-mcp"};static canonicalizeMcpServer(e,t){const r=u.KNOWN_MCP_TOOLS[t.toLowerCase()];return r&&w.has(e.toLowerCase())?r:e}static formatMcpDetail(e,t){return e?t?`${u.canonicalizeMcpServer(e,t)}/${t}`:e:t}parseToolAction(e,t){const r=e.toLowerCase(),i=r.replace(/[_-]/g,""),a=(...n)=>{for(const c of n){if(typeof c=="string"&&c.trim())return p(c);if(Array.isArray(c)&&c.length>0){const l=c[0];if(typeof l=="string"&&l.trim())return p(l)}}};if(r.includes("skill")||r.includes("disclose"))return{type:"skill",label:"Calling skill",detail:t?.name?p(String(t.name)):void 0};const o=u.KNOWN_MCP_TOOLS[r];if(o)return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(o,e)};if(r.startsWith("mcp__")){const n=e.split("__"),c=n[1]||"",l=n.slice(2).join("__");return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(c,l)}}if(r.startsWith("mcp_")||r.includes("_mcp_"))return{type:"mcp",label:"Calling MCP",detail:e.replace(/^mcp_/,"").replace(/_/g," ")};if(r.includes("-mcp__")){const n=e.split("__"),c=n[0],l=n.slice(1).join("__");return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(c,l)}}if(i==="edit"||i==="editfile"||i==="strreplace"||i==="editcode"||i==="applypatch"||i==="multiedit")return{type:"edit_file",label:"\u7F16\u8F91\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.target_file,t?.targetFile)};if(i==="write"||i==="writefile"||i==="fswrite")return{type:"write_file",label:"\u5199\u5165\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.target_file,t?.targetFile)};if(i==="read"||i==="readfile"||i==="readcode"||i==="readmultiplefiles")return{type:"read_file",label:"\u8BFB\u53D6\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.paths,t?.target_file,t?.targetFile)};if(i==="bash"||i==="execute"||i==="shell"||i==="pwsh"||i==="executepwsh"||i==="controlpwshprocess"||i==="runcommand"){const n=a(t?.command,t?.cmd,t?.argv);return{type:"bash",label:"\u6267\u884C\u547D\u4EE4",detail:n&&n.length>m?`${n.substring(0,m)}...\uFF08\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:n}}return i==="search"||i==="grep"||i==="find"||i==="glob"||i==="grepsearch"||i==="filesearch"?{type:"search",label:"\u641C\u7D22\u6587\u4EF6",detail:t?.query?p(String(t.query)):void 0}:r.includes("web")||r.includes("fetch")||r.includes("http")?{type:"web",label:"\u7F51\u7EDC\u8BF7\u6C42",detail:t?.url?p(String(t.url)):void 0}:{type:"tool_using",label:"Calling tool",detail:e}}updateStatus(e,t,r,i,a,o){this.currentStatus=e,t&&(this.currentAction={type:t,label:r,detail:i,input:o});const n={agentId:this.config.agentId,status:e,actionType:t??void 0,actionLabel:t?this.currentAction?.label:void 0,actionDetail:t?this.currentAction?.detail:void 0,actionInput:t?this.currentAction?.input:void 0,actionResult:a,timestamp:new Date().toISOString()};h.info(`[StatusReporter] \u72B6\u6001\u66F4\u65B0: ${e}${r?` - ${r}`:""}`),this.config.sendStatusUpdate(n)}clearAction(){this.currentAction=null}formatToolInput(e){if(!(!e||Object.keys(e).length===0))try{const t=p(JSON.stringify(f(e),null,2)),r=6e3;return t.length<=r?t:`${t.slice(0,r)}
1
+ import{EventEmitter as _}from"node:events";import{logger as h}from"./logger.js";const d="[temp clipboard paste file]",g=/[A-Z]:(?:\\\\|\\)[^\r\n"'`]*?(?:\\\\|\\)mini-term-clipboard(?:\\\\|\\)paste-\d+\.txt/gi,A=/\/[^\r\n"'`]*?\/mini-term-clipboard\/paste-\d+\.txt/gi,S=/mini-term-clipboard[\\/]paste-\d+\.txt/gi,w=new Set(["aws-mcp","agents-work-studio"]),m=500;function p(s){return s.replace(g,d).replace(A,d).replace(S,d)}const y=/^(password|passwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|authorization|credential)/i;function f(s,e=0){if(e>8)return s;if(Array.isArray(s))return s.map(t=>f(t,e+1));if(s!==null&&typeof s=="object"){const t={};for(const[r,i]of Object.entries(s))typeof i=="string"&&y.test(r)?t[r]="[redacted]":t[r]=f(i,e+1);return t}return s}class u extends _{config;currentStatus="stopped";currentAction=null;constructor(e){super(),this.config=e}reportStarting(){this.updateStatus("starting")}reportRunning(){this.updateStatus("running")}reportWaitingInput(){this.updateStatus("waiting_input"),this.clearAction()}reportThinking(){this.updateStatus("thinking"),this.clearAction()}reportStopped(){this.updateStatus("stopped"),this.clearAction()}reportError(){this.updateStatus("error"),this.clearAction()}reportToolUse(e,t){const r=this.parseToolAction(e,t);this.updateStatus("tool_using",r.type,r.label,r.detail,void 0,this.formatToolInput(t))}reportToolResult(e){this.updateStatus("tool_using",this.currentAction?.type,this.currentAction?.label,this.currentAction?.detail,this.formatToolResult(e),this.currentAction?.input)}reportToolError(e){const t=e instanceof Error?e.message:String(e);this.updateStatus("error",this.currentAction?.type,this.currentAction?.label||"Tool call failed",this.currentAction?.detail,t,this.currentAction?.input),this.clearAction()}static KNOWN_MCP_TOOLS={get_colleague:"aws-mcp",get_group_rooms:"aws-mcp",list_project_members:"aws-mcp",get_profile:"aws-mcp",hire_colleague:"aws-mcp",send_group:"aws-mcp",send_private:"aws-mcp",poll_message:"aws-mcp",get_message:"aws-mcp",get_dm_history:"aws-mcp",get_group_history:"aws-mcp",my_task:"aws-mcp",create_task_instance_comment:"aws-mcp",submit_task_result:"aws-mcp",start_task_rollback:"aws-mcp",finish_task_rollback:"aws-mcp",create_memory:"aws-mcp",read_memory:"aws-mcp",update_memory:"aws-mcp",delete_memory:"aws-mcp",search_memory:"aws-mcp",list_memories:"aws-mcp"};static canonicalizeMcpServer(e,t){const r=u.KNOWN_MCP_TOOLS[t.toLowerCase()];return r&&w.has(e.toLowerCase())?r:e}static formatMcpDetail(e,t){return e?t?`${u.canonicalizeMcpServer(e,t)}/${t}`:e:t}parseToolAction(e,t){const r=e.toLowerCase(),i=r.replace(/[_-]/g,""),a=(...n)=>{for(const c of n){if(typeof c=="string"&&c.trim())return p(c);if(Array.isArray(c)&&c.length>0){const l=c[0];if(typeof l=="string"&&l.trim())return p(l)}}};if(r.includes("skill")||r.includes("disclose"))return{type:"skill",label:"Calling skill",detail:t?.name?p(String(t.name)):void 0};const o=u.KNOWN_MCP_TOOLS[r];if(o)return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(o,e)};if(r.startsWith("mcp__")){const n=e.split("__"),c=n[1]||"",l=n.slice(2).join("__");return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(c,l)}}if(r.startsWith("mcp_")||r.includes("_mcp_"))return{type:"mcp",label:"Calling MCP",detail:e.replace(/^mcp_/,"").replace(/_/g," ")};if(r.includes("-mcp__")){const n=e.split("__"),c=n[0],l=n.slice(1).join("__");return{type:"mcp",label:"Calling MCP",detail:u.formatMcpDetail(c,l)}}if(i==="edit"||i==="editfile"||i==="strreplace"||i==="editcode"||i==="applypatch"||i==="multiedit")return{type:"edit_file",label:"\u7F16\u8F91\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.target_file,t?.targetFile)};if(i==="write"||i==="writefile"||i==="fswrite")return{type:"write_file",label:"\u5199\u5165\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.target_file,t?.targetFile)};if(i==="read"||i==="readfile"||i==="readcode"||i==="readmultiplefiles")return{type:"read_file",label:"\u8BFB\u53D6\u6587\u4EF6",detail:a(t?.path,t?.file_path,t?.filePath,t?.paths,t?.target_file,t?.targetFile)};if(i==="bash"||i==="execute"||i==="shell"||i==="pwsh"||i==="executepwsh"||i==="controlpwshprocess"||i==="runcommand"){const n=a(t?.command,t?.cmd,t?.argv);return{type:"bash",label:"\u6267\u884C\u547D\u4EE4",detail:n&&n.length>m?`${n.substring(0,m)}...\uFF08\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:n}}return i==="search"||i==="grep"||i==="find"||i==="glob"||i==="grepsearch"||i==="filesearch"?{type:"search",label:"\u641C\u7D22\u6587\u4EF6",detail:t?.query?p(String(t.query)):void 0}:r.includes("web")||r.includes("fetch")||r.includes("http")?{type:"web",label:"\u7F51\u7EDC\u8BF7\u6C42",detail:t?.url?p(String(t.url)):void 0}:{type:"tool_using",label:"Calling tool",detail:e}}updateStatus(e,t,r,i,a,o){this.currentStatus=e,t&&(this.currentAction={type:t,label:r,detail:i,input:o});const n={agentId:this.config.agentId,status:e,actionType:t??void 0,actionLabel:t?this.currentAction?.label:void 0,actionDetail:t?this.currentAction?.detail:void 0,actionInput:t?this.currentAction?.input:void 0,actionResult:a,timestamp:new Date().toISOString()};h.info(`[StatusReporter] \u72B6\u6001\u66F4\u65B0: ${e}${r?` - ${r}`:""}`),this.config.sendStatusUpdate(n)}clearAction(){this.currentAction=null}formatToolInput(e){if(!(!e||Object.keys(e).length===0))try{const t=p(JSON.stringify(f(e),null,2)),r=6e3;return t.length<=r?t:`${t.slice(0,r)}
2
2
  ...(input too long, truncated)`}catch{return}}formatToolResult(e){let t;try{t=typeof e=="string"?e:JSON.stringify(e,null,2)}catch(o){t=`[Unable to serialize tool result: ${o instanceof Error?o.message:String(o)}]`}const r=t||String(e),i=4e3,a=p(r);return a.length<=i?a:`${a.slice(0,i)}
3
3
  ...(result too long, truncated)`}getCurrentStatus(){return{agentId:this.config.agentId,status:this.currentStatus,actionType:this.currentAction?.type,actionLabel:this.currentAction?.label,actionDetail:this.currentAction?.detail,actionInput:this.currentAction?.input,timestamp:new Date().toISOString()}}}export{u as StatusReporter,p as redactTransientClipboardPastePaths};
4
4
 
@@ -52,6 +52,10 @@ export declare function findBridgeCapabilityByToolName(toolName: string): Bridge
52
52
 
53
53
  export declare function collapsibleToolGroupKeys(): string[];
54
54
 
55
+ export declare const TOOL_GROUP_MANIFEST_PREFIX = "ACODE_TOOL_GROUPS_V1:";
56
+
57
+ export declare function buildToolGroupManifest(): string;
58
+
55
59
  export declare function resolveToolGroupState(group: ToolGroupDef, configState: FeatureState, expanded: boolean): ToolGroupState;
56
60
 
57
61
  export declare function buildToolGroupPrompt(collapsedGroups: readonly ToolGroupDef[]): string | undefined;
@@ -1,3 +1,3 @@
1
- import{DEBUG_LOG_TOOL_NAMES as n,DRAW_TOOL_NAMES as u,FILE_CHANGES_HISTORY_TOOL_NAMES as s,HIRE_TOOL_NAMES as i,LAUNCH_CONFIG_TOOL_NAMES as d,MEETING_TOOL_NAMES as f,OFFICE_TOOL_NAMES as p,PENCIL_TOOL_NAMES as c,TASK_TOOL_NAMES as y}from"./mcp-tools.js";const m=new Set(["disabled","collapsed","expanded"]);function O(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&m.has(e))return e}const a=[{key:"launch",label:"\u542F\u52A8\u9879\u7BA1\u7406",featureKey:"agentSys.launchItem",toolNames:d,collapsible:!0,defaultState:"collapsed",summary:"\u7BA1\u7406\u5F00\u53D1\u670D\u52A1\u8FDB\u7A0B\uFF08\u542F\u52A8/\u505C\u6B62/\u91CD\u542F/\u67E5\u770B\u65E5\u5FD7\uFF09"},{key:"hire",label:"\u62DB\u8058\u5DE5\u5177",featureKey:"agentSys.hire",toolNames:i,collapsible:!0,defaultState:"collapsed",summary:"\u62DB\u8058\u65B0\u7684\u540C\u4E8B Agent\uFF08\u5355\u4E2A\u6216\u6279\u91CF\uFF09"},{key:"pencil",label:"\u8BBE\u8BA1\u753B\u5E03(pencil)",featureKey:"pencil",toolNames:c,collapsible:!0,defaultState:"collapsed",summary:"UI design editor. Open-source Figma alternative."},{key:"draw",label:"\u7ED8\u56FE",featureKey:"draw",toolNames:u,collapsible:!0,defaultState:"collapsed",summary:"\u7ED8\u5236 draw.io \u6D41\u7A0B\u56FE / \u6CF3\u9053\u56FE\uFF0C\u5BFC\u51FA XML"},{key:"office",label:"Office \u6587\u4EF6",featureKey:"office",toolNames:p,collapsible:!0,defaultState:"collapsed",summary:"\u521B\u5EFA\u4E0E\u7F16\u8F91 Word/Excel/PowerPoint\uFF08docx/xlsx/pptx\uFF0CApache POI \u683C\u5F0F\u5C42\uFF09\uFF1AWord \u652F\u6301 run/\u5355\u5143\u683C\u7EA7\u7CBE\u51C6\u7F16\u8F91\u3001\u6279\u6CE8\u3001\u4FEE\u8BA2\u3001\u516C\u5F0F\u3001\u76EE\u5F55\u9875\u7801\u3001\u4E09\u7EBF\u8868\u3001\u6807\u9898\u7F16\u53F7\u4E0E\u683C\u5F0F\u89C4\u8303\u68C0\u67E5/\u4E00\u952E\u4FEE\u6B63\uFF1B\u6821\u9A8C\u3001\u751F\u6210 HTML \u9884\u89C8\u3001\u5728 Dashboard \u9762\u677F\u4E2D\u5B9E\u65F6\u67E5\u770B\uFF0C\u53EF\u53D1\u6D88\u606F\u5361\u7247\u5206\u4EAB\u6587\u4EF6\uFF1B\u6587\u6863\u81EA\u52A8\u767B\u8BB0\u4E3A\u4E91\u6587\u6863\uFF0C\u652F\u6301\u5217\u51FA/\u5206\u4EAB\u7ED9\u5176\u4ED6 Agent \u534F\u4F5C\uFF08read|write\uFF09\u4E0E\u8FFD\u8D76\u53D8\u66F4"},{key:"task",label:"\u6D41\u7A0B\u4EFB\u52A1",featureKey:"collaboration.task",toolNames:y,collapsible:!0,defaultState:"collapsed",summary:"\u5904\u7406\u6D41\u7A0B\u7EBF\u4EFB\u52A1\uFF1A\u67E5\u770B\u5F53\u524D\u4EFB\u52A1\u3001\u63D0\u4EA4\u6267\u884C\u7ED3\u679C\u3001\u62D2\u7EDD/\u7EC8\u6B62/\u56DE\u9000\u4EFB\u52A1\u3001\u7ED9\u6D41\u7A0B\u5B9E\u4F8B\u7559\u8A00"},{key:"meeting",label:"\u4F1A\u8BAE",featureKey:"collaboration.meeting",toolNames:f,collapsible:!0,defaultState:"collapsed",summary:"\u521B\u5EFA/\u52A0\u5165\u4F1A\u8BAE\u3001\u53D1\u8A00\u3001\u67E5\u770B\u4F1A\u8BAE\u4FE1\u606F\u3001\u79BB\u5F00/\u7ED3\u675F\u4F1A\u8BAE"},{key:"debug",label:"\u8C03\u8BD5\u65E5\u5FD7",featureKey:"collaboration.debug",toolNames:n,collapsible:!0,defaultState:"collapsed",summary:"\u6309\u6761\u4EF6\u5206\u9875\u67E5\u8BE2 Debug \u65E5\u5FD7\u4E0E\u83B7\u53D6\u65E5\u5FD7\u4E0A\u62A5\u914D\u7F6E"},{key:"fileHistory",label:"\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",featureKey:"collaboration.fileHistory",toolNames:s,collapsible:!0,defaultState:"collapsed",summary:"\u6309\u89D2\u8272/\u5B9E\u4F8B/\u6587\u4EF6\u8DEF\u5F84\u8FC7\u6EE4\u67E5\u8BE2\u6587\u4EF6\u53D8\u66F4\u5386\u53F2"}],b=new Map(a.map(e=>[e.key,e])),_=(()=>{const e=new Map;for(const t of a)for(const l of t.toolNames)e.set(l,t);return e})();function N(e){return b.get(e)}const r=[{key:"browser",label:"\u6D4F\u89C8\u5668\u64CD\u4F5C",featureKey:"browser",defaultState:"collapsed",summary:"\u542F\u52A8\u6D4F\u89C8\u5668\u4F1A\u8BDD\u3001\u5BFC\u822A\u3001\u622A\u56FE\u4E0E\u9875\u9762\u4EA4\u4E92"},{key:"desktop",label:"\u684C\u9762\u64CD\u4F5C",featureKey:"desktop",defaultState:"disabled",summary:"\u622A\u5C4F\u3001\u9F20\u6807\u952E\u76D8\u63A7\u5236\u4E0E UI \u81EA\u52A8\u5316\uFF08Computer Use\uFF09"}];function T(e){return r.find(t=>t.key===e)}function E(e){return _.get(e)}function x(e){const t=a.find(o=>o.featureKey===e);return t?t.defaultState:r.find(o=>o.featureKey===e)?.defaultState}function A(e){return r.find(t=>e.startsWith(`${t.key}_`))}function k(){return a.filter(e=>e.collapsible).map(e=>e.key)}function L(e,t,l){return e.featureKey&&t==="disabled"?"disabled":e.collapsible&&t==="collapsed"&&!l?"collapsed":"expanded"}function g(e){return e.length===0?void 0:["## \u6309\u9700\u5DE5\u5177\u96C6","","\u4EE5\u4E0B\u5DE5\u5177\u96C6\u9ED8\u8BA4\u6536\u8D77\u4EE5\u4FDD\u6301\u5DE5\u5177\u5217\u8868\u7A33\u5B9A\u5E76\u8282\u7701\u4E0A\u4E0B\u6587\u3002\u5F53\u4EFB\u52A1\u9700\u8981\u65F6\uFF0C\u5148\u8C03\u7528 expand_tools \u5C55\u5F00\uFF0C","\u5DE5\u5177\u5B9A\u4E49\uFF08\u540D\u79F0/\u8BF4\u660E/\u53C2\u6570 schema\uFF09\u968F expand_tools \u7684\u8FD4\u56DE\u7ED3\u679C\u4E0B\u53D1\uFF0C\u5F53\u8F6E\u5373\u53EF\u7ECF call_tool \u8C03\u7528\uFF1A",'call_tool({ name: "<\u5DE5\u5177\u540D>", arguments: {...} })',"",...e.map(l=>`- ${l.key}\uFF08${l.label}\uFF09\uFF1A${l.summary}`),"",'\u793A\u4F8B\uFF1Aexpand_tools({ group: "pencil" })'].join(`
2
- `)}export{r as BRIDGE_LAZY_CAPABILITIES,a as TOOL_GROUPS,g as buildToolGroupPrompt,k as collapsibleToolGroupKeys,x as defaultStateForFeatureKey,A as findBridgeCapabilityByToolName,T as findBridgeLazyCapability,N as findToolGroup,E as findToolGroupByToolName,O as normalizeFeatureState,L as resolveToolGroupState};
1
+ import{DEBUG_LOG_TOOL_NAMES as n,DRAW_TOOL_NAMES as s,EMAIL_TOOL_NAMES as u,FILE_CHANGES_HISTORY_TOOL_NAMES as i,HIRE_TOOL_NAMES as d,LAUNCH_CONFIG_TOOL_NAMES as f,MEETING_TOOL_NAMES as p,OFFICE_TOOL_NAMES as c,PENCIL_TOOL_NAMES as m,TASK_TOOL_NAMES as y}from"./mcp-tools.js";const b=new Set(["disabled","collapsed","expanded"]);function T(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&b.has(e))return e}const a=[{key:"launch",label:"\u542F\u52A8\u9879\u7BA1\u7406",featureKey:"agentSys.launchItem",toolNames:f,collapsible:!0,defaultState:"collapsed",summary:"\u7BA1\u7406\u9879\u76EE\u4E2D\u4E1A\u52A1\u7A0B\u5E8F\u7684\u8D77\u505C\uFF0C\u82E5\u540E\u9762\u9700\u8981\u542F\u52A8\u9879\u76EE\u5E94\u4F7F\u7528\u6B64\u5DE5\u5177"},{key:"hire",label:"\u62DB\u8058\u5DE5\u5177",featureKey:"agentSys.hire",toolNames:d,collapsible:!0,defaultState:"collapsed",summary:"\u62DB\u8058\u65B0\u7684\u540C\u4E8B Agent\uFF08\u5355\u4E2A\u6216\u6279\u91CF\uFF09"},{key:"pencil",label:"\u8BBE\u8BA1\u753B\u5E03(pencil)",featureKey:"pencil",toolNames:m,collapsible:!0,defaultState:"collapsed",summary:"UI design editor. Open-source Figma alternative."},{key:"draw",label:"\u7ED8\u56FE",featureKey:"draw",toolNames:s,collapsible:!0,defaultState:"collapsed",summary:"\u7ED8\u5236 draw.io \u6D41\u7A0B\u56FE / \u6CF3\u9053\u56FE\uFF0C\u5BFC\u51FA XML"},{key:"office",label:"Office \u6587\u4EF6",featureKey:"office",toolNames:c,collapsible:!0,defaultState:"collapsed",summary:"\u521B\u5EFA\u4E0E\u7F16\u8F91 Word/Excel/PowerPoint\uFF08docx/xlsx/pptx\uFF0CApache POI \u683C\u5F0F\u5C42\uFF09\uFF1AWord \u652F\u6301 run/\u5355\u5143\u683C\u7EA7\u7CBE\u51C6\u7F16\u8F91\u3001\u6279\u6CE8\u3001\u4FEE\u8BA2\u3001\u516C\u5F0F\u3001\u76EE\u5F55\u9875\u7801\u3001\u4E09\u7EBF\u8868\u3001\u6807\u9898\u7F16\u53F7\u4E0E\u683C\u5F0F\u89C4\u8303\u68C0\u67E5/\u4E00\u952E\u4FEE\u6B63\uFF1B\u6821\u9A8C\u3001\u751F\u6210 HTML \u9884\u89C8\u3001\u5728 Dashboard \u9762\u677F\u4E2D\u5B9E\u65F6\u67E5\u770B\uFF0C\u53EF\u53D1\u6D88\u606F\u5361\u7247\u5206\u4EAB\u6587\u4EF6\uFF1B\u6587\u6863\u81EA\u52A8\u767B\u8BB0\u4E3A\u4E91\u6587\u6863\uFF0C\u652F\u6301\u5217\u51FA/\u5206\u4EAB\u7ED9\u5176\u4ED6 Agent \u534F\u4F5C\uFF08read|write\uFF09\u4E0E\u8FFD\u8D76\u53D8\u66F4"},{key:"task",label:"\u6D41\u7A0B\u4EFB\u52A1",featureKey:"collaboration.task",toolNames:y,collapsible:!0,defaultState:"collapsed",summary:"\u5904\u7406\u6D41\u7A0B\u7EBF\u4EFB\u52A1\uFF1A\u67E5\u770B\u5F53\u524D\u4EFB\u52A1\u3001\u63D0\u4EA4\u6267\u884C\u7ED3\u679C\u3001\u56DE\u9000\u4EFB\u52A1\u3001\u7ED9\u6D41\u7A0B\u5B9E\u4F8B\u7559\u8A00"},{key:"meeting",label:"\u4F1A\u8BAE",featureKey:"collaboration.meeting",toolNames:p,collapsible:!0,defaultState:"collapsed",summary:"\u521B\u5EFA/\u52A0\u5165\u4F1A\u8BAE\u3001\u53D1\u8A00\u3001\u67E5\u770B\u4F1A\u8BAE\u4FE1\u606F\u3001\u79BB\u5F00/\u7ED3\u675F\u4F1A\u8BAE"},{key:"debug",label:"\u8C03\u8BD5\u65E5\u5FD7",featureKey:"collaboration.debug",toolNames:n,collapsible:!0,defaultState:"collapsed",summary:"\u6309\u6761\u4EF6\u5206\u9875\u67E5\u8BE2 Debug \u65E5\u5FD7\u4E0E\u83B7\u53D6\u65E5\u5FD7\u4E0A\u62A5\u914D\u7F6E"},{key:"fileHistory",label:"\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",featureKey:"collaboration.fileHistory",toolNames:i,collapsible:!0,defaultState:"collapsed",summary:"\u6309\u89D2\u8272/\u5B9E\u4F8B/\u6587\u4EF6\u8DEF\u5F84\u8FC7\u6EE4\u67E5\u8BE2\u6587\u4EF6\u53D8\u66F4\u5386\u53F2"},{key:"email",label:"\u90AE\u7BB1",featureKey:"email",toolNames:u,collapsible:!0,defaultState:"collapsed",summary:"\u6536\u53D1\u89D2\u8272\u5B9E\u4F8B\u57DF\u540D\u90AE\u7BB1\uFF08xxxxx@\u57DF\u540D\uFF09\uFF1A\u53D1\u4FE1\u3001\u5217\u90AE\u4EF6\u3001\u8BFB\u6B63\u6587\u4E0E\u9644\u4EF6\u3001\u56DE\u4FE1\u4FDD\u6301\u7EBF\u7A0B\u3001\u786E\u8BA4\u4E1A\u52A1\u6D88\u8D39"}],_=new Map(a.map(e=>[e.key,e])),O=(()=>{const e=new Map;for(const t of a)for(const l of t.toolNames)e.set(l,t);return e})();function x(e){return _.get(e)}const r=[{key:"browser",label:"\u6D4F\u89C8\u5668\u64CD\u4F5C",featureKey:"browser",defaultState:"collapsed",summary:"\u542F\u52A8\u6D4F\u89C8\u5668\u4F1A\u8BDD\u3001\u5BFC\u822A\u3001\u622A\u56FE\u4E0E\u9875\u9762\u4EA4\u4E92"},{key:"desktop",label:"\u684C\u9762\u64CD\u4F5C",featureKey:"desktop",defaultState:"disabled",summary:"\u622A\u5C4F\u3001\u9F20\u6807\u952E\u76D8\u63A7\u5236\u4E0E UI \u81EA\u52A8\u5316\uFF08Computer Use\uFF09"}];function E(e){return r.find(t=>t.key===e)}function A(e){return O.get(e)}function L(e){const t=a.find(o=>o.featureKey===e);return t?t.defaultState:r.find(o=>o.featureKey===e)?.defaultState}function k(e){return r.find(t=>e.startsWith(`${t.key}_`))}function M(){return a.filter(e=>e.collapsible).map(e=>e.key)}const S="ACODE_TOOL_GROUPS_V1:";function I(){const e=a.filter(t=>t.collapsible).map(t=>({key:t.key,label:t.label,toolNames:[...t.toolNames]}));return`${S}${JSON.stringify({groups:e})}`}function K(e,t,l){return e.featureKey&&t==="disabled"?"disabled":e.collapsible&&t==="collapsed"&&!l?"collapsed":"expanded"}function g(e){return e.length===0?void 0:["## \u6309\u9700\u5DE5\u5177\u96C6","","\u4EE5\u4E0B\u5DE5\u5177\u96C6\u9ED8\u8BA4\u6536\u8D77\u4EE5\u4FDD\u6301\u5DE5\u5177\u5217\u8868\u7A33\u5B9A\u5E76\u8282\u7701\u4E0A\u4E0B\u6587\u3002\u5F53\u4EFB\u52A1\u9700\u8981\u65F6\uFF0C\u5148\u8C03\u7528 expand_tools \u5C55\u5F00\uFF0C","\u5DE5\u5177\u5B9A\u4E49\uFF08\u540D\u79F0/\u8BF4\u660E/\u53C2\u6570 schema\uFF09\u968F expand_tools \u7684\u8FD4\u56DE\u7ED3\u679C\u4E0B\u53D1\uFF0C\u5F53\u8F6E\u5373\u53EF\u7ECF call_tool \u8C03\u7528\uFF1A",'call_tool({ name: "<\u5DE5\u5177\u540D>", arguments: {...} })',"",...e.map(l=>`- ${l.key}\uFF08${l.label}\uFF09\uFF1A${l.summary}`),"",'\u793A\u4F8B\uFF1Aexpand_tools({ group: "pencil" })'].join(`
2
+ `)}export{r as BRIDGE_LAZY_CAPABILITIES,a as TOOL_GROUPS,S as TOOL_GROUP_MANIFEST_PREFIX,I as buildToolGroupManifest,g as buildToolGroupPrompt,M as collapsibleToolGroupKeys,L as defaultStateForFeatureKey,k as findBridgeCapabilityByToolName,E as findBridgeLazyCapability,x as findToolGroup,A as findToolGroupByToolName,T as normalizeFeatureState,K as resolveToolGroupState};
3
3
 
@@ -174,10 +174,51 @@ export interface GroupRoomInfo {
174
174
  export interface GroupRoomsResponse {
175
175
  groups: GroupRoomInfo[];
176
176
  }
177
+
178
+ export interface ProjectHumanMember {
179
+ userId: string;
180
+ nickname: string;
181
+
182
+ projectRole: string;
183
+
184
+ isOwner: boolean;
185
+
186
+ online: boolean;
187
+ avatarUrl?: string;
188
+
189
+ mailboxAddress?: string;
190
+ }
191
+ export interface ProjectMembersResponse {
192
+ projectId: string | null;
193
+ members: ProjectHumanMember[];
194
+ onlineCount?: number;
195
+ totalCount?: number;
196
+
197
+ note?: string;
198
+ }
199
+
200
+ export interface ReplyToRef {
201
+
202
+ messageId: string;
203
+
204
+ senderId?: string;
205
+
206
+ senderName?: string;
207
+
208
+ snapshot?: string;
209
+
210
+ prefix?: string;
211
+
212
+ suffix?: string;
213
+
214
+ pos?: number;
215
+ }
177
216
  export interface GroupMessage {
178
217
  msgId: number;
179
218
  senderId: string;
180
219
  senderName: string;
220
+
221
+ senderType?: "HUMAN" | "AGENT" | string;
181
222
  projectId?: string;
182
223
  roomId?: string;
183
224
 
@@ -185,6 +226,8 @@ export interface GroupMessage {
185
226
  content: string;
186
227
  timestamp: string;
187
228
 
229
+ replyTo?: ReplyToRef[];
230
+
188
231
  tokens?: TokenUsage;
189
232
 
190
233
  modelInfo?: ModelInfo;
@@ -216,6 +259,8 @@ export interface DirectMessage {
216
259
  callId?: string;
217
260
  senderId: string;
218
261
  senderName: string;
262
+
263
+ senderType?: "HUMAN" | "AGENT" | string;
219
264
  receiverId?: string;
220
265
  content: string;
221
266
  requireReply: boolean;
@@ -223,6 +268,8 @@ export interface DirectMessage {
223
268
  force?: boolean;
224
269
  prompt?: string;
225
270
 
271
+ replyTo?: ReplyToRef[];
272
+
226
273
  role?: 'system' | 'user' | 'assistant';
227
274
  timestamp: string;
228
275
 
@@ -426,7 +473,7 @@ export interface HireBatchResult {
426
473
  results: HireBatchItemResult[];
427
474
  }
428
475
 
429
- export type McpToolName = "get_colleague" | "get_group_rooms" | "get_profile" | "hire_colleague" | "send_group" | "send_private" | "poll_message" | "get_message" | "get_dm_history" | "get_group_history" | "start_listening" | "stop_listening";
476
+ export type McpToolName = "get_colleague" | "get_group_rooms" | "list_project_members" | "get_profile" | "hire_colleague" | "send_group" | "send_private" | "poll_message" | "get_message" | "get_dm_history" | "get_group_history" | "start_listening" | "stop_listening";
430
477
 
431
478
  export type CardType = "pencil" | "draw" | "office";
432
479
 
@@ -455,6 +502,8 @@ export interface SendPrivateArgs {
455
502
  attachments?: string[];
456
503
 
457
504
  card?: Card;
505
+
506
+ replyTo?: ReplyToRef[];
458
507
  }
459
508
 
460
509
  export interface SendGroupArgs {
@@ -465,6 +514,8 @@ export interface SendGroupArgs {
465
514
  attachments?: string[];
466
515
 
467
516
  card?: Card;
517
+
518
+ replyTo?: ReplyToRef[];
468
519
  }
469
520
 
470
521
  export interface GetDmHistoryArgs {
@@ -1,2 +1,2 @@
1
- import{EventEmitter as f}from"node:events";import c from"ws";import{logger as r}from"./logger.js";import{meetingDebugLog as u}from"./meeting-debug-log.js";const T=9e3,S=3e4,b=1e3,l=100,d=3,g=3,k=5,p=6e4,E=50,m=1e3;class _ extends f{ws=null;config;agentId=null;heartbeatTimer=null;heartbeatTimeoutTimer=null;reconnectAttempts=0;reconnectTimer=null;isManualClose=!1;websocketFactory;openedAt=null;lastRefreshedToken=null;consecutiveRefreshFailures=0;logBatchQueue=[];logBatchTimer=null;logSequenceNumber=0;pendingLogBatches=new Map;isProcessingLogBatch=!1;processedMsgIds=new Map;constructor(e,t){super(),this.config=e,this.websocketFactory=t??(s=>new c(s))}connect(e){return new Promise((t,s)=>{this.prepareConnection(e);const n=this.buildWebSocketUrl(e);r.info(`[WebSocket] \u6B63\u5728\u8FDE\u63A5: ${this.maskRuntimeTokenInUrl(n)}`);const{rejectOnce:o,resolveOnce:i}=this.createSettledHandlers(t,s);try{this.ws=this.websocketFactory(n),this.setupWebSocketEventHandlers(this.ws,o,i)}catch(a){o(a instanceof Error?a:new Error(String(a)))}})}prepareConnection(e){this.agentId=e,this.isManualClose=!1,this.ws&&this.ws.readyState!==c.CLOSED&&(this.ws.removeAllListeners(),this.ws.terminate())}buildWebSocketUrl(e){const t=new URL(this.config.serverUrl);t.searchParams.set("agentId",e);const s=this.config.runtimeAccessToken?.trim();return s&&t.searchParams.set("runtimeAccessToken",s),t.toString()}maskRuntimeTokenInUrl(e){try{const t=new URL(e);return t.searchParams.has("runtimeAccessToken")&&t.searchParams.set("runtimeAccessToken","***"),t.toString()}catch{return e.replace(/([?&]runtimeAccessToken=)[^&]*/u,"$1***")}}createSettledHandlers(e,t){let s=!1;return{rejectOnce:i=>{s||(s=!0,t(i))},resolveOnce:()=>{s||(s=!0,e())}}}setupWebSocketEventHandlers(e,t,s){let n=!1;e.on("open",()=>{n=!0,this.handleWebSocketOpen(s)}),e.on("message",o=>this.handleWebSocketMessage(o)),e.on("pong",()=>this.markHeartbeatReceived()),e.on("close",(o,i)=>this.handleWebSocketClose(o,i,n,t)),e.on("error",o=>this.handleWebSocketError(o,n,t))}handleWebSocketOpen(e){r.info("[WebSocket] \u8FDE\u63A5\u5DF2\u5EFA\u7ACB"),this.openedAt=Date.now(),this.lastRefreshedToken=null,this.clearReconnectTimer(),this.startHeartbeat(),this.emit("connected"),e()}handleWebSocketMessage(e){try{const t=JSON.parse(e.toString()),s=this.extractReliableMessageId(t),n=s!==null&&this.markMsgIdProcessed(s);if(this.acknowledgeReliableMessage(t),n){r.info("[WebSocket] \u5FFD\u7565\u91CD\u590D\u6295\u9012\u7684\u53EF\u9760\u6D88\u606F: msgId=%s, type=%s",s,t.type);return}this.handleMessage(t)}catch(t){const s=e.toString(),n=s.length>200?`${s.slice(0,200)}...(truncated, ${s.length} total)`:s;r.warn("[WebSocket] \u6D88\u606F\u89E3\u6790\u5931\u8D25, dataLength=%s, preview=%s:",s.length,n,t)}}extractReliableMessageId(e){const t=e.data;if(!t||typeof t!="object")return null;const s=t,n=String(s._msgId||"").trim(),o=s._requireAck===!0||s._requireAck==="true";return!n||!o?null:n}markMsgIdProcessed(e){if(this.processedMsgIds.has(e))return!0;if(this.processedMsgIds.set(e,Date.now()),this.processedMsgIds.size>m){let t=0;const s=this.processedMsgIds.size-m;for(const n of this.processedMsgIds.keys()){if(t>=s)break;this.processedMsgIds.delete(n),t++}}return!1}acknowledgeReliableMessage(e){const t=this.extractReliableMessageId(e);t&&this.send({type:"MESSAGE_ACK",data:{msgId:t},timestamp:new Date().toISOString()})}async handleWebSocketClose(e,t,s,n){const o=t.toString(),i=this.ws?.readyState;r.warn(`[WebSocket] \u8FDE\u63A5\u5173\u95ED: code=${e}, reason=${o}, readyState=${i}, opened=${s}, reconnectAttempts=${this.reconnectAttempts}`),this.stopHeartbeat(),this.clearHeartbeatTimeout(),this.emit("disconnected",e,t),this.openedAt!==null&&Date.now()-this.openedAt>=p&&(this.reconnectAttempts=0,this.consecutiveRefreshFailures=0),this.openedAt=null,s||n(new Error(`WebSocket \u8FDE\u63A5\u5728\u5EFA\u7ACB\u524D\u5173\u95ED: code=${e}, reason=${o}`)),this.isManualClose||(e===1008?await this.handleTokenExpiredAndReconnect():this.scheduleReconnect())}async handleTokenExpiredAndReconnect(){const e=await this.refreshRuntimeTokenOnPolicyRejection();if(e==="refreshed"){r.info("[WebSocket] runtime token \u5DF2\u5237\u65B0\uFF0C\u4F7F\u7528\u65B0 token \u91CD\u8FDE"),this.consecutiveRefreshFailures=0,this.scheduleReconnect();return}if(e==="unchanged"){r.warn("[WebSocket] bridge \u8FD4\u56DE token \u672A\u53D8\u5316\u4E14\u670D\u52A1\u7AEF 1008 \u62D2\u7EDD\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85\u65B0 token \u7B7E\u53D1"),this.emit("tokenRejected",this.config.runtimeAccessToken),this.enterSlowReconnect();return}if(this.consecutiveRefreshFailures+=1,this.consecutiveRefreshFailures>=g){r.error(`[WebSocket] runtime token \u5237\u65B0\u8FDE\u7EED\u5931\u8D25 ${this.consecutiveRefreshFailures} \u6B21\uFF0C\u964D\u7EA7\u4E3A\u6162\u901F\u91CD\u8BD5\u7B49\u5F85 bridge \u6062\u590D`),this.emit("tokenRefreshFailed",this.consecutiveRefreshFailures),this.enterSlowReconnect();return}r.warn(`[WebSocket] runtime token \u5237\u65B0\u5931\u8D25\uFF0C\u7B2C ${this.consecutiveRefreshFailures}/${g} \u6B21\u5C1D\u8BD5\u91CD\u8FDE`),this.scheduleReconnect()}enterSlowReconnect(){this.reconnectAttempts=Math.max(this.reconnectAttempts,k),this.scheduleReconnect()}async refreshRuntimeTokenOnPolicyRejection(){const e=this.config.runtimeBridgeBaseUrl;if(!e||!this.agentId)return"failed";const t=this.config.runtimeAccessToken||"",s=Math.min(this.config.mcpHttpRequestTimeoutMs??12e4,1e4),n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const i=await fetch(`${e}/runtime/binding/refresh-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:this.agentId,currentToken:t,forceRefresh:!0}),signal:n.signal});if(!i.ok)return r.warn(`[WebSocket] bridge refresh-token \u8FD4\u56DE ${i.status}\uFF0C\u65E0\u6CD5\u5237\u65B0`),"failed";const h=(await i.json()).runtimeAccessToken;return!h||h===t?"unchanged":(this.config.runtimeAccessToken=h,this.lastRefreshedToken=t,r.info("[WebSocket] runtimeAccessToken \u5DF2\u901A\u8FC7 bridge refresh \u66F4\u65B0"),"refreshed")}catch(i){return i instanceof Error&&i.name==="AbortError"?r.warn(`[WebSocket] bridge refresh-token \u8D85\u65F6\uFF08${s}ms\uFF09`):(r.warn("[WebSocket] bridge refresh-token \u5F02\u5E38: %s",i instanceof Error?i.message:String(i)),i instanceof Error&&i.stack&&r.warn("[WebSocket] refresh-token \u5F02\u5E38\u5806\u6808:",i.stack.slice(0,2e3))),"failed"}finally{clearTimeout(o)}}handleWebSocketError(e,t,s){const n=this.ws?.readyState;r.error("[WebSocket] \u8FDE\u63A5\u9519\u8BEF: readyState=%s, opened=%s, reconnectAttempts=%s, message=%s",n,t,this.reconnectAttempts,e.message),r.error("[WebSocket] \u9519\u8BEF\u5806\u6808:",e.stack?.slice(0,2e3)),this.emit("error",e),t||s(e)}disconnect(){this.isManualClose=!0,this.stopHeartbeat(),this.clearHeartbeatTimeout(),this.clearReconnectTimer(),this.ws&&(this.ws.readyState===c.OPEN&&this.ws.close(1e3,"Agent logout"),this.ws=null),this.agentId=null,r.info("[WebSocket] \u5DF2\u65AD\u5F00\u8FDE\u63A5")}send(e){const t=this.ws?.readyState;if(!this.ws||t!==c.OPEN)return r.warn("[WebSocket] \u8FDE\u63A5\u672A\u5EFA\u7ACB\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F: readyState=%s, isManualClose=%s, agentId=%s",t,this.isManualClose,this.agentId),!1;try{return this.ws.send(JSON.stringify(e)),!0}catch(s){return r.error("[WebSocket] send() \u53D1\u9001\u6D88\u606F\u5F02\u5E38: readyState=%s, error=%s",t,s),!1}}sendMcpNodeLog(e){return this.isConnected()?(this.logBatchQueue.push(e),this.logBatchTimer||(this.logBatchTimer=setTimeout(()=>{this.logBatchTimer=null,this.flushLogBatch()},l)),!0):!1}flushLogBatch(){if(this.logBatchQueue.length===0||this.isProcessingLogBatch)return;const e=this.logBatchQueue.splice(0,E);if(e.length===0)return;this.isProcessingLogBatch=!0,this.logSequenceNumber+=1;const t=this.logSequenceNumber;new Promise((n,o)=>{this.pendingLogBatches.set(t,{logs:e,sequenceNumber:t,retryCount:0,resolve:n,reject:o})}).then(()=>{this.isProcessingLogBatch=!1,this.logBatchQueue.length>0&&(this.logBatchTimer=setTimeout(()=>{this.logBatchTimer=null,this.flushLogBatch()},l))}).catch(()=>{this.isProcessingLogBatch=!1}),this.sendLogBatch(t)}sendLogBatch(e){const t=this.pendingLogBatches.get(e);if(!t)return;this.send({type:"MCP_NODE_LOG_BATCH",data:{sequenceNumber:e,logs:t.logs},timestamp:new Date().toISOString()})||this.handleLogBatchSendFailure(e)}handleLogBatchSendFailure(e){const t=this.pendingLogBatches.get(e);t&&(t.retryCount+=1,t.retryCount<=d?(r.warn(`[WebSocket] \u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25\uFF0C\u7B2C ${t.retryCount} \u6B21\u91CD\u8BD5`),setTimeout(()=>{this.sendLogBatch(e)},l*t.retryCount)):(r.error(`[WebSocket] \u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25\uFF0C\u5DF2\u91CD\u8BD5 ${d} \u6B21\uFF0C\u4E22\u5F03`),this.pendingLogBatches.delete(e),t.reject(new Error(`\u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25`))))}handleLogAck(e){const s=Number(e?.ackSequenceNumber);if(!s||!this.pendingLogBatches.has(s))return;const n=this.pendingLogBatches.get(s);n&&(this.pendingLogBatches.delete(s),n.resolve())}isConnected(){return this.ws!==null&&this.ws.readyState===c.OPEN}handleMessage(e){switch(e.type){case"GROUP_MSG":this.emit("groupMessage",e.data);break;case"DM_MSG":this.emit("directMessage",e.data);break;case"MEETING_MSG":u("ws.MEETING_MSG",`\u6536\u5230\u4F1A\u8BAE\u6D88\u606F WS \u63A8\u9001: msgId=${String(e.data?.msgId??"-")} content=${String(e.data?.content??"").slice(0,120)}`),this.emit("meetingMessage",e.data);break;case"SYSTEM_NOTIFY":u("ws.SYSTEM_NOTIFY",`type=${String(e.data?.type??"-")}`),this.emit("systemNotify",e.data);break;case"ONLINE_CHANGE":this.emit("onlineChange",e.data);break;case"HEARTBEAT":this.markHeartbeatReceived();break;case"PROFILE_INFO":r.info("[WebSocket] \u6536\u5230 PROFILE_INFO \u6D88\u606F"),this.emit("profileInfo",e.data);break;case"AGENT_CONFIG":r.info("[WebSocket] \u6536\u5230 AGENT_CONFIG \u6D88\u606F"),this.emit("agentConfig",e.data);break;case"AGENT_STATUS":r.info("[WebSocket] \u6536\u5230 AGENT_STATUS \u6D88\u606F"),this.emit("agentStatus",e.data);break;case"LOG_ACK":this.handleLogAck(e.data);break;case"GROUP_READ_RECEIPT":case"DM_READ_RECEIPT":case"TERMINAL_OUTPUT":case"TERMINAL_STATUS":case"MCP_NODE_LOG":case"AGENT_EVENTS_DELTA":break;default:r.warn("[WebSocket] \u672A\u77E5\u6D88\u606F\u7C7B\u578B:",e.type)}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{this.isConnected()&&(this.ensureHeartbeatTimeout(),this.sendProtocolPing(),this.send({type:"HEARTBEAT",data:"ping",timestamp:new Date().toISOString()}))},this.config.heartbeatInterval)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.clearHeartbeatTimeout()}sendProtocolPing(){if(!(!this.ws||this.ws.readyState!==c.OPEN))try{this.ws.ping()}catch(e){r.warn("[WebSocket] \u534F\u8BAE\u5C42 ping \u53D1\u9001\u5931\u8D25\uFF0C\u7EC8\u6B62\u8FDE\u63A5\u5E76\u91CD\u8FDE:",e instanceof Error?e.message:String(e)),this.ws.terminate()}}markHeartbeatReceived(){this.clearHeartbeatTimeout()}ensureHeartbeatTimeout(){this.heartbeatTimeoutTimer||(this.heartbeatTimeoutTimer=setTimeout(()=>{this.heartbeatTimeoutTimer=null,!(!this.ws||this.ws.readyState!==c.OPEN)&&(r.warn(`[WebSocket] ${this.resolveHeartbeatTimeout()}ms \u672A\u6536\u5230\u5FC3\u8DF3\u54CD\u5E94\uFF0C\u7EC8\u6B62\u8FDE\u63A5\u5E76\u89E6\u53D1\u91CD\u8FDE`),this.ws.terminate())},this.resolveHeartbeatTimeout()))}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null)}resolveHeartbeatTimeout(){return this.config.heartbeatTimeout??T}scheduleReconnect(){const e=this.config.maxReconnectAttempts!==-1;if(e&&this.reconnectAttempts>=this.config.maxReconnectAttempts){r.error("[WebSocket] \u91CD\u8FDE\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF0C\u653E\u5F03\u91CD\u8FDE"),this.emit("reconnectFailed");return}if(this.reconnectTimer)return;this.reconnectAttempts++;const t=Math.min(this.config.reconnectInterval*Math.pow(2,this.reconnectAttempts-1),this.config.reconnectMaxInterval??S),s=Math.random()*(this.config.reconnectJitterMs??b),n=Math.round(t+s),o=e?`\u7B2C ${this.reconnectAttempts}/${this.config.maxReconnectAttempts} \u6B21`:`\u7B2C ${this.reconnectAttempts} \u6B21\uFF08\u65E0\u9650\u91CD\u8BD5\u6A21\u5F0F\uFF09`;r.warn(`[WebSocket] ${n}ms \u540E\u5C1D\u8BD5${o}\u91CD\u8FDE (base=${Math.round(t)}ms, jitter=+${Math.round(s)}ms)...`),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.agentId&&this.connect(this.agentId).catch(i=>{const a=i instanceof Error?i.message:String(i),h=i instanceof Error?i.stack:void 0;r.warn("[WebSocket] \u91CD\u8FDE\u5931\u8D25 (attempt #%s), \u7EE7\u7EED\u91CD\u8BD5: %s",this.reconnectAttempts,a),h&&r.warn("[WebSocket] \u91CD\u8FDE\u5931\u8D25\u5806\u6808:",h.slice(0,2e3)),this.scheduleReconnect()})},n)}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}}export{_ as WebSocketClient};
1
+ import{EventEmitter as f}from"node:events";import a from"ws";import{logger as r}from"./logger.js";import{meetingDebugLog as u}from"./meeting-debug-log.js";const T=9e3,S=3e4,b=1e3,l=100,d=3,g=3,k=5,p=6e4,E=50,m=1e3;class _ extends f{ws=null;config;agentId=null;heartbeatTimer=null;heartbeatTimeoutTimer=null;reconnectAttempts=0;reconnectTimer=null;isManualClose=!1;websocketFactory;openedAt=null;lastRefreshedToken=null;consecutiveRefreshFailures=0;logBatchQueue=[];logBatchTimer=null;logSequenceNumber=0;pendingLogBatches=new Map;isProcessingLogBatch=!1;processedMsgIds=new Map;constructor(e,t){super(),this.config=e,this.websocketFactory=t??(s=>new a(s))}connect(e){return new Promise((t,s)=>{this.prepareConnection(e);const n=this.buildWebSocketUrl(e);r.info(`[WebSocket] \u6B63\u5728\u8FDE\u63A5: ${this.maskRuntimeTokenInUrl(n)}`);const{rejectOnce:o,resolveOnce:i}=this.createSettledHandlers(t,s);try{this.ws=this.websocketFactory(n),this.setupWebSocketEventHandlers(this.ws,o,i)}catch(c){o(c instanceof Error?c:new Error(String(c)))}})}prepareConnection(e){this.agentId=e,this.isManualClose=!1,this.ws&&this.ws.readyState!==a.CLOSED&&(this.ws.removeAllListeners(),this.ws.terminate())}buildWebSocketUrl(e){const t=new URL(this.config.serverUrl);t.searchParams.set("agentId",e);const s=this.config.runtimeAccessToken?.trim();return s&&t.searchParams.set("runtimeAccessToken",s),t.toString()}maskRuntimeTokenInUrl(e){try{const t=new URL(e);return t.searchParams.has("runtimeAccessToken")&&t.searchParams.set("runtimeAccessToken","***"),t.toString()}catch{return e.replace(/([?&]runtimeAccessToken=)[^&]*/u,"$1***")}}createSettledHandlers(e,t){let s=!1;return{rejectOnce:i=>{s||(s=!0,t(i))},resolveOnce:()=>{s||(s=!0,e())}}}setupWebSocketEventHandlers(e,t,s){let n=!1;e.on("open",()=>{n=!0,this.handleWebSocketOpen(s)}),e.on("message",o=>this.handleWebSocketMessage(o)),e.on("pong",()=>this.markHeartbeatReceived()),e.on("close",(o,i)=>this.handleWebSocketClose(o,i,n,t)),e.on("error",o=>this.handleWebSocketError(o,n,t))}handleWebSocketOpen(e){r.info("[WebSocket] \u8FDE\u63A5\u5DF2\u5EFA\u7ACB"),this.openedAt=Date.now(),this.lastRefreshedToken=null,this.clearReconnectTimer(),this.startHeartbeat(),this.emit("connected"),e()}handleWebSocketMessage(e){try{const t=JSON.parse(e.toString()),s=this.extractReliableMessageId(t),n=s!==null&&this.markMsgIdProcessed(s);if(this.acknowledgeReliableMessage(t),n){r.info("[WebSocket] \u5FFD\u7565\u91CD\u590D\u6295\u9012\u7684\u53EF\u9760\u6D88\u606F: msgId=%s, type=%s",s,t.type);return}this.handleMessage(t)}catch(t){const s=e.toString(),n=s.length>200?`${s.slice(0,200)}...(truncated, ${s.length} total)`:s;r.warn("[WebSocket] \u6D88\u606F\u89E3\u6790\u5931\u8D25, dataLength=%s, preview=%s:",s.length,n,t)}}extractReliableMessageId(e){const t=e.data;if(!t||typeof t!="object")return null;const s=t,n=String(s._msgId||"").trim(),o=s._requireAck===!0||s._requireAck==="true";return!n||!o?null:n}markMsgIdProcessed(e){if(this.processedMsgIds.has(e))return!0;if(this.processedMsgIds.set(e,Date.now()),this.processedMsgIds.size>m){let t=0;const s=this.processedMsgIds.size-m;for(const n of this.processedMsgIds.keys()){if(t>=s)break;this.processedMsgIds.delete(n),t++}}return!1}acknowledgeReliableMessage(e){const t=this.extractReliableMessageId(e);t&&this.send({type:"MESSAGE_ACK",data:{msgId:t},timestamp:new Date().toISOString()})}async handleWebSocketClose(e,t,s,n){const o=t.toString(),i=this.ws?.readyState;r.warn(`[WebSocket] \u8FDE\u63A5\u5173\u95ED: code=${e}, reason=${o}, readyState=${i}, opened=${s}, reconnectAttempts=${this.reconnectAttempts}`),this.stopHeartbeat(),this.clearHeartbeatTimeout(),this.emit("disconnected",e,t),this.openedAt!==null&&Date.now()-this.openedAt>=p&&(this.reconnectAttempts=0,this.consecutiveRefreshFailures=0),this.openedAt=null,s||n(new Error(`WebSocket \u8FDE\u63A5\u5728\u5EFA\u7ACB\u524D\u5173\u95ED: code=${e}, reason=${o}`)),this.isManualClose||(e===1008?await this.handleTokenExpiredAndReconnect():this.scheduleReconnect())}async handleTokenExpiredAndReconnect(){const e=await this.refreshRuntimeTokenOnPolicyRejection();if(!this.isManualClose){if(e==="refreshed"){r.info("[WebSocket] runtime token \u5DF2\u5237\u65B0\uFF0C\u4F7F\u7528\u65B0 token \u91CD\u8FDE"),this.consecutiveRefreshFailures=0,this.scheduleReconnect();return}if(e==="unchanged"){r.warn("[WebSocket] bridge \u8FD4\u56DE token \u672A\u53D8\u5316\u4E14\u670D\u52A1\u7AEF 1008 \u62D2\u7EDD\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85\u65B0 token \u7B7E\u53D1"),this.emit("tokenRejected",this.config.runtimeAccessToken),this.enterSlowReconnect();return}if(this.consecutiveRefreshFailures+=1,this.consecutiveRefreshFailures>=g){r.error(`[WebSocket] runtime token \u5237\u65B0\u8FDE\u7EED\u5931\u8D25 ${this.consecutiveRefreshFailures} \u6B21\uFF0C\u964D\u7EA7\u4E3A\u6162\u901F\u91CD\u8BD5\u7B49\u5F85 bridge \u6062\u590D`),this.emit("tokenRefreshFailed",this.consecutiveRefreshFailures),this.enterSlowReconnect();return}r.warn(`[WebSocket] runtime token \u5237\u65B0\u5931\u8D25\uFF0C\u7B2C ${this.consecutiveRefreshFailures}/${g} \u6B21\u5C1D\u8BD5\u91CD\u8FDE`),this.scheduleReconnect()}}enterSlowReconnect(){this.reconnectAttempts=Math.max(this.reconnectAttempts,k),this.scheduleReconnect()}async refreshRuntimeTokenOnPolicyRejection(){const e=this.config.runtimeBridgeBaseUrl;if(!e||!this.agentId)return"failed";const t=this.config.runtimeAccessToken||"",s=Math.min(this.config.mcpHttpRequestTimeoutMs??12e4,1e4),n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const i=await fetch(`${e}/runtime/binding/refresh-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:this.agentId,currentToken:t,forceRefresh:!0}),signal:n.signal});if(!i.ok)return r.warn(`[WebSocket] bridge refresh-token \u8FD4\u56DE ${i.status}\uFF0C\u65E0\u6CD5\u5237\u65B0`),"failed";const h=(await i.json()).runtimeAccessToken;return!h||h===t?"unchanged":(this.config.runtimeAccessToken=h,this.lastRefreshedToken=t,r.info("[WebSocket] runtimeAccessToken \u5DF2\u901A\u8FC7 bridge refresh \u66F4\u65B0"),"refreshed")}catch(i){return i instanceof Error&&i.name==="AbortError"?r.warn(`[WebSocket] bridge refresh-token \u8D85\u65F6\uFF08${s}ms\uFF09`):(r.warn("[WebSocket] bridge refresh-token \u5F02\u5E38: %s",i instanceof Error?i.message:String(i)),i instanceof Error&&i.stack&&r.warn("[WebSocket] refresh-token \u5F02\u5E38\u5806\u6808:",i.stack.slice(0,2e3))),"failed"}finally{clearTimeout(o)}}handleWebSocketError(e,t,s){const n=this.ws?.readyState;r.error("[WebSocket] \u8FDE\u63A5\u9519\u8BEF: readyState=%s, opened=%s, reconnectAttempts=%s, message=%s",n,t,this.reconnectAttempts,e.message),r.error("[WebSocket] \u9519\u8BEF\u5806\u6808:",e.stack?.slice(0,2e3)),this.emit("error",e),t||s(e)}disconnect(){this.isManualClose=!0,this.stopHeartbeat(),this.clearHeartbeatTimeout(),this.clearReconnectTimer(),this.ws&&(this.ws.readyState===a.OPEN?this.ws.close(1e3,"Agent logout"):this.ws.readyState!==a.CLOSED&&this.ws.terminate(),this.ws=null),this.agentId=null,r.info("[WebSocket] \u5DF2\u65AD\u5F00\u8FDE\u63A5")}send(e){const t=this.ws?.readyState;if(!this.ws||t!==a.OPEN)return r.warn("[WebSocket] \u8FDE\u63A5\u672A\u5EFA\u7ACB\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F: readyState=%s, isManualClose=%s, agentId=%s",t,this.isManualClose,this.agentId),!1;try{return this.ws.send(JSON.stringify(e)),!0}catch(s){return r.error("[WebSocket] send() \u53D1\u9001\u6D88\u606F\u5F02\u5E38: readyState=%s, error=%s",t,s),!1}}sendMcpNodeLog(e){return this.isConnected()?(this.logBatchQueue.push(e),this.logBatchTimer||(this.logBatchTimer=setTimeout(()=>{this.logBatchTimer=null,this.flushLogBatch()},l)),!0):!1}flushLogBatch(){if(this.logBatchQueue.length===0||this.isProcessingLogBatch)return;const e=this.logBatchQueue.splice(0,E);if(e.length===0)return;this.isProcessingLogBatch=!0,this.logSequenceNumber+=1;const t=this.logSequenceNumber;new Promise((n,o)=>{this.pendingLogBatches.set(t,{logs:e,sequenceNumber:t,retryCount:0,resolve:n,reject:o})}).then(()=>{this.isProcessingLogBatch=!1,this.logBatchQueue.length>0&&(this.logBatchTimer=setTimeout(()=>{this.logBatchTimer=null,this.flushLogBatch()},l))}).catch(()=>{this.isProcessingLogBatch=!1}),this.sendLogBatch(t)}sendLogBatch(e){const t=this.pendingLogBatches.get(e);if(!t)return;this.send({type:"MCP_NODE_LOG_BATCH",data:{sequenceNumber:e,logs:t.logs},timestamp:new Date().toISOString()})||this.handleLogBatchSendFailure(e)}handleLogBatchSendFailure(e){const t=this.pendingLogBatches.get(e);t&&(t.retryCount+=1,t.retryCount<=d?(r.warn(`[WebSocket] \u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25\uFF0C\u7B2C ${t.retryCount} \u6B21\u91CD\u8BD5`),setTimeout(()=>{this.sendLogBatch(e)},l*t.retryCount)):(r.error(`[WebSocket] \u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25\uFF0C\u5DF2\u91CD\u8BD5 ${d} \u6B21\uFF0C\u4E22\u5F03`),this.pendingLogBatches.delete(e),t.reject(new Error(`\u65E5\u5FD7\u6279\u6B21 #${e} \u53D1\u9001\u5931\u8D25`))))}handleLogAck(e){const s=Number(e?.ackSequenceNumber);if(!s||!this.pendingLogBatches.has(s))return;const n=this.pendingLogBatches.get(s);n&&(this.pendingLogBatches.delete(s),n.resolve())}isConnected(){return this.ws!==null&&this.ws.readyState===a.OPEN}handleMessage(e){switch(e.type){case"GROUP_MSG":this.emit("groupMessage",e.data);break;case"DM_MSG":this.emit("directMessage",e.data);break;case"MEETING_MSG":u("ws.MEETING_MSG",`\u6536\u5230\u4F1A\u8BAE\u6D88\u606F WS \u63A8\u9001: msgId=${String(e.data?.msgId??"-")} content=${String(e.data?.content??"").slice(0,120)}`),this.emit("meetingMessage",e.data);break;case"SYSTEM_NOTIFY":u("ws.SYSTEM_NOTIFY",`type=${String(e.data?.type??"-")}`),this.emit("systemNotify",e.data);break;case"ONLINE_CHANGE":this.emit("onlineChange",e.data);break;case"HEARTBEAT":this.markHeartbeatReceived();break;case"PROFILE_INFO":r.info("[WebSocket] \u6536\u5230 PROFILE_INFO \u6D88\u606F"),this.emit("profileInfo",e.data);break;case"AGENT_CONFIG":r.info("[WebSocket] \u6536\u5230 AGENT_CONFIG \u6D88\u606F"),this.emit("agentConfig",e.data);break;case"AGENT_STATUS":r.info("[WebSocket] \u6536\u5230 AGENT_STATUS \u6D88\u606F"),this.emit("agentStatus",e.data);break;case"LOG_ACK":this.handleLogAck(e.data);break;case"GROUP_READ_RECEIPT":case"DM_READ_RECEIPT":case"TERMINAL_OUTPUT":case"TERMINAL_STATUS":case"MCP_NODE_LOG":case"AGENT_EVENTS_DELTA":break;default:r.warn("[WebSocket] \u672A\u77E5\u6D88\u606F\u7C7B\u578B:",e.type)}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{this.isConnected()&&(this.ensureHeartbeatTimeout(),this.sendProtocolPing(),this.send({type:"HEARTBEAT",data:"ping",timestamp:new Date().toISOString()}))},this.config.heartbeatInterval)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.clearHeartbeatTimeout()}sendProtocolPing(){if(!(!this.ws||this.ws.readyState!==a.OPEN))try{this.ws.ping()}catch(e){r.warn("[WebSocket] \u534F\u8BAE\u5C42 ping \u53D1\u9001\u5931\u8D25\uFF0C\u7EC8\u6B62\u8FDE\u63A5\u5E76\u91CD\u8FDE:",e instanceof Error?e.message:String(e)),this.ws.terminate()}}markHeartbeatReceived(){this.clearHeartbeatTimeout()}ensureHeartbeatTimeout(){this.heartbeatTimeoutTimer||(this.heartbeatTimeoutTimer=setTimeout(()=>{this.heartbeatTimeoutTimer=null,!(!this.ws||this.ws.readyState!==a.OPEN)&&(r.warn(`[WebSocket] ${this.resolveHeartbeatTimeout()}ms \u672A\u6536\u5230\u5FC3\u8DF3\u54CD\u5E94\uFF0C\u7EC8\u6B62\u8FDE\u63A5\u5E76\u89E6\u53D1\u91CD\u8FDE`),this.ws.terminate())},this.resolveHeartbeatTimeout()))}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null)}resolveHeartbeatTimeout(){return this.config.heartbeatTimeout??T}scheduleReconnect(){if(this.isManualClose)return;const e=this.config.maxReconnectAttempts!==-1;if(e&&this.reconnectAttempts>=this.config.maxReconnectAttempts){r.error("[WebSocket] \u91CD\u8FDE\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF0C\u653E\u5F03\u91CD\u8FDE"),this.emit("reconnectFailed");return}if(this.reconnectTimer)return;this.reconnectAttempts++;const t=Math.min(this.config.reconnectInterval*Math.pow(2,this.reconnectAttempts-1),this.config.reconnectMaxInterval??S),s=Math.random()*(this.config.reconnectJitterMs??b),n=Math.round(t+s),o=e?`\u7B2C ${this.reconnectAttempts}/${this.config.maxReconnectAttempts} \u6B21`:`\u7B2C ${this.reconnectAttempts} \u6B21\uFF08\u65E0\u9650\u91CD\u8BD5\u6A21\u5F0F\uFF09`;r.warn(`[WebSocket] ${n}ms \u540E\u5C1D\u8BD5${o}\u91CD\u8FDE (base=${Math.round(t)}ms, jitter=+${Math.round(s)}ms)...`),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.agentId&&this.connect(this.agentId).catch(i=>{const c=i instanceof Error?i.message:String(i),h=i instanceof Error?i.stack:void 0;r.warn("[WebSocket] \u91CD\u8FDE\u5931\u8D25 (attempt #%s), \u7EE7\u7EED\u91CD\u8BD5: %s",this.reconnectAttempts,c),h&&r.warn("[WebSocket] \u91CD\u8FDE\u5931\u8D25\u5806\u6808:",h.slice(0,2e3)),this.scheduleReconnect()})},n)}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}}export{_ as WebSocketClient};
2
2
 
@@ -15,7 +15,7 @@
15
15
  "build": "tsc && node ../../scripts/minify-dist.mjs",
16
16
  "dev": "tsc --watch",
17
17
  "start": "node dist/index.js",
18
- "test": "npm run build && tsc -p tsconfig.test.json && node --test --test-timeout=60000 \"dist-test/**/*.test.js\"",
18
+ "test": "npm run build && tsc -p tsconfig.test.json && node --test --test-force-exit --test-timeout=60000 \"dist-test/**/*.test.js\"",
19
19
  "prepare": "npm run build",
20
20
  "lint": "eslint src --max-warnings 0",
21
21
  "lint:fix": "eslint src --fix",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-runtime-bridge",
3
- "version": "1.9.162",
3
+ "version": "1.9.169",
4
4
  "description": "AgentsWorkStudio runtime bridge service for machine-level agent runtime integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",