shennian 0.3.27 → 0.3.29
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.
|
@@ -296,8 +296,8 @@
|
|
|
296
296
|
},
|
|
297
297
|
{
|
|
298
298
|
"file": "src/integrations/room-session-hook.js",
|
|
299
|
-
"beforeBytes":
|
|
300
|
-
"afterBytes":
|
|
299
|
+
"beforeBytes": 12856,
|
|
300
|
+
"afterBytes": 6456
|
|
301
301
|
},
|
|
302
302
|
{
|
|
303
303
|
"file": "src/integrations/workbuddy-plugin-bundle.js",
|
|
@@ -401,8 +401,8 @@
|
|
|
401
401
|
},
|
|
402
402
|
{
|
|
403
403
|
"file": "src/room/activation-service.js",
|
|
404
|
-
"beforeBytes":
|
|
405
|
-
"afterBytes":
|
|
404
|
+
"beforeBytes": 15683,
|
|
405
|
+
"afterBytes": 9330
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
"file": "src/room/agent-tool.js",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import E from"node:crypto";import{callDaemonIpc as T}from"../daemon-ipc/client.js";import{DaemonIpcError as
|
|
2
|
-
`)}function
|
|
1
|
+
import E from"node:crypto";import{callDaemonIpc as T}from"../daemon-ipc/client.js";import{DaemonIpcError as h}from"../daemon-ipc/protocol.js";import{normalizeRoomActionParameters as z}from"../room/room-action-schema.js";import{SHENNIAN_ROOM_TOOL_NAME as N}from"../room/tool-schema.js";import{roomMcpHostToolName as O}from"./room-plugin-shared.js";const H=256*1024,_={SessionStart:"active",UserPromptSubmit:"active",PreCompact:"active",PostCompact:"active",PreToolUse:"active",Stop:"idle",SessionEnd:"idle"};async function F(t,o=process.stdin,n=process.stdout,r=T){let s="";for await(const a of o)if(s+=Buffer.isBuffer(a)?a.toString("utf8"):String(a),Buffer.byteLength(s,"utf8")>H)return"ignored";const e=j(t,s);if(!e)return"ignored";let d=!1;try{await r({method:"room-host-session.observe",params:{runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey,hostContextHash:e.hostContextHash,workspaceHash:e.workspaceHash,workspacePath:e.workspacePath,lifecycleState:e.lifecycleState,eventName:e.eventName},timeoutMs:2e3})}catch(a){if(a instanceof h&&a.code==="machine_not_authorized")d=!0;else return"unavailable"}if(e.eventName!=="PreToolUse")return"observed";if(e.toolName!==O(e.runtimeAdapter)||!e.toolInput)return"ignored";let i=null,c="";try{if(i=K(e.toolInput),c=C(e,i),i.action==="room.create"||i.action==="room.join")try{const u=await r({method:"authorized-action.status",params:{idempotencyKey:c},timeoutMs:2e3}),I=A(u);return S(n,e.runtimeAdapter,e.toolInput,I),"authorized"}catch(u){if(!(u instanceof h)||u.code!=="pending_action_not_found")throw u}if(d)return await w(e,i,c,n,r);const a=await r({method:"room-session.resolve",params:{runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey},timeoutMs:2e3}),l=x(a),P=await r({method:"room-invocation.issue",params:{registryKey:l,action:i.action,targetTool:N,actionParameters:i.actionParameters},timeoutMs:2e3}),k=v(P),b={action:e.toolInput.action,...$(i.actionParameters),_shennianRegistryKey:l,_shennianInvocationToken:k};return y(n,{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",permissionDecisionReason:"Authorized by the local Shennian daemon for this Agent conversation.",...g(e.runtimeAdapter,b)}}),"authorized"}catch(a){if(a instanceof h&&a.code==="machine_not_authorized"&&i&&(i.action==="room.create"||i.action==="room.join"))try{return await w(e,i,c,n,r)}catch{}return y(n,{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:"This Agent conversation is not connected to Shennian yet. Open it from Shennian or use the repair connection action."}}),"denied"}}async function w(t,o,n,r,s){if(o.action!=="room.create"&&o.action!=="room.join")throw new Error("authorization_requires_onboarding_action");const e=await s({method:"authorized-action.create",params:{actionType:o.action,actionSummary:M(o.action,o.actionParameters),actionPayload:U(t,o),idempotencyKey:n,returnTo:"/spaces"},timeoutMs:12e3});return S(r,t.runtimeAdapter,t.toolInput,A(e)),"authorized"}function j(t,o){if(t!=="codex"&&t!=="claude_code"&&t!=="workbuddy")return null;let n;try{n=JSON.parse(o)}catch{return null}if(!n||typeof n!="object"||Array.isArray(n))return null;const r=n,s=m(r.session_id,1024),e=D(r.hook_event_name);if(!s||!e)return null;const d=m(r.transcript_path,4096)??"",i=m(r.cwd,4096)??"",c=e==="PreToolUse"?m(r.tool_name,256):null,a=e==="PreToolUse"?B(r.tool_input):null,l=e==="PreToolUse"?m(r.tool_use_id??r.tool_call_id,512):null;return{runtimeAdapter:t,sourceSessionKey:s,hostContextHash:f(`${s}\0${d}`),workspaceHash:i?f(i):null,workspacePath:i||null,lifecycleState:_[e],eventName:e,toolName:c,toolInput:a,toolRequestId:l}}function K(t){const o=R(t.action);if(Object.keys(t).some(r=>r.startsWith("_shennian")))throw new Error("hidden_input");const n=Object.fromEntries(Object.entries(t).filter(([r])=>r!=="action"));return{action:o,actionParameters:z(o,n)}}function $(t){if(!t||Array.isArray(t)||typeof t!="object")throw new Error("invalid_action_parameters");return t}function R(t){const o={create:"room.create",join:"room.join",read:"room.read",send:"room.send",mode:"room.mode",status:"room.status"};if(typeof t!="string"||!(t in o))throw new Error("invalid_action");return o[t]}function x(t){const o=p(t,"registryKey");if(!/^[a-f0-9]{64}$/.test(o))throw new Error("invalid_registry");return o}function v(t){const o=p(t,"invocationToken");if(!/^sni_v1_[A-Za-z0-9_-]{40,80}$/.test(o))throw new Error("invalid_token");return o}function A(t){const o=p(t,"id");if(!/^[A-Za-z0-9_-]{8,128}$/.test(o))throw new Error("invalid_pending_action");return o}function C(t,o){const n=t.toolRequestId??f(JSON.stringify(o.actionParameters));return`${o.action.replace(".","-")}-auth:${f(`${t.runtimeAdapter}\0${t.sourceSessionKey}\0${n}`)}`}function U(t,o){return{schemaVersion:1,runtimeAdapter:t.runtimeAdapter,sourceSessionKey:t.sourceSessionKey,hostContextHash:t.hostContextHash,workspaceHash:t.workspaceHash,workspacePath:t.workspacePath,lifecycleState:t.lifecycleState,action:o.action,actionParameters:o.actionParameters}}function M(t,o){if(!o||Array.isArray(o)||typeof o!="object")throw new Error("invalid_authorized_action");const n=typeof o.agentAlias=="string"?o.agentAlias:"";return t==="room.create"?`\u521B\u5EFA\u7FA4\u804A\u300C${typeof o.name=="string"?o.name:""}\u300D\uFF0C\u5E76\u4EE5 Agent\u300C${n}\u300D\u52A0\u5165`:`\u4F7F\u7528\u5F53\u524D\u9080\u8BF7\u52A0\u5165\u7FA4\u804A\uFF0C\u5E76\u4EE5 Agent\u300C${n}\u300D\u53C2\u4E0E`}function S(t,o,n,r){const s={...n,_shennianAuthorizedActionId:r};y(t,{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",permissionDecisionReason:"Shennian will open a secure browser authorization and continue this action automatically.",...g(o,s)}})}function g(t,o){return t==="workbuddy"?{updatedInput:o,modifiedInput:o}:{updatedInput:o}}function p(t,o){if(!t||Array.isArray(t)||typeof t!="object")throw new Error("invalid_response");const n=t[o];if(typeof n!="string")throw new Error("invalid_response");return n}function D(t){return typeof t=="string"&&t in _?t:null}function m(t,o){if(typeof t!="string")return null;const n=t.trim();return!n||n.length>o||/[\0\r\n]/.test(n)?null:n}function B(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function y(t,o){t.write(`${JSON.stringify(o)}
|
|
2
|
+
`)}function f(t){return E.createHash("sha256").update(t,"utf8").digest("hex")}export{j as parseRoomSessionHookInput,F as runRoomSessionHook};
|
|
@@ -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}>
|