shennian 0.3.34 → 0.3.35

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.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 129,
5
+ "fileCount": 130,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -356,8 +356,8 @@
356
356
  },
357
357
  {
358
358
  "file": "src/native-fusion/parser-common.js",
359
- "beforeBytes": 7572,
360
- "afterBytes": 3488
359
+ "beforeBytes": 7754,
360
+ "afterBytes": 3606
361
361
  },
362
362
  {
363
363
  "file": "src/native-fusion/parsers.js",
@@ -566,8 +566,8 @@
566
566
  },
567
567
  {
568
568
  "file": "src/session/handlers/chat.js",
569
- "beforeBytes": 29425,
570
- "afterBytes": 12272
569
+ "beforeBytes": 29613,
570
+ "afterBytes": 12377
571
571
  },
572
572
  {
573
573
  "file": "src/session/handlers/control.js",
@@ -624,6 +624,11 @@
624
624
  "beforeBytes": 3925,
625
625
  "afterBytes": 1918
626
626
  },
627
+ {
628
+ "file": "src/session/tool-summary.js",
629
+ "beforeBytes": 1401,
630
+ "afterBytes": 731
631
+ },
627
632
  {
628
633
  "file": "src/session/types.js",
629
634
  "beforeBytes": 159,
@@ -1,4 +1,4 @@
1
- import{createHash as N}from"node:crypto";import g from"node:fs";import C from"node:os";import n from"node:path";const h=64*1024*1024,x=["/root/.claude-mem/observer-session"],E=x.map(z);function B(e){return _(e.replace(/\r\n/g,`
2
- `).trim())}const I=/^\s*::git-[a-z-]+\{[^\n]*\}\s*$/gm;function _(e){if(!e)return"";if(!/(^|\n)\s*::git-[a-z-]+\{[^\n]*\}\s*(?=\n|$)/.test(e))return e;const r=e.replace(I,"");return r.trim()?r.replace(/[ \t]+\n/g,`
3
- `).replace(/\n+$/g,""):""}function J(e){if(typeof e!="string")return null;const t=Date.parse(e);return Number.isFinite(t)?t:null}function R(e){try{const t=JSON.parse(e);return typeof t=="object"&&t!==null?t:null}catch{return null}}function v(e,t,r){const u=g.statSync(e).size;if(t>=u)return u;const y=g.openSync(e,"r");try{const S=Buffer.allocUnsafe(262144);let l=t,p=t,o=Buffer.alloc(0),f=!1;for(;l<u;){const m=g.readSync(y,S,0,Math.min(262144,u-l),l);if(m<=0)break;l+=m;let s=S.subarray(0,m);o.length>0&&(s=Buffer.concat([o,s]),o=Buffer.alloc(0));let c=0;for(;c<s.length;){const a=s.indexOf(10,c);if(a<0)break;const d=s.subarray(c,a),T=p;p+=a-c+1,c=a+1,!f&&d.length>0&&d.length<=h&&r(d.toString("utf8"),T),f=!1}if(c<s.length){const a=s.subarray(c);f||a.length>h?(f=!0,p+=a.length,o=Buffer.alloc(0)):o=Buffer.from(a)}}return!f&&o.length>0&&o.length<=h&&r(o.toString("utf8"),p),u}finally{g.closeSync(y)}}function F(e){return typeof e.cwd=="string"&&e.cwd.trim()?e.cwd:null}function G(e){return n.basename(n.dirname(e))==="subagents"}function b(e){const t=n.resolve(e);return process.platform==="win32"?t.toLowerCase():t}function w(e,t){const r=b(e),i=b(t);return r===i||r.startsWith(i+n.sep)}function z(e){return n.resolve(e).replace(/\//g,"-")}function M(e){return x.some(t=>w(e,t))}function D(e){return E.includes(e)}function U(e){const t=n.join(C.homedir(),".claude","projects"),r=n.relative(t,e);if(!r||r.startsWith("..")||n.isAbsolute(r))return!1;const[i]=r.split(n.sep);return i?D(i):!1}function V(e,t){return`${e}:${t}`}function H(e,t,r){return`${N("sha1").update(e).digest("hex").slice(0,16)}:${t}:${r}`}function W(e){if(e==null)return"";if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}function K(e){return e.replace(/\r\n/g,`
4
- `).trim()}function X(e){if(typeof e!="string")return e;const t=e.trim();if(!t)return"";try{return JSON.parse(t)}catch{return e}}function Y(e,t,r){return JSON.stringify({v:1,type:"tool",name:e,status:r!==void 0?"completed":"running",resultOmitted:!0})}function O(e){return e.replace(/[[\]\\]/g,"\\$&")}function k(e,t="Generated image"){return`![${O(t)}](<${e}>)`}function q(e){const t=n.basename(e)||"generated-image.png";return JSON.stringify({v:1,type:"image",content:k(e,t),attachments:[{path:e,name:t,mimeType:"image/png",kind:"image"}]})}function Q(e){const t=n.extname(e).toLowerCase();return t===".png"?"image/png":t===".jpg"||t===".jpeg"?"image/jpeg":t===".webp"?"image/webp":t===".gif"?"image/gif":"application/octet-stream"}export{q as buildImagePayload,k as buildMarkdownImageRef,Y as buildToolPayload,z as encodeClaudeProjectDir,O as escapeMarkdownLabel,Q as inferMimeType,G as isClaudeSubagentTranscript,w as isSameOrChildPath,V as makeCursor,H as makeEventKey,b as normalizePathForCompare,B as normalizeText,K as normalizeToolText,X as parseStructuredString,F as readClaudeEventCwd,v as readJsonlLines,J as readTimestamp,R as safeParse,W as safeStringify,D as shouldIgnoreClaudeProjectDir,U as shouldIgnoreClaudeTranscriptPath,M as shouldIgnoreNativeScanPath};
1
+ import{createHash as N}from"node:crypto";import m from"node:fs";import C from"node:os";import n from"node:path";import{buildToolArgsSummary as E}from"../session/tool-summary.js";const h=64*1024*1024,x=["/root/.claude-mem/observer-session"],I=x.map(D);function R(e){return w(e.replace(/\r\n/g,`
2
+ `).trim())}const _=/^\s*::git-[a-z-]+\{[^\n]*\}\s*$/gm;function w(e){if(!e)return"";if(!/(^|\n)\s*::git-[a-z-]+\{[^\n]*\}\s*(?=\n|$)/.test(e))return e;const r=e.replace(_,"");return r.trim()?r.replace(/[ \t]+\n/g,`
3
+ `).replace(/\n+$/g,""):""}function v(e){if(typeof e!="string")return null;const t=Date.parse(e);return Number.isFinite(t)?t:null}function F(e){try{const t=JSON.parse(e);return typeof t=="object"&&t!==null?t:null}catch{return null}}function G(e,t,r){const s=m.statSync(e).size;if(t>=s)return s;const y=m.openSync(e,"r");try{const S=Buffer.allocUnsafe(262144);let l=t,p=t,o=Buffer.alloc(0),f=!1;for(;l<s;){const g=m.readSync(y,S,0,Math.min(262144,s-l),l);if(g<=0)break;l+=g;let c=S.subarray(0,g);o.length>0&&(c=Buffer.concat([o,c]),o=Buffer.alloc(0));let u=0;for(;u<c.length;){const a=c.indexOf(10,u);if(a<0)break;const d=c.subarray(u,a),T=p;p+=a-u+1,u=a+1,!f&&d.length>0&&d.length<=h&&r(d.toString("utf8"),T),f=!1}if(u<c.length){const a=c.subarray(u);f||a.length>h?(f=!0,p+=a.length,o=Buffer.alloc(0)):o=Buffer.from(a)}}return!f&&o.length>0&&o.length<=h&&r(o.toString("utf8"),p),s}finally{m.closeSync(y)}}function M(e){return typeof e.cwd=="string"&&e.cwd.trim()?e.cwd:null}function U(e){return n.basename(n.dirname(e))==="subagents"}function b(e){const t=n.resolve(e);return process.platform==="win32"?t.toLowerCase():t}function z(e,t){const r=b(e),i=b(t);return r===i||r.startsWith(i+n.sep)}function D(e){return n.resolve(e).replace(/\//g,"-")}function V(e){return x.some(t=>z(e,t))}function O(e){return I.includes(e)}function H(e){const t=n.join(C.homedir(),".claude","projects"),r=n.relative(t,e);if(!r||r.startsWith("..")||n.isAbsolute(r))return!1;const[i]=r.split(n.sep);return i?O(i):!1}function W(e,t){return`${e}:${t}`}function K(e,t,r){return`${N("sha1").update(e).digest("hex").slice(0,16)}:${t}:${r}`}function X(e){if(e==null)return"";if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}function Y(e){return e.replace(/\r\n/g,`
4
+ `).trim()}function q(e){if(typeof e!="string")return e;const t=e.trim();if(!t)return"";try{return JSON.parse(t)}catch{return e}}function Q(e,t,r){const i=E(t),s={v:1,type:"tool",name:e,status:r!==void 0?"completed":"running",resultOmitted:!0,...i!==void 0?{argsSummary:i}:{}};return JSON.stringify(s)}function k(e){return e.replace(/[[\]\\]/g,"\\$&")}function A(e,t="Generated image"){return`![${k(t)}](<${e}>)`}function Z(e){const t=n.basename(e)||"generated-image.png";return JSON.stringify({v:1,type:"image",content:A(e,t),attachments:[{path:e,name:t,mimeType:"image/png",kind:"image"}]})}function ee(e){const t=n.extname(e).toLowerCase();return t===".png"?"image/png":t===".jpg"||t===".jpeg"?"image/jpeg":t===".webp"?"image/webp":t===".gif"?"image/gif":"application/octet-stream"}export{Z as buildImagePayload,A as buildMarkdownImageRef,Q as buildToolPayload,D as encodeClaudeProjectDir,k as escapeMarkdownLabel,ee as inferMimeType,U as isClaudeSubagentTranscript,z as isSameOrChildPath,W as makeCursor,K as makeEventKey,b as normalizePathForCompare,R as normalizeText,Y as normalizeToolText,q as parseStructuredString,M as readClaudeEventCwd,G as readJsonlLines,v as readTimestamp,F as safeParse,X as safeStringify,O as shouldIgnoreClaudeProjectDir,H as shouldIgnoreClaudeTranscriptPath,V as shouldIgnoreNativeScanPath};
@@ -1,2 +1,2 @@
1
- import F from"node:os";import{createAgent as Q}from"../../agents/adapter.js";import{buildApprovalPendingPayload as Y,buildUserMessagePayload as V}from"@shennian/wire";import{reportLog as T}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as G}from"../../native-fusion/parsers.js";import{appendMessage as x,recordSession as O}from"../store.js";import{mergeProjectedSessions as X}from"../projection.js";import{buildManagedAgentEnv as Z}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as ee}from"../remote-attachments.js";function te(e){if(!Array.isArray(e))return;const t=e.map(s=>{if(!s||typeof s!="object")return null;const a=s,d=typeof a.path=="string"?a.path:"",l=typeof a.name=="string"?a.name:"",g=typeof a.mimeType=="string"?a.mimeType:"";if(!d||!l||!g)return null;const i=typeof a.previewData=="string"&&a.previewData.trim()?a.previewData.trim():void 0;return{path:d,name:l,mimeType:g,kind:g.startsWith("image/")?"image":"file",...i?{previewData:i}:{}}}).filter(s=>s!=null);return t.length?t:void 0}function ne(e){const t=e.indexOf(`
2
- `),s=t>0?Math.min(t,80):Math.min(e.length,80);return e.slice(0,s)}function ae(e,t,s={}){if(e.state==="tool-call"||e.state==="tool-result"){const a={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:t,detailRef:a,...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...s}}return{...e,sessionId:t,...s}}const se=3e4;function re(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function oe(e,t){return`Agent send failed: ${t instanceof Error?t.message:String(t)}`}function W(e,t){return e!=="manager"?e:t==="claude"?"claude":"codex"}function L(e,t,s){e.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:t.sessionId,message:t,session:{id:t.sessionId,agentType:s.agentType,agentSessionId:s.agentSessionId??null,modelId:s.modelId??null,workDir:s.workDir,status:"active",externalChannel:null}}})}function de(e,t){O({sessionId:t.sessionId,agentType:t.agentType,workDir:t.workDir,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t.sessionId,agentType:t.agentType,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,workDir:t.workDir,status:"active",externalChannel:null}}})}function H(e){return Z(e)}function U(e,t,s){return{}}function j(e,t,s,a,d,l){e.configure?.({sessionId:t,externalChannel:a??null,env:{...H(s),...U(t,a,d),...l?{SHENNIAN_ROOM_REGISTRY_KEY:l}:{}}})}function ie(e,t,s){if(e!=="claude"||!s)return t;const a=t.trim();return!!a&&a.startsWith("-")&&!a.includes("/")?G(s)??t:t}function le(e,t,s,a){let d=null;function l(n,r={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:ae(n,t,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function g(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function i(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:t,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function f(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},se),n.heartbeatTimer.unref?.())}function y(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(l({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}a.on("agentEvent",n=>{const r=e.sessions.get(t),S=re(n),w=n.state==="final"||n.state==="error"||n.state==="aborted";if(r&&(r.nextEventSeq=n.seq+1,w||(r.currentRunId=n.runId),!w&&S&&(r.currentRunPhase=S,f(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),e.managerRuntime?.noteAgentEvent(t,n),n.state==="delta"&&n.thinking)return;n.state!=="delta"&&T({level:"info",sessionId:t,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:s}}),n.state==="delta"&&n.text&&!n.thinking?x(t,{id:`agent-${n.runId}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?x(t,{id:`agent-${n.runId}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?x(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:Y(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&x(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.message});const I=`${t}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&e.runTextAcc.set(I,(e.runTextAcc.get(I)??"")+n.text),n.agentSessionId&&n.agentSessionId!==d&&(d=n.agentSessionId,e.nativeFusion?.noteManagedSourceSession(t,W(s,n.source),n.agentSessionId),r&&O({sessionId:t,agentType:s,workDir:r.workDir,agentSessionId:n.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t,agentType:s,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const m=n.text??"";if(!m)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==n.runId&&y(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=m,r.pendingTextEvent.seq=n.seq);return}let R={};if(n.state==="final"){y(r);const m=e.runTextAcc.get(I)??"";m&&(R={messageSummary:ne(m)}),e.runTextAcc.delete(I)}else n.state==="error"||n.state==="aborted"?(y(r),e.runTextAcc.delete(I)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&y(r);w&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,g(r),e.chatQueue?.noteTerminal(t)),l(n,R)}),a.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${t} agentType=${s}: ${n.message}`),e.sessions.delete(t),e.chatQueue?.noteTerminal(t),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:n.message,runId:"",seq:0}})})}function ce(e,t){if(e.processedReqIds.add(t),e.processedReqIds.size>1e3){const s=e.processedReqIds.values().next().value;e.processedReqIds.delete(s)}}async function P(e){e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{})}function B(e,t,s,a,d,l,g){return g?e.send(t,s,a,d,l,g):l?.trim()?e.send(t,s,a,d,l):d?.length?e.send(t,s,a,d):a?e.send(t,s,a):e.send(t,s)}async function ue(e,t,s,a,d,l,g){e.evictIdleSessions();const i=Q(s);if(!i)throw new Error(`Unsupported agent: ${s}`);j(i,t,s,l,g),await i.start(t,a,d);const f={adapter:i,workDir:a,agentType:s,agentSessionId:d??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:g??null,externalChannelEnv:{...H(s),...U(t,l,g)}};return e.sessions.set(t,f),le(e,t,s,i),f}function ge(e,t){const s=e.sessions.get(t),a=s?.currentRunId;if(!s||!a)return;const d=s.nextEventSeq;e.runTextAcc.delete(`${t}:${a}`),s.pendingTextEvent=null,s.currentRunId=null,s.currentRunPhase=null,s.nextEventSeq=0,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:t,runId:a,seq:d},seq:d,id:`agent-evt-${a}-${d}`}),e.chatQueue?.noteTerminal(t)}async function xe(e,t,s){if(e.processedReqIds.has(t.id)){e.client.sendRes({type:"res",id:t.id,ok:!0});return}ce(e,t.id);const{sessionId:a,text:d,agentType:l,workDir:g,agentSessionId:i,modelId:f,systemPrompt:y,managerDefaultWorkerAgentType:n,managerDefaultWorkerModelId:r,reasoningEffort:S,clientMessageId:w,sessionListProjection:I,waitForDispatch:R,responseId:m,roomContextRegistryKey:$,suppressExternalOwnerEcho:J}=t.params,A=m||t.id;X(I);const b=null,M="";if(!a||!d){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:"sessionId and text are required"});return}const u=l;u==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(a,n??null,r??null);const q=(u==="claude"||u==="codex"||u==="workbuddy")&&typeof S=="string"&&S.trim()?S.trim():void 0,E=e.resolvePath(ie(u,g||F.homedir(),i)||F.homedir()),D=E,_=te(t.params.attachments),p=_?.length?await ee({text:d,attachments:_,workDir:E}):{text:d,attachments:_,localized:!1};let o=e.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==E||JSON.stringify(o.externalChannel??null)!==JSON.stringify(b??null)){e.sessions.delete(a);try{await P(o)}catch{e.processedReqIds.delete(t.id)}o=void 0}else if(i&&o.agentSessionId!==i)try{await o.adapter.resume(i),o.agentSessionId=i}catch{e.sessions.delete(a);try{await P(o)}catch{e.processedReqIds.delete(t.id)}o=void 0}}if(!o)try{o=await ue(e,a,u,E,i,b,M)}catch(c){const h=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${l}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${t.id} sessionId=${a} agentType=${l} workDir=${E} agentSessionId=${i??""}: ${h}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:h,runId:"",seq:0}}),e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:h});return}$&&/^[a-f0-9]{64}$/.test($)&&j(o.adapter,a,u,b,M,$);const C={id:w??`user-${t.id}`,sessionId:a,role:"user",ts:Date.now(),payload:V(p.text,p.attachments)};T({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:t.id,agentType:u,modelId:f,reasoningEffort:q}});const z=c=>{de(e,{sessionId:a,agentType:u,workDir:D,agentSessionId:o.agentSessionId??i??null,modelId:f}),o.currentRunId||(o.nextEventSeq=0),e.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:W(u,f),canonicalMessageId:w??null,sourceSessionKey:o.agentSessionId??i??null,text:p.text,managedEchoPolicy:c?.deliveryMode==="external_owner_queue"&&!J?"import_following":"suppress_following"}),x(a,C),L(e,C,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??i??null,modelId:f})},v=async(c,h)=>{const k=oe(u,c);console.error(`[chat.send] send failed reqId=${t.id} sessionId=${a} agentType=${l} workDir=${E} agentSessionId=${o.agentSessionId??i??""}: ${k}`),e.sessions.delete(a);try{await P(o)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!h){const N={id:`agent-error-${t.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};x(a,N),L(e,N,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??i??null,modelId:f})}h&&(e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:k}))};if(R){let c;try{const h=p.attachments;c=await B(o.adapter,p.text,f,q,h,y,s),T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}catch(h){await v(h,!0);return}z(c??void 0),e.client.sendRes({type:"res",id:A,ok:!0,...p.localized||c?.deliveryMode==="external_owner_queue"?{payload:{...p.localized?{localizedAttachments:!0}:{},...c?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:c.deliveryMode,queuedSubmissionId:c.queuedSubmissionId}:{}}}:{}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});return}z(),e.client.sendRes({type:"res",id:A,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});const K=p.attachments;B(o.adapter,p.text,f,q,K,y,s).then(()=>{T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}).catch(c=>{v(c,!1)})}async function Ae(e,t){const{sessionId:s}=t.params,a=e.sessions.get(s);if(a){try{await a.adapter.stop()}catch{}ge(e,s),e.activityPublisher?.publish(s,null)}e.client.sendRes({type:"res",id:t.id,ok:!0})}export{Ae as handleChatAbort,xe as handleChatSend,de as sendSessionUpdateEvent};
1
+ import F from"node:os";import{createAgent as Q}from"../../agents/adapter.js";import{buildApprovalPendingPayload as Y,buildUserMessagePayload as V}from"@shennian/wire";import{reportLog as T}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as G}from"../../native-fusion/parsers.js";import{appendMessage as x,recordSession as O}from"../store.js";import{mergeProjectedSessions as X}from"../projection.js";import{buildManagedAgentEnv as Z}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as ee}from"../remote-attachments.js";import{buildToolArgsSummary as te}from"../tool-summary.js";function ne(e){if(!Array.isArray(e))return;const t=e.map(r=>{if(!r||typeof r!="object")return null;const a=r,o=typeof a.path=="string"?a.path:"",l=typeof a.name=="string"?a.name:"",g=typeof a.mimeType=="string"?a.mimeType:"";if(!o||!l||!g)return null;const i=typeof a.previewData=="string"&&a.previewData.trim()?a.previewData.trim():void 0;return{path:o,name:l,mimeType:g,kind:g.startsWith("image/")?"image":"file",...i?{previewData:i}:{}}}).filter(r=>r!=null);return t.length?t:void 0}function ae(e){const t=e.indexOf(`
2
+ `),r=t>0?Math.min(t,80):Math.min(e.length,80);return e.slice(0,r)}function re(e,t,r={}){if(e.state==="tool-call"||e.state==="tool-result"){const a={runId:e.runId,sourceSeq:e.seq},o=te(e.args);return{state:e.state,runId:e.runId,seq:e.seq,sessionId:t,detailRef:a,...e.name?{name:e.name}:{},...o!==void 0?{argsSummary:o}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...r}}return{...e,sessionId:t,...r}}const se=3e4;function oe(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function de(e,t){return`Agent send failed: ${t instanceof Error?t.message:String(t)}`}function W(e,t){return e!=="manager"?e:t==="claude"?"claude":"codex"}function L(e,t,r){e.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:t.sessionId,message:t,session:{id:t.sessionId,agentType:r.agentType,agentSessionId:r.agentSessionId??null,modelId:r.modelId??null,workDir:r.workDir,status:"active",externalChannel:null}}})}function ie(e,t){O({sessionId:t.sessionId,agentType:t.agentType,workDir:t.workDir,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t.sessionId,agentType:t.agentType,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,workDir:t.workDir,status:"active",externalChannel:null}}})}function H(e){return Z(e)}function U(e,t,r){return{}}function j(e,t,r,a,o,l){e.configure?.({sessionId:t,externalChannel:a??null,env:{...H(r),...U(t,a,o),...l?{SHENNIAN_ROOM_REGISTRY_KEY:l}:{}}})}function le(e,t,r){if(e!=="claude"||!r)return t;const a=t.trim();return!!a&&a.startsWith("-")&&!a.includes("/")?G(r)??t:t}function ce(e,t,r,a){let o=null;function l(n,s={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:re(n,t,s),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function g(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function i(n){if(!n.currentRunId||!n.currentRunPhase)return;const s=n.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:t,runId:n.currentRunId,seq:s,runPhase:n.currentRunPhase},seq:s,id:`agent-heartbeat-${n.currentRunId}-${s}-${Date.now()}`})}function f(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},se),n.heartbeatTimer.unref?.())}function y(n){const s=n?.pendingTextEvent;!n||!s||!s.text||(l({state:"delta",runId:s.runId,seq:s.seq,text:s.text,thinking:s.thinking||void 0}),n.pendingTextEvent=null)}a.on("agentEvent",n=>{const s=e.sessions.get(t),S=oe(n),w=n.state==="final"||n.state==="error"||n.state==="aborted";if(s&&(s.nextEventSeq=n.seq+1,w||(s.currentRunId=n.runId),!w&&S&&(s.currentRunPhase=S,f(s)),n.agentSessionId&&(s.agentSessionId=n.agentSessionId)),e.managerRuntime?.noteAgentEvent(t,n),n.state==="delta"&&n.thinking)return;n.state!=="delta"&&T({level:"info",sessionId:t,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:r}}),n.state==="delta"&&n.text&&!n.thinking?x(t,{id:`agent-${n.runId}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?x(t,{id:`agent-${n.runId}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?x(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:Y(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&x(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.message});const m=`${t}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&e.runTextAcc.set(m,(e.runTextAcc.get(m)??"")+n.text),n.agentSessionId&&n.agentSessionId!==o&&(o=n.agentSessionId,e.nativeFusion?.noteManagedSourceSession(t,W(r,n.source),n.agentSessionId),s&&O({sessionId:t,agentType:r,workDir:s.workDir,agentSessionId:n.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t,agentType:r,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const I=n.text??"";if(!I)return;s?.pendingTextEvent&&s.pendingTextEvent.runId!==n.runId&&y(s),s&&!s.pendingTextEvent&&(s.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:!1}),s?.pendingTextEvent&&(s.pendingTextEvent.text+=I,s.pendingTextEvent.seq=n.seq);return}let R={};if(n.state==="final"){y(s);const I=e.runTextAcc.get(m)??"";I&&(R={messageSummary:ae(I)}),e.runTextAcc.delete(m)}else n.state==="error"||n.state==="aborted"?(y(s),e.runTextAcc.delete(m)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&y(s);w&&s?.currentRunId===n.runId&&(s.currentRunId=null,s.currentRunPhase=null,s.nextEventSeq=0,g(s),e.chatQueue?.noteTerminal(t)),l(n,R)}),a.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${t} agentType=${r}: ${n.message}`),e.sessions.delete(t),e.chatQueue?.noteTerminal(t),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:n.message,runId:"",seq:0}})})}function ue(e,t){if(e.processedReqIds.add(t),e.processedReqIds.size>1e3){const r=e.processedReqIds.values().next().value;e.processedReqIds.delete(r)}}async function P(e){e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{})}function B(e,t,r,a,o,l,g){return g?e.send(t,r,a,o,l,g):l?.trim()?e.send(t,r,a,o,l):o?.length?e.send(t,r,a,o):a?e.send(t,r,a):e.send(t,r)}async function ge(e,t,r,a,o,l,g){e.evictIdleSessions();const i=Q(r);if(!i)throw new Error(`Unsupported agent: ${r}`);j(i,t,r,l,g),await i.start(t,a,o);const f={adapter:i,workDir:a,agentType:r,agentSessionId:o??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:g??null,externalChannelEnv:{...H(r),...U(t,l,g)}};return e.sessions.set(t,f),ce(e,t,r,i),f}function fe(e,t){const r=e.sessions.get(t),a=r?.currentRunId;if(!r||!a)return;const o=r.nextEventSeq;e.runTextAcc.delete(`${t}:${a}`),r.pendingTextEvent=null,r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,r.heartbeatTimer&&(clearInterval(r.heartbeatTimer),r.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:t,runId:a,seq:o},seq:o,id:`agent-evt-${a}-${o}`}),e.chatQueue?.noteTerminal(t)}async function Re(e,t,r){if(e.processedReqIds.has(t.id)){e.client.sendRes({type:"res",id:t.id,ok:!0});return}ue(e,t.id);const{sessionId:a,text:o,agentType:l,workDir:g,agentSessionId:i,modelId:f,systemPrompt:y,managerDefaultWorkerAgentType:n,managerDefaultWorkerModelId:s,reasoningEffort:S,clientMessageId:w,sessionListProjection:m,waitForDispatch:R,responseId:I,roomContextRegistryKey:$,suppressExternalOwnerEcho:J}=t.params,A=I||t.id;X(m);const b=null,M="";if(!a||!o){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:"sessionId and text are required"});return}const u=l;u==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(a,n??null,s??null);const q=(u==="claude"||u==="codex"||u==="workbuddy")&&typeof S=="string"&&S.trim()?S.trim():void 0,E=e.resolvePath(le(u,g||F.homedir(),i)||F.homedir()),D=E,_=ne(t.params.attachments),p=_?.length?await ee({text:o,attachments:_,workDir:E}):{text:o,attachments:_,localized:!1};let d=e.sessions.get(a);if(d){if(d.lastActiveAt=Date.now(),d.agentType!==u||d.workDir!==E||JSON.stringify(d.externalChannel??null)!==JSON.stringify(b??null)){e.sessions.delete(a);try{await P(d)}catch{e.processedReqIds.delete(t.id)}d=void 0}else if(i&&d.agentSessionId!==i)try{await d.adapter.resume(i),d.agentSessionId=i}catch{e.sessions.delete(a);try{await P(d)}catch{e.processedReqIds.delete(t.id)}d=void 0}}if(!d)try{d=await ge(e,a,u,E,i,b,M)}catch(c){const h=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${l}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${t.id} sessionId=${a} agentType=${l} workDir=${E} agentSessionId=${i??""}: ${h}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:h,runId:"",seq:0}}),e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:h});return}$&&/^[a-f0-9]{64}$/.test($)&&j(d.adapter,a,u,b,M,$);const C={id:w??`user-${t.id}`,sessionId:a,role:"user",ts:Date.now(),payload:V(p.text,p.attachments)};T({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:t.id,agentType:u,modelId:f,reasoningEffort:q}});const z=c=>{ie(e,{sessionId:a,agentType:u,workDir:D,agentSessionId:d.agentSessionId??i??null,modelId:f}),d.currentRunId||(d.nextEventSeq=0),e.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:W(u,f),canonicalMessageId:w??null,sourceSessionKey:d.agentSessionId??i??null,text:p.text,managedEchoPolicy:c?.deliveryMode==="external_owner_queue"&&!J?"import_following":"suppress_following"}),x(a,C),L(e,C,{agentType:u,workDir:D,agentSessionId:d.agentSessionId??i??null,modelId:f})},N=async(c,h)=>{const k=de(u,c);console.error(`[chat.send] send failed reqId=${t.id} sessionId=${a} agentType=${l} workDir=${E} agentSessionId=${d.agentSessionId??i??""}: ${k}`),e.sessions.delete(a);try{await P(d)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!h){const v={id:`agent-error-${t.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};x(a,v),L(e,v,{agentType:u,workDir:D,agentSessionId:d.agentSessionId??i??null,modelId:f})}h&&(e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:A,ok:!1,error:k}))};if(R){let c;try{const h=p.attachments;c=await B(d.adapter,p.text,f,q,h,y,r),T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}catch(h){await N(h,!0);return}z(c??void 0),e.client.sendRes({type:"res",id:A,ok:!0,...p.localized||c?.deliveryMode==="external_owner_queue"?{payload:{...p.localized?{localizedAttachments:!0}:{},...c?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:c.deliveryMode,queuedSubmissionId:c.queuedSubmissionId}:{}}}:{}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});return}z(),e.client.sendRes({type:"res",id:A,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});const K=p.attachments;B(d.adapter,p.text,f,q,K,y,r).then(()=>{T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}).catch(c=>{N(c,!1)})}async function ke(e,t){const{sessionId:r}=t.params,a=e.sessions.get(r);if(a){try{await a.adapter.stop()}catch{}fe(e,r),e.activityPublisher?.publish(r,null)}e.client.sendRes({type:"res",id:t.id,ok:!0})}export{ke as handleChatAbort,Re as handleChatSend,ie as sendSessionUpdateEvent};
@@ -0,0 +1 @@
1
+ export declare function buildToolArgsSummary(value: unknown): unknown;
@@ -0,0 +1 @@
1
+ const o=240;function c(t){if(t==null)return;if(!t||typeof t!="object"||Array.isArray(t))return r(t);const n={};for(const[i,e]of Object.entries(t))if(!(e==null||e==="")&&(n[i]=r(e),Object.keys(n).length===2))break;return Object.keys(n).length?n:void 0}function r(t){if(typeof t=="string")return s(t)?"[SYSTEM CONTEXT REDACTED]":t.replace(/\s+/g," ").trim().slice(0,240);const n=JSON.stringify(t);return String(n??t).replace(/\s+/g," ").slice(0,240)}function s(t){const n=t.trim();return/^<environment_context>[\s\S]*<\/environment_context>$/i.test(n)||/^# AGENTS\.md instructions for [^\n]+[\s\S]*<INSTRUCTIONS>[\s\S]*<\/INSTRUCTIONS>/i.test(n)||/^<turn_aborted>[\s\S]*<\/turn_aborted>$/i.test(n)}export{c as buildToolArgsSummary};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.3.34",
3
+ "version": "0.3.35",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {