shennian 0.4.28 → 0.4.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.
@@ -521,8 +521,8 @@
521
521
  },
522
522
  {
523
523
  "file": "src/native-fusion/service.js",
524
- "beforeBytes": 34698,
525
- "afterBytes": 15552
524
+ "beforeBytes": 36125,
525
+ "afterBytes": 16121
526
526
  },
527
527
  {
528
528
  "file": "src/native-fusion/session-header.js",
@@ -736,8 +736,8 @@
736
736
  },
737
737
  {
738
738
  "file": "src/session/handlers/chat.js",
739
- "beforeBytes": 56203,
740
- "afterBytes": 24136
739
+ "beforeBytes": 57908,
740
+ "afterBytes": 24817
741
741
  },
742
742
  {
743
743
  "file": "src/session/handlers/control.js",
@@ -831,13 +831,13 @@
831
831
  },
832
832
  {
833
833
  "file": "src/session/run-recovery/journal.js",
834
- "beforeBytes": 8644,
835
- "afterBytes": 4226
834
+ "beforeBytes": 8713,
835
+ "afterBytes": 4267
836
836
  },
837
837
  {
838
838
  "file": "src/session/run-recovery/schema.js",
839
- "beforeBytes": 5964,
840
- "afterBytes": 3907
839
+ "beforeBytes": 6517,
840
+ "afterBytes": 4173
841
841
  },
