shennian 0.3.28 → 0.3.30

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.
@@ -136,8 +136,8 @@
136
136
  },
137
137
  {
138
138
  "file": "src/agents/workbuddy.js",
139
- "beforeBytes": 12451,
140
- "afterBytes": 6549
139
+ "beforeBytes": 13410,
140
+ "afterBytes": 6941
141
141
  },
142
142
  {
143
143
  "file": "src/commands/agent.js",
@@ -401,8 +401,8 @@
401
401
  },
402
402
  {
403
403
  "file": "src/room/activation-service.js",
404
- "beforeBytes": 15557,
405
- "afterBytes": 9269
404
+ "beforeBytes": 15683,
405
+ "afterBytes": 9330
406
406
  },
407
407
  {
408
408
  "file": "src/room/agent-tool.js",
@@ -2,6 +2,7 @@ import type { ChatAttachmentMeta, ExternalChannelSessionStatus, SessionRunPhase
2
2
  import { AgentAdapter, type AgentSendContext } from './adapter.js';
3
3
  export declare function normalizeWorkBuddyModelId(modelId?: string | null): string | undefined;
4
4
  export declare function normalizeWorkBuddyReasoningEffort(value?: string | null): string | undefined;
5
+ export declare function workBuddySystemPromptArgs(systemPrompt: string | null, platform: NodeJS.Platform, promptFile?: string): string[];
5
6
  export declare class WorkBuddyAdapter extends AgentAdapter {
6
7
  readonly type: "workbuddy";
7
8
  private process;
@@ -1,3 +1,3 @@
1
- import{createInterface as g}from"node:readline";import{randomUUID as y}from"node:crypto";import{AgentAdapter as I,registerAgent as S}from"./adapter.js";import{resolveBuiltinCommand as k,spawnAgentCommand as _}from"./command-spec.js";import{buildAgentProcessEnv as x}from"../agent-env.js";import{buildPlatformInstructions as w}from"./platform-instructions.js";import{ensureWorkBuddyRoomPluginBundle as E}from"../integrations/workbuddy-plugin-bundle.js";import{roomMcpHostToolName as P}from"../integrations/room-plugin-shared.js";const B=new Set(["minimal","low","medium","high","xhigh","max"]);function T(i){const t=i?.trim();return t&&t!=="auto"?t:void 0}function W(i){const t=i?.trim();if(t){if(B.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}class C extends I{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,s,e){this.workDir=s,this.seq=0,e&&(this.agentSessionId=e)}async send(t,s,e,o,a,n){await this.killProcess(),this.runId=y(),this.resetRunState();const u=n?.source==="room_activation",r=["-p",t,"--output-format","stream-json","--verbose","--permission-mode",u?"dontAsk":"auto","--setting-sources","user,project,local"],h=T(s);h&&r.push("--model",h);const m=E(),l=P("workbuddy");u?r.push("--allowedTools",l,"--tools",`NoDefer(${l})`,"--mcp-config",m.mcpFile,"--strict-mcp-config","--disallowedTools","mcp__shennian_room__shennian_agent","--max-turns","2"):r.push("--allowedTools",l,"--tools",`*,NoDefer(${l})`),r.push("--plugin-dir",m.pluginRoot);const p=this.shennianSessionId?.startsWith("room-managed-")&&!this.agentSessionId&&!u?null:w(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);p&&r.push("--append-system-prompt",p);const f=W(e);f&&r.push("--effort",f),this.agentSessionId&&r.push("--resume",this.agentSessionId),this.spawnAndParse(r)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const s=k("workbuddy");if(!s){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const e=_(s,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:x(this.extraEnv)});this.process=e,g({input:e.stdout}).on("line",n=>{if(n.trim())try{this.handleStreamEvent(JSON.parse(n))}catch{}});let a="";e.stderr?.on("data",n=>{a=`${a}${n.toString()}`.slice(-8e3)}),e.on("close",n=>{this.process===e&&(this.process=null,this.runPhase=null,this.handleProcessClose(n,a))}),e.on("error",n=>{if(this.process!==e)return;this.process=null,this.runPhase=null;const u=n.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:u?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":d(n.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const e=t.message?.content;if(e?.length)for(const o of e)this.handleContentBlock(o);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:c(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:d(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const s=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens??0,outputTokens:s.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:c(t.content)})}emitText(t,s){this.runPhase=s?"thinking":"streaming_text";const e=!s&&this.hasEmittedText?`
1
+ import{createInterface as y}from"node:readline";import{randomUUID as I}from"node:crypto";import{AgentAdapter as k,registerAgent as w}from"./adapter.js";import{resolveBuiltinCommand as S,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as _}from"../agent-env.js";import{buildPlatformInstructions as E,ensurePlatformInstructionsFile as B}from"./platform-instructions.js";import{ensureWorkBuddyRoomPluginBundle as P}from"../integrations/workbuddy-plugin-bundle.js";import{roomMcpHostToolName as T}from"../integrations/room-plugin-shared.js";const W=new Set(["minimal","low","medium","high","xhigh","max"]);function C(n){const t=n?.trim();return t&&t!=="auto"?t:void 0}function A(n){const t=n?.trim();if(t){if(W.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}function D(n,t,e){if(!n)return[];if(t==="win32"){if(!e)throw new Error("WorkBuddy system prompt file is required on Windows.");return["--system-prompt-file",e]}return["--append-system-prompt",n]}class O extends k{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,e,s){this.workDir=e,this.seq=0,s&&(this.agentSessionId=s)}async send(t,e,s,o,a,i){await this.killProcess(),this.runId=I(),this.resetRunState();const u=i?.source==="room_activation",r=["-p",t,"--output-format","stream-json","--verbose","--permission-mode",u?"dontAsk":"auto","--setting-sources","user,project,local"],h=C(e);h&&r.push("--model",h);const m=P(),l=T("workbuddy");u?r.push("--allowedTools",l,"--tools",`NoDefer(${l})`,"--mcp-config",m.mcpFile,"--strict-mcp-config","--disallowedTools","mcp__shennian_room__shennian_agent","--max-turns","2"):r.push("--allowedTools",l,"--tools",`*,NoDefer(${l})`),r.push("--plugin-dir",m.pluginRoot);const p=this.shennianSessionId?.startsWith("room-managed-")&&!this.agentSessionId&&!u?null:E(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);if(p){const g=process.platform==="win32"?B(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a):void 0;r.push(...D(p,process.platform,g))}const f=A(s);f&&r.push("--effort",f),this.agentSessionId&&r.push("--resume",this.agentSessionId),this.spawnAndParse(r)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const e=S("workbuddy");if(!e){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const s=x(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:_(this.extraEnv)});this.process=s,y({input:s.stdout}).on("line",i=>{if(i.trim())try{this.handleStreamEvent(JSON.parse(i))}catch{}});let a="";s.stderr?.on("data",i=>{a=`${a}${i.toString()}`.slice(-8e3)}),s.on("close",i=>{this.process===s&&(this.process=null,this.runPhase=null,this.handleProcessClose(i,a))}),s.on("error",i=>{if(this.process!==s)return;this.process=null,this.runPhase=null;const u=i.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:u?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":d(i.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const s=t.message?.content;if(s?.length)for(const o of s)this.handleContentBlock(o);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:c(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:d(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const e=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:e?{inputTokens:e.input_tokens??0,outputTokens:e.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:c(t.content)})}emitText(t,e){this.runPhase=e?"thinking":"streaming_text";const s=!e&&this.hasEmittedText?`
2
2
 
3
- `:"";this.emitEvent({state:"delta",text:e+t,thinking:s||void 0}),s||(this.hasEmittedText=!0)}handleProcessClose(t,s){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:d(s)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const o=()=>{e||(e=!0,s())};t.once("close",o),setTimeout(()=>{t.kill("SIGKILL"),o()},3e3).unref?.()}))}}function c(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return"[unserializable WorkBuddy tool result]"}}function d(i){return i.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}S("workbuddy",()=>new C);export{C as WorkBuddyAdapter,T as normalizeWorkBuddyModelId,W as normalizeWorkBuddyReasoningEffort,d as sanitizeWorkBuddyError};
3
+ `:"";this.emitEvent({state:"delta",text:s+t,thinking:e||void 0}),e||(this.hasEmittedText=!0)}handleProcessClose(t,e){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:d(e)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,t.kill("SIGTERM"),await new Promise(e=>{let s=!1;const o=()=>{s||(s=!0,e())};t.once("close",o),setTimeout(()=>{t.kill("SIGKILL"),o()},3e3).unref?.()}))}}function c(n){if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return"[unserializable WorkBuddy tool result]"}}function d(n){return n.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}w("workbuddy",()=>new O);export{O as WorkBuddyAdapter,C as normalizeWorkBuddyModelId,A as normalizeWorkBuddyReasoningEffort,d as sanitizeWorkBuddyError,D as workBuddySystemPromptArgs};
@@ -1,4 +1,4 @@
1
- import{selectRoomActivationTargets as A}from"./activation-policy.js";import{isInterruptedRoomActivation as _}from"./session-registry.js";const M=4,w=6e4,$=6,g=5*6e4,C=5*6e4;class O{deps;constructor(e){this.deps=e}async processMessages(e,t,i,s={roomName:"\u5F53\u524D\u7FA4\u804A"}){const a=[...t].sort((o,c)=>q(o.sequence,c.sequence));for(const o of a){const c=new Set(A(o,i).map(d=>d.registration.registryKey));for(const d of i){const r=this.deps.registry.getByRegistryKey(d.registryKey);if(!(!r?.binding||r.binding.roomId!==e)&&!(BigInt(o.sequence)<=BigInt(r.binding.lastActivatedSequence))){if(c.has(r.registryKey)){const u=(o.activationCause?.hopCount??0)+(o.author.principalType==="agent"?1:0),p=o.activationCause?.rootCauseMessageId??o.id;if(u>M)this.audit(r,o.id,p,u,"suppressed","max_hops");else{const m=r.binding.activeActivation;m&&_(m)&&await this.stopActiveActivation(r,"suppressed","daemon_restart_interrupted",this.deps.now?.()??new Date);const y=h([o]),I=r.binding.activationMode==="mention_only"?S([...(r.binding.mentionContext??[]).map(b=>b.deliveryText),y]):y;this.deps.registry.enqueueActivation(r.registryKey,{causeMessageId:o.id,rootCauseMessageId:p,sequence:o.sequence,hopCount:u,enqueuedAt:(this.deps.now?.()??new Date).toISOString(),attempts:0,deliveryText:I,systemPrompt:f(s,r)},this.deps.now?.()??new Date,r.binding.activationMode==="mention_only"),this.audit(r,o.id,p,u,"queued","policy_match")}}else r.binding.activationMode==="mention_only"&&o.kind!=="system"&&o.author.membershipId!==r.binding.agentMembershipId&&this.deps.registry.appendMentionContext(r.registryKey,{sequence:o.sequence,deliveryText:h([o])},this.deps.now?.()??new Date);this.deps.registry.advanceCursor({registryKey:r.registryKey,cursor:"activated",sequence:o.sequence})}}}for(const o of i)await this.drain(o.registryKey)}async drain(e){await this.deps.registry.runExclusive(e,async()=>{let t=this.deps.registry.getByRegistryKey(e),i=t?.binding;if(!t||!i)return;if(i.activeActivation){const c=this.deps.now?.()??new Date,d=this.deps.activationTurnTimeoutMs??C,r=Date.parse(i.activeActivation.dispatchedAt??i.activeActivation.enqueuedAt);if(c.getTime()-r<d||!await this.stopActiveActivation(t,"failed","turn_timeout",c)||(t=this.deps.registry.getByRegistryKey(e),i=t?.binding,!t||!i))return}const s=i.activationQueue[0];if(!s||i.status!=="active"||i.activationMode==="paused"||!t.capabilities.canResumeIdleSession||t.lifecycleState!=="inactive"&&!t.capabilities.canActivateWhileHostOpen)return;const a=this.deps.observations.getBySource(t);if(!a?.workspacePath||a.lifecycleState==="closed")return;const o=this.deps.registry.claimActivation({registryKey:e,windowMs:w,maxActivations:$,pauseMs:g,now:this.deps.now?.()});if(!o.allowed){o.newlyPaused&&this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"suppressed","rate_limited");return}this.deps.registry.markActivationDispatching(e,s.causeMessageId);try{const c=await this.deps.activate({sessionId:t.nianSessionId,agentType:v(t.runtimeAdapter),agentSessionId:t.sourceSessionKey,workDir:a.workspacePath,text:s.deliveryText??"\u7FA4\u804A\u4E2D\u6709\u4E00\u6761\u65B0\u6D88\u606F\uFF0C\u8BF7\u7ED3\u5408\u5F53\u524D\u7FA4\u804A\u4E0A\u4E0B\u6587\u5904\u7406\u3002",systemPrompt:s.systemPrompt??f({roomName:"\u5F53\u524D\u7FA4\u804A"},t),roomContextRegistryKey:t.registryKey,clientMessageId:`room-activation-${i.bindingId}-${s.causeMessageId}`});this.deps.registry.updateLifecycle(e,c?.externalOwnerQueued?"inactive":"active"),this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"activated","idle_resume")}catch(c){throw this.deps.registry.retryActiveActivation({registryKey:e,maxAttempts:3,pauseMs:g,now:this.deps.now?.()}),this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"failed",c instanceof Error?c.name:"activation_error"),c}})}async stopActiveActivation(e,t,i,s){const a=e.binding?.activeActivation;if(!a)return!0;try{await this.deps.abort({sessionId:e.nianSessionId,agentType:v(e.runtimeAdapter)})}catch(o){return this.audit(e,a.causeMessageId,a.rootCauseMessageId,a.hopCount,"failed",o instanceof Error?`${i}_${o.name}`:`${i}_abort_error`),!1}return this.deps.registry.clearActiveActivation(e.registryKey,s),this.deps.registry.updateLifecycle(e.registryKey,"inactive",s),this.audit(e,a.causeMessageId,a.rootCauseMessageId,a.hopCount,t,i),!0}audit(e,t,i,s,a,o){e.binding&&this.deps.audit?.record({roomId:e.binding.roomId,bindingId:e.binding.bindingId,causeMessageId:t,rootCauseMessageId:i,hopCount:s,outcome:a,reason:o,at:this.deps.now?.()})}}function h(n){const e=n.map(t=>{const i=t.text?.trim()||"\u53D1\u9001\u4E86\u4E00\u6761\u6D88\u606F",s=t.attachments.length>0?`
1
+ import{selectRoomActivationTargets as A}from"./activation-policy.js";import{isInterruptedRoomActivation as _}from"./session-registry.js";const M=4,w=6e4,$=6,g=5*6e4,C=5*6e4;class O{deps;constructor(e){this.deps=e}async processMessages(e,t,i,s={roomName:"\u5F53\u524D\u7FA4\u804A"}){const a=[...t].sort((o,c)=>q(o.sequence,c.sequence));for(const o of a){const c=new Set(A(o,i).map(d=>d.registration.registryKey));for(const d of i){const r=this.deps.registry.getByRegistryKey(d.registryKey);if(!(!r?.binding||r.binding.roomId!==e)&&!(r.binding.status!=="active"&&r.binding.status!=="paused")&&!(BigInt(o.sequence)<=BigInt(r.binding.lastActivatedSequence))){if(c.has(r.registryKey)){const u=(o.activationCause?.hopCount??0)+(o.author.principalType==="agent"?1:0),p=o.activationCause?.rootCauseMessageId??o.id;if(u>M)this.audit(r,o.id,p,u,"suppressed","max_hops");else{const m=r.binding.activeActivation;m&&_(m)&&await this.stopActiveActivation(r,"suppressed","daemon_restart_interrupted",this.deps.now?.()??new Date);const y=h([o]),I=r.binding.activationMode==="mention_only"?S([...(r.binding.mentionContext??[]).map(b=>b.deliveryText),y]):y;this.deps.registry.enqueueActivation(r.registryKey,{causeMessageId:o.id,rootCauseMessageId:p,sequence:o.sequence,hopCount:u,enqueuedAt:(this.deps.now?.()??new Date).toISOString(),attempts:0,deliveryText:I,systemPrompt:f(s,r)},this.deps.now?.()??new Date,r.binding.activationMode==="mention_only"),this.audit(r,o.id,p,u,"queued","policy_match")}}else r.binding.activationMode==="mention_only"&&o.kind!=="system"&&o.author.membershipId!==r.binding.agentMembershipId&&this.deps.registry.appendMentionContext(r.registryKey,{sequence:o.sequence,deliveryText:h([o])},this.deps.now?.()??new Date);this.deps.registry.advanceCursor({registryKey:r.registryKey,cursor:"activated",sequence:o.sequence})}}}for(const o of i)await this.drain(o.registryKey)}async drain(e){await this.deps.registry.runExclusive(e,async()=>{let t=this.deps.registry.getByRegistryKey(e),i=t?.binding;if(!t||!i)return;if(i.activeActivation){const c=this.deps.now?.()??new Date,d=this.deps.activationTurnTimeoutMs??C,r=Date.parse(i.activeActivation.dispatchedAt??i.activeActivation.enqueuedAt);if(c.getTime()-r<d||!await this.stopActiveActivation(t,"failed","turn_timeout",c)||(t=this.deps.registry.getByRegistryKey(e),i=t?.binding,!t||!i))return}const s=i.activationQueue[0];if(!s||i.status!=="active"||i.activationMode==="paused"||!t.capabilities.canResumeIdleSession||t.lifecycleState!=="inactive"&&!t.capabilities.canActivateWhileHostOpen)return;const a=this.deps.observations.getBySource(t);if(!a?.workspacePath||a.lifecycleState==="closed")return;const o=this.deps.registry.claimActivation({registryKey:e,windowMs:w,maxActivations:$,pauseMs:g,now:this.deps.now?.()});if(!o.allowed){o.newlyPaused&&this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"suppressed","rate_limited");return}this.deps.registry.markActivationDispatching(e,s.causeMessageId);try{const c=await this.deps.activate({sessionId:t.nianSessionId,agentType:v(t.runtimeAdapter),agentSessionId:t.sourceSessionKey,workDir:a.workspacePath,text:s.deliveryText??"\u7FA4\u804A\u4E2D\u6709\u4E00\u6761\u65B0\u6D88\u606F\uFF0C\u8BF7\u7ED3\u5408\u5F53\u524D\u7FA4\u804A\u4E0A\u4E0B\u6587\u5904\u7406\u3002",systemPrompt:s.systemPrompt??f({roomName:"\u5F53\u524D\u7FA4\u804A"},t),roomContextRegistryKey:t.registryKey,clientMessageId:`room-activation-${i.bindingId}-${s.causeMessageId}`});this.deps.registry.updateLifecycle(e,c?.externalOwnerQueued?"inactive":"active"),this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"activated","idle_resume")}catch(c){throw this.deps.registry.retryActiveActivation({registryKey:e,maxAttempts:3,pauseMs:g,now:this.deps.now?.()}),this.audit(t,s.causeMessageId,s.rootCauseMessageId,s.hopCount,"failed",c instanceof Error?c.name:"activation_error"),c}})}async stopActiveActivation(e,t,i,s){const a=e.binding?.activeActivation;if(!a)return!0;try{await this.deps.abort({sessionId:e.nianSessionId,agentType:v(e.runtimeAdapter)})}catch(o){return this.audit(e,a.causeMessageId,a.rootCauseMessageId,a.hopCount,"failed",o instanceof Error?`${i}_${o.name}`:`${i}_abort_error`),!1}return this.deps.registry.clearActiveActivation(e.registryKey,s),this.deps.registry.updateLifecycle(e.registryKey,"inactive",s),this.audit(e,a.causeMessageId,a.rootCauseMessageId,a.hopCount,t,i),!0}audit(e,t,i,s,a,o){e.binding&&this.deps.audit?.record({roomId:e.binding.roomId,bindingId:e.binding.bindingId,causeMessageId:t,rootCauseMessageId:i,hopCount:s,outcome:a,reason:o,at:this.deps.now?.()})}}function h(n){const e=n.map(t=>{const i=t.text?.trim()||"\u53D1\u9001\u4E86\u4E00\u6761\u6D88\u606F",s=t.attachments.length>0?`
2
2
  \u9644\u4EF6\uFF1A${t.attachments.map(a=>a.name).join("\u3001")}`:"";return{speaker:t.author.displayName,body:`${i}${s}`}});return l(e)}function S(n){return l(n.map(T))}function T(n){const e=n.match(/^\[群消息\][ \t]+<([^>\n]+)>\n([\s\S]*)$/);if(e)return{speaker:e[1],body:e[2]};const t=n.match(/^\[群消息\]\n<([^>\n]+)>\n([\s\S]*)$/);if(t)return{speaker:t[1],body:t[2]};const i=n.match(/^群消息\n([^\n]+)\n([\s\S]*)$/);if(i)return{speaker:i[1],body:i[2]};const s=n.match(/^([^\n]+)\n([\s\S]*)$/);return s?{speaker:s[1],body:s[2]}:{speaker:"\u7FA4\u6210\u5458",body:n.trim()}}function l(n){if(n.length===1){const[e]=n;return`[\u7FA4\u6D88\u606F] <${e.speaker}>
3
3
  ${e.body}`}return`[\u7FA4\u6D88\u606F]
4
4
  ${n.map(e=>`<${e.speaker}>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.3.28",
3
+ "version": "0.3.30",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {