shennian 0.3.5 → 0.3.7
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.
- package/dist/publish-build-manifest.json +10 -10
- package/dist/src/index.js +1 -1
- package/dist/src/native-fusion/service.d.ts +1 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/types.d.ts +1 -0
- package/dist/src/room/managed-room-binding.d.ts +2 -0
- package/dist/src/room/managed-room-binding.js +1 -1
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/upgrade/engine.js +2 -2
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/native-session.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/native-session.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -266,8 +266,8 @@
|
|
|
266
266
|
},
|
|
267
267
|
{
|
|
268
268
|
"file": "src/index.js",
|
|
269
|
-
"beforeBytes":
|
|
270
|
-
"afterBytes":
|
|
269
|
+
"beforeBytes": 25142,
|
|
270
|
+
"afterBytes": 13054
|
|
271
271
|
},
|
|
272
272
|
{
|
|
273
273
|
"file": "src/integrations/claude-room-plugin-lifecycle.js",
|
|
@@ -366,8 +366,8 @@
|
|
|
366
366
|
},
|
|
367
367
|
{
|
|
368
368
|
"file": "src/native-fusion/service.js",
|
|
369
|
-
"beforeBytes":
|
|
370
|
-
"afterBytes":
|
|
369
|
+
"beforeBytes": 7841,
|
|
370
|
+
"afterBytes": 3598
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"file": "src/native-fusion/state.js",
|
|
@@ -466,8 +466,8 @@
|
|
|
466
466
|
},
|
|
467
467
|
{
|
|
468
468
|
"file": "src/room/managed-room-binding.js",
|
|
469
|
-
"beforeBytes":
|
|
470
|
-
"afterBytes":
|
|
469
|
+
"beforeBytes": 3203,
|
|
470
|
+
"afterBytes": 1658
|
|
471
471
|
},
|
|
472
472
|
{
|
|
473
473
|
"file": "src/room/managed-room-session.js",
|
|
@@ -561,8 +561,8 @@
|
|
|
561
561
|
},
|
|
562
562
|
{
|
|
563
563
|
"file": "src/session/handlers/chat.js",
|
|
564
|
-
"beforeBytes":
|
|
565
|
-
"afterBytes":
|
|
564
|
+
"beforeBytes": 30611,
|
|
565
|
+
"afterBytes": 13371
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
568
|
"file": "src/session/handlers/control.js",
|
|
@@ -631,8 +631,8 @@
|
|
|
631
631
|
},
|
|
632
632
|
{
|
|
633
633
|
"file": "src/upgrade/engine.js",
|
|
634
|
-
"beforeBytes":
|
|
635
|
-
"afterBytes":
|
|
634
|
+
"beforeBytes": 15457,
|
|
635
|
+
"afterBytes": 6563
|
|
636
636
|
},
|
|
637
637
|
{
|
|
638
638
|
"file": "src/upgrade/scheduler.js",
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Command as ae}from"commander";import I from"chalk";import U from"node:os";import b from"node:fs";import{loadConfig as a,saveConfig as J,getConfigPath as ce,getShennianDir as me,resolveShennianPath as W,normalizeAutoUpgradePolicy as le}from"./config/index.js";import{CliRelayClient as de}from"./relay/client.js";import{registerPairCommand as pe,runSmartStart as ge}from"./commands/pair.js";import{clearDaemonPidIfOwner as j,createDaemonInstanceId as he,clearDaemonLauncher as K,findRunningDaemonProcessIds as ue,isRemoteAccessDisabled as fe,isIsolatedDaemonE2eInstance as ve,registerDaemonCommand as Ie,writeDaemonPid as q,writeDaemonLauncher as Q}from"./commands/daemon.js";import{registerAgentCommand as Se}from"./commands/agent.js";import{registerManagerCommand as we}from"./commands/manager.js";import{registerUpgradeCommand as ye}from"./commands/upgrade.js";import{registerToolsCommand as Re}from"./commands/tools.js";import{registerIntegrationCommand as ke}from"./commands/integration.js";import{registerRoomCommand as Ce}from"./commands/room.js";import{SessionManager as Te}from"./session/manager.js";import{SERVERS as O,regionToUrl as Ae,urlToRegion as De}from"./region.js";import{getCurrentVersion as X,handleStartupCrashCheck as $e}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Ee}from"./upgrade/scheduler.js";import{detectAgents as Ue}from"./agents/detect.js";import{augmentProcessPath as Y}from"./env-path.js";Y();const Z=X();import{getCachedAgentInfos as be,resolveAgentInfos as Oe}from"./agents/model-registry.js";import{initCliLogReporter as Ne,reportLog as S}from"./log-reporter.js";import{isNativeFusionEnabled as Pe}from"./native-fusion/config.js";import{NativeSessionFusionService as Me}from"./native-fusion/service.js";import{startDaemonLogRetention as Le}from"./daemon-log.js";import{startDaemonIpcServer as He}from"./daemon-ipc/server.js";import{createAuthorizedActionIpcHandlers as xe}from"./room/authorized-action-ipc.js";import{PendingAuthorizedActionStore as _e}from"./room/pending-authorized-actions.js";import{HttpDeviceAuthorizationClient as ze}from"./room/device-authorization-client.js";import{AuthorizedActionCoordinator as Ve}from"./room/authorized-action-coordinator.js";import{RoomSessionRegistry as Be}from"./room/session-registry.js";import{createRoomSessionRegistryIpcHandlers as Fe}from"./room/session-registry-ipc.js";import{RoomInvocationTokenAuthority as Ge}from"./room/invocation-token.js";import{createRoomInvocationTokenIpcHandlers as Je}from"./room/invocation-token-ipc.js";import{HttpRoomBindingClient as We}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as je}from"./room/managed-room-binding.js";import{createRoomBindingIpcHandlers as Ke}from"./room/room-binding-ipc.js";import{RoomHostSessionObservationStore as qe}from"./room/host-session-observations.js";import{createRoomHostSessionObservationIpcHandlers as Qe}from"./room/host-session-observation-ipc.js";import{runWorkBuddySessionHook as Xe}from"./integrations/workbuddy-session-hook.js";import{runRoomSessionHook as Ye}from"./integrations/room-session-hook.js";import{RoomJsonlMirror as ee}from"./room/jsonl-mirror.js";import{RoomMirrorSyncService as Ze}from"./room/mirror-sync-service.js";import{RoomActivationService as eo}from"./room/activation-service.js";import{RoomActivationAudit as oo}from"./room/activation-audit.js";import{RoomAttachmentCache as no}from"./room/attachment-cache.js";import{RoomAttachmentUploader as to}from"./room/attachment-upload.js";import{runRoomToolServer as ro}from"./room/tool-server.js";import{RoomAuthorizedActionExecutor as io}from"./room/room-authorized-action-executor.js";import{createRoomOperatorIpcHandlers as so}from"./room/operator-ipc.js";import{openExternalUrl as ao}from"./commands/pair-browser.js";const oe=me(),co=W("daemon.pid");function mo(){try{const o=b.readFileSync(co,"utf-8").trim();if(o.startsWith("{")){const r=JSON.parse(o),c=Number(r.pid);return Number.isInteger(c)&&c>0?c:null}const n=parseInt(o,10);return Number.isInteger(n)&&n>0?n:null}catch{return null}}function lo(o){return o.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function po(o){const n=[`trigger=${o.trigger??"unknown"}`,`phase=${o.phase}`,`code=${o.code??"unknown"}`,`attempt=${o.reconnectAttempt}`];return o.reason&&n.push(`reason=${o.reason}`),o.error&&n.push(`error=${o.error}`),n.join(" ")}async function ne(o,n=5e3){const r=Date.now();for(;Date.now()-r<n;){try{process.kill(o,0)}catch{return!0}await new Promise(c=>setTimeout(c,100))}try{return process.kill(o,0),!1}catch{return!0}}const t=new ae;t.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(Z),t.enablePositionalOptions(),ke(t),Ce(t),t.option("--api <url>","Server URL override").option("--name <name>","Machine name",U.hostname()).action(async o=>{const n=a(),r=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??n.serverUrl??void 0;await ge(r,o.name)}),t.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async o=>{const n=W("env.json");try{const e=JSON.parse(b.readFileSync(n,"utf-8"));for(const[s,m]of Object.entries(e))process.env[s]||(process.env[s]=m);Y()}catch{}const r=Le();fe()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(r),process.exit(0));const c=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),N=async(e,s)=>{console.log(`[${new Date().toISOString()}] ${s} (PID ${e})`),process.kill(e,"SIGTERM"),await ne(e)||(process.kill(e,"SIGKILL"),await ne(e,2e3))};try{const e=mo();if(e&&e!==process.pid)try{process.kill(e,0),c?await N(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const A=ve(process.env,oe)?[]:ue(process.pid);if(A.length>0)if(c)for(const e of A)try{await N(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${A[0]}), skipping duplicate start`),process.exit(0);const l=he();q(process.pid,l,{version:Z}),Q(process.pid,void 0,l),process.on("exit",()=>{j(process.pid,l),K(l)}),await $e()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));let i=a();const h=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??i.serverUrl??O.cn.url,u=X(),D=Ue(),f=D.map(e=>e.type),$=be(D),P=new _e,d=new Be,v=new qe,M=new Ge(d),p=new We(h),re=new no({actionClient:p}),ie=new to({actionClient:p}),L=new ze(h);let E=null;const H=await He({handlers:{...xe({store:P,authorizationClient:L,machineName:U.hostname(),machineOs:`${process.platform} ${U.release()}`,agentList:f,openPublicLoginUrl:ao}),...Fe({registry:d,observations:v,sessionResolver:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),...Qe({store:v,registry:d,getMachineId:()=>a().machineId,onRegistrationIdle:e=>{E?.drain(e).catch(s=>{console.error("[room.activation] idle drain failed",s)})}}),...Je({authority:M,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),...Ke({authority:M,registry:d,bindingClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}},mirrorFactory:e=>new ee(e),attachmentCache:re,attachmentUploader:ie,observations:v}),...so({registry:d,actionClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}})}}),se=new io({registry:d,observations:v,actionClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),x=new Ve(P,L,se,({machineId:e,machineToken:s})=>{J({...a(),machineId:e,machineToken:s,serverUrl:h})});let w=!1;const y=()=>{w||(w=!0,H.close().finally(()=>process.exit(0)))};if(process.once("SIGINT",y),process.once("SIGTERM",y),!i.machineToken){for(console.log(`[${new Date().toISOString()}] Waiting for browser device authorization...`);!w&&!i.machineToken;)await x.runOnce(),i=a(),i.machineToken||await new Promise(e=>setTimeout(e,1e3));if(w)return}process.removeListener("SIGINT",y),process.removeListener("SIGTERM",y);const _=setInterval(()=>{x.runOnce().catch(e=>{console.error("[room.authorization] pending action retry failed",e)})},1e3);_.unref?.();const z=`${lo(h)}/relay/machine`,V=i.machineToken;if(!V)return;i.machineId&&Ne(h,i.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${z}... (v${u}) agents: ${f.join(",")}`),S({level:"info",wsEvent:"daemon.start",metadata:{version:u,agents:f}});let R=null,k=null;const B=le(i.autoUpgrade),g=new de({serverUrl:z,machineToken:V,cliVersion:u,agentList:f,autoUpgradePolicy:B,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),S({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&g.sendEvent({type:"event",event:"machine.agents",payload:{agentList:f,agents:$}}),Oe(D,{serverUrl:i.serverUrl??h,authToken:i.machineToken??i.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&g.sendEvent({type:"event",event:"machine.agents",payload:{agentList:f,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:s})=>{const m=e();s(),m&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${m.from} \u2192 ${m.to}`),g.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:m.from,to:m.to}}))}).catch(()=>{}),C.start(),R?.handleConnected(),k?.start()},onDisconnected:e=>{k?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${po(e)}`),S({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),S({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),T.handleReq(e)}});R=Pe()?new Me(g):null,k=new Ze({registry:d,actionClient:p,getMachineCredentials:()=>({machineToken:a().machineToken}),mirrorFactory:e=>new ee(e),onMessages:async(e,s,m)=>{await E?.processMessages(e,s,m)}});const C=new Ee({currentVersion:u,machineId:i.machineId??"unknown-machine",serverUrl:i.serverUrl??h,getIdleState:()=>T.getUpgradeIdleState(),startUpgrade:async e=>{const{handleUpgradeStart:s}=await import("./commands/upgrade.js");await s(g,"auto-upgrade",e,{currentVersion:u})}});C.setPolicy(B);const T=new Te(g,R,u,C,new je({registry:d,bindingClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}));E=new eo({registry:d,observations:v,activate:e=>T.activateRoomSession(e),audit:new oo}),b.mkdirSync(oe,{recursive:!0}),q(process.pid,l,{version:u}),Q(process.pid,void 0,l),g.connect(),process.stdin.resume();let F=!1;const G=async()=>{if(!F){F=!0,console.log(I.gray(`
|
|
1
|
+
import{Command as ae}from"commander";import I from"chalk";import U from"node:os";import b from"node:fs";import{loadConfig as a,saveConfig as J,getConfigPath as ce,getShennianDir as me,resolveShennianPath as W,normalizeAutoUpgradePolicy as le}from"./config/index.js";import{CliRelayClient as de}from"./relay/client.js";import{registerPairCommand as pe,runSmartStart as ge}from"./commands/pair.js";import{clearDaemonPidIfOwner as j,createDaemonInstanceId as he,clearDaemonLauncher as K,findRunningDaemonProcessIds as ue,isRemoteAccessDisabled as fe,isIsolatedDaemonE2eInstance as ve,registerDaemonCommand as Ie,writeDaemonPid as q,writeDaemonLauncher as Q}from"./commands/daemon.js";import{registerAgentCommand as Se}from"./commands/agent.js";import{registerManagerCommand as we}from"./commands/manager.js";import{registerUpgradeCommand as ye}from"./commands/upgrade.js";import{registerToolsCommand as Re}from"./commands/tools.js";import{registerIntegrationCommand as ke}from"./commands/integration.js";import{registerRoomCommand as Ce}from"./commands/room.js";import{SessionManager as Te}from"./session/manager.js";import{SERVERS as O,regionToUrl as Ae,urlToRegion as De}from"./region.js";import{getCurrentVersion as X,handleStartupCrashCheck as $e}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Ee}from"./upgrade/scheduler.js";import{detectAgents as Ue}from"./agents/detect.js";import{augmentProcessPath as Y}from"./env-path.js";Y();const Z=X();import{getCachedAgentInfos as be,resolveAgentInfos as Oe}from"./agents/model-registry.js";import{initCliLogReporter as Ne,reportLog as S}from"./log-reporter.js";import{isNativeFusionEnabled as Pe}from"./native-fusion/config.js";import{NativeSessionFusionService as Me}from"./native-fusion/service.js";import{startDaemonLogRetention as Le}from"./daemon-log.js";import{startDaemonIpcServer as He}from"./daemon-ipc/server.js";import{createAuthorizedActionIpcHandlers as xe}from"./room/authorized-action-ipc.js";import{PendingAuthorizedActionStore as _e}from"./room/pending-authorized-actions.js";import{HttpDeviceAuthorizationClient as ze}from"./room/device-authorization-client.js";import{AuthorizedActionCoordinator as Ve}from"./room/authorized-action-coordinator.js";import{RoomSessionRegistry as Be}from"./room/session-registry.js";import{createRoomSessionRegistryIpcHandlers as Fe}from"./room/session-registry-ipc.js";import{RoomInvocationTokenAuthority as Ge}from"./room/invocation-token.js";import{createRoomInvocationTokenIpcHandlers as Je}from"./room/invocation-token-ipc.js";import{HttpRoomBindingClient as We}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as je}from"./room/managed-room-binding.js";import{createRoomBindingIpcHandlers as Ke}from"./room/room-binding-ipc.js";import{RoomHostSessionObservationStore as qe}from"./room/host-session-observations.js";import{createRoomHostSessionObservationIpcHandlers as Qe}from"./room/host-session-observation-ipc.js";import{runWorkBuddySessionHook as Xe}from"./integrations/workbuddy-session-hook.js";import{runRoomSessionHook as Ye}from"./integrations/room-session-hook.js";import{RoomJsonlMirror as ee}from"./room/jsonl-mirror.js";import{RoomMirrorSyncService as Ze}from"./room/mirror-sync-service.js";import{RoomActivationService as eo}from"./room/activation-service.js";import{RoomActivationAudit as oo}from"./room/activation-audit.js";import{RoomAttachmentCache as no}from"./room/attachment-cache.js";import{RoomAttachmentUploader as to}from"./room/attachment-upload.js";import{runRoomToolServer as ro}from"./room/tool-server.js";import{RoomAuthorizedActionExecutor as io}from"./room/room-authorized-action-executor.js";import{createRoomOperatorIpcHandlers as so}from"./room/operator-ipc.js";import{openExternalUrl as ao}from"./commands/pair-browser.js";const oe=me(),co=W("daemon.pid");function mo(){try{const o=b.readFileSync(co,"utf-8").trim();if(o.startsWith("{")){const r=JSON.parse(o),c=Number(r.pid);return Number.isInteger(c)&&c>0?c:null}const n=parseInt(o,10);return Number.isInteger(n)&&n>0?n:null}catch{return null}}function lo(o){return o.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function po(o){const n=[`trigger=${o.trigger??"unknown"}`,`phase=${o.phase}`,`code=${o.code??"unknown"}`,`attempt=${o.reconnectAttempt}`];return o.reason&&n.push(`reason=${o.reason}`),o.error&&n.push(`error=${o.error}`),n.join(" ")}async function ne(o,n=5e3){const r=Date.now();for(;Date.now()-r<n;){try{process.kill(o,0)}catch{return!0}await new Promise(c=>setTimeout(c,100))}try{return process.kill(o,0),!1}catch{return!0}}const t=new ae;t.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(Z),t.enablePositionalOptions(),ke(t),Ce(t),t.option("--api <url>","Server URL override").option("--name <name>","Machine name",U.hostname()).action(async o=>{const n=a(),r=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??n.serverUrl??void 0;await ge(r,o.name)}),t.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async o=>{const n=W("env.json");try{const e=JSON.parse(b.readFileSync(n,"utf-8"));for(const[s,m]of Object.entries(e))process.env[s]||(process.env[s]=m);Y()}catch{}const r=Le();fe()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(r),process.exit(0));const c=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),N=async(e,s)=>{console.log(`[${new Date().toISOString()}] ${s} (PID ${e})`),process.kill(e,"SIGTERM"),await ne(e)||(process.kill(e,"SIGKILL"),await ne(e,2e3))};try{const e=mo();if(e&&e!==process.pid)try{process.kill(e,0),c?await N(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const A=ve(process.env,oe)?[]:ue(process.pid);if(A.length>0)if(c)for(const e of A)try{await N(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${A[0]}), skipping duplicate start`),process.exit(0);const l=he();q(process.pid,l,{version:Z}),Q(process.pid,void 0,l),process.on("exit",()=>{j(process.pid,l),K(l)}),await $e()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));let i=a();const h=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??i.serverUrl??O.cn.url,u=X(),D=Ue(),f=D.map(e=>e.type),$=be(D),P=new _e,d=new Be,v=new qe,M=new Ge(d),p=new We(h),re=new no({actionClient:p}),ie=new to({actionClient:p}),L=new ze(h);let E=null;const H=await He({handlers:{...xe({store:P,authorizationClient:L,machineName:U.hostname(),machineOs:`${process.platform} ${U.release()}`,agentList:f,openPublicLoginUrl:ao}),...Fe({registry:d,observations:v,sessionResolver:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),...Qe({store:v,registry:d,getMachineId:()=>a().machineId,onRegistrationIdle:e=>{E?.drain(e).catch(s=>{console.error("[room.activation] idle drain failed",s)})}}),...Je({authority:M,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),...Ke({authority:M,registry:d,bindingClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}},mirrorFactory:e=>new ee(e),attachmentCache:re,attachmentUploader:ie,observations:v}),...so({registry:d,actionClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}})}}),se=new io({registry:d,observations:v,actionClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}}}),x=new Ve(P,L,se,({machineId:e,machineToken:s})=>{J({...a(),machineId:e,machineToken:s,serverUrl:h})});let w=!1;const y=()=>{w||(w=!0,H.close().finally(()=>process.exit(0)))};if(process.once("SIGINT",y),process.once("SIGTERM",y),!i.machineToken){for(console.log(`[${new Date().toISOString()}] Waiting for browser device authorization...`);!w&&!i.machineToken;)await x.runOnce(),i=a(),i.machineToken||await new Promise(e=>setTimeout(e,1e3));if(w)return}process.removeListener("SIGINT",y),process.removeListener("SIGTERM",y);const _=setInterval(()=>{x.runOnce().catch(e=>{console.error("[room.authorization] pending action retry failed",e)})},1e3);_.unref?.();const z=`${lo(h)}/relay/machine`,V=i.machineToken;if(!V)return;i.machineId&&Ne(h,i.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${z}... (v${u}) agents: ${f.join(",")}`),S({level:"info",wsEvent:"daemon.start",metadata:{version:u,agents:f}});let R=null,k=null;const B=le(i.autoUpgrade),g=new de({serverUrl:z,machineToken:V,cliVersion:u,agentList:f,autoUpgradePolicy:B,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),S({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&g.sendEvent({type:"event",event:"machine.agents",payload:{agentList:f,agents:$}}),Oe(D,{serverUrl:i.serverUrl??h,authToken:i.machineToken??i.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&g.sendEvent({type:"event",event:"machine.agents",payload:{agentList:f,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:s})=>{const m=e();s(),m&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${m.from} \u2192 ${m.to}`),g.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:m.from,to:m.to}}))}).catch(()=>{}),C.start(),R?.handleConnected(),k?.start()},onDisconnected:e=>{k?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${po(e)}`),S({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),S({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),T.handleReq(e)}});R=Pe()?new Me(g):null,k=new Ze({registry:d,actionClient:p,getMachineCredentials:()=>({machineToken:a().machineToken}),mirrorFactory:e=>new ee(e),onMessages:async(e,s,m)=>{await E?.processMessages(e,s,m)}});const C=new Ee({currentVersion:u,machineId:i.machineId??"unknown-machine",serverUrl:i.serverUrl??h,getIdleState:()=>T.getUpgradeIdleState(),startUpgrade:async e=>{const{handleUpgradeStart:s}=await import("./commands/upgrade.js");await s(g,"auto-upgrade",e,{currentVersion:u})}});C.setPolicy(B);const T=new Te(g,R,u,C,new je({registry:d,observations:v,bindingClient:p,getMachineCredentials:()=>{const e=a();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}));E=new eo({registry:d,observations:v,activate:e=>T.activateRoomSession(e),audit:new oo}),b.mkdirSync(oe,{recursive:!0}),q(process.pid,l,{version:u}),Q(process.pid,void 0,l),g.connect(),process.stdin.resume();let F=!1;const G=async()=>{if(!F){F=!0,console.log(I.gray(`
|
|
2
2
|
Disconnecting...`)),S({level:"info",wsEvent:"daemon.stop"}),clearInterval(r),clearInterval(_);try{await T.cleanup(),C.stop(),R?.stop(),k?.stop(),g.disconnect(),await H.close(),j(process.pid,l),K(l)}finally{process.exit(0)}}};process.on("SIGINT",()=>{G()}),process.on("SIGTERM",()=>{G()})}),t.command("workbuddy-session-hook",{hidden:!0}).description("(internal) Receive a trusted WorkBuddy plugin lifecycle event").action(async()=>{await Xe()}),t.command("room-session-hook",{hidden:!0}).description("(internal) Authorize the official Room tool for one trusted Agent Session").argument("<runtime>","Trusted runtime adapter").action(async o=>{o!=="codex"&&o!=="claude_code"&&o!=="workbuddy"||await Ye(o)}),t.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").action(async()=>{await ro()});const te=t.command("config").description("View or modify configuration");te.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${ce()}`);const n={...a()};if(n.machineToken&&(n.machineToken=n.machineToken.slice(0,12)+"..."),n.serverUrl){const r=De(n.serverUrl);console.log(`Region: ${r} (${O[r].label})`)}console.log(JSON.stringify(n,null,2))}),te.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((o,n)=>{const r=a();if(o==="server"){n!=="cn"&&n!=="global"&&(console.error(I.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const c=n;r.serverUrl=Ae(c),J(r),console.log(I.green(`\u2713 Server set to ${O[c].label}`)),console.log(I.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(I.red(`\u2717 Unknown config key: ${o}. Supported: server`)),process.exit(1)}),pe(t),Ie(t),Se(t),we(t),ye(t),Re(t),t.parse();
|
|
@@ -16,6 +16,7 @@ export declare class NativeSessionFusionService {
|
|
|
16
16
|
canonicalMessageId?: string | null;
|
|
17
17
|
sourceSessionKey?: string | null;
|
|
18
18
|
text: string;
|
|
19
|
+
managedEchoPolicy?: 'suppress_following' | 'import_following';
|
|
19
20
|
}): void;
|
|
20
21
|
noteManagedSourceSession(sessionId: string, agentType: string, sourceSessionKey: string | null): void;
|
|
21
22
|
private pruneState;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`).trim()}function
|
|
1
|
+
import{randomUUID as S}from"node:crypto";import w from"node:fs";import{listClaudeTranscriptFiles as M,listCodexRolloutFiles as C,listOpenCodeSessionFiles as A,parseClaudeTranscriptChunk as T,parseCodexRolloutChunk as x,parseOpenCodeSessionFile as _}from"./parsers.js";import{loadNativeScannerState as I,saveNativeScannerState as P}from"./state.js";const h=6e4,m=h*2,E=30*6e4,g=20;function y(c){return c.replace(/\r\n/g,`
|
|
2
|
+
`).trim()}function N(c){return c.split(/[\\/]+/).includes(".codex")}class F{client;timer=null;scanPromise=null;pendingClaims=new Map;suppressionWindows=new Map;constructor(e){this.client=e}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},h))}stop(){this.timer&&clearInterval(this.timer),this.timer=null}handleConnected(){this.start(),this.scanNow().catch(e=>{console.error("[native-fusion] initial scan failed",e)})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;s!=="codex"&&s!=="claude"&&s!=="opencode"||this.pendingClaims.set(e.sessionId,{sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,text:y(e.text),createdAt:Date.now(),expiresAt:Date.now()+m,sourceSessionKey:e.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following"})}noteManagedSourceSession(e,s,n){if(!n)return;const t=this.pendingClaims.get(e);t&&t.sourceAgentType===s&&(t.sourceSessionKey=n)}pruneState(){const e=Date.now();for(const[s,n]of this.pendingClaims.entries())n.expiresAt<=e&&this.pendingClaims.delete(s);for(const[s,n]of this.suppressionWindows.entries())n.endsAt<=e&&this.suppressionWindows.delete(s)}async scanNow(){if(this.client.getState()==="connected")return this.scanPromise?this.scanPromise:(this.scanPromise=this.runScan().finally(()=>{this.scanPromise=null}),this.scanPromise)}async runScan(){this.pruneState();const e=I(),s={...e.files},n=[],t=[...C(),...M(),...A()];for(const i of t){const o=w.statSync(i),r=e.files[i];if(!r){s[i]={offset:o.size,mtimeMs:o.mtimeMs};continue}const d=N(i),a=i.endsWith(".opencode-session.json"),l=a&&r?.mtimeMs!==o.mtimeMs?r.offset:r?.offset??0,f=a?_(i,l):d?x(i,l):T(i,l);s[i]={offset:f.nextOffset,mtimeMs:o.mtimeMs};for(const u of f.events){const p=this.tryClaimManagedEcho(u);if(p){n.push(p);continue}this.isSuppressed(u)||n.push(u)}}for(let i=0;i<n.length;i+=g){const o=n.slice(i,i+g);if(o.length===0)continue;const r=o.map(({repairHint:d,...a})=>a);await this.client.sendBufferedEvent({type:"event",event:"native.session.events",id:`native-fusion-${S()}`,payload:{events:r}},6e4)}e.files=s,P(e)}tryClaimManagedEcho(e){const s=Date.now();for(const[n,t]of this.pendingClaims.entries())if(t.sourceAgentType===e.agentType&&!(t.expiresAt<=s)&&e.role==="user"&&t.sourceSessionKey&&t.sourceSessionKey===e.sourceSessionKey&&!(Math.abs(e.ts-t.createdAt)>m)&&y(e.payload)===t.text)return this.pendingClaims.delete(n),t.managedEchoPolicy==="suppress_following"&&this.suppressionWindows.set(`${e.agentType}:${e.sourceSessionKey}`,{sessionId:n,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+E}),{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:t.canonicalMessageId,managedEchoPolicy:t.managedEchoPolicy};return null}isSuppressed(e){const s=`${e.agentType}:${e.sourceSessionKey}`,n=this.suppressionWindows.get(s);return!n||e.ts<n.startedAt?!1:e.ts>n.endsAt?(this.suppressionWindows.delete(s),!1):e.role==="user"?(this.suppressionWindows.delete(s),!1):!0}}export{F as NativeSessionFusionService};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentType } from '@shennian/wire';
|
|
2
2
|
import type { HttpRoomBindingClient } from './room-binding-client.js';
|
|
3
|
+
import type { RoomHostSessionObservationStore } from './host-session-observations.js';
|
|
3
4
|
import type { RoomSessionRegistry } from './session-registry.js';
|
|
4
5
|
export type ManagedRoomBindInput = {
|
|
5
6
|
roomId: string;
|
|
@@ -28,6 +29,7 @@ export declare class TrustedManagedRoomBinder implements ManagedRoomBinder {
|
|
|
28
29
|
private readonly deps;
|
|
29
30
|
constructor(deps: {
|
|
30
31
|
registry: RoomSessionRegistry;
|
|
32
|
+
observations: RoomHostSessionObservationStore;
|
|
31
33
|
bindingClient: Pick<HttpRoomBindingClient, 'create'>;
|
|
32
34
|
getMachineCredentials: () => {
|
|
33
35
|
machineId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
import c from"node:crypto";class h{deps;constructor(e){this.deps=e}async bind(e){const{machineId:i,machineToken:o}=this.deps.getMachineCredentials();if(!i||!o)throw new Error("Machine is not paired with Shennian.");const s=g(e.agentType),d=this.deps.hostProcessIdentity(),r=this.deps.registry.register({machineId:i,runtimeAdapter:s,sourceSessionKey:e.agentSessionId,nianSessionId:e.nianSessionId,hostProcessIdentity:d,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:!0,canActivateWhileHostOpen:!0}});this.deps.observations.observe({machineId:i,runtimeAdapter:s,sourceSessionKey:e.agentSessionId,hostContextHash:a(d),workspaceHash:a(e.workDir),workspacePath:e.workDir,lifecycleState:"active",eventName:"ManagedBind"});const t=await this.deps.bindingClient.create({machineToken:o,bindingIntentId:e.assignmentIntentId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:s,sessionRegistryKey:r.registryKey,activationCapability:"managed",activationMode:"auto_follow"});return this.deps.registry.setBinding({registryKey:r.registryKey,bindingId:t.binding.id,roomId:t.binding.roomId,agentIdentityId:t.binding.agentIdentityId,agentMembershipId:t.binding.agentMembershipId,status:t.binding.status,activationMode:t.binding.activationMode}),t}}function a(n){return c.createHash("sha256").update(n,"utf8").digest("hex")}function g(n){if(n==="codex")return"codex";if(n==="claude")return"claude_code";if(n==="workbuddy"||n==="custom:workbuddy")return"workbuddy";throw new Error(`Agent ${n} does not support managed Room binding.`)}export{h as TrustedManagedRoomBinder};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function Z(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const ee=3e4;function te(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ne(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function N(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function v(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:null}}})}function ae(t,e){z({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function we(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function Ae(t){return!!(t?.configured??t?.connected)}function B(t){return K(t)}function L(t,e,a){return{}}function re(t,e,a,s,o){t.configure?.({sessionId:e,externalChannel:s??null,env:{...B(a),...L(e,s,o)}})}function Te(t,e,a){return null}function se(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?J(a)??e:e}function oe(t,e,a,s){let o=null;function u(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:Z(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function d(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function i(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function m(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},ee),n.heartbeatTimer.unref?.())}function I(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(u({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),T=te(n),E=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,E||(r.currentRunId=n.runId),!E&&T&&(r.currentRunPhase=T,m(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&w({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:U(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const y=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(y,(t.runTextAcc.get(y)??"")+n.text),n.agentSessionId&&n.agentSessionId!==o&&(o=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,N(a,n.source),n.agentSessionId),r&&z({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const f=n.text??"";if(!f)return;const R=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==R)&&I(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:R}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=f,r.pendingTextEvent.seq=n.seq);return}let x={};if(n.state==="final"){I(r);const f=t.runTextAcc.get(y)??"";f&&(x={messageSummary:X(f)}),t.runTextAcc.delete(y)}else n.state==="error"||n.state==="aborted"?(I(r),t.runTextAcc.delete(y)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&I(r);E&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,d(r),t.chatQueue?.noteTerminal(e)),u(n,x)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function le(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function D(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function W(t,e,a,s,o,u){return u?.trim()?t.send(e,a,s,o,u):o?.length?t.send(e,a,s,o):s?t.send(e,a,s):t.send(e,a)}async function de(t,e,a,s,o,u,d){t.evictIdleSessions();const i=H(a);if(!i)throw new Error(`Unsupported agent: ${a}`);re(i,e,a,u,d),await i.start(e,s,o);const m={adapter:i,workDir:s,agentType:a,agentSessionId:o??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:u??null,externalReplyTarget:d??null,externalChannelEnv:{...B(a),...L(e,u,d)}};return t.sessions.set(e,m),oe(t,e,a,i),m}function ie(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),t.chatQueue?.noteTerminal(e)}async function Ee(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}le(t,e.id);const{sessionId:a,text:s,agentType:o,workDir:u,agentSessionId:d,modelId:i,systemPrompt:m,managerDefaultWorkerAgentType:I,managerDefaultWorkerModelId:n,reasoningEffort:r,clientMessageId:T,sessionListProjection:E,waitForDispatch:y,responseId:x}=e.params,f=x||e.id;Q(E);const R=null,O="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:"sessionId and text are required"});return}const g=o;g==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,I??null,n??null);const k=(g==="claude"||g==="codex"||g==="workbuddy")&&typeof r=="string"&&r.trim()?r.trim():void 0,S=t.resolvePath(se(g,u||_.homedir(),d)||_.homedir()),$=S,q=Y(e.params.attachments),p=q?.length?await V({text:s,attachments:q,workDir:S}):{text:s,attachments:q,localized:!1};let l=t.sessions.get(a);if(l){if(l.lastActiveAt=Date.now(),l.agentType!==g||l.workDir!==S||JSON.stringify(l.externalChannel??null)!==JSON.stringify(R??null)){t.sessions.delete(a);try{await D(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}else if(d&&l.agentSessionId!==d)try{await l.adapter.resume(d),l.agentSessionId=d}catch{t.sessions.delete(a);try{await D(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}}if(!l)try{l=await de(t,a,g,S,d,R,O)}catch(c){const h=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${o}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${S} agentSessionId=${d??""}: ${h}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:h,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:h});return}const P={id:T??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(p.text,p.attachments)};w({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:g,modelId:i,reasoningEffort:k}});const M=()=>{ae(t,{sessionId:a,agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:i}),l.currentRunId||(l.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:g,sourceAgentType:N(g,i),canonicalMessageId:T??null,sourceSessionKey:l.agentSessionId??d??null,text:p.text}),A(a,P),v(t,P,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:i})},C=async(c,h)=>{const b=ne(g,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${S} agentSessionId=${l.agentSessionId??d??""}: ${b}`),t.sessions.delete(a);try{await D(l)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:b,runId:"",seq:0}}),!h){const F={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:b};A(a,F),v(t,F,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:i})}h&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:b}))};if(y){let c;try{const h=p.attachments;c=await W(l.adapter,p.text,i,k,h,m),w({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(h){await C(h,!0);return}M(),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized||c?.deliveryMode==="external_owner_queue"?{payload:{...p.localized?{localizedAttachments:!0}:{},...c?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:c.deliveryMode,queuedSubmissionId:c.queuedSubmissionId}:{}}}:{}}),w({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}M(),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),w({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const j=p.attachments;W(l.adapter,p.text,i,k,j,m).then(()=>{w({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{C(c,!1)})}async function Re(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}ie(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{Re as handleChatAbort,Ee as handleChatSend};
|
|
1
|
+
import F from"node:os";import{createAgent as H}from"../../agents/adapter.js";import{buildApprovalPendingPayload as U,buildUserMessagePayload as G}from"@shennian/wire";import{reportLog as S}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as J}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as v}from"../store.js";import{mergeProjectedSessions as Q}from"../projection.js";import{buildManagedAgentEnv as K}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as V}from"../remote-attachments.js";function Y(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,o=typeof s.path=="string"?s.path:"",u=typeof s.name=="string"?s.name:"",d=typeof s.mimeType=="string"?s.mimeType:"";if(!o||!u||!d)return null;const c=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:o,name:u,mimeType:d,kind:d.startsWith("image/")?"image":"file",...c?{previewData:c}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function X(t){const e=t.indexOf(`
|
|
2
|
+
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function Z(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const ee=3e4;function te(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ne(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function z(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function N(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:null}}})}function ae(t,e){v({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function Se(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function Ae(t){return!!(t?.configured??t?.connected)}function B(t){return K(t)}function L(t,e,a){return{}}function re(t,e,a,s,o){t.configure?.({sessionId:e,externalChannel:s??null,env:{...B(a),...L(e,s,o)}})}function Ee(t,e,a){return null}function se(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?J(a)??e:e}function oe(t,e,a,s){let o=null;function u(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:Z(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function d(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function c(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function m(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{c(n)},ee),n.heartbeatTimer.unref?.())}function I(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(u({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),E=te(n),T=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,T||(r.currentRunId=n.runId),!T&&E&&(r.currentRunPhase=E,m(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&S({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:U(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const y=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(y,(t.runTextAcc.get(y)??"")+n.text),n.agentSessionId&&n.agentSessionId!==o&&(o=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,z(a,n.source),n.agentSessionId),r&&v({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const f=n.text??"";if(!f)return;const x=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==x)&&I(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:x}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=f,r.pendingTextEvent.seq=n.seq);return}let R={};if(n.state==="final"){I(r);const f=t.runTextAcc.get(y)??"";f&&(R={messageSummary:X(f)}),t.runTextAcc.delete(y)}else n.state==="error"||n.state==="aborted"?(I(r),t.runTextAcc.delete(y)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&I(r);T&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,d(r),t.chatQueue?.noteTerminal(e)),u(n,R)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function le(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function D(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function W(t,e,a,s,o,u){return u?.trim()?t.send(e,a,s,o,u):o?.length?t.send(e,a,s,o):s?t.send(e,a,s):t.send(e,a)}async function de(t,e,a,s,o,u,d){t.evictIdleSessions();const c=H(a);if(!c)throw new Error(`Unsupported agent: ${a}`);re(c,e,a,u,d),await c.start(e,s,o);const m={adapter:c,workDir:s,agentType:a,agentSessionId:o??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:u??null,externalReplyTarget:d??null,externalChannelEnv:{...B(a),...L(e,u,d)}};return t.sessions.set(e,m),oe(t,e,a,c),m}function ie(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),t.chatQueue?.noteTerminal(e)}async function Te(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}le(t,e.id);const{sessionId:a,text:s,agentType:o,workDir:u,agentSessionId:d,modelId:c,systemPrompt:m,managerDefaultWorkerAgentType:I,managerDefaultWorkerModelId:n,reasoningEffort:r,clientMessageId:E,sessionListProjection:T,waitForDispatch:y,responseId:R}=e.params,f=R||e.id;Q(T);const x=null,O="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:"sessionId and text are required"});return}const g=o;g==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,I??null,n??null);const k=(g==="claude"||g==="codex"||g==="workbuddy")&&typeof r=="string"&&r.trim()?r.trim():void 0,w=t.resolvePath(se(g,u||F.homedir(),d)||F.homedir()),$=w,q=Y(e.params.attachments),p=q?.length?await V({text:s,attachments:q,workDir:w}):{text:s,attachments:q,localized:!1};let l=t.sessions.get(a);if(l){if(l.lastActiveAt=Date.now(),l.agentType!==g||l.workDir!==w||JSON.stringify(l.externalChannel??null)!==JSON.stringify(x??null)){t.sessions.delete(a);try{await D(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}else if(d&&l.agentSessionId!==d)try{await l.adapter.resume(d),l.agentSessionId=d}catch{t.sessions.delete(a);try{await D(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}}if(!l)try{l=await de(t,a,g,w,d,x,O)}catch(i){const h=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${o}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${w} agentSessionId=${d??""}: ${h}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:h,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:h});return}const P={id:E??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(p.text,p.attachments)};S({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:g,modelId:c,reasoningEffort:k}});const M=i=>{ae(t,{sessionId:a,agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:c}),l.currentRunId||(l.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:g,sourceAgentType:z(g,c),canonicalMessageId:E??null,sourceSessionKey:l.agentSessionId??d??null,text:p.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"?"import_following":"suppress_following"}),A(a,P),N(t,P,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:c})},_=async(i,h)=>{const b=ne(g,i);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${w} agentSessionId=${l.agentSessionId??d??""}: ${b}`),t.sessions.delete(a);try{await D(l)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:b,runId:"",seq:0}}),!h){const C={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:b};A(a,C),N(t,C,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??d??null,modelId:c})}h&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:b}))};if(y){let i;try{const h=p.attachments;i=await W(l.adapter,p.text,c,k,h,m),S({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(h){await _(h,!0);return}M(i??void 0),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized||i?.deliveryMode==="external_owner_queue"?{payload:{...p.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}:{}}),S({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}M(),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),S({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const j=p.attachments;W(l.adapter,p.text,c,k,j,m).then(()=>{S({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(i=>{_(i,!1)})}async function xe(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}ie(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{xe as handleChatAbort,Te as handleChatSend};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import i from"node:fs";import p from"node:path";import{execSync as
|
|
1
|
+
import i from"node:fs";import p from"node:path";import{execSync as F,execFile as D}from"node:child_process";import{promisify as O}from"node:util";import{fileURLToPath as L}from"node:url";import{getShennianDir as $,resolveShennianPath as d}from"../config/index.js";const f=O(D),m=d("upgrade-attempt.json"),J=3,I="https://registry.npmjs.org",H=10*6e4,U=[5*6e4,30*6e4,120*6e4,360*6e4];function y(){try{const r=B();if(r)return JSON.parse(i.readFileSync(r,"utf-8")).version}catch{}return"0.0.0"}function B(r=L(import.meta.url)){let e=p.dirname(r);for(let n=0;n<6;n++){const t=p.join(e,"package.json");if(i.existsSync(t)&&JSON.parse(i.readFileSync(t,"utf-8")).name==="shennian")return t;e=p.dirname(e)}return null}async function G(){const r=await fetch("https://registry.npmjs.org/shennian/latest",{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!r.ok)throw new Error(`npm registry returned ${r.status}`);return(await r.json()).version}function P(r,e){const n=u=>u.replace(/^v/,"").split(".").map(Number),[t,s,o]=n(r),[a,l,c]=n(e);return a>t?"major":a===t&&l>s?"minor":a===t&&l===s&&c>o?"patch":"none"}function Y(){return F("npm root -g",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim()}function z(){const r=Y();return p.join(r,"shennian","dist","bin","shennian.js")}function K(){try{return JSON.parse(i.readFileSync(m,"utf-8"))}catch{return null}}function g(r){i.mkdirSync($(),{recursive:!0}),i.writeFileSync(m,JSON.stringify(r,null,2))}function h(){try{i.unlinkSync(m)}catch{}}function _(){return d("upgrade-failures.json")}function X(){return d("upgrade.lock")}function N(r=X(),e={}){const n=e.now??Date.now(),t=e.pid??process.pid,s=e.isProcessAlive??(c=>{try{return process.kill(c,0),!0}catch{return!1}});i.mkdirSync(p.dirname(r),{recursive:!0});const o=()=>i.openSync(r,"wx",384);let a;try{a=o()}catch(c){if(c.code!=="EEXIST")throw c;let u=!1;try{const v=JSON.parse(i.readFileSync(r,"utf-8")),E=Number(v.pid),b=Number(v.createdAt);u=!Number.isInteger(E)||!Number.isFinite(b)||n-b>H||!s(E)}catch{u=!0}if(!u)throw new Error("Another Shennian upgrade is already running");i.rmSync(r,{force:!0}),a=o()}i.writeFileSync(a,JSON.stringify({pid:t,createdAt:n})),i.closeSync(a);let l=!1;return{release(){if(!l){l=!0;try{i.unlinkSync(r)}catch{}}}}}function k(r=_()){try{const e=JSON.parse(i.readFileSync(r,"utf-8"));return!e||typeof e!="object"||!e.versions?{versions:{}}:{versions:e.versions}}catch{return{versions:{}}}}function R(r){i.mkdirSync($(),{recursive:!0}),i.writeFileSync(_(),JSON.stringify(r,null,2))}function Z(r){return U[Math.min(Math.max(r-1,0),U.length-1)]}function nr(r,e=Date.now(),n=k()){const t=n.versions[r];return!!(t&&t.nextRetryAt>e)}function or(r,e,n=Date.now()){const t=k(),s=t.versions[r],o=(s?.failureCount??0)+1,a={version:r,failureCount:o,firstFailedAt:s?.firstFailedAt??n,lastFailedAt:n,nextRetryAt:n+Z(o),error:e};return t.versions[r]=a,R(t),a}function w(r){const e=k();e.versions[r]&&(delete e.versions[r],R(e))}async function ar(){const r=K();if(!r)return!1;if(Date.now()-r.attemptAt>600*1e3)return h(),!1;if(r.attemptCount++,r.attemptCount>=J){console.error(`[upgrade] New version crashed ${r.attemptCount} times, rolling back to ${r.from}...`);let n;try{n=N()}catch(t){return console.error(`[upgrade] Rollback deferred: ${t instanceof Error?t.message:String(t)}`),!1}try{return await M(r.from),h(),console.error(`[upgrade] Rolled back to ${r.from}. Restarting...`),!0}catch(t){return console.error(`[upgrade] Rollback failed: ${t instanceof Error?t.message:String(t)}`),h(),!1}finally{n.release()}}return g(r),!1}async function ir(r,e,n={}){let t;try{t=N()}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}try{return await q(r,e,n)}finally{t.release()}}async function q(r,e,n={}){const t=n.currentVersion??y(),s=y();if(t===r)return w(r),{ok:!1,error:`Already on version ${r}`};e({step:"checking"});try{F("npm --version",{stdio:"pipe",windowsHide:!0})}catch{return{ok:!1,error:"npm is not available in PATH"}}if(s===r){e({step:"verifying",version:r});try{await A(r)}catch(o){return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}`}}return g({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),w(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}e({step:"backing-up"}),e({step:"installing",version:r});try{await j(r)}catch(o){const a=await T(t);return{ok:!1,error:`npm install failed: ${o instanceof Error?o.message:String(o)}${a.ok?"":`; rollback failed: ${a.error}`}`,rolledBack:a.ok}}e({step:"verifying",version:r});try{await A(r)}catch(o){const a=await T(t);return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}${a.ok?"":`; rollback failed: ${a.error}`}`,rolledBack:a.ok}}return g({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),w(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}function C(r){if(!/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(r))throw new Error(`Invalid npm version: ${r}`)}function S(){return process.platform==="win32"?"npm.cmd":"npm"}function x(r){return{timeout:r,windowsHide:!0,shell:process.platform==="win32"}}async function j(r){C(r);try{await f(S(),["install","-g",`shennian@${r}`],x(12e4))}catch(e){const n=e instanceof Error?e.message:String(e);try{await f(S(),["install","-g",`shennian@${r}`,"--registry",I],{...x(12e4)})}catch(t){const s=t instanceof Error?t.message:String(t);throw new Error(`${n}
|
|
2
2
|
--- npmjs fallback ---
|
|
3
|
-
${s}`)}}}async function
|
|
3
|
+
${s}`)}}}async function A(r){C(r);const e=z(),{stdout:n}=await f(process.execPath,[e,"--version"],{timeout:1e4,windowsHide:!0});if(n.trim()!==r)throw new Error(`Version verification failed: expected ${r}, got ${n.trim()||"empty output"}`);await f(S(),["ls","-g",`shennian@${r}`,"--omit=dev","--depth=0"],{...x(3e4)})}async function M(r,e={}){await(e.install??j)(r),await(e.verify??A)(r)}async function T(r){try{return await M(r),{ok:!0}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function sr(r){const e=r??y(),n=await G(),t=P(e,n);return t==="none"?{hasUpdate:!1}:{hasUpdate:!0,current:e,latest:n,changeType:t}}export{N as acquireUpgradeLock,sr as checkForUpdate,h as clearUpgradeAttempt,w as clearUpgradeFailure,P as compareVersions,G as fetchLatestVersion,B as findPackageJson,y as getCurrentVersion,Z as getUpgradeRetryDelayMs,ar as handleStartupCrashCheck,j as installShennianVersion,nr as isUpgradeVersionInCooldown,ir as performUpgrade,K as readUpgradeAttempt,k as readUpgradeFailures,or as recordUpgradeFailure,M as rollbackToExactVersion,A as verifyInstalledVersion,g as writeUpgradeAttempt};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { AgentType } from './session.ts';
|
|
2
|
+
import type { RoomActivationMode } from './room.ts';
|
|
2
3
|
export type AgentWorkspaceRoomLink = {
|
|
3
4
|
bindingId: string;
|
|
4
5
|
status: string;
|
|
5
6
|
roomId: string;
|
|
6
7
|
roomName: string;
|
|
8
|
+
activationMode: RoomActivationMode;
|
|
7
9
|
};
|
|
8
10
|
export type AgentWorkspaceSession = {
|
|
9
11
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-workspace.d.ts","sourceRoot":"","sources":["../src/agent-workspace.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"agent-workspace.d.ts","sourceRoot":"","sources":["../src/agent-workspace.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAEnD,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,kBAAkB,CAAA;CACnC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;KAClB,GAAG,IAAI,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,cAAc,EAAE,SAAS,GAAG,IAAI,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAClC,CAAA"}
|
|
@@ -12,6 +12,7 @@ export type NativeSessionEventPayload = {
|
|
|
12
12
|
modelId?: string | null;
|
|
13
13
|
workDir?: string;
|
|
14
14
|
claimCanonicalMessageId?: string | null;
|
|
15
|
+
managedEchoPolicy?: 'suppress_following' | 'import_following';
|
|
15
16
|
terminal?: boolean;
|
|
16
17
|
};
|
|
17
18
|
export type NativeSessionImportBatch = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-session.d.ts","sourceRoot":"","sources":["../src/native-session.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,sBAAsB,GACtB,0BAA0B,GAC1B,yBAAyB,GACzB,oBAAoB,CAAA;AAExB,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC1C,UAAU,EAAE,uBAAuB,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,yBAAyB,EAAE,CAAA;CACpC,CAAA"}
|
|
1
|
+
{"version":3,"file":"native-session.d.ts","sourceRoot":"","sources":["../src/native-session.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,sBAAsB,GACtB,0BAA0B,GAC1B,yBAAyB,GACzB,oBAAoB,CAAA;AAExB,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC1C,UAAU,EAAE,uBAAuB,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,kBAAkB,CAAA;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,yBAAyB,EAAE,CAAA;CACpC,CAAA"}
|