842
842
  {
843
843
  "file": "src/session/store.js",
@@ -21,6 +21,13 @@ export declare class NativeSessionFusionService {
21
21
  start(): void;
22
22
  stop(): void;
23
23
  setExternalTerminalHandler(handler: ((sessionId: string) => void) | null): void;
24
+ restoreExternalObservation(params: {
25
+ sessionId: string;
26
+ sourceSessionKey: string;
27
+ runId: string;
28
+ canonicalMessageId: string;
29
+ createdAt: number;
30
+ }): boolean;
24
31
  handleConnected(): void;
25
32
  registerManagedSend(params: {
26
33
  sessionId: string;
@@ -1,2 +1,2 @@
1
- import N from"node:fs";import W from"node:crypto";import{publishPendingSessionIndexes as O}from"../session/index-publisher.js";import{NativeFusionFileWatcher as $}from"./file-watcher.js";import{NativeEventIdentityConflictError as z,NativeFusionLocalRepository as U}from"./local-repository.js";import{listClaudeTranscriptFiles as H,listCodexRolloutFiles as V,listOpenCodeSessionFiles as Q,listNativeTranscriptRoots as Y,inspectNativeSessionFile as j,lookupCodexThreadName as X,parseClaudeTranscriptChunkCooperatively as G,parseCodexRolloutChunkCooperatively as J,parseOpenCodeSessionFile as Z}from"./parsers.js";import{loadNativeScannerState as ee,saveNativeScannerState as P}from"./state.js";const se=5*6e4,te=2*6e4,ie=30*6e4,ne=2e3,oe=1,k=16,re=3e4,R=240*6e4;function ae(d){return d.replace(/\r\n/g,`
2
- `).trim()}function b(){return new Promise(d=>setImmediate(d))}function ce(d){return d.split(/[\\/]+/).includes(".codex")}function F(d){try{return N.statSync(d).mtimeMs}catch{return 0}}class ve{client;repository;timer=null;activeTimer=null;scanPromise=null;queuedTargetFiles=new Set;pendingBoundaryFiles=new Set;sourceFiles=new Map;fullScanQueued=!1;watchEnabled=!1;lifecycleRevision=0;watcher=new $(e=>{this.scanNow(e).catch(s=>{console.error("[native-fusion] watched file scan failed",s)})});pendingClaims;suppressionWindows;externalObservations=new Map;externalTerminalHandler=null;constructor(e,s=new U){this.client=e,this.repository=s,this.pendingClaims=new Map((this.repository.listManagedClaims?.()??[]).map(t=>[t.canonicalMessageId,t])),this.suppressionWindows=new Map((this.repository.listManagedSuppressions?.()??[]).map(t=>[M(t.agentType,t.sourceSessionKey),t]))}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},se))}stop(){this.lifecycleRevision+=1,this.timer&&clearInterval(this.timer),this.timer=null,this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null,this.pendingBoundaryFiles.clear(),this.watchEnabled=!1,this.watcher.stop()}setExternalTerminalHandler(e){this.externalTerminalHandler=e}handleConnected(){const e=++this.lifecycleRevision;this.watchEnabled=!0,this.scanNow().catch(s=>{console.error("[native-fusion] initial scan failed",s)}).finally(()=>{this.lifecycleRevision===e&&this.start()})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;if(s!=="codex"&&s!=="claude"&&s!=="opencode")return;const t=e.canonicalMessageId,n=this.pendingClaims.get(t),c=D(e.text);if(n&&(n.sessionId!==e.sessionId||n.sourceAgentType!==s||n.textHash!==c))throw new Error(`managed echo claim identity conflict: ${t}`);const f={sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,textHash:c,createdAt:n?.createdAt??Date.now(),sourceSessionKey:e.sourceSessionKey??n?.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following",externalRunId:e.externalRunId??null};if(this.repository.upsertManagedClaim?.(f),this.pendingClaims.set(t,f),e.externalRunId&&e.sourceSessionKey){const h=`${s}:${e.sourceSessionKey}`,p=this.externalObservations.get(h)??[];p.push({sessionId:e.sessionId,sourceSessionKey:e.sourceSessionKey,runId:e.externalRunId,canonicalMessageId:e.canonicalMessageId,state:"queued",createdAt:Date.now(),lastPublishedAt:Date.now()}),this.externalObservations.set(h,p),this.emitExternalActivity(p[p.length-1],"queued"),this.ensureActiveScanning()}}cancelManagedSend(e){this.repository.removeManagedClaim?.(e),this.pendingClaims.delete(e)}noteManagedSourceSession(e,s,t){if(t){this.repository.updateManagedClaimSource?.(e,s,t);for(const n of this.pendingClaims.values())n.sessionId===e&&n.sourceAgentType===s&&(n.sourceSessionKey=t)}}handleSessionDeleted(e){for(const[s,t]of this.pendingClaims.entries())t.sessionId===e&&this.pendingClaims.delete(s);for(const[s,t]of this.suppressionWindows.entries())t.sessionId===e&&this.suppressionWindows.delete(s);for(const[s,t]of this.externalObservations.entries()){const n=t.filter(c=>c.sessionId!==e);n.length===0?this.externalObservations.delete(s):this.externalObservations.set(s,n)}this.repository.purgeSession(e)}ensureActiveScanning(e=!0){this.activeTimer||(this.activeTimer=setInterval(()=>{if(this.externalObservations.size===0&&this.pendingBoundaryFiles.size===0){this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null;return}this.scanActiveTargets()},ne),e&&this.scanActiveTargets())}scanActiveTargets(){const e=this.activeScanTargets();e===void 0&&this.scanPromise||this.scanNow(e).catch(s=>{console.error("[native-fusion] active observation scan failed",s)})}activeScanTargets(){const e=[...this.externalObservations.keys()];if(!e.some(s=>!this.sourceFiles.has(s)))return[...new Set([...this.pendingBoundaryFiles,...e.flatMap(s=>{const t=this.sourceFiles.get(s);return t?[t]:[]})])]}emitExternalActivity(e,s){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${s}-${e.lastPublishedAt}`,payload:{state:s==="queued"?"start":"heartbeat",sessionId:e.sessionId,runId:e.runId,seq:s==="queued"?0:1,runPhase:"thinking",canStop:!1,owner:"external",ownerLabel:"Codex Desktop",lifecycle:s}})}emitExternalTerminal(e,s="completed"){const t=s==="completed"?"final":s==="aborted"?"aborted":"error";this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${t}`,payload:{state:t,sessionId:e.sessionId,runId:e.runId,seq:2,...t==="error"?{message:"Codex Desktop turn failed"}:{},owner:"external",ownerLabel:"Codex Desktop"}}),this.externalTerminalHandler?.(e.sessionId)}pruneState(){const e=Date.now();for(const[s,t]of this.suppressionWindows.entries())t.endsAt>e||(this.repository.removeManagedSuppression?.(t.agentType,t.sourceSessionKey),this.suppressionWindows.delete(s))}async scanNow(e){if(this.client.getState()==="connected"){if(this.scanPromise){const s=this.scanPromise;if(e)for(const t of e)this.queuedTargetFiles.add(t);else this.fullScanQueued=!0;if(await s,this.fullScanQueued)return this.fullScanQueued=!1,this.queuedTargetFiles.clear(),this.scanNow();if(this.queuedTargetFiles.size>0){const t=[...this.queuedTargetFiles];return this.queuedTargetFiles.clear(),this.scanNow(t)}return}return this.scanPromise=this.runScanLoop(e).finally(()=>{this.scanPromise=null}),this.scanPromise}}async runScanLoop(e){let s=e?[...new Set(e)]:void 0;for(;;){if(await this.runScan(s),this.fullScanQueued){await b(),this.fullScanQueued=!1,this.queuedTargetFiles.clear(),s=void 0;continue}if(this.queuedTargetFiles.size>0){await b(),s=[...this.queuedTargetFiles],this.queuedTargetFiles.clear();continue}return}}async runScan(e){this.pruneState(),this.refreshExternalObservations();const s=ee(),t={...s.files},n=new Map;let c=!1;const f=o=>{const a=new Set,S=l=>{try{this.repository.commitEvents(l)}catch(r){if(!(r instanceof z))throw r;const y=l.find(E=>E.sourceEventKey===r.sourceEventKey);if(!y)throw r;a.add(y.sourceEventKey),console.warn(`[native-fusion] quarantined conflicting native event ${y.sourceEventKey}`);const T=l.filter(E=>E!==y);T.length>0&&S(T)}};return S(o),a},h=e?[...e]:[...V(),...H(),...Q()].sort((o,a)=>F(a)-F(o));!e&&this.watchEnabled&&this.watcher.refresh(h,Y());let p=0,w=!1;for(;h.length>0||w&&this.queuedTargetFiles.size>0;){let o;if(w&&this.queuedTargetFiles.size>0){if(o=[...this.queuedTargetFiles].sort((i,u)=>F(u)-F(i))[0],o){this.queuedTargetFiles.delete(o);const i=h.indexOf(o);i>=0&&h.splice(i,1)}w=!1}else o=h.shift(),w=!0;if(!o)break;if(p>0&&p%oe===0&&await b(),p+=1,!N.existsSync(o)){this.watchEnabled&&this.watcher.untrackFile(o),this.pendingBoundaryFiles.delete(o);for(const[i,u]of this.sourceFiles.entries())u===o&&this.sourceFiles.delete(i);continue}this.watchEnabled&&this.watcher.trackFile(o);const a=N.statSync(o),S=ce(o),l=o.endsWith(".opencode-session.json");let r=s.files[o];const y=`${String(a.dev)}:${String(a.ino)}:${String(a.birthtimeMs)}`;let T=!r;if(r&&!l&&(a.size<r.offset||r.fileIdentity&&r.fileIdentity!==y)&&(r=void 0,T=!0),!!(r&&r.fileIdentity===y&&r.mtimeMs===a.mtimeMs&&r.offset>=a.size&&r.sources?.length)&&r){for(const i of r.sources??[])this.sourceFiles.set(M(i.agentType,i.sourceSessionKey),o);r.classification==="live"&&r.awaitingUserBoundary?this.pendingBoundaryFiles.add(o):this.pendingBoundaryFiles.delete(o);continue}const g=r?.sources?.length&&!l?{status:"ready",createdAtMs:r.sessionCreatedAtMs??a.birthtimeMs,sources:r.sources}:j(o);if(g.status==="pending"){a.birthtimeMs>=s.fusionEpochMs&&this.pendingBoundaryFiles.add(o);continue}for(const i of g.sources)this.sourceFiles.set(M(i.agentType,i.sourceSessionKey),o);if(!l&&g.sources.length>0&&g.sources.every(i=>this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey))){t[o]={...r??{daemonInstallationId:s.daemonInstallationId,classification:g.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:g.createdAtMs,sourceBoundaryEstablished:{}},offset:a.size,mtimeMs:a.mtimeMs,fileIdentity:y};continue}if(!r)r={daemonInstallationId:s.daemonInstallationId,offset:0,mtimeMs:a.mtimeMs,classification:g.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:g.createdAtMs,sourceBoundaryEstablished:{}};else if(l&&r.mtimeMs===a.mtimeMs)continue;const x=l?0:r.offset;let m;try{if(m=l?Z(o,x):S?await J(o,x):await G(o,x),!l&&m.nextOffset<x)throw new Error("native transcript cursor moved backwards")}catch(i){console.error("[native-fusion] target file scan failed; isolated for retry",i);continue}let A,v;if(l){const i=ue(m.events,r,s.fusionEpochMs,T,a.mtimeMs,m.nextOffset);A=i.events,v=i.cursor}else if(T&&r.classification==="historical")A=[],v={...r,offset:m.nextOffset,mtimeMs:a.mtimeMs,awaitingUserBoundary:!0};else{const i=le(m.events,r,m.nextOffset,a.mtimeMs);A=i.events,v=i.cursor}v.fileIdentity=y,v.sources=g.sources;const K=[],_=new Map,q=new Map;for(const i of A){if(this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey))continue;const u=this.tryClaimManagedEcho(i);if(u){K.push(u.event),_.set(u.claimKey,u.suppression??null),u.suppression&&q.set(M(u.suppression.agentType,u.suppression.sourceSessionKey),{window:u.suppression,claimKey:u.claimKey});continue}const C=this.suppressionFor(i,q,_);if(C){K.push({...i,claimSessionId:C.sessionId,localDisposition:"managed_echo_suppressed"});continue}K.push(i)}const I=K.sort((i,u)=>i.ts-u.ts),B=new Set;try{for(let i=0;i<I.length;i+=k){const u=f(I.slice(i,i+k));for(const C of u)B.add(C);c=!0,i+k<I.length&&await b()}}catch(i){console.error("[native-fusion] target file commit failed; isolated for retry",i);continue}const L=new Set(I.filter(i=>B.has(i.sourceEventKey)).flatMap(i=>i.claimCanonicalMessageId?[i.claimCanonicalMessageId]:[]));for(const[i,u]of _)L.has(i)||(this.repository.completeManagedClaim?.(i,u??void 0),this.pendingClaims.delete(i),u&&this.suppressionWindows.set(M(u.agentType,u.sourceSessionKey),u));for(const i of m.events)this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey)||i.title?.trim()&&i.titleSource==="agent_native"&&n.set(`${i.agentType}:${i.sourceSessionKey}`,i);for(const i of I)B.has(i.sourceEventKey)||this.observeExternalLifecycle(i);t[o]=v,s.files=t,P(s),v.classification==="live"&&v.awaitingUserBoundary?this.pendingBoundaryFiles.add(o):this.pendingBoundaryFiles.delete(o),I.length>0&&await O(this.client).catch(i=>{console.error("[native-fusion] index projection sync failed; retained for retry",i)})}c||this.repository.commitEvents([]);for(const o of n.values())this.repository.observeNativeTitle(o.agentType,o.sourceSessionKey,o.title??"");for(const o of this.repository.listSourceBindings()){if(o.agentType!=="codex")continue;const a=X(o.sourceSessionKey);a&&this.repository.observeNativeTitle("codex",o.sourceSessionKey,a)}s.files=t,P(s),this.pendingBoundaryFiles.size>0&&this.ensureActiveScanning(!1),this.repository.repairMissingUserBoundaries?.(),await O(this.client).catch(o=>{console.error("[native-fusion] index projection sync failed; retained for retry",o)})}refreshExternalObservations(){const e=Date.now();for(const[s,t]of this.externalObservations.entries()){const n=t.filter(f=>e-f.createdAt<R);if(n.length===0){this.externalObservations.delete(s);continue}this.externalObservations.set(s,n);const c=n[0];e-c.lastPublishedAt<re||(c.lastPublishedAt=e,this.emitExternalActivity(c,c.state))}}tryClaimManagedEcho(e){const s=Date.now();for(const[t,n]of this.pendingClaims.entries()){if(n.sourceAgentType!==e.agentType||e.role!=="user"||!n.sourceSessionKey||n.sourceSessionKey!==e.sourceSessionKey)continue;const c=n.externalRunId?R:te;if(Math.abs(e.ts-n.createdAt)>c||D(e.payload)!==n.textHash)continue;const f=n.managedEchoPolicy==="suppress_following"?{sessionId:n.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,claimSourceEventKey:e.sourceEventKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+ie}:void 0;return{claimKey:t,suppression:f,event:{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:n.canonicalMessageId,claimSessionId:n.sessionId,managedEchoPolicy:n.managedEchoPolicy}}}return null}observeExternalLifecycle(e){const s=`${e.agentType}:${e.sourceSessionKey}`,t=this.externalObservations.get(s);if(!t?.length)return;const n=t[0];if(e.claimCanonicalMessageId===n.canonicalMessageId&&n.state==="queued"&&(this.repository.updateMessageDeliveryState(n.sessionId,n.canonicalMessageId,"executing"),n.state="running",n.lastPublishedAt=Date.now(),this.emitExternalActivity(n,"running")),!e.terminal||n.state!=="running")return;const c=e.terminalState??"completed";this.repository.updateMessageDeliveryState(n.sessionId,n.canonicalMessageId,c==="aborted"?"cancelled":c==="failed"?"failed":"completed"),this.emitExternalTerminal(n,c),t.shift(),t.length===0?this.externalObservations.delete(s):(this.externalObservations.set(s,t),t[0].lastPublishedAt=Date.now(),this.emitExternalActivity(t[0],"queued"))}suppressionFor(e,s,t){const n=M(e.agentType,e.sourceSessionKey),c=s.get(n),f=c?.window??this.suppressionWindows.get(n);return!f||e.ts<f.startedAt?null:e.ts>f.endsAt?(this.clearSuppression(n,f,c,s,t),null):e.role==="user"?(e.sourceEventKey===f.claimSourceEventKey||this.clearSuppression(n,f,c,s,t),null):f}clearSuppression(e,s,t,n,c){if(t){n.delete(e),c.set(t.claimKey,null);return}this.repository.removeManagedSuppression?.(s.agentType,s.sourceSessionKey),this.suppressionWindows.delete(e)}}function D(d){return W.createHash("sha256").update(ae(d)).digest("hex")}function M(d,e){return`${d}:${e}`}function le(d,e,s,t){if(!e.awaitingUserBoundary)return{events:d,cursor:{...e,offset:s,mtimeMs:t}};if(d.length===0)return{events:[],cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!0}};const n=d.findIndex(c=>c.role==="user");return n<0?{events:[],cursor:{...e,mtimeMs:t,awaitingUserBoundary:!0}}:{events:d.slice(n),cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!1}}}function ue(d,e,s,t,n,c){const f={...e.sourceBoundaryEstablished??{}},h=e.eventWatermarkTs??-1,p=new Set(e.eventKeysAtWatermark??[]),w=t?d:d.filter(l=>l.ts>h||l.ts===h&&!p.has(l.sourceEventKey)),o=[];for(const l of w){const r=l.sourceSessionKey;if(f[r]){o.push(l);continue}!(!t||(l.sourceSessionCreatedAtMs??0)>=s)||l.role!=="user"||(f[r]=!0,o.push(l))}const a=d.reduce((l,r)=>Math.max(l,r.ts),h),S=new Set(a===h?e.eventKeysAtWatermark??[]:[]);for(const l of d)l.ts===a&&S.add(l.sourceEventKey);return{events:o,cursor:{...e,offset:c,mtimeMs:n,eventWatermarkTs:a>=0?a:void 0,eventKeysAtWatermark:a>=0?[...S]:void 0,sourceBoundaryEstablished:f}}}export{ve as NativeSessionFusionService};
1
+ import N from"node:fs";import $ from"node:crypto";import{publishPendingSessionIndexes as q}from"../session/index-publisher.js";import{NativeFusionFileWatcher as W}from"./file-watcher.js";import{NativeEventIdentityConflictError as z,NativeFusionLocalRepository as U}from"./local-repository.js";import{listClaudeTranscriptFiles as H,listCodexRolloutFiles as V,listOpenCodeSessionFiles as Q,listNativeTranscriptRoots as Y,inspectNativeSessionFile as j,lookupCodexThreadName as X,parseClaudeTranscriptChunkCooperatively as G,parseCodexRolloutChunkCooperatively as J,parseOpenCodeSessionFile as Z}from"./parsers.js";import{loadNativeScannerState as ee,saveNativeScannerState as P}from"./state.js";const se=5*6e4,te=2*6e4,ie=30*6e4,ne=2e3,oe=1,O=16,re=3e4,R=240*6e4;function ae(f){return f.replace(/\r\n/g,`
2
+ `).trim()}function C(){return new Promise(f=>setImmediate(f))}function ce(f){return f.split(/[\\/]+/).includes(".codex")}function F(f){try{return N.statSync(f).mtimeMs}catch{return 0}}class ve{client;repository;timer=null;activeTimer=null;scanPromise=null;queuedTargetFiles=new Set;pendingBoundaryFiles=new Set;sourceFiles=new Map;fullScanQueued=!1;watchEnabled=!1;lifecycleRevision=0;watcher=new W(e=>{this.scanNow(e).catch(s=>{console.error("[native-fusion] watched file scan failed",s)})});pendingClaims;suppressionWindows;externalObservations=new Map;externalTerminalHandler=null;constructor(e,s=new U){this.client=e,this.repository=s,this.pendingClaims=new Map((this.repository.listManagedClaims?.()??[]).map(t=>[t.canonicalMessageId,t])),this.suppressionWindows=new Map((this.repository.listManagedSuppressions?.()??[]).map(t=>[M(t.agentType,t.sourceSessionKey),t]))}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},se))}stop(){this.lifecycleRevision+=1,this.timer&&clearInterval(this.timer),this.timer=null,this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null,this.pendingBoundaryFiles.clear(),this.watchEnabled=!1,this.watcher.stop()}setExternalTerminalHandler(e){this.externalTerminalHandler=e}restoreExternalObservation(e){if(!e.sessionId||!e.sourceSessionKey||!e.runId||!e.canonicalMessageId||!Number.isFinite(e.createdAt))return!1;const s=`codex:${e.sourceSessionKey}`,t=this.externalObservations.get(s)??[];if(t.some(u=>u.runId===e.runId))return!0;const n=Date.now(),a={...e,state:this.pendingClaims.has(e.canonicalMessageId)?"queued":"running",createdAt:Math.min(e.createdAt,n),lastPublishedAt:n};return t.push(a),t.sort((u,h)=>u.createdAt-h.createdAt),this.externalObservations.set(s,t),this.emitExternalActivity(a,a.state),this.ensureActiveScanning(!1),!0}handleConnected(){const e=++this.lifecycleRevision;this.watchEnabled=!0,this.scanNow().catch(s=>{console.error("[native-fusion] initial scan failed",s)}).finally(()=>{this.lifecycleRevision===e&&this.start()})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;if(s!=="codex"&&s!=="claude"&&s!=="opencode")return;const t=e.canonicalMessageId,n=this.pendingClaims.get(t),a=D(e.text);if(n&&(n.sessionId!==e.sessionId||n.sourceAgentType!==s||n.textHash!==a))throw new Error(`managed echo claim identity conflict: ${t}`);const u={sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,textHash:a,createdAt:n?.createdAt??Date.now(),sourceSessionKey:e.sourceSessionKey??n?.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following",externalRunId:e.externalRunId??null};if(this.repository.upsertManagedClaim?.(u),this.pendingClaims.set(t,u),e.externalRunId&&e.sourceSessionKey){const h=`${s}:${e.sourceSessionKey}`,p=this.externalObservations.get(h)??[];p.push({sessionId:e.sessionId,sourceSessionKey:e.sourceSessionKey,runId:e.externalRunId,canonicalMessageId:e.canonicalMessageId,state:"queued",createdAt:Date.now(),lastPublishedAt:Date.now()}),this.externalObservations.set(h,p),this.emitExternalActivity(p[p.length-1],"queued"),this.ensureActiveScanning()}}cancelManagedSend(e){this.repository.removeManagedClaim?.(e),this.pendingClaims.delete(e)}noteManagedSourceSession(e,s,t){if(t){this.repository.updateManagedClaimSource?.(e,s,t);for(const n of this.pendingClaims.values())n.sessionId===e&&n.sourceAgentType===s&&(n.sourceSessionKey=t)}}handleSessionDeleted(e){for(const[s,t]of this.pendingClaims.entries())t.sessionId===e&&this.pendingClaims.delete(s);for(const[s,t]of this.suppressionWindows.entries())t.sessionId===e&&this.suppressionWindows.delete(s);for(const[s,t]of this.externalObservations.entries()){const n=t.filter(a=>a.sessionId!==e);n.length===0?this.externalObservations.delete(s):this.externalObservations.set(s,n)}this.repository.purgeSession(e)}ensureActiveScanning(e=!0){this.activeTimer||(this.activeTimer=setInterval(()=>{if(this.externalObservations.size===0&&this.pendingBoundaryFiles.size===0){this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null;return}this.scanActiveTargets()},ne),e&&this.scanActiveTargets())}scanActiveTargets(){const e=this.activeScanTargets();e===void 0&&this.scanPromise||this.scanNow(e).catch(s=>{console.error("[native-fusion] active observation scan failed",s)})}activeScanTargets(){const e=[...this.externalObservations.keys()];if(!e.some(s=>!this.sourceFiles.has(s)))return[...new Set([...this.pendingBoundaryFiles,...e.flatMap(s=>{const t=this.sourceFiles.get(s);return t?[t]:[]})])]}emitExternalActivity(e,s){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${s}-${e.lastPublishedAt}`,payload:{state:s==="queued"?"start":"heartbeat",sessionId:e.sessionId,runId:e.runId,seq:s==="queued"?0:1,runPhase:"thinking",canStop:!1,owner:"external",ownerLabel:"Codex Desktop",lifecycle:s}})}emitExternalTerminal(e,s="completed"){const t=s==="completed"?"final":s==="aborted"?"aborted":"error";this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${t}`,payload:{state:t,sessionId:e.sessionId,runId:e.runId,seq:2,...t==="error"?{message:"Codex Desktop turn failed"}:{},owner:"external",ownerLabel:"Codex Desktop"}}),this.externalTerminalHandler?.(e.sessionId)}pruneState(){const e=Date.now();for(const[s,t]of this.suppressionWindows.entries())t.endsAt>e||(this.repository.removeManagedSuppression?.(t.agentType,t.sourceSessionKey),this.suppressionWindows.delete(s))}async scanNow(e){if(this.client.getState()==="connected"){if(this.scanPromise){const s=this.scanPromise;if(e)for(const t of e)this.queuedTargetFiles.add(t);else this.fullScanQueued=!0;if(await s,this.fullScanQueued)return this.fullScanQueued=!1,this.queuedTargetFiles.clear(),this.scanNow();if(this.queuedTargetFiles.size>0){const t=[...this.queuedTargetFiles];return this.queuedTargetFiles.clear(),this.scanNow(t)}return}return this.scanPromise=this.runScanLoop(e).finally(()=>{this.scanPromise=null}),this.scanPromise}}async runScanLoop(e){let s=e?[...new Set(e)]:void 0;for(;;){if(await this.runScan(s),this.fullScanQueued){await C(),this.fullScanQueued=!1,this.queuedTargetFiles.clear(),s=void 0;continue}if(this.queuedTargetFiles.size>0){await C(),s=[...this.queuedTargetFiles],this.queuedTargetFiles.clear();continue}return}}async runScan(e){this.pruneState(),this.refreshExternalObservations();const s=ee(),t={...s.files},n=new Map;let a=!1;const u=o=>{const c=new Set,S=l=>{try{this.repository.commitEvents(l)}catch(r){if(!(r instanceof z))throw r;const y=l.find(x=>x.sourceEventKey===r.sourceEventKey);if(!y)throw r;c.add(y.sourceEventKey),console.warn(`[native-fusion] quarantined conflicting native event ${y.sourceEventKey}`);const T=l.filter(x=>x!==y);T.length>0&&S(T)}};return S(o),c},h=e?[...e]:[...V(),...H(),...Q()].sort((o,c)=>F(c)-F(o));!e&&this.watchEnabled&&this.watcher.refresh(h,Y());let p=0,w=!1;for(;h.length>0||w&&this.queuedTargetFiles.size>0;){let o;if(w&&this.queuedTargetFiles.size>0){if(o=[...this.queuedTargetFiles].sort((i,d)=>F(d)-F(i))[0],o){this.queuedTargetFiles.delete(o);const i=h.indexOf(o);i>=0&&h.splice(i,1)}w=!1}else o=h.shift(),w=!0;if(!o)break;if(p>0&&p%oe===0&&await C(),p+=1,!N.existsSync(o)){this.watchEnabled&&this.watcher.untrackFile(o),this.pendingBoundaryFiles.delete(o);for(const[i,d]of this.sourceFiles.entries())d===o&&this.sourceFiles.delete(i);continue}this.watchEnabled&&this.watcher.trackFile(o);const c=N.statSync(o),S=ce(o),l=o.endsWith(".opencode-session.json");let r=s.files[o];const y=`${String(c.dev)}:${String(c.ino)}:${String(c.birthtimeMs)}`;let T=!r;if(r&&!l&&(c.size<r.offset||r.fileIdentity&&r.fileIdentity!==y)&&(r=void 0,T=!0),!!(r&&r.fileIdentity===y&&r.mtimeMs===c.mtimeMs&&r.offset>=c.size&&r.sources?.length)&&r){for(const i of r.sources??[])this.sourceFiles.set(M(i.agentType,i.sourceSessionKey),o);r.classification==="live"&&r.awaitingUserBoundary?this.pendingBoundaryFiles.add(o):this.pendingBoundaryFiles.delete(o);continue}const g=r?.sources?.length&&!l?{status:"ready",createdAtMs:r.sessionCreatedAtMs??c.birthtimeMs,sources:r.sources}:j(o);if(g.status==="pending"){c.birthtimeMs>=s.fusionEpochMs&&this.pendingBoundaryFiles.add(o);continue}for(const i of g.sources)this.sourceFiles.set(M(i.agentType,i.sourceSessionKey),o);if(!l&&g.sources.length>0&&g.sources.every(i=>this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey))){t[o]={...r??{daemonInstallationId:s.daemonInstallationId,classification:g.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:g.createdAtMs,sourceBoundaryEstablished:{}},offset:c.size,mtimeMs:c.mtimeMs,fileIdentity:y};continue}if(!r)r={daemonInstallationId:s.daemonInstallationId,offset:0,mtimeMs:c.mtimeMs,classification:g.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:g.createdAtMs,sourceBoundaryEstablished:{}};else if(l&&r.mtimeMs===c.mtimeMs)continue;const E=l?0:r.offset;let m;try{if(m=l?Z(o,E):S?await J(o,E):await G(o,E),!l&&m.nextOffset<E)throw new Error("native transcript cursor moved backwards")}catch(i){console.error("[native-fusion] target file scan failed; isolated for retry",i);continue}let A,v;if(l){const i=ue(m.events,r,s.fusionEpochMs,T,c.mtimeMs,m.nextOffset);A=i.events,v=i.cursor}else if(T&&r.classification==="historical")A=[],v={...r,offset:m.nextOffset,mtimeMs:c.mtimeMs,awaitingUserBoundary:!0};else{const i=le(m.events,r,m.nextOffset,c.mtimeMs);A=i.events,v=i.cursor}v.fileIdentity=y,v.sources=g.sources;const K=[],_=new Map,k=new Map;for(const i of A){if(this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey))continue;const d=this.tryClaimManagedEcho(i);if(d){K.push(d.event),_.set(d.claimKey,d.suppression??null),d.suppression&&k.set(M(d.suppression.agentType,d.suppression.sourceSessionKey),{window:d.suppression,claimKey:d.claimKey});continue}const b=this.suppressionFor(i,k,_);if(b){K.push({...i,claimSessionId:b.sessionId,localDisposition:"managed_echo_suppressed"});continue}K.push(i)}const I=K.sort((i,d)=>i.ts-d.ts),B=new Set;try{for(let i=0;i<I.length;i+=O){const d=u(I.slice(i,i+O));for(const b of d)B.add(b);a=!0,i+O<I.length&&await C()}}catch(i){console.error("[native-fusion] target file commit failed; isolated for retry",i);continue}const L=new Set(I.filter(i=>B.has(i.sourceEventKey)).flatMap(i=>i.claimCanonicalMessageId?[i.claimCanonicalMessageId]:[]));for(const[i,d]of _)L.has(i)||(this.repository.completeManagedClaim?.(i,d??void 0),this.pendingClaims.delete(i),d&&this.suppressionWindows.set(M(d.agentType,d.sourceSessionKey),d));for(const i of m.events)this.repository.isSourceDeleted?.(i.agentType,i.sourceSessionKey)||i.title?.trim()&&i.titleSource==="agent_native"&&n.set(`${i.agentType}:${i.sourceSessionKey}`,i);for(const i of I)B.has(i.sourceEventKey)||this.observeExternalLifecycle(i);t[o]=v,s.files=t,P(s),v.classification==="live"&&v.awaitingUserBoundary?this.pendingBoundaryFiles.add(o):this.pendingBoundaryFiles.delete(o),I.length>0&&await q(this.client).catch(i=>{console.error("[native-fusion] index projection sync failed; retained for retry",i)})}a||this.repository.commitEvents([]);for(const o of n.values())this.repository.observeNativeTitle(o.agentType,o.sourceSessionKey,o.title??"");for(const o of this.repository.listSourceBindings()){if(o.agentType!=="codex")continue;const c=X(o.sourceSessionKey);c&&this.repository.observeNativeTitle("codex",o.sourceSessionKey,c)}s.files=t,P(s),this.pendingBoundaryFiles.size>0&&this.ensureActiveScanning(!1),this.repository.repairMissingUserBoundaries?.(),await q(this.client).catch(o=>{console.error("[native-fusion] index projection sync failed; retained for retry",o)})}refreshExternalObservations(){const e=Date.now();for(const[s,t]of this.externalObservations.entries()){const n=t.filter(u=>e-u.createdAt<R);if(n.length===0){this.externalObservations.delete(s);continue}this.externalObservations.set(s,n);const a=n[0];e-a.lastPublishedAt<re||(a.lastPublishedAt=e,this.emitExternalActivity(a,a.state))}}tryClaimManagedEcho(e){const s=Date.now();for(const[t,n]of this.pendingClaims.entries()){if(n.sourceAgentType!==e.agentType||e.role!=="user"||!n.sourceSessionKey||n.sourceSessionKey!==e.sourceSessionKey)continue;const a=n.externalRunId?R:te;if(Math.abs(e.ts-n.createdAt)>a||D(e.payload)!==n.textHash)continue;const u=n.managedEchoPolicy==="suppress_following"?{sessionId:n.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,claimSourceEventKey:e.sourceEventKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+ie}:void 0;return{claimKey:t,suppression:u,event:{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:n.canonicalMessageId,claimSessionId:n.sessionId,managedEchoPolicy:n.managedEchoPolicy}}}return null}observeExternalLifecycle(e){const s=`${e.agentType}:${e.sourceSessionKey}`,t=this.externalObservations.get(s);if(!t?.length)return;const n=t[0];if(e.claimCanonicalMessageId===n.canonicalMessageId&&n.state==="queued"&&(this.repository.updateMessageDeliveryState(n.sessionId,n.canonicalMessageId,"executing"),n.state="running",n.lastPublishedAt=Date.now(),this.emitExternalActivity(n,"running")),!e.terminal||n.state!=="running")return;const a=e.terminalState??"completed";this.repository.updateMessageDeliveryState(n.sessionId,n.canonicalMessageId,a==="aborted"?"cancelled":a==="failed"?"failed":"completed"),this.emitExternalTerminal(n,a),t.shift(),t.length===0?this.externalObservations.delete(s):(this.externalObservations.set(s,t),t[0].lastPublishedAt=Date.now(),this.emitExternalActivity(t[0],"queued"))}suppressionFor(e,s,t){const n=M(e.agentType,e.sourceSessionKey),a=s.get(n),u=a?.window??this.suppressionWindows.get(n);return!u||e.ts<u.startedAt?null:e.ts>u.endsAt?(this.clearSuppression(n,u,a,s,t),null):e.role==="user"?(e.sourceEventKey===u.claimSourceEventKey||this.clearSuppression(n,u,a,s,t),null):u}clearSuppression(e,s,t,n,a){if(t){n.delete(e),a.set(t.claimKey,null);return}this.repository.removeManagedSuppression?.(s.agentType,s.sourceSessionKey),this.suppressionWindows.delete(e)}}function D(f){return $.createHash("sha256").update(ae(f)).digest("hex")}function M(f,e){return`${f}:${e}`}function le(f,e,s,t){if(!e.awaitingUserBoundary)return{events:f,cursor:{...e,offset:s,mtimeMs:t}};if(f.length===0)return{events:[],cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!0}};const n=f.findIndex(a=>a.role==="user");return n<0?{events:[],cursor:{...e,mtimeMs:t,awaitingUserBoundary:!0}}:{events:f.slice(n),cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!1}}}function ue(f,e,s,t,n,a){const u={...e.sourceBoundaryEstablished??{}},h=e.eventWatermarkTs??-1,p=new Set(e.eventKeysAtWatermark??[]),w=t?f:f.filter(l=>l.ts>h||l.ts===h&&!p.has(l.sourceEventKey)),o=[];for(const l of w){const r=l.sourceSessionKey;if(u[r]){o.push(l);continue}!(!t||(l.sourceSessionCreatedAtMs??0)>=s)||l.role!=="user"||(u[r]=!0,o.push(l))}const c=f.reduce((l,r)=>Math.max(l,r.ts),h),S=new Set(c===h?e.eventKeysAtWatermark??[]:[]);for(const l of f)l.ts===c&&S.add(l.sourceEventKey);return{events:o,cursor:{...e,offset:a,mtimeMs:n,eventWatermarkTs:c>=0?c:void 0,eventKeysAtWatermark:c>=0?[...S]:void 0,sourceBoundaryEstablished:u}}}export{ve as NativeSessionFusionService};
@@ -1,2 +1,2 @@
1
- import pe from"node:os";import{createHash as q,randomUUID as De}from"node:crypto";import{createAgent as be}from"../../agents/adapter.js";import{buildApprovalPendingPayload as qe,buildUserMessagePayload as me}from"@shennian/wire";import{ManagerModeAdapter as Ce}from"../../agents/manager.js";import{reportLog as C}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as $e}from"../../native-fusion/parsers.js";import{appendMessage as $,getDaemonInstallationId as ae,getMessageDeliveryStatus as je,recordSession as U,upsertMessage as j}from"../store.js";import{mergeProjectedSessions as Oe}from"../projection.js";import{buildManagedAgentEnv as We}from"../../agents/config-status.js";import{parsePersonalAttachmentReferences as He}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as Je,markAttachmentReferences as Be}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as _}from"../index-publisher.js";import{writeToolDetail as Ne}from"../tool-detail-store.js";import{getPersonalSyncIdentity as fe}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as ye}from"../../room/managed-prompt-composer.js";import{getManagedRoomIpcRoot as Fe,MANAGED_ROOM_IPC_ROOT_ENV as ze}from"../../daemon-ipc/paths.js";import{refreshMachineAgents as Ve}from"./agents.js";function he(e,n,a){if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const s=e.managedRoomPromptSnapshot;if(!s)throw new Error("managed_room_prompt_snapshot_missing");if(!n?.trim())throw new Error("managed_room_prompt_incomplete");if(!a||!/^mrc_[A-Za-z0-9_-]{43}$/.test(a))throw new Error("managed_room_context_unavailable");const r=q("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),u=q("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(s.runtimePermissionPolicyHash!==r||s.resolvedWorkDirHash!==u||s.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function Ue(e){const n=e.indexOf(`
2
- `),a=n>0?Math.min(n,80):Math.min(e.length,80);return e.slice(0,a)}function Ie(e,n,a){return`${e}:${q("sha256").update(`${n}\0${a??""}`).digest("hex")}`}function Le(e,n,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:n,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:n,...a}}const Ke=3e4;function Qe(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 Re(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function Se(e,n){return e!=="manager"?e:n==="claude"?"claude":"codex"}function Ge(e,n){U({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ke(e){return We(e)}function we(e,n,a){return{}}function L(e,n,a,s,r,u,c,m){const l=a==="codex";e.configure?.({sessionId:n,externalChannel:s??null,env:{...ke(a),...we(n,s,r),...u&&!l?{SHENNIAN_MANAGED_ROOM_CONTEXT:u,[ze]:Fe()}:{}},...c?{managedAgentPolicy:c}:{},...l?{managedRoomContextToken:u??null,managedRoomExecutor:u?m??null:null}:{}})}function oe(e,n,a){const s=n.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),n.managedRoomContextToken=a}function B(e,n){const a=n?.managedRoomContextToken;!n||!a||(n.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Xe(e,n,a){if(e!=="claude"||!a)return n;const s=n.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?$e(a)??n:n}function Ye(e,n,a,s){let r=null;function u(t,o={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:Le(t,n,o),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function c(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function m(t){if(!t.currentRunId||!t.currentRunPhase)return;const o=t.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:n,runId:t.currentRunId,seq:o,runPhase:t.currentRunPhase},seq:o,id:`agent-heartbeat-${t.currentRunId}-${o}-${Date.now()}`})}function l(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{m(t)},Ke),t.heartbeatTimer.unref?.())}function y(t){const o=t?.pendingTextEvent;!t||!o||!o.text||($(n,{id:`agent-${o.runId}-${o.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:o.text}),_(e.client),u({state:"delta",runId:o.runId,seq:o.seq,text:o.text,thinking:o.thinking||void 0}),t.pendingTextEvent=null)}s.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&Ve(e).catch(()=>{});const o=e.sessions.get(n),k=Qe(t),v=t.state==="final"||t.state==="error"||t.state==="aborted";if(o&&(o.nextEventSeq=t.seq+1,v||(o.currentRunId=t.runId),!v&&k&&(o.currentRunPhase=k,l(o)),t.agentSessionId&&(o.agentSessionId=t.agentSessionId),o.journalRunId)){const h={agentSessionId:t.agentSessionId??o.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...v?{}:{phase:k==="waiting_approval"?"waiting_approval":"running"}};e.runJournal?.update(n,o.journalRunId,h)}if(e.managerRuntime?.noteAgentEvent(n,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&C({level:"info",sessionId:n,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:a}});let E=!1;if(t.state==="tool-call"||t.state==="tool-result"){const h=t.toolCallId?`agent-tool-${q("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;Ne({sessionId:n,toolCallId:h,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?j:$)(n,{id:h,sessionId:n,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:h,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),E=!0}else t.state==="approval-pending"?($(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:qe({...t.approval,permission:t.permission})}),E=!0,o&&U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,attentionId:Ie("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&($(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:t.message}),E=!0);E&&_(e.client);const w=`${n}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&e.runTextAcc.set(w,(e.runTextAcc.get(w)??"")+t.text),t.agentSessionId&&t.agentSessionId!==r&&(r=t.agentSessionId,e.nativeFusion?.noteManagedSourceSession(n,Se(a,t.source),t.agentSessionId),o&&U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:t.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n,agentType:a,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const h=t.text??"";if(!h)return;o?.pendingTextEvent&&o.pendingTextEvent.runId!==t.runId&&y(o),o&&!o.pendingTextEvent&&(o.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),o?.pendingTextEvent&&(o.pendingTextEvent.text+=h,o.pendingTextEvent.seq=t.seq);return}let N={};if(t.state==="final"){y(o);const h=e.runTextAcc.get(w)??"";h&&(N={messageSummary:Ue(h)}),e.runTextAcc.delete(w)}else t.state==="error"||t.state==="aborted"?(y(o),e.runTextAcc.delete(w)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&y(o);v&&o?.currentRunId===t.runId&&(B(e,o),o.currentRunId=null,o.currentRunPhase=null,o.nextEventSeq=0,c(o),e.chatQueue?.noteTerminal(n),U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:Ie("terminal",t.runId),lastActivityAt:new Date().toISOString()}),_(e.client),o.journalRunId&&(e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null)),u(t,N)}),s.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${n} agentType=${a}: ${t.message}`);const o=e.sessions.get(n);B(e,o),o?.journalRunId&&(e.runJournal?.update(n,o.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null),e.sessions.delete(n),e.chatQueue?.noteTerminal(n),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:t.message,runId:"",seq:0}})})}function Ze(e,n){if(e.processedReqIds.add(n),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function K(e,n){B(e,n),n.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null),n.adapter.removeAllListeners(),await n.adapter.stop().catch(()=>{})}function Ae(e,n,a,s,r,u,c){return c?e.send(n,a,s,r,u,c):u?.trim()?e.send(n,a,s,r,u):r?.length?e.send(n,a,s,r):s?e.send(n,a,s):e.send(n,a)}function en(e,n,a,s,r,u,c){return e.prepareSend?e.prepareSend(n,a,s,r,u,c):Promise.resolve()}async function Pe(e,n,a,s,r,u,c,m,l,y="user"){e.evictIdleSessions();const t=be(a);if(!t)throw new Error(`Unsupported agent: ${a}`);const o=s==="manager"&&a!=="manager"?new Ce(t,a):t;L(o,n,a,c,m,null,l,e.managedRoomExecutor),y==="internal"?await o.start(n,r,u,{nativeSessionVisibility:y}):await o.start(n,r,u);const k={adapter:o,workDir:r,agentType:a,sessionMode:s,nativeSessionVisibility:y,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:m??null,externalChannelEnv:{...ke(a),...we(n,c,m)},managedRoomContextToken:null,journalRunId:null};return e.sessions.set(n,k),Ye(e,n,a,o),k}async function An(e,n,a=()=>{}){let s=null,r=null,u=null,c;if(n.source==="managed_room"||n.source==="managed_direct"){const l=await e.prepareManagedRecovery?.(n);if(!l)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(l.agentType!==n.agentType||l.sessionMode!==n.sessionMode||e.resolvePath(l.workDir)!==e.resolvePath(n.workDir)||l.managedRoomPromptSnapshot.managedRoomPolicyVersion!==n.managedPolicyVersion||l.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==n.managedRuntimePolicyHash)return e.revokeManagedRoomContextToken?.(l.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};const y={source:"room_activation",managedAgentPolicy:l.managedAgentPolicy,managedRoomPromptSnapshot:l.managedRoomPromptSnapshot};he(y,l.systemPrompt,l.managedRoomContextToken),s=l.managedAgentPolicy,r=l.managedRoomContextToken,u=l.systemPrompt,c={...y,recovery:"upgrade"}}else if(n.source==="manager_worker"){const l=n.parentSessionId;if(s=l?e.managerRuntime?.getManagedAgentPolicyForWorker(l,n.workDir)??null:null,!s)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(q("sha256").update(JSON.stringify({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement})).digest("hex")!==n.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};u=ye({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement,resolvedWorkDir:s.adapterPolicy.workDir})}c??={source:"upgrade_recovery",recovery:"upgrade"};let m=e.sessions.get(n.sessionId);return m||(m=await Pe(e,n.sessionId,n.agentType,n.sessionMode,n.workDir,n.agentSessionId,null,null,s,n.nativeSessionVisibility)),r&&(oe(e,m,r),L(m.adapter,n.sessionId,n.agentType,null,null,r,s,e.managedRoomExecutor)),m.journalRunId=n.runId,m.currentRunId=n.providerRunId??`recovery:${n.runId}`,m.currentRunPhase="thinking",m.adapter.recoverInterruptedRun({sessionId:n.sessionId,shennianRunId:n.runId,workDir:n.workDir,agentSessionId:n.agentSessionId,modelId:n.modelId,reasoningEffort:n.reasoningEffort,providerRunId:n.providerRunId,lastObservedEventSeq:n.lastObservedEventSeq,continueDispatchState:n.continueDispatchState,systemPrompt:u,sendContext:c,beforeContinueDispatch:a})}function nn(e,n){const a=e.sessions.get(n),s=a?.currentRunId;if(!a||!s)return;const r=a.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),B(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:r},seq:r,id:`agent-evt-${s}-${r}`}),a.journalRunId&&(e.runJournal?.remove(n,a.journalRunId),e.recoveryBarrier?.end(n),a.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function Pn(e,n,a){const s=a?n.params.managedRoomContextToken??null:null;let r=!1;try{await tn(e,n,a,()=>{r=!0})}finally{s&&!r&&e.revokeManagedRoomContextToken?.(s)}}async function tn(e,n,a,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:r,text:u,agentType:c,sessionMode:m,managerConfig:l,workDir:y,agentSessionId:t,modelId:o,systemPrompt:k,managerDefaultWorkerAgentType:v,managerDefaultWorkerModelId:E,reasoningEffort:w,clientMessageId:N,sessionListProjection:h,waitForDispatch:Q,responseId:_e,managedRoomContextToken:O,suppressExternalOwnerEcho:ve,queuedBatchItems:G,managedWorkerParentSessionId:M,managedRecoverySource:Ee}=n.params,I=_e||n.id;Oe(h);const F=null,X="";if(a?.source==="room_activation"&&(he(a,k,O),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(Ze(e,n.id),!r||!u){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(r)&&await e.recoveryBarrier.wait(r);const p=c,D=p==="manager"||m==="manager"?"manager":"standard";D==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(r,v??null,E??null);const W=(p==="claude"||p==="codex"||p==="workbuddy"||p==="pi-coding-agent"||p.startsWith("acp:"))&&typeof w=="string"&&w.trim()?w.trim():void 0,A=e.resolvePath(Xe(p,y||pe.homedir(),t)||pe.homedir()),P=a?.managedAgentPolicy??(M?e.managerRuntime?.getManagedAgentPolicyForWorker(M,A)??null:null);if(M&&!P)throw new Error("managed_worker_permission_context_unavailable");const Y=p==="codex"&&(a?.source==="room_activation"||M)?"internal":"user",Z=M&&P?ye({requestedPolicy:P.requestedPolicy,enforcement:P.enforcement,resolvedWorkDir:P.adapterPolicy.workDir}):k,xe=A,z=He(n.params.attachments);z?.length&&Je(A,z);const R={text:u,attachments:z,localized:!1};let d=e.sessions.get(r);if(d){if(d.lastActiveAt=Date.now(),d.agentType!==p||(d.sessionMode??(d.agentType==="manager"?"manager":"standard"))!==D||d.workDir!==A||(d.nativeSessionVisibility??"user")!==Y||JSON.stringify(d.externalChannel??null)!==JSON.stringify(F??null)){e.sessions.delete(r);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}else if(t&&d.agentSessionId!==t)try{await d.adapter.resume(t),d.agentSessionId=t}catch{e.sessions.delete(r);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}}if(!d)try{d=await Pe(e,r,p,D,A,t,F,X,P,Y)}catch(i){const f=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${c}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${r} agentType=${c} workDir=${A} agentSessionId=${t??""}: ${f}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:f,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:f});return}const S={id:N??`user-${n.id}`,sessionId:r,role:"user",ts:Date.now(),payload:me(R.text,R.attachments)},re=Array.isArray(G)&&G.length>0?G.map(i=>({id:i.clientMessageId??i.id,sessionId:r,role:"user",ts:Date.parse(i.createdAt),payload:me(i.text,i.attachments)})):null,V=re??[S],x=je(r,S.id),se=x.state==="queued";if(x.state!=="not_found"&&!se){e.client.sendRes({type:"res",id:I,ok:!0,payload:x});return}if(Q){a?.source==="room_activation"&&L(d.adapter,r,p,F,X,O,a.managedAgentPolicy,e.managedRoomExecutor);try{await en(d.adapter,R.text,o,W,R.attachments,Z,a?{source:a.source}:void 0)}catch(i){e.processedReqIds.delete(n.id),e.sessions.delete(r),await K(e,d),e.client.sendRes({type:"res",id:I,ok:!1,error:i instanceof Error?i.message:String(i)});return}}C({level:"info",sessionId:r,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:p,sessionMode:D,managerConfig:l??null,modelId:o,managerDefaultWorkerAgentType:v??null,managerDefaultWorkerModelId:E??null,reasoningEffort:W,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const H=(i,f)=>({...fe(ae()),sessionId:r,clientMessageId:S.id,messageId:S.id,deliveryState:i,bodyRevision:f,committedAt:new Date(S.ts).toISOString()}),ie=i=>{e.nativeFusion?.registerManagedSend({sessionId:r,agentType:p,sourceAgentType:Se(p,o),canonicalMessageId:S.id,sourceSessionKey:d.agentSessionId??t??null,text:R.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"&&!ve?"import_following":"suppress_following",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??S.id}`:null})},de=()=>{d.currentRunId||(d.currentRunId=`dispatch:${n.id}`,d.currentRunPhase="thinking",d.nextEventSeq=0)},le=()=>{if(!e.runJournal||d.journalRunId)return;const i=`run:${De()}`;e.runJournal.begin({daemonInstallationId:ae(),sessionId:r,runId:i,clientMessageId:S.id,agentType:p,sessionMode:D,workDir:A,agentSessionId:d.agentSessionId??t??null,modelId:o??null,reasoningEffort:W??null,nativeSessionVisibility:Y,providerRunId:null,source:a?.source==="room_activation"?Ee==="managed_direct"?"managed_direct":"managed_room":M?"manager_worker":"personal",parentSessionId:M??null,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:a?.managedRoomPromptSnapshot.managedRoomPolicyVersion??null,managedRuntimePolicyHash:a?.managedRoomPromptSnapshot.runtimePermissionPolicyHash??(P?q("sha256").update(JSON.stringify({requestedPolicy:P.requestedPolicy,enforcement:P.enforcement})).digest("hex"):null)}),d.journalRunId=i},ue=()=>{if(ie(),se)return{...fe(ae()),sessionId:r,clientMessageId:x.clientMessageId,messageId:x.messageId,deliveryState:x.deliveryState,bodyRevision:x.bodyRevision,committedAt:x.committedAt};try{Ge(e,{sessionId:r,agentType:p,sessionMode:D,managerConfig:l??null,workDir:xe,agentSessionId:d.agentSessionId??t??null,modelId:o,managerDefaultWorkerAgentType:v??null,managerDefaultWorkerModelId:E??null});let i=0;for(const[f,g]of V.entries()){const T=re?j(r,g,"committed"):$(r,g,"committed");f===0&&(i=T)}return Be(A,z??[]),_(e.client),H("committed",i)}catch(i){throw e.nativeFusion?.cancelManagedSend?.(S.id),i}},ce=i=>{d.currentRunId||(d.nextEventSeq=0),ie(i);const f=i?.deliveryMode==="external_owner_queue"?"queued":"executing";let g=0;for(const[T,J]of V.entries()){const b=j(r,J,f);T===0&&(g=b)}return _(e.client),H(f,g)},ee=async(i,f)=>{e.nativeFusion?.cancelManagedSend?.(S.id);const g=Re(p,i);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${r} agentType=${c} workDir=${A} agentSessionId=${d.agentSessionId??t??""}: ${g}`),d.adapter.hasPendingAuthenticationRetry?.()===!0){f&&e.client.sendRes({type:"res",id:I,ok:!0,payload:H("queued",0)});return}e.sessions.delete(r),d.journalRunId&&(e.runJournal?.update(r,d.journalRunId,{phase:"terminal"}),e.runJournal?.remove(r,d.journalRunId),e.recoveryBarrier?.end(r),d.journalRunId=null);try{await K(e,d)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:g,runId:"",seq:0}}),!f){const J={id:`agent-error-${n.id}-${Date.now()}`,sessionId:r,role:"agent",ts:Date.now(),payload:g};$(r,J),_(e.client)}f&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:g}))};if(Q){try{ue()}catch(g){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:`Durable message commit failed: ${g instanceof Error?g.message:String(g)}`});return}de(),le();let i;try{a?.source==="room_activation"&&(oe(e,d,O),s());const g=R.attachments;i=await Ae(d.adapter,R.text,o,W,g,Z,a?{source:a.source}:void 0),C({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(g){if(d.adapter.hasPendingAuthenticationRetry?.()){let b=0;for(const[ne,te]of V.entries()){const Te=j(r,te,"queued");ne===0&&(b=Te)}_(e.client),await ee(g,!1),e.client.sendRes({type:"res",id:I,ok:!0,payload:H("queued",b)});return}let T=0;for(const[b,ne]of V.entries()){const te=j(r,ne,"failed");b===0&&(T=te)}_(e.client);const J=Re(p,g);await ee(g,!1),e.client.sendRes({type:"res",id:I,ok:!0,payload:{...H("failed",T),failureMessage:J}});return}const f=ce(i??void 0);e.client.sendRes({type:"res",id:I,ok:!0,payload:{...f,...R.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}),C({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let ge;try{ge=ue()}catch(i){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:`Durable message commit failed: ${i instanceof Error?i.message:String(i)}`});return}de(),le(),a?.source==="room_activation"&&(L(d.adapter,r,p,F,X,O,a.managedAgentPolicy,e.managedRoomExecutor),oe(e,d,O),s()),ce(),e.client.sendRes({type:"res",id:I,ok:!0,payload:{...ge,...R.localized?{localizedAttachments:!0}:{}}}),C({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Me=R.attachments;Ae(d.adapter,R.text,o,W,Me,Z,a?{source:a.source}:void 0).then(()=>{C({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(i=>{j(r,S,d.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),_(e.client),ee(i,!1)})}async function _n(e,n){const{sessionId:a}=n.params,s=e.sessions.get(a);if(s){s.journalRunId&&e.runJournal?.markAborted(a,s.journalRunId),B(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}nn(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:n.id,ok:!0})}export{_n as handleChatAbort,Pn as handleChatSend,An as recoverJournaledRun,Ge as sendSessionUpdateEvent};
1
+ import fe from"node:os";import{createHash as C,randomUUID as be}from"node:crypto";import{createAgent as qe}from"../../agents/adapter.js";import{buildApprovalPendingPayload as Ce,buildUserMessagePayload as me}from"@shennian/wire";import{ManagerModeAdapter as $e}from"../../agents/manager.js";import{reportLog as $}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as je}from"../../native-fusion/parsers.js";import{appendMessage as j,getDaemonInstallationId as oe,getMessageDeliveryStatus as Oe,recordSession as U,upsertMessage as D}from"../store.js";import{mergeProjectedSessions as We}from"../projection.js";import{buildManagedAgentEnv as He}from"../../agents/config-status.js";import{parsePersonalAttachmentReferences as Je}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as Be,markAttachmentReferences as Ne}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as w}from"../index-publisher.js";import{writeToolDetail as Fe}from"../tool-detail-store.js";import{getPersonalSyncIdentity as ye}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Ie}from"../../room/managed-prompt-composer.js";import{getManagedRoomIpcRoot as ze,MANAGED_ROOM_IPC_ROOT_ENV as Ve}from"../../daemon-ipc/paths.js";import{refreshMachineAgents as Ue}from"./agents.js";function he(e,n,a){if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const s=e.managedRoomPromptSnapshot;if(!s)throw new Error("managed_room_prompt_snapshot_missing");if(!n?.trim())throw new Error("managed_room_prompt_incomplete");if(!a||!/^mrc_[A-Za-z0-9_-]{43}$/.test(a))throw new Error("managed_room_context_unavailable");const o=C("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),u=C("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(s.runtimePermissionPolicyHash!==o||s.resolvedWorkDirHash!==u||s.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function Le(e){const n=e.indexOf(`
2
+ `),a=n>0?Math.min(n,80):Math.min(e.length,80);return e.slice(0,a)}function Re(e,n,a){return`${e}:${C("sha256").update(`${n}\0${a??""}`).digest("hex")}`}function Ke(e,n,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:n,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:n,...a}}const Qe=3e4;function Ge(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 Se(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function we(e,n){return e!=="manager"?e:n==="claude"?"claude":"codex"}function Xe(e,n){U({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ke(e){return He(e)}function _e(e,n,a){return{}}function L(e,n,a,s,o,u,c,f){const l=a==="codex";e.configure?.({sessionId:n,externalChannel:s??null,env:{...ke(a),..._e(n,s,o),...u&&!l?{SHENNIAN_MANAGED_ROOM_CONTEXT:u,[Ve]:ze()}:{}},...c?{managedAgentPolicy:c}:{},...l?{managedRoomContextToken:u??null,managedRoomExecutor:u?f??null:null}:{}})}function re(e,n,a){const s=n.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),n.managedRoomContextToken=a}function N(e,n){const a=n?.managedRoomContextToken;!n||!a||(n.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Ye(e,n,a){if(e!=="claude"||!a)return n;const s=n.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?je(a)??n:n}function Ze(e,n,a,s){let o=null;function u(t,r={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:Ke(t,n,r),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function c(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function f(t){if(!t.currentRunId||!t.currentRunPhase)return;const r=t.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:n,runId:t.currentRunId,seq:r,runPhase:t.currentRunPhase},seq:r,id:`agent-heartbeat-${t.currentRunId}-${r}-${Date.now()}`})}function l(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{f(t)},Qe),t.heartbeatTimer.unref?.())}function y(t){const r=t?.pendingTextEvent;!t||!r||!r.text||(j(n,{id:`agent-${r.runId}-${r.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:r.text}),w(e.client),u({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),t.pendingTextEvent=null)}s.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&Ue(e).catch(()=>{});const r=e.sessions.get(n),k=Ge(t),x=t.state==="final"||t.state==="error"||t.state==="aborted";if(r&&(r.nextEventSeq=t.seq+1,x||(r.currentRunId=t.runId),!x&&k&&(r.currentRunPhase=k,l(r)),t.agentSessionId&&(r.agentSessionId=t.agentSessionId),r.journalRunId)){const I={agentSessionId:t.agentSessionId??r.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...x?{}:{phase:k==="waiting_approval"?"waiting_approval":"running"}};e.runJournal?.update(n,r.journalRunId,I)}if(e.managerRuntime?.noteAgentEvent(n,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&$({level:"info",sessionId:n,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:a}});let P=!1;if(t.state==="tool-call"||t.state==="tool-result"){const I=t.toolCallId?`agent-tool-${C("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;Fe({sessionId:n,toolCallId:I,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?D:j)(n,{id:I,sessionId:n,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:I,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),P=!0}else t.state==="approval-pending"?(j(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:Ce({...t.approval,permission:t.permission})}),P=!0,r&&U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,attentionId:Re("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(j(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:t.message}),P=!0);P&&w(e.client);const _=`${n}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&e.runTextAcc.set(_,(e.runTextAcc.get(_)??"")+t.text),t.agentSessionId&&t.agentSessionId!==o&&(o=t.agentSessionId,e.nativeFusion?.noteManagedSourceSession(n,we(a,t.source),t.agentSessionId),r&&U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:t.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n,agentType:a,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const I=t.text??"";if(!I)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==t.runId&&y(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=I,r.pendingTextEvent.seq=t.seq);return}let F={};if(t.state==="final"){y(r);const I=e.runTextAcc.get(_)??"";I&&(F={messageSummary:Le(I)}),e.runTextAcc.delete(_)}else t.state==="error"||t.state==="aborted"?(y(r),e.runTextAcc.delete(_)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&y(r);x&&r?.currentRunId===t.runId&&(N(e,r),r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,c(r),e.chatQueue?.noteTerminal(n),U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:Re("terminal",t.runId),lastActivityAt:new Date().toISOString()}),w(e.client),r.journalRunId&&(e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null)),u(t,F)}),s.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${n} agentType=${a}: ${t.message}`);const r=e.sessions.get(n);N(e,r),r?.journalRunId&&(e.runJournal?.update(n,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null),e.sessions.delete(n),e.chatQueue?.noteTerminal(n),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:t.message,runId:"",seq:0}})})}function en(e,n){if(e.processedReqIds.add(n),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function K(e,n){N(e,n),n.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null),n.adapter.removeAllListeners(),await n.adapter.stop().catch(()=>{})}function ve(e,n,a,s,o,u,c){return c?e.send(n,a,s,o,u,c):u?.trim()?e.send(n,a,s,o,u):o?.length?e.send(n,a,s,o):s?e.send(n,a,s):e.send(n,a)}function nn(e,n,a,s,o,u,c){return e.prepareSend?e.prepareSend(n,a,s,o,u,c):Promise.resolve()}async function Ae(e,n,a,s,o,u,c,f,l,y="user"){e.evictIdleSessions();const t=qe(a);if(!t)throw new Error(`Unsupported agent: ${a}`);const r=s==="manager"&&a!=="manager"?new $e(t,a):t;L(r,n,a,c,f,null,l,e.managedRoomExecutor),y==="internal"?await r.start(n,o,u,{nativeSessionVisibility:y}):await r.start(n,o,u);const k={adapter:r,workDir:o,agentType:a,sessionMode:s,nativeSessionVisibility:y,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:f??null,externalChannelEnv:{...ke(a),..._e(n,c,f)},managedRoomContextToken:null,journalRunId:null};return e.sessions.set(n,k),Ze(e,n,a,r),k}async function vn(e,n,a=()=>{}){let s=null,o=null,u=null,c;if(n.source==="managed_room"||n.source==="managed_direct"){const l=await e.prepareManagedRecovery?.(n);if(!l)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(l.agentType!==n.agentType||l.sessionMode!==n.sessionMode||e.resolvePath(l.workDir)!==e.resolvePath(n.workDir)||l.managedRoomPromptSnapshot.managedRoomPolicyVersion!==n.managedPolicyVersion||l.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==n.managedRuntimePolicyHash)return e.revokeManagedRoomContextToken?.(l.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};const y={source:"room_activation",managedAgentPolicy:l.managedAgentPolicy,managedRoomPromptSnapshot:l.managedRoomPromptSnapshot};he(y,l.systemPrompt,l.managedRoomContextToken),s=l.managedAgentPolicy,o=l.managedRoomContextToken,u=l.systemPrompt,c={...y,recovery:"upgrade"}}else if(n.source==="manager_worker"){const l=n.parentSessionId;if(s=l?e.managerRuntime?.getManagedAgentPolicyForWorker(l,n.workDir)??null:null,!s)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(C("sha256").update(JSON.stringify({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement})).digest("hex")!==n.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};u=Ie({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement,resolvedWorkDir:s.adapterPolicy.workDir})}c??={source:"upgrade_recovery",recovery:"upgrade"};let f=e.sessions.get(n.sessionId);return f||(f=await Ae(e,n.sessionId,n.agentType,n.sessionMode,n.workDir,n.agentSessionId,null,null,s,n.nativeSessionVisibility)),o&&(re(e,f,o),L(f.adapter,n.sessionId,n.agentType,null,null,o,s,e.managedRoomExecutor)),f.journalRunId=n.runId,f.currentRunId=n.providerRunId??`recovery:${n.runId}`,f.currentRunPhase="thinking",n.agentType==="codex"&&n.deliveryMode==="external_owner_queue"&&n.agentSessionId&&n.externalRunId&&e.nativeFusion?.restoreExternalObservation({sessionId:n.sessionId,sourceSessionKey:n.agentSessionId,runId:n.externalRunId,canonicalMessageId:n.clientMessageId,createdAt:Date.parse(n.createdAt)})?{result:"reattached"}:f.adapter.recoverInterruptedRun({sessionId:n.sessionId,shennianRunId:n.runId,workDir:n.workDir,agentSessionId:n.agentSessionId,modelId:n.modelId,reasoningEffort:n.reasoningEffort,providerRunId:n.providerRunId,lastObservedEventSeq:n.lastObservedEventSeq,continueDispatchState:n.continueDispatchState,systemPrompt:u,sendContext:c,beforeContinueDispatch:a})}function tn(e,n){const a=e.sessions.get(n),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),N(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),a.journalRunId&&(e.runJournal?.remove(n,a.journalRunId),e.recoveryBarrier?.end(n),a.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function An(e,n,a){const s=a?n.params.managedRoomContextToken??null:null;let o=!1;try{await an(e,n,a,()=>{o=!0})}finally{s&&!o&&e.revokeManagedRoomContextToken?.(s)}}async function an(e,n,a,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:o,text:u,agentType:c,sessionMode:f,managerConfig:l,workDir:y,agentSessionId:t,modelId:r,systemPrompt:k,managerDefaultWorkerAgentType:x,managerDefaultWorkerModelId:P,reasoningEffort:_,clientMessageId:F,sessionListProjection:I,waitForDispatch:Q,responseId:xe,managedRoomContextToken:O,suppressExternalOwnerEcho:Pe,queuedBatchItems:G,managedWorkerParentSessionId:E,managedRecoverySource:Me}=n.params,h=xe||n.id;We(I);const z=null,X="";if(a?.source==="room_activation"&&(he(a,k,O),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(en(e,n.id),!o||!u){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(o)&&await e.recoveryBarrier.wait(o);const p=c,b=p==="manager"||f==="manager"?"manager":"standard";b==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(o,x??null,P??null);const W=(p==="claude"||p==="codex"||p==="workbuddy"||p==="pi-coding-agent"||p.startsWith("acp:"))&&typeof _=="string"&&_.trim()?_.trim():void 0,v=e.resolvePath(Ye(p,y||fe.homedir(),t)||fe.homedir()),A=a?.managedAgentPolicy??(E?e.managerRuntime?.getManagedAgentPolicyForWorker(E,v)??null:null);if(E&&!A)throw new Error("managed_worker_permission_context_unavailable");const Y=p==="codex"&&(a?.source==="room_activation"||E)?"internal":"user",Z=E&&A?Ie({requestedPolicy:A.requestedPolicy,enforcement:A.enforcement,resolvedWorkDir:A.adapterPolicy.workDir}):k,Ee=v,V=Je(n.params.attachments);V?.length&&Be(v,V);const S={text:u,attachments:V,localized:!1};let d=e.sessions.get(o);if(d){if(d.lastActiveAt=Date.now(),d.agentType!==p||(d.sessionMode??(d.agentType==="manager"?"manager":"standard"))!==b||d.workDir!==v||(d.nativeSessionVisibility??"user")!==Y||JSON.stringify(d.externalChannel??null)!==JSON.stringify(z??null)){e.sessions.delete(o);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}else if(t&&d.agentSessionId!==t)try{await d.adapter.resume(t),d.agentSessionId=t}catch{e.sessions.delete(o);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}}if(!d)try{d=await Ae(e,o,p,b,v,t,z,X,A,Y)}catch(i){const m=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${c}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${o} agentType=${c} workDir=${v} agentSessionId=${t??""}: ${m}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:m,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:m});return}const R={id:F??`user-${n.id}`,sessionId:o,role:"user",ts:Date.now(),payload:me(S.text,S.attachments)},se=Array.isArray(G)&&G.length>0?G.map(i=>({id:i.clientMessageId??i.id,sessionId:o,role:"user",ts:Date.parse(i.createdAt),payload:me(i.text,i.attachments)})):null,H=se??[R],M=Oe(o,R.id),ie=M.state==="queued";if(M.state!=="not_found"&&!ie){e.client.sendRes({type:"res",id:h,ok:!0,payload:M});return}if(Q){a?.source==="room_activation"&&L(d.adapter,o,p,z,X,O,a.managedAgentPolicy,e.managedRoomExecutor);try{await nn(d.adapter,S.text,r,W,S.attachments,Z,a?{source:a.source}:void 0)}catch(i){e.processedReqIds.delete(n.id),e.sessions.delete(o),await K(e,d),e.client.sendRes({type:"res",id:h,ok:!1,error:i instanceof Error?i.message:String(i)});return}}$({level:"info",sessionId:o,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:p,sessionMode:b,managerConfig:l??null,modelId:r,managerDefaultWorkerAgentType:x??null,managerDefaultWorkerModelId:P??null,reasoningEffort:W,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const J=(i,m)=>({...ye(oe()),sessionId:o,clientMessageId:R.id,messageId:R.id,deliveryState:i,bodyRevision:m,committedAt:new Date(R.ts).toISOString()}),ee=i=>{e.nativeFusion?.registerManagedSend({sessionId:o,agentType:p,sourceAgentType:we(p,r),canonicalMessageId:R.id,sourceSessionKey:d.agentSessionId??t??null,text:S.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"&&!Pe?"import_following":"suppress_following",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??R.id}`:null})},de=()=>{d.currentRunId||(d.currentRunId=`dispatch:${n.id}`,d.currentRunPhase="thinking",d.nextEventSeq=0)},le=()=>{if(!e.runJournal||d.journalRunId)return;const i=`run:${be()}`;e.runJournal.begin({daemonInstallationId:oe(),sessionId:o,runId:i,clientMessageId:R.id,agentType:p,sessionMode:b,workDir:v,agentSessionId:d.agentSessionId??t??null,modelId:r??null,reasoningEffort:W??null,nativeSessionVisibility:Y,providerRunId:null,source:a?.source==="room_activation"?Me==="managed_direct"?"managed_direct":"managed_room":E?"manager_worker":"personal",parentSessionId:E??null,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:a?.managedRoomPromptSnapshot.managedRoomPolicyVersion??null,managedRuntimePolicyHash:a?.managedRoomPromptSnapshot.runtimePermissionPolicyHash??(A?C("sha256").update(JSON.stringify({requestedPolicy:A.requestedPolicy,enforcement:A.enforcement})).digest("hex"):null)}),d.journalRunId=i},ue=()=>{if(ee(),ie)return{...ye(oe()),sessionId:o,clientMessageId:M.clientMessageId,messageId:M.messageId,deliveryState:M.deliveryState,bodyRevision:M.bodyRevision,committedAt:M.committedAt};try{Xe(e,{sessionId:o,agentType:p,sessionMode:b,managerConfig:l??null,workDir:Ee,agentSessionId:d.agentSessionId??t??null,modelId:r,managerDefaultWorkerAgentType:x??null,managerDefaultWorkerModelId:P??null});let i=0;for(const[m,g]of H.entries()){const T=se?D(o,g,"committed"):j(o,g,"committed");m===0&&(i=T)}return Ne(v,V??[]),w(e.client),J("committed",i)}catch(i){throw e.nativeFusion?.cancelManagedSend?.(R.id),i}},ce=i=>{d.journalRunId&&e.runJournal?.update(o,d.journalRunId,{deliveryMode:i?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??R.id}`:null})},ge=i=>{d.currentRunId||(d.nextEventSeq=0),ce(i),ee(i);const m=i?.deliveryMode==="external_owner_queue"?"queued":"executing";let g=0;for(const[T,B]of H.entries()){const q=D(o,B,m);T===0&&(g=q)}return w(e.client),J(m,g)},ne=async(i,m)=>{e.nativeFusion?.cancelManagedSend?.(R.id);const g=Se(p,i);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${o} agentType=${c} workDir=${v} agentSessionId=${d.agentSessionId??t??""}: ${g}`),d.adapter.hasPendingAuthenticationRetry?.()===!0){m&&e.client.sendRes({type:"res",id:h,ok:!0,payload:J("queued",0)});return}e.sessions.delete(o),d.journalRunId&&(e.runJournal?.update(o,d.journalRunId,{phase:"terminal"}),e.runJournal?.remove(o,d.journalRunId),e.recoveryBarrier?.end(o),d.journalRunId=null);try{await K(e,d)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:g,runId:"",seq:0}}),!m){const B={id:`agent-error-${n.id}-${Date.now()}`,sessionId:o,role:"agent",ts:Date.now(),payload:g};j(o,B),w(e.client)}m&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:g}))};if(Q){try{ue()}catch(g){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:`Durable message commit failed: ${g instanceof Error?g.message:String(g)}`});return}de(),le();let i;try{a?.source==="room_activation"&&(re(e,d,O),s());const g=S.attachments;i=await ve(d.adapter,S.text,r,W,g,Z,a?{source:a.source}:void 0),$({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(g){if(d.adapter.hasPendingAuthenticationRetry?.()){let q=0;for(const[te,ae]of H.entries()){const De=D(o,ae,"queued");te===0&&(q=De)}w(e.client),await ne(g,!1),e.client.sendRes({type:"res",id:h,ok:!0,payload:J("queued",q)});return}let T=0;for(const[q,te]of H.entries()){const ae=D(o,te,"failed");q===0&&(T=ae)}w(e.client);const B=Se(p,g);await ne(g,!1),e.client.sendRes({type:"res",id:h,ok:!0,payload:{...J("failed",T),failureMessage:B}});return}const m=ge(i??void 0);e.client.sendRes({type:"res",id:h,ok:!0,payload:{...m,...S.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}),$({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let pe;try{pe=ue()}catch(i){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:`Durable message commit failed: ${i instanceof Error?i.message:String(i)}`});return}de(),le(),a?.source==="room_activation"&&(L(d.adapter,o,p,z,X,O,a.managedAgentPolicy,e.managedRoomExecutor),re(e,d,O),s()),ge(),e.client.sendRes({type:"res",id:h,ok:!0,payload:{...pe,...S.localized?{localizedAttachments:!0}:{}}}),$({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Te=S.attachments;ve(d.adapter,S.text,r,W,Te,Z,a?{source:a.source}:void 0).then(i=>{if(i?.deliveryMode==="external_owner_queue"){ce(i),ee(i);for(const m of H)D(o,m,"queued");w(e.client)}$({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(i=>{D(o,R,d.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),w(e.client),ne(i,!1)})}async function xn(e,n){const{sessionId:a}=n.params,s=e.sessions.get(a);if(s){s.journalRunId&&e.runJournal?.markAborted(a,s.journalRunId),N(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}tn(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:n.id,ok:!0})}export{xn as handleChatAbort,An as handleChatSend,vn as recoverJournaledRun,Xe as sendSessionUpdateEvent};
@@ -1,5 +1,5 @@
1
1
  import { type RunJournalRecord } from './schema.js';
2
- type JournalInput = Omit<RunJournalRecord, 'schemaVersion' | 'lastObservedEventSeq' | 'phase' | 'upgradeJobId' | 'interruptionReason' | 'continueDispatchState' | 'recoveryAttempts' | 'createdAt' | 'updatedAt' | 'recoveryReason'>;
2
+ type JournalInput = Omit<RunJournalRecord, 'schemaVersion' | 'lastObservedEventSeq' | 'phase' | 'upgradeJobId' | 'interruptionReason' | 'continueDispatchState' | 'recoveryAttempts' | 'createdAt' | 'updatedAt' | 'recoveryReason' | 'deliveryMode' | 'externalRunId'>;
3
3
  export type RunJournalLoadResult = {
4
4
  records: RunJournalRecord[];
5
5
  quarantined: string[];
@@ -1,2 +1,2 @@
1
- import n from"node:fs";import s from"node:path";import{createHash as p,randomUUID as u}from"node:crypto";import{resolveShennianPath as S}from"../../config/index.js";import{RUN_JOURNAL_SCHEMA_VERSION as w,isRecoverableJournalPhase as y,parseRunJournalRecord as h}from"./schema.js";function f(a,t){return p("sha256").update(`${a}\0${t}`).digest("hex")+".json"}function c(a){try{const t=n.lstatSync(a);if(t.isSymbolicLink()||!t.isFile())throw new Error("journal target is not a regular file")}catch(t){if(t.code!=="ENOENT")throw t}}function l(a){if(process.platform==="win32")return;const t=n.openSync(a,"r");try{n.fsyncSync(t)}finally{n.closeSync(t)}}function m(a){for(let t=0;t<3;t+=1){n.mkdirSync(a,{recursive:!0,mode:448});try{const r=n.lstatSync(a);if(r.isSymbolicLink()||!r.isDirectory())throw new Error("journal directory is unsafe");process.platform!=="win32"&&n.chmodSync(a,448);return}catch(r){if(r.code!=="ENOENT"||t===2)throw r}}}class N{daemonInstallationId;directory;quarantineDirectory;constructor(t,r={}){this.daemonInstallationId=t,this.directory=r.directory??S("runtime","run-recovery","active"),this.quarantineDirectory=s.join(s.dirname(this.directory),"quarantine"),m(this.directory),m(this.quarantineDirectory)}begin(t){const r=new Date().toISOString(),e={...t,schemaVersion:w,lastObservedEventSeq:-1,phase:"dispatching",upgradeJobId:null,interruptionReason:null,continueDispatchState:"none",recoveryAttempts:0,recoveryReason:null,createdAt:r,updatedAt:r};return this.write(e),e}update(t,r,e){const o=this.get(t,r);if(!o)return null;const i=h({...o,...e,updatedAt:new Date().toISOString()});return this.write(i),i}get(t,r){const e=this.recordPath(t,r);try{c(e);const o=h(JSON.parse(n.readFileSync(e,"utf8")));if(o.sessionId!==t||o.runId!==r)throw new Error("journal identity mismatch");return o}catch(o){return o.code==="ENOENT"||this.quarantine(e),null}}loadRecoverable(){return this.load(t=>y(t.phase))}loadPendingReconciliation(){return this.load(t=>y(t.phase)||t.phase==="interrupted_by_upgrade"||t.phase==="recovery_failed"||t.phase==="aborted")}load(t){const r=[],e=[];for(const o of n.readdirSync(this.directory)){if(!o.endsWith(".json"))continue;const i=s.join(this.directory,o);try{c(i);const d=h(JSON.parse(n.readFileSync(i,"utf8")));if(d.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");if(f(d.sessionId,d.runId)!==o)throw new Error("journal filename identity mismatch");t(d)&&r.push(d)}catch{e.push(this.quarantine(i))}}return r.sort((o,i)=>o.createdAt.localeCompare(i.createdAt)),{records:r,quarantined:e}}markPlannedUpgrade(t){const{records:r}=this.loadRecoverable();for(const e of r)this.update(e.sessionId,e.runId,{upgradeJobId:t,interruptionReason:"planned_upgrade"});return l(this.directory),r.length}markAborted(t,r){this.update(t,r,{phase:"aborted"})}markSessionAborted(t){const r=this.loadRecoverable().records.filter(e=>e.sessionId===t);for(const e of r)this.markAborted(e.sessionId,e.runId);return this.sync(),r.length}remove(t,r){const e=this.recordPath(t,r);c(e);try{n.unlinkSync(e)}catch(o){if(o.code!=="ENOENT")throw o}l(this.directory)}sync(){for(const t of n.readdirSync(this.directory)){if(!t.endsWith(".json"))continue;const r=s.join(this.directory,t);c(r);const e=n.openSync(r,process.platform==="win32"?"r+":"r");try{n.fsyncSync(e)}finally{n.closeSync(e)}}l(this.directory)}recordPath(t,r){return s.join(this.directory,f(t,r))}write(t){if(t.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");const r=h(t),e=this.recordPath(r.sessionId,r.runId);c(e);const o=`${e}.tmp-${process.pid}-${u()}`;try{n.writeFileSync(o,`${JSON.stringify(r,null,2)}
2
- `,{encoding:"utf8",mode:384,flag:"wx"}),process.platform!=="win32"&&n.chmodSync(o,384);const i=n.openSync(o,process.platform==="win32"?"r+":"r");try{n.fsyncSync(i)}finally{n.closeSync(i)}n.renameSync(o,e),l(this.directory)}finally{try{n.unlinkSync(o)}catch{}}}quarantine(t){const r=s.join(this.quarantineDirectory,`${s.basename(t)}.${Date.now()}.${u()}.invalid`);try{return c(t),n.renameSync(t,r),process.platform!=="win32"&&n.chmodSync(r,384),l(this.quarantineDirectory),r}catch{return t}}}export{N as ActiveRunJournal};
1
+ import n from"node:fs";import s from"node:path";import{createHash as p,randomUUID as u}from"node:crypto";import{resolveShennianPath as S}from"../../config/index.js";import{RUN_JOURNAL_SCHEMA_VERSION as w,isRecoverableJournalPhase as y,parseRunJournalRecord as h}from"./schema.js";function f(a,t){return p("sha256").update(`${a}\0${t}`).digest("hex")+".json"}function c(a){try{const t=n.lstatSync(a);if(t.isSymbolicLink()||!t.isFile())throw new Error("journal target is not a regular file")}catch(t){if(t.code!=="ENOENT")throw t}}function l(a){if(process.platform==="win32")return;const t=n.openSync(a,"r");try{n.fsyncSync(t)}finally{n.closeSync(t)}}function m(a){for(let t=0;t<3;t+=1){n.mkdirSync(a,{recursive:!0,mode:448});try{const r=n.lstatSync(a);if(r.isSymbolicLink()||!r.isDirectory())throw new Error("journal directory is unsafe");process.platform!=="win32"&&n.chmodSync(a,448);return}catch(r){if(r.code!=="ENOENT"||t===2)throw r}}}class R{daemonInstallationId;directory;quarantineDirectory;constructor(t,r={}){this.daemonInstallationId=t,this.directory=r.directory??S("runtime","run-recovery","active"),this.quarantineDirectory=s.join(s.dirname(this.directory),"quarantine"),m(this.directory),m(this.quarantineDirectory)}begin(t){const r=new Date().toISOString(),e={...t,schemaVersion:w,lastObservedEventSeq:-1,phase:"dispatching",upgradeJobId:null,interruptionReason:null,continueDispatchState:"none",deliveryMode:"direct",externalRunId:null,recoveryAttempts:0,recoveryReason:null,createdAt:r,updatedAt:r};return this.write(e),e}update(t,r,e){const o=this.get(t,r);if(!o)return null;const i=h({...o,...e,updatedAt:new Date().toISOString()});return this.write(i),i}get(t,r){const e=this.recordPath(t,r);try{c(e);const o=h(JSON.parse(n.readFileSync(e,"utf8")));if(o.sessionId!==t||o.runId!==r)throw new Error("journal identity mismatch");return o}catch(o){return o.code==="ENOENT"||this.quarantine(e),null}}loadRecoverable(){return this.load(t=>y(t.phase))}loadPendingReconciliation(){return this.load(t=>y(t.phase)||t.phase==="interrupted_by_upgrade"||t.phase==="recovery_failed"||t.phase==="aborted")}load(t){const r=[],e=[];for(const o of n.readdirSync(this.directory)){if(!o.endsWith(".json"))continue;const i=s.join(this.directory,o);try{c(i);const d=h(JSON.parse(n.readFileSync(i,"utf8")));if(d.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");if(f(d.sessionId,d.runId)!==o)throw new Error("journal filename identity mismatch");t(d)&&r.push(d)}catch{e.push(this.quarantine(i))}}return r.sort((o,i)=>o.createdAt.localeCompare(i.createdAt)),{records:r,quarantined:e}}markPlannedUpgrade(t){const{records:r}=this.loadRecoverable();for(const e of r)this.update(e.sessionId,e.runId,{upgradeJobId:t,interruptionReason:"planned_upgrade"});return l(this.directory),r.length}markAborted(t,r){this.update(t,r,{phase:"aborted"})}markSessionAborted(t){const r=this.loadRecoverable().records.filter(e=>e.sessionId===t);for(const e of r)this.markAborted(e.sessionId,e.runId);return this.sync(),r.length}remove(t,r){const e=this.recordPath(t,r);c(e);try{n.unlinkSync(e)}catch(o){if(o.code!=="ENOENT")throw o}l(this.directory)}sync(){for(const t of n.readdirSync(this.directory)){if(!t.endsWith(".json"))continue;const r=s.join(this.directory,t);c(r);const e=n.openSync(r,process.platform==="win32"?"r+":"r");try{n.fsyncSync(e)}finally{n.closeSync(e)}}l(this.directory)}recordPath(t,r){return s.join(this.directory,f(t,r))}write(t){if(t.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");const r=h(t),e=this.recordPath(r.sessionId,r.runId);c(e);const o=`${e}.tmp-${process.pid}-${u()}`;try{n.writeFileSync(o,`${JSON.stringify(r,null,2)}
2
+ `,{encoding:"utf8",mode:384,flag:"wx"}),process.platform!=="win32"&&n.chmodSync(o,384);const i=n.openSync(o,process.platform==="win32"?"r+":"r");try{n.fsyncSync(i)}finally{n.closeSync(i)}n.renameSync(o,e),l(this.directory)}finally{try{n.unlinkSync(o)}catch{}}}quarantine(t){const r=s.join(this.quarantineDirectory,`${s.basename(t)}.${Date.now()}.${u()}.invalid`);try{return c(t),n.renameSync(t,r),process.platform!=="win32"&&n.chmodSync(r,384),l(this.quarantineDirectory),r}catch{return t}}}export{R as ActiveRunJournal};
@@ -4,6 +4,7 @@ export declare const RECOVERY_CONTINUE_TEXT: "Continue.";
4
4
  export type RunJournalPhase = 'dispatching' | 'running' | 'waiting_approval' | 'recovering' | 'terminal' | 'interrupted_by_upgrade' | 'recovery_failed' | 'aborted';
5
5
  export type RunRecoverySource = 'personal' | 'managed_room' | 'managed_direct' | 'manager_worker';
6
6
  export type ContinueDispatchState = 'none' | 'intent' | 'accepted';
7
+ export type RunDeliveryMode = 'direct' | 'external_owner_queue';
7
8
  export type RunJournalRecord = {
8
9
  schemaVersion: typeof RUN_JOURNAL_SCHEMA_VERSION;
9
10
  daemonInstallationId: string;
@@ -32,6 +33,8 @@ export type RunJournalRecord = {
32
33
  upgradeJobId: string | null;
33
34
  interruptionReason: 'daemon_crash' | 'planned_upgrade' | 'os_restart' | null;
34
35
  continueDispatchState: ContinueDispatchState;
36
+ deliveryMode: RunDeliveryMode;
37
+ externalRunId: string | null;
35
38
  recoveryAttempts: number;
36
39
  /** Non-sensitive stable reason used to replay a pending terminal commit. */
37
40
  recoveryReason?: string | null;
@@ -1 +1 @@
1
- import{isAvailableAgentType as d}from"@shennian/wire";const a=1,m="Continue.",c=new Set(["dispatching","running","waiting_approval","recovering","terminal","interrupted_by_upgrade","recovery_failed","aborted"]),u=new Set(["personal","managed_room","managed_direct","manager_worker"]),p=new Set(["none","intent","accepted"]),g=new Set(["standard","manager"]);function t(n,e){if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function r(n,e){if(n==null)return null;if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function s(n,e){const o=t(n,e);if(!Number.isFinite(Date.parse(o)))throw new Error(`invalid ${e}`);return o}function v(n){if(!n||typeof n!="object"||Array.isArray(n))throw new Error("invalid run journal record");const e=n;if(e.schemaVersion!==a)throw new Error(`unsupported run journal schema: ${String(e.schemaVersion)}`);const o=t(e.agentType,"agentType");if(!d(o))throw new Error("invalid agentType");if(!c.has(e.phase))throw new Error("invalid phase");if(!u.has(e.source))throw new Error("invalid source");if(!p.has(e.continueDispatchState))throw new Error("invalid continueDispatchState");if(!g.has(e.sessionMode))throw new Error("invalid sessionMode");if(!Number.isSafeInteger(e.lastObservedEventSeq)||Number(e.lastObservedEventSeq)<-1)throw new Error("invalid lastObservedEventSeq");if(!Number.isSafeInteger(e.recoveryAttempts)||Number(e.recoveryAttempts)<0)throw new Error("invalid recoveryAttempts");if(e.activationHopCount!=null&&(!Number.isSafeInteger(e.activationHopCount)||Number(e.activationHopCount)<0))throw new Error("invalid activationHopCount");if(e.source==="managed_room"&&(!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount==null||!e.managedPolicyVersion||!e.managedRuntimePolicyHash))throw new Error("managed room recovery identity is incomplete");if(e.source==="manager_worker"&&(!e.parentSessionId||!e.managedRuntimePolicyHash))throw new Error("manager worker recovery identity is incomplete");const i=e.interruptionReason;if(i!=null&&i!=="daemon_crash"&&i!=="planned_upgrade"&&i!=="os_restart")throw new Error("invalid interruptionReason");return{schemaVersion:a,daemonInstallationId:t(e.daemonInstallationId,"daemonInstallationId"),sessionId:t(e.sessionId,"sessionId"),runId:t(e.runId,"runId"),clientMessageId:t(e.clientMessageId,"clientMessageId"),agentType:o,sessionMode:e.sessionMode,workDir:t(e.workDir,"workDir"),agentSessionId:r(e.agentSessionId,"agentSessionId"),modelId:r(e.modelId,"modelId"),reasoningEffort:r(e.reasoningEffort,"reasoningEffort"),nativeSessionVisibility:e.nativeSessionVisibility==="internal"?"internal":"user",providerRunId:r(e.providerRunId,"providerRunId"),lastObservedEventSeq:Number(e.lastObservedEventSeq),phase:e.phase,source:e.source,parentSessionId:r(e.parentSessionId,"parentSessionId"),roomContextRegistryKey:r(e.roomContextRegistryKey,"roomContextRegistryKey"),activationCauseMessageId:r(e.activationCauseMessageId,"activationCauseMessageId"),rootCauseMessageId:r(e.rootCauseMessageId,"rootCauseMessageId"),activationSequence:r(e.activationSequence,"activationSequence"),activationHopCount:e.activationHopCount==null?null:Number(e.activationHopCount),managedPolicyVersion:r(e.managedPolicyVersion,"managedPolicyVersion"),managedRuntimePolicyHash:r(e.managedRuntimePolicyHash,"managedRuntimePolicyHash"),upgradeJobId:r(e.upgradeJobId,"upgradeJobId"),interruptionReason:i,continueDispatchState:e.continueDispatchState,recoveryAttempts:Number(e.recoveryAttempts),recoveryReason:r(e.recoveryReason,"recoveryReason"),createdAt:s(e.createdAt,"createdAt"),updatedAt:s(e.updatedAt,"updatedAt")}}function I(n){return n==="dispatching"||n==="running"||n==="waiting_approval"||n==="recovering"}export{m as RECOVERY_CONTINUE_TEXT,a as RUN_JOURNAL_SCHEMA_VERSION,I as isRecoverableJournalPhase,v as parseRunJournalRecord};
1
+ import{isAvailableAgentType as d}from"@shennian/wire";const a=1,m="Continue.",u=new Set(["dispatching","running","waiting_approval","recovering","terminal","interrupted_by_upgrade","recovery_failed","aborted"]),c=new Set(["personal","managed_room","managed_direct","manager_worker"]),l=new Set(["none","intent","accepted"]),p=new Set(["standard","manager"]);function t(n,e){if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function r(n,e){if(n==null)return null;if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function s(n,e){const o=t(n,e);if(!Number.isFinite(Date.parse(o)))throw new Error(`invalid ${e}`);return o}function v(n){if(!n||typeof n!="object"||Array.isArray(n))throw new Error("invalid run journal record");const e=n;if(e.schemaVersion!==a)throw new Error(`unsupported run journal schema: ${String(e.schemaVersion)}`);const o=t(e.agentType,"agentType");if(!d(o))throw new Error("invalid agentType");if(!u.has(e.phase))throw new Error("invalid phase");if(!c.has(e.source))throw new Error("invalid source");if(!l.has(e.continueDispatchState))throw new Error("invalid continueDispatchState");if(e.deliveryMode!=null&&e.deliveryMode!=="direct"&&e.deliveryMode!=="external_owner_queue")throw new Error("invalid deliveryMode");if(!p.has(e.sessionMode))throw new Error("invalid sessionMode");if(!Number.isSafeInteger(e.lastObservedEventSeq)||Number(e.lastObservedEventSeq)<-1)throw new Error("invalid lastObservedEventSeq");if(!Number.isSafeInteger(e.recoveryAttempts)||Number(e.recoveryAttempts)<0)throw new Error("invalid recoveryAttempts");if(e.activationHopCount!=null&&(!Number.isSafeInteger(e.activationHopCount)||Number(e.activationHopCount)<0))throw new Error("invalid activationHopCount");if(e.source==="managed_room"&&(!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount==null||!e.managedPolicyVersion||!e.managedRuntimePolicyHash))throw new Error("managed room recovery identity is incomplete");if(e.source==="manager_worker"&&(!e.parentSessionId||!e.managedRuntimePolicyHash))throw new Error("manager worker recovery identity is incomplete");const i=e.interruptionReason;if(i!=null&&i!=="daemon_crash"&&i!=="planned_upgrade"&&i!=="os_restart")throw new Error("invalid interruptionReason");return{schemaVersion:a,daemonInstallationId:t(e.daemonInstallationId,"daemonInstallationId"),sessionId:t(e.sessionId,"sessionId"),runId:t(e.runId,"runId"),clientMessageId:t(e.clientMessageId,"clientMessageId"),agentType:o,sessionMode:e.sessionMode,workDir:t(e.workDir,"workDir"),agentSessionId:r(e.agentSessionId,"agentSessionId"),modelId:r(e.modelId,"modelId"),reasoningEffort:r(e.reasoningEffort,"reasoningEffort"),nativeSessionVisibility:e.nativeSessionVisibility==="internal"?"internal":"user",providerRunId:r(e.providerRunId,"providerRunId"),lastObservedEventSeq:Number(e.lastObservedEventSeq),phase:e.phase,source:e.source,parentSessionId:r(e.parentSessionId,"parentSessionId"),roomContextRegistryKey:r(e.roomContextRegistryKey,"roomContextRegistryKey"),activationCauseMessageId:r(e.activationCauseMessageId,"activationCauseMessageId"),rootCauseMessageId:r(e.rootCauseMessageId,"rootCauseMessageId"),activationSequence:r(e.activationSequence,"activationSequence"),activationHopCount:e.activationHopCount==null?null:Number(e.activationHopCount),managedPolicyVersion:r(e.managedPolicyVersion,"managedPolicyVersion"),managedRuntimePolicyHash:r(e.managedRuntimePolicyHash,"managedRuntimePolicyHash"),upgradeJobId:r(e.upgradeJobId,"upgradeJobId"),interruptionReason:i,continueDispatchState:e.continueDispatchState,deliveryMode:e.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:r(e.externalRunId,"externalRunId"),recoveryAttempts:Number(e.recoveryAttempts),recoveryReason:r(e.recoveryReason,"recoveryReason"),createdAt:s(e.createdAt,"createdAt"),updatedAt:s(e.updatedAt,"updatedAt")}}function y(n){return n==="dispatching"||n==="running"||n==="waiting_approval"||n==="recovering"}export{m as RECOVERY_CONTINUE_TEXT,a as RUN_JOURNAL_SCHEMA_VERSION,y as isRecoverableJournalPhase,v as parseRunJournalRecord};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.28",
3
+ "version": "0.4.29",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {