shennian 0.5.37 → 0.5.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 298,
5
+ "fileCount": 303,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian-adapter-host.js",
@@ -569,6 +569,11 @@
569
569
  "beforeBytes": 1711,
570
570
  "afterBytes": 1157
571
571
  },
572
+ {
573
+ "file": "src/commands/recordings.js",
574
+ "beforeBytes": 900,
575
+ "afterBytes": 646
576
+ },
572
577
  {
573
578
  "file": "src/commands/room.js",
574
579
  "beforeBytes": 27719,
@@ -596,8 +601,8 @@
596
601
  },
597
602
  {
598
603
  "file": "src/commands/steward.js",
599
- "beforeBytes": 4750,
600
- "afterBytes": 2727
604
+ "beforeBytes": 6094,
605
+ "afterBytes": 3708
601
606
  },
602
607
  {
603
608
  "file": "src/commands/support.js",
@@ -706,8 +711,8 @@
706
711
  },
707
712
  {
708
713
  "file": "src/index.js",
709
- "beforeBytes": 46127,
710
- "afterBytes": 22372
714
+ "beforeBytes": 46231,
715
+ "afterBytes": 22447
711
716
  },
712
717
  {
713
718
  "file": "src/local-apps/service.js",
@@ -884,6 +889,11 @@
884
889
  "beforeBytes": 910,
885
890
  "afterBytes": 479
886
891
  },
892
+ {
893
+ "file": "src/personal-workspace/recordings.js",
894
+ "beforeBytes": 11686,
895
+ "afterBytes": 6520
896
+ },
887
897
  {
888
898
  "file": "src/personal-workspace/service.js",
889
899
  "beforeBytes": 6845,
@@ -1199,11 +1209,21 @@
1199
1209
  "beforeBytes": 676,
1200
1210
  "afterBytes": 392
1201
1211
  },
1212
+ {
1213
+ "file": "src/session/handlers/personal-recording.js",
1214
+ "beforeBytes": 522,
1215
+ "afterBytes": 362
1216
+ },
1202
1217
  {
1203
1218
  "file": "src/session/handlers/personal-workspace.js",
1204
1219
  "beforeBytes": 519,
1205
1220
  "afterBytes": 366
1206
1221
  },
1222
+ {
1223
+ "file": "src/session/handlers/personal.js",
1224
+ "beforeBytes": 582,
1225
+ "afterBytes": 332
1226
+ },
1207
1227
  {
1208
1228
  "file": "src/session/handlers/project-fs.js",
1209
1229
  "beforeBytes": 3778,
@@ -1261,8 +1281,8 @@
1261
1281
  },
1262
1282
  {
1263
1283
  "file": "src/session/manager.js",
1264
- "beforeBytes": 42660,
1265
- "afterBytes": 22450
1284
+ "beforeBytes": 42545,
1285
+ "afterBytes": 22383
1266
1286
  },
1267
1287
  {
1268
1288
  "file": "src/session/native-cleanup-outbox.js",
@@ -1396,8 +1416,8 @@
1396
1416
  },
1397
1417
  {
1398
1418
  "file": "src/steward/configure.js",
1399
- "beforeBytes": 1799,
1400
- "afterBytes": 1027
1419
+ "beforeBytes": 1912,
1420
+ "afterBytes": 1094
1401
1421
  },
1402
1422
  {
1403
1423
  "file": "src/steward/failover.js",
@@ -1409,6 +1429,11 @@
1409
1429
  "beforeBytes": 3176,
1410
1430
  "afterBytes": 5735
1411
1431
  },
1432
+ {
1433
+ "file": "src/steward/primary-machine.js",
1434
+ "beforeBytes": 1085,
1435
+ "afterBytes": 669
1436
+ },
1412
1437
  {
1413
1438
  "file": "src/steward/session.js",
1414
1439
  "beforeBytes": 3433,
@@ -0,0 +1,3 @@
1
+ import{configureRecordingDirectory as o,recordingDirectory as t}from"../personal-workspace/recordings.js";function c(e){e.command("recordings").description("Configure private original-audio storage on this Client").command("directory [absolute-path]").description("Show or configure the receiving directory (restart Client after changing it)").action(r=>{try{const i=r?o(r):t();process.stdout.write(`${JSON.stringify({ok:!0,directory:i,restartRequired:!!r,previousFilesNotMigrated:!!r})}
2
+ `)}catch{process.stdout.write(`${JSON.stringify({ok:!1,error:"recording_directory_invalid"})}
3
+ `),process.exitCode=1}})}export{c as registerRecordingCommand};
@@ -1,6 +1,8 @@
1
- import m from"node:fs";import{configurePersonalPaths as y}from"../steward/configure.js";import{readPersonalPaths as h}from"../steward/settings.js";import{getStewardDir as p}from"../steward/workspace.js";import{callDaemonIpc as g}from"../daemon-ipc/client.js";import{DaemonIpcError as i}from"../daemon-ipc/protocol.js";import{STEWARD_SAY_MAX_CHARS as f,STEWARD_SESSION_ID_ENV as S}from"../steward/session.js";const _={write:o=>process.stdout.write(o),fail:()=>{process.exitCode=1}};function O(o,e={}){const r=e.io??_,l=e.callDaemon??g,t=e.env??process.env,u=e.readStdin??(()=>m.readFileSync(0,"utf8")),d=o.command("steward").description("Talk to the user as the Shennian steward");d.command("paths").description("Show Personal Agent and diary directories (no credentials)").action(()=>{r.write(`${JSON.stringify({ok:!0,workspace:p(),diary:h().diary??null})}
2
- `)}),d.command("configure").description("Set local Personal Agent / diary directories; restart Client after changing workspace").option("--workspace <directory>","Absolute Personal Agent directory").option("--diary <directory>","Absolute diary directory").action(c=>{try{r.write(`${JSON.stringify({ok:!0,...y(c),restartRequired:!0})}
3
- `)}catch{r.write(`${JSON.stringify({ok:!1,error:"personal_configuration_failed",message:"Use absolute, non-symlink directories separate from Client credentials."})}
4
- `),r.fail()}}),d.command("say [text]").description("Send a message the user will see on their phone; in a steward session everything else you output stays hidden from them").option("--file <path>","Read the message from a file").option("--stdin","Read the message from standard input").action(async(c,w)=>{try{const n=t[S]?.trim(),a=k(c,w,u),s=await l({method:"steward.say",params:n?{sessionId:n,text:a}:{text:a}});r.write(`${JSON.stringify({ok:!0,command:"steward.say",result:s})}
5
- `)}catch(n){const a=n instanceof i,s=!a&&n?.code==="ENOENT";r.write(`${JSON.stringify({ok:!1,error:a?n.code:s?"daemon_unavailable":"steward_command_failed",message:a?n.message:s?"Shennian is not running on this computer.":"Shennian steward command failed.",nextAction:null})}
6
- `),r.fail()}})}function k(o,e,r){if([o!==void 0,e.file!==void 0,e.stdin===!0].filter(Boolean).length!==1)throw new i("steward_say_invalid","Provide exactly one of: text, --file, --stdin.");let t;if(e.file!==void 0)try{t=m.readFileSync(e.file,"utf8")}catch{throw new i("steward_say_invalid","The message file could not be read.")}else if(e.stdin)try{t=r()}catch{throw new i("steward_say_invalid","Standard input could not be read.")}else t=o??"";if(t=t.trim(),!t||t.length>f)throw new i("steward_say_invalid",`Provide a non-empty message of at most ${f} characters.`);return t}export{O as registerStewardCommand};
1
+ import f from"node:fs";import{primaryMachineRequest as y}from"../steward/primary-machine.js";import{configurePersonalPaths as w}from"../steward/configure.js";import{readPersonalPaths as h}from"../steward/settings.js";import{getStewardDir as g}from"../steward/workspace.js";import{callDaemonIpc as S}from"../daemon-ipc/client.js";import{DaemonIpcError as d}from"../daemon-ipc/protocol.js";import{STEWARD_SAY_MAX_CHARS as p,STEWARD_SESSION_ID_ENV as _}from"../steward/session.js";const v={write:a=>process.stdout.write(a),fail:()=>{process.exitCode=1}};function P(a,r={}){const e=r.io??v,l=r.callDaemon??S,t=r.env??process.env,u=r.readStdin??(()=>f.readFileSync(0,"utf8")),c=a.command("steward").description("Talk to the user as the Shennian steward");c.command("primary").description("Read the account primary computer, or explicitly select this paired computer").option("--set-current","Select this paired computer as primary; never migrates files").option("--expected-revision <number>","Exact current primary-setting revision").option("--confirm","Confirm the primary computer selection").action(async i=>{try{const n=Number(i.expectedRevision);if(i.setCurrent&&(!i.confirm||i.expectedRevision===void 0||!Number.isSafeInteger(n)||n<0))throw new Error("personal_primary_confirmation_required");const o=await y(i.setCurrent?{expectedRevision:n,confirmed:!0}:void 0);e.write(`${JSON.stringify({ok:!0,...o})}
2
+ `)}catch(n){e.write(`${JSON.stringify({ok:!1,error:n instanceof Error&&/^personal_[a-z_]+$/.test(n.message)?n.message:"personal_primary_request_failed"})}
3
+ `),e.fail()}}),c.command("paths").description("Show Personal Agent and diary directories (no credentials)").action(()=>{e.write(`${JSON.stringify({ok:!0,workspace:g(),diary:h().diary??null})}
4
+ `)}),c.command("configure").description("Set local Personal Agent / diary directories; restart Client after changing workspace").option("--workspace <directory>","Absolute Personal Agent directory").option("--diary <directory>","Absolute diary directory").option("--clear-diary","Disconnect the diary directory without deleting any files").action(i=>{try{e.write(`${JSON.stringify({ok:!0,...w(i),restartRequired:!0})}
5
+ `)}catch{e.write(`${JSON.stringify({ok:!1,error:"personal_configuration_failed",message:"Use absolute, non-symlink directories separate from Client credentials."})}
6
+ `),e.fail()}}),c.command("say [text]").description("Send a message the user will see on their phone; in a steward session everything else you output stays hidden from them").option("--file <path>","Read the message from a file").option("--stdin","Read the message from standard input").action(async(i,n)=>{try{const o=t[_]?.trim(),s=k(i,n,u),m=await l({method:"steward.say",params:o?{sessionId:o,text:s}:{text:s}});e.write(`${JSON.stringify({ok:!0,command:"steward.say",result:m})}
7
+ `)}catch(o){const s=o instanceof d,m=!s&&o?.code==="ENOENT";e.write(`${JSON.stringify({ok:!1,error:s?o.code:m?"daemon_unavailable":"steward_command_failed",message:s?o.message:m?"Shennian is not running on this computer.":"Shennian steward command failed.",nextAction:null})}
8
+ `),e.fail()}})}function k(a,r,e){if([a!==void 0,r.file!==void 0,r.stdin===!0].filter(Boolean).length!==1)throw new d("steward_say_invalid","Provide exactly one of: text, --file, --stdin.");let t;if(r.file!==void 0)try{t=f.readFileSync(r.file,"utf8")}catch{throw new d("steward_say_invalid","The message file could not be read.")}else if(r.stdin)try{t=e()}catch{throw new d("steward_say_invalid","Standard input could not be read.")}else t=a??"";if(t=t.trim(),!t||t.length>p)throw new d("steward_say_invalid",`Provide a non-empty message of at most ${p} characters.`);return t}export{P as registerStewardCommand};
package/dist/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{registerConfigCommand as we}from"./commands/config.js";import{registerLocalAppsCommand as Ce}from"./commands/local-apps.js";import{registerScheduleCommand as ke}from"./commands/schedule.js";import{resolvePersonalScheduleContext as Re}from"./schedules/personal-context.js";import{isStewardSessionId as be}from"./steward/session.js";import{executeServerSchedule as ne,deliverServerSchedule as Ae}from"./schedules/server-client.js";import{Command as Pe}from"commander";import Ee from"chalk";import Te from"node:os";import{randomUUID as De}from"node:crypto";import z from"node:fs";import{loadConfig as m,getShennianDir as Me,resolveShennianPath as K,normalizeAutoUpgradePolicy as Ue}from"./config/index.js";import{CliRelayClient as _e}from"./relay/client.js";import{collectKnownLogSecrets as Ne,installCliLogRedaction as Oe}from"./log-redaction.js";import{registerPairCommand as xe,runSmartStart as $e}from"./commands/pair.js";import{registerLogoutCommand as Le}from"./commands/logout.js";import{clearDaemonPidIfOwner as re,createDaemonInstanceId as Ve,clearDaemonLauncher as ae,findRunningDaemonProcessIds as je,isRemoteAccessDisabled as ie,prepareRemoteAccessPause as Fe,stopPreparedRemoteAccessService as He,isIsolatedDaemonE2eInstance as Be,getDaemonStatus as se,registerDaemonCommand as We,writeDaemonPid as ce,writeDaemonLauncher as de}from"./commands/daemon.js";import{registerRuntimeCommand as Ge}from"./commands/runtime.js";import{registerAdapterCommand as qe}from"./commands/adapter.js";import{registerAgentCommand as ze}from"./commands/agent.js";import{registerManagerCommand as Ke}from"./commands/manager.js";import{registerWorkerCommand as Je}from"./commands/worker.js";import{registerProjectCommand as Qe}from"./commands/project.js";import{registerStewardCommand as Ye}from"./commands/steward.js";import{handleUpgradeStart as Ze,registerUpgradeCommand as Xe}from"./commands/upgrade.js";import{registerToolsCommand as et}from"./commands/tools.js";import{registerQueueCommand as tt}from"./commands/queue.js";import{registerSkillCommand as ot}from"./commands/skill.js";import{refreshExistingSkillForHosts as nt}from"./skill/hosts.js";import{registerSetupCommand as rt}from"./commands/setup.js";import{getUnavailableAcpAgents as at}from"./agents/acp/discovery.js";import{registerCommandReference as it}from"./commands/command-reference.js";import{registerIntegrationCommand as st}from"./commands/integration.js";import{registerRoomCommand as ct}from"./commands/room.js";import{registerContactCommand as dt}from"./commands/contact.js";import{registerSupportCommand as lt}from"./commands/support.js";import{SessionManager as mt}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as pt}from"./session/handlers/project-fs.js";import{SERVERS as ut}from"./region.js";import{clearUpgradeAttempt as gt,getCurrentVersion as le,handleStartupCrashCheck as ft,readUpgradeAttempt as ht}from"./upgrade/engine.js";import{AutoUpgradeScheduler as It}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as vt}from"./upgrade/updater-bootstrap.js";import{launchUpdater as St,markUpdaterHealthy as yt}from"./upgrade/updater-launcher.js";import{detectAgents as me}from"./agents/detect.js";import{PublicAgentDeliveryWorker as wt}from"./agents/public-delivery-worker.js";import{augmentProcessPath as pe}from"./env-path.js";import{acquireDaemonInstanceLock as Ct}from"./commands/daemon-instance-lock.js";pe();const T=le();import{getCachedAgentInfos as L,resolveAgentInfos as kt}from"./agents/model-registry.js";import{initCliLogReporter as Rt,reportLog as D,reportUpgradeAggregateMetric as bt}from"./log-reporter.js";import{isNativeFusionEnabled as At}from"./native-fusion/config.js";import{NativeSessionFusionService as Pt}from"./native-fusion/service.js";import{startDaemonLogRetention as Et}from"./daemon-log.js";import{startDaemonIpcServer as ue}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as Tt,resolveManagedRoomIpcPaths as Dt}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as Mt}from"./daemon-ipc/control.js";import{createAgentReadinessHandlers as Ut}from"./daemon-ipc/agent-readiness.js";import{scanMachineAgents as ge}from"./session/handlers/agents.js";import{validateAgentWorkspaceConfiguration as _t}from"./session/handlers/agent-workspace-validation.js";import{DAEMON_IPC_VERSION as Nt}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as Ot}from"./room/session-registry.js";import{HttpRoomBindingClient as xt}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as $t}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Lt}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Vt}from"./room/mirror-sync-service.js";import{handleLiveRoomDelivery as jt}from"./room/live-delivery.js";import{NativeSourceDeletionStore as Ft}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as Ht,isCurrentRegistration as Bt}from"./room/registration-authority.js";import{RoomActivationService as Wt,resolveManagedAgentPolicy as Gt}from"./room/activation-service.js";import{prepareStandaloneAgentTurn as qt}from"./room/standalone-agent-turn.js";import{RoomActivationAudit as zt}from"./room/activation-audit.js";import{RoomAttachmentCache as Kt}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Jt}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as Qt}from"./room/managed-context.js";import{createManagedRoomExecutor as Yt}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as fe,SESSION_SYNC_ADVERTISED_CAPABILITIES as he}from"@shennian/wire";import{getDaemonInstallationId as Zt}from"./session/store.js";import{OWNER_DIRECT_TURN_OPTIONS as Xt}from"./session/queue-helpers.js";import{synchronizeMachinePersonalAuthority as eo}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as Ie,ensurePersonalDataEpoch as to}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as oo,DeletionSyncTerminalError as no}from"./session/deletion-sync-state.js";const ve=Me(),ro=K("daemon.pid"),ao=K("daemon.instance.lock");function io(){try{const i=z.readFileSync(ro,"utf-8").trim();if(i.startsWith("{")){const v=JSON.parse(i),l=Number(v.pid);return Number.isInteger(l)&&l>0?l:null}const u=parseInt(i,10);return Number.isInteger(u)&&u>0?u:null}catch{return null}}function so(i){return i.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function J(){process.stdout.write(`${JSON.stringify({ok:!1,error:"integration_command_retired",message:"Room MCP and Hooks were retired. Use the Shennian Skill and CLI.",nextAction:{type:"open_install_guide",url:"https://shennian.net/install.md"}})}
2
- `),process.exitCode=1}function co(i){const u=[`trigger=${i.trigger??"unknown"}`,`phase=${i.phase}`,`code=${i.code??"unknown"}`,`attempt=${i.reconnectAttempt}`];return i.reason&&u.push(`reason=${i.reason}`),i.error&&u.push(`error=${i.error}`),u.join(" ")}const a=new Pe;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(T),a.enablePositionalOptions(),st(a),ct(a),dt(a),lt(a),ke(a),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",Te.hostname()).action(async i=>{const u=m(),v=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??u.serverUrl??void 0;await $e(v,i.name)}),a.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async i=>{const u=K("env.json");try{const e=JSON.parse(z.readFileSync(u,"utf-8"));for(const[o,t]of Object.entries(e))process.env[o]||(process.env[o]=t);pe()}catch{}Oe(Ne(process.env,m()));const v=Et();ie()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(v),process.exit(0));const l=Ve(),C=Ct({lockPath:ao,instanceId:l});C.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(C.ownerPid?` (PID ${C.ownerPid})`:"")+", skipping duplicate start"),clearInterval(v),process.exit(0));try{const e=io();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),C.release(),process.exit(0)}catch{}}catch{}const Q=Be(process.env,ve)?[]:je(process.pid);Q.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${Q[0]}), skipping duplicate start`),C.release(),process.exit(0)),ce(process.pid,l,{version:T}),de(process.pid,void 0,l),process.on("exit",()=>{re(process.pid,l),ae(l)}),process.on("exit",C.release);let V=null;try{V=vt()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const M=await ft();if(M){V||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{St({fromVersion:T,targetVersion:M.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:M.jobId},{readiness:V}),console.error(`[upgrade] New version crashed ${M.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{to()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const d=m(),p=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??d.serverUrl??ut.cn.url,f=le(),c=await me({serverUrl:p,authToken:d.machineToken??d.accessToken}),S=c.map(e=>e.type);let j=L(c);const h=new Ot,U=new Lt,R=new Qt(h),y=new xt(p),Se=new Kt({actionClient:y}),ye=new Jt({actionClient:y});let w=null,r;const Y=Yt({authority:R,actionClient:y,attachmentCache:Se,attachmentUploader:ye,observations:U,getMachineCredentials:()=>({machineToken:m().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),onSendOutcome:e=>r.noteManagedRoomSendOutcome(e),getActiveRunId:(e,o)=>r.getManagedRoomActiveRunId(e,o),scheduleExecutor:(e,o,t)=>ne({serverUrl:p,machineToken:m().machineToken,sessionId:e,action:o,args:t}),onPaused:({registryKey:e,sessionId:o})=>{const n=h.getByRegistryKey(e)?.binding;n&&h.setBinding({registryKey:e,bindingId:n.bindingId,roomId:n.roomId,agentIdentityId:n.agentIdentityId,agentMembershipId:n.agentMembershipId,status:"paused",activationMode:"paused"}),R.revokeSession(e),r?.discardPendingManagedRoomMessages(o)}});let F=null,H=null,B=null,W=null,Z=!1;const b=await ue({paths:Tt(),handlers:{...Mt({daemonVersion:f,protocolVersion:Nt,getStatus:()=>se(),getAgents:()=>c,requestShutdown:()=>{W?W():Z=!0},completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),bindManagedRoom:e=>r.bindManagedRoomFromLocal(e),stewardSay:e=>r.stewardSayFromLocal(e),startUpgrade:async e=>{if(!F)throw new Error("upgrade_unavailable");return F(e)},prepareExternalUpgrade:e=>{if(!H)throw new Error("external_upgrade_unavailable");return H(e)},cancelExternalUpgrade:()=>{if(!B)throw new Error("external_upgrade_unavailable");return B()}}),...Ut({getStatus:()=>se(),getSnapshot:()=>L(c).map(e=>{const o=c.find(t=>t.type===e.type);return{...e,runtimePlatform:o?.runtimePlatform,runtimeIsWsl:o?.runtimeIsWsl}}),getUnavailable:at,discover:async e=>{if(!r)throw new Error("daemon_starting");const o=await ge(!0,e);if(e){const n=c.filter(g=>g.type!==e);c.splice(0,c.length,...n,...o.detectedAgents)}else c.splice(0,c.length,...o.detectedAgents);const t=L(c);return s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:c.map(n=>n.type),agents:t}}),o.agents.map(n=>{const g=o.detectedAgents.find(q=>q.type===n.type);return{...n,runtimePlatform:g?.runtimePlatform,runtimeIsWsl:g?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return _t(e,{ignoreNativeSession:(o,t)=>P?.ignoreNativeSource(o,t)})}})}});let A;try{A=await ue({paths:Dt(),handlers:{"managed-room.execute":e=>Y(e),"schedule.personal":async e=>{const o=e,t=Re(o?.context);if(h.getByNianSessionId(t)?.binding||!be(t))throw new Error("schedule_personal_context_required");return await ne({serverUrl:p,machineToken:m().machineToken,sessionId:t,action:o.operation,args:o})}}})}catch(e){throw await b.close(),e}let X=!1;const _=()=>{X||(X=!0,Promise.allSettled([b.close(),A.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",_),process.once("SIGTERM",_),!d.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([b.close(),A.close()]),process.exitCode=1;return}process.removeListener("SIGINT",_),process.removeListener("SIGTERM",_);const ee=`${so(p)}/relay/machine`,N=d.machineToken;if(!N)return;try{await eo({serverUrl:p,machineToken:N,machineId:d.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([b.close(),A.close()]),process.exit(1)}d.machineId&&Rt(p,d.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${ee}... (v${f}) agents: ${S.join(",")}`),D({level:"info",wsEvent:"daemon.start",metadata:{version:f,agents:S}});let P=null,E=null,k=0,G=!1,I=ht();const te=Ue(d.autoUpgrade),O=d.machineId?new wt({serverUrl:p,machineId:d.machineId,getMachineToken:()=>m().machineToken,getDetectedAgents:()=>me({serverUrl:p,authToken:m().machineToken}),onRuntimeChanged:async()=>{const e=k,o=await ge(!0);if(c.splice(0,c.length,...o.detectedAgents),S.splice(0,S.length,...o.agentList),j=o.agents,!(await s.sendReq({type:"req",id:De(),method:"machine.agents.report",params:{agents:o.agents}},2e4)).ok)throw new Error("machine_capability_report_rejected");e===k&&s.getState()==="connected"&&O?.start()},onError:()=>console.warn("[public-agent] delivery attempt failed")}):null,s=new _e({serverUrl:ee,machineToken:N,cliVersion:f,agentList:S,autoUpgradePolicy:te,sessionSyncProtocolVersion:fe,sessionSyncCapabilities:he,daemonInstallationId:Zt(),dataEpoch:Ie,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),D({level:"info",wsEvent:"daemon.connected"}),s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:S,agents:j}}),kt(c,{serverUrl:d.serverUrl??p,authToken:d.machineToken??d.accessToken}).then(t=>{JSON.stringify(t)!==JSON.stringify(j)&&s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:S,agents:t}})}).catch(()=>{}),I&&s.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:I.from,to:I.to,...I.jobId?{jobId:I.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),x.start(),E?.start();const e=++k,o=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),I){const t=I;I=null,t.jobId&&yt(t.jobId,t.to),gt(),console.log(`[${new Date().toISOString()}] [upgrade] ${t.operation==="rollback"?"Rolled back":"Healthy"}: ${t.from} \u2192 ${t.to}`),bt({kind:"upgrade",result:t.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),s.sendEvent({type:"event",event:"upgrade",payload:{state:t.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:t.from,to:t.to,...t.jobId?{jobId:t.jobId}:{}}}),t.operation!=="rollback"&&s.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:t.from,to:t.to}})}G||(G=!0,nt({clientVersion:f}).then(t=>{const n=t.filter(g=>!g.ok||!["current","registered","updated"].includes(g.result.status));n.length>0&&console.warn(`[skill] ${n.length} installed Skill copies need attention; run shennian setup for details`)}).catch(()=>console.warn("[skill] Official Skill refresh failed; Client remains available")).finally(()=>{G=!1})),e===k&&s.getState()==="connected"&&(P?.handleConnected(),O?.start())}catch(t){if(console.error("[session.deletions] startup catch-up failed",t),e===k&&s.getState()==="connected"){if(t instanceof no)return;const n=t instanceof oo?Math.max(1e3,t.retryAfterMs):5e3;setTimeout(()=>{o()},n).unref?.()}}};o()},onDisconnected:e=>{k+=1,r?.revokeProjectFsHandles(),O?.stop(),E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${co(e)}`),D({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||r?.revokeProjectFsHandles()},onReq:e=>{if(console.log(`[${new Date().toISOString()}] [req] ${e.method}`),D({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),e.method==="room.message.deliver"){jt(s,E,e);return}r.handleReq(e)}});P=At()?new Pt(s):null,E=new Vt({registry:h,observations:U,actionClient:y,getMachineCredentials:()=>({machineToken:m().machineToken}),isSessionDeleted:e=>new Ft().hasSession(e),onMessages:async(e,o,t,n)=>{await w?.processMessages(e,o,t,n)},onBindingPaused:e=>{e.lifecycleState==="closed"?(R.revokeSession(e.registryKey),r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")})):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const x=new It({currentVersion:f,machineId:d.machineId??"unknown-machine",serverUrl:d.serverUrl??p,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:fe,dataEpoch:Ie,advertisedCapabilities:he,updaterProtocolVersion:1,startUpgrade:async(e,o)=>{const{handleUpgradeStart:t}=await import("./commands/upgrade.js");await t(s,"auto-upgrade",e,{currentVersion:f,prepareForUpgrade:n=>r.prepareForUpgrade(n),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:o?void 0:()=>r.getUpgradeIdleState().idle})}});x.setPolicy(te),r=new mt(s,P,f,x,new $t({registry:h,observations:U,bindingClient:y,getMachineCredentials:()=>{const e=m();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}),{prepare:()=>Fe(),isDisabled:()=>ie(),shutdownAfterResponse:()=>{setTimeout(()=>{He(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>R.revokeToken(e),Y,null,pt(N),()=>L(c)),F=async e=>{const o=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=typeof o.targetVersion=="string"?o.targetVersion:void 0,n=o.confirmedMajor===!0;return await Ze(s,`local-upgrade-${Date.now()}`,t,{currentVersion:f,confirmedMajor:n,prepareForUpgrade:q=>r.prepareForUpgrade(q),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},H=e=>{const o=e&&typeof e=="object"&&!Array.isArray(e)?e:{},n=`desktop-${(typeof o.targetVersion=="string"?o.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:n,...r.prepareForUpgrade(n)}},B=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),w=new Wt({registry:h,observations:U,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const o=m().machineToken?.trim(),t=e.binding;if(!o||!t)throw new Error("managed_room_context_unavailable");const n=await y.status({machineToken:o,roomId:t.roomId,bindingId:t.bindingId});if(!Bt(h,e)||!Ht(e,n))throw new Error("managed_room_binding_unavailable");return{roomName:n.room.name,memberCount:n.room.memberCount,members:n.room.members,agentsByIdentityId:n.agent?{[n.agentIdentityId]:n.agent}:{},effectiveModelsBySessionId:n.effectiveModelId!==void 0?{[e.nianSessionId]:n.effectiveModelId}:void 0,agentSystemPromptsByIdentityId:n.agent?{[n.agentIdentityId]:n.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,o,t,n)=>{const g=m().machineToken;if(!g)throw new Error("machine_not_authorized");return R.issue({registryKey:e,machineCredential:g,activationCauseMessageId:o,allowedActions:t,propagateWorkerRoomOrigin:n})},audit:new zt,prepareUnboundDirectTurn:qt,resolveManagedAgentPolicy:e=>Gt({...e,runtime:c.find(o=>o.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>Ae({serverUrl:p,machineToken:m().machineToken,req:e,client:s,queue:r.getScheduleQueue(),registry:h}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(h.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const t=await y.status({machineToken:m().machineToken,roomId:e.roomId,bindingId:e.bindingId});return t.status==="active"&&t.room.status==="active"?"ready":"ended"},r.setManagedRoomTurnPreparer(e=>w.prepareConversationTurn(e)),r.setManagedAgentDirectTurnPreparer((e,o)=>w.prepareDirectConversationTurn(e,o)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?w.prepareDirectConversationTurn(e.sessionId,Xt):e.source==="manager_event"?w.prepareDirectConversationTurn(e.sessionId,{allowedRoomActions:[],managerEvent:!0}):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:w.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),z.mkdirSync(ve,{recursive:!0}),ce(process.pid,l,{version:f}),de(process.pid,void 0,l),s.connect(),process.stdin.resume();let oe=!1;const $=async()=>{if(!oe){oe=!0,console.log(Ee.gray(`
3
- Disconnecting...`)),D({level:"info",wsEvent:"daemon.stop"}),clearInterval(v),O?.stop();try{await r.cleanup(),x.stop(),P?.stop(),E?.stop(),s.disconnect(),await Promise.allSettled([b.close(),A.close()]),re(process.pid,l),ae(l)}finally{process.exit(0)}}};W=$,Z&&$(),process.on("SIGINT",()=>{$()}),process.on("SIGTERM",()=>{$()})}),a.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>J()),a.command("room-session-hook",{hidden:!0}).description("(internal) Authorize the official Room tool for one trusted Agent Session").argument("<runtime>","Trusted runtime adapter").allowUnknownOption(!0).action(()=>J()),a.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>J()),we(a),rt(a),xe(a),Le(a),We(a),Ce(a),Ge(a),qe(a,{clientVersion:T}),ze(a),Ke(a),Je(a),Qe(a),Ye(a),Xe(a),et(a),tt(a),ot(a),it(a,T),a.parse();
1
+ import{registerConfigCommand as we}from"./commands/config.js";import{registerLocalAppsCommand as Ce}from"./commands/local-apps.js";import{registerScheduleCommand as Re}from"./commands/schedule.js";import{resolvePersonalScheduleContext as ke}from"./schedules/personal-context.js";import{isStewardSessionId as be}from"./steward/session.js";import{executeServerSchedule as ne,deliverServerSchedule as Ae}from"./schedules/server-client.js";import{Command as Pe}from"commander";import Ee from"chalk";import Te from"node:os";import{randomUUID as De}from"node:crypto";import z from"node:fs";import{loadConfig as m,getShennianDir as Me,resolveShennianPath as K,normalizeAutoUpgradePolicy as Ue}from"./config/index.js";import{CliRelayClient as _e}from"./relay/client.js";import{collectKnownLogSecrets as Ne,installCliLogRedaction as Oe}from"./log-redaction.js";import{registerPairCommand as xe,runSmartStart as $e}from"./commands/pair.js";import{registerLogoutCommand as Le}from"./commands/logout.js";import{clearDaemonPidIfOwner as re,createDaemonInstanceId as Ve,clearDaemonLauncher as ae,findRunningDaemonProcessIds as je,isRemoteAccessDisabled as ie,prepareRemoteAccessPause as Fe,stopPreparedRemoteAccessService as He,isIsolatedDaemonE2eInstance as Be,getDaemonStatus as se,registerDaemonCommand as We,writeDaemonPid as ce,writeDaemonLauncher as de}from"./commands/daemon.js";import{registerRuntimeCommand as Ge}from"./commands/runtime.js";import{registerAdapterCommand as qe}from"./commands/adapter.js";import{registerAgentCommand as ze}from"./commands/agent.js";import{registerManagerCommand as Ke}from"./commands/manager.js";import{registerWorkerCommand as Je}from"./commands/worker.js";import{registerProjectCommand as Qe}from"./commands/project.js";import{registerStewardCommand as Ye}from"./commands/steward.js";import{registerRecordingCommand as Ze}from"./commands/recordings.js";import{handleUpgradeStart as Xe,registerUpgradeCommand as eo}from"./commands/upgrade.js";import{registerToolsCommand as oo}from"./commands/tools.js";import{registerQueueCommand as to}from"./commands/queue.js";import{registerSkillCommand as no}from"./commands/skill.js";import{refreshExistingSkillForHosts as ro}from"./skill/hosts.js";import{registerSetupCommand as ao}from"./commands/setup.js";import{getUnavailableAcpAgents as io}from"./agents/acp/discovery.js";import{registerCommandReference as so}from"./commands/command-reference.js";import{registerIntegrationCommand as co}from"./commands/integration.js";import{registerRoomCommand as lo}from"./commands/room.js";import{registerContactCommand as mo}from"./commands/contact.js";import{registerSupportCommand as po}from"./commands/support.js";import{SessionManager as uo}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as go}from"./session/handlers/project-fs.js";import{SERVERS as fo}from"./region.js";import{clearUpgradeAttempt as ho,getCurrentVersion as le,handleStartupCrashCheck as Io,readUpgradeAttempt as vo}from"./upgrade/engine.js";import{AutoUpgradeScheduler as So}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as yo}from"./upgrade/updater-bootstrap.js";import{launchUpdater as wo,markUpdaterHealthy as Co}from"./upgrade/updater-launcher.js";import{detectAgents as me}from"./agents/detect.js";import{PublicAgentDeliveryWorker as Ro}from"./agents/public-delivery-worker.js";import{augmentProcessPath as pe}from"./env-path.js";import{acquireDaemonInstanceLock as ko}from"./commands/daemon-instance-lock.js";pe();const T=le();import{getCachedAgentInfos as L,resolveAgentInfos as bo}from"./agents/model-registry.js";import{initCliLogReporter as Ao,reportLog as D,reportUpgradeAggregateMetric as Po}from"./log-reporter.js";import{isNativeFusionEnabled as Eo}from"./native-fusion/config.js";import{NativeSessionFusionService as To}from"./native-fusion/service.js";import{startDaemonLogRetention as Do}from"./daemon-log.js";import{startDaemonIpcServer as ue}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as Mo,resolveManagedRoomIpcPaths as Uo}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as _o}from"./daemon-ipc/control.js";import{createAgentReadinessHandlers as No}from"./daemon-ipc/agent-readiness.js";import{scanMachineAgents as ge}from"./session/handlers/agents.js";import{validateAgentWorkspaceConfiguration as Oo}from"./session/handlers/agent-workspace-validation.js";import{DAEMON_IPC_VERSION as xo}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as $o}from"./room/session-registry.js";import{HttpRoomBindingClient as Lo}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as Vo}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as jo}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Fo}from"./room/mirror-sync-service.js";import{handleLiveRoomDelivery as Ho}from"./room/live-delivery.js";import{NativeSourceDeletionStore as Bo}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as Wo,isCurrentRegistration as Go}from"./room/registration-authority.js";import{RoomActivationService as qo,resolveManagedAgentPolicy as zo}from"./room/activation-service.js";import{prepareStandaloneAgentTurn as Ko}from"./room/standalone-agent-turn.js";import{RoomActivationAudit as Jo}from"./room/activation-audit.js";import{RoomAttachmentCache as Qo}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Yo}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as Zo}from"./room/managed-context.js";import{createManagedRoomExecutor as Xo}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as fe,SESSION_SYNC_ADVERTISED_CAPABILITIES as he}from"@shennian/wire";import{getDaemonInstallationId as et}from"./session/store.js";import{OWNER_DIRECT_TURN_OPTIONS as ot}from"./session/queue-helpers.js";import{synchronizeMachinePersonalAuthority as tt}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as Ie,ensurePersonalDataEpoch as nt}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as rt,DeletionSyncTerminalError as at}from"./session/deletion-sync-state.js";const ve=Me(),it=K("daemon.pid"),st=K("daemon.instance.lock");function ct(){try{const i=z.readFileSync(it,"utf-8").trim();if(i.startsWith("{")){const v=JSON.parse(i),l=Number(v.pid);return Number.isInteger(l)&&l>0?l:null}const u=parseInt(i,10);return Number.isInteger(u)&&u>0?u:null}catch{return null}}function dt(i){return i.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function J(){process.stdout.write(`${JSON.stringify({ok:!1,error:"integration_command_retired",message:"Room MCP and Hooks were retired. Use the Shennian Skill and CLI.",nextAction:{type:"open_install_guide",url:"https://shennian.net/install.md"}})}
2
+ `),process.exitCode=1}function lt(i){const u=[`trigger=${i.trigger??"unknown"}`,`phase=${i.phase}`,`code=${i.code??"unknown"}`,`attempt=${i.reconnectAttempt}`];return i.reason&&u.push(`reason=${i.reason}`),i.error&&u.push(`error=${i.error}`),u.join(" ")}const a=new Pe;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(T),a.enablePositionalOptions(),co(a),lo(a),mo(a),po(a),Re(a),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",Te.hostname()).action(async i=>{const u=m(),v=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??u.serverUrl??void 0;await $e(v,i.name)}),a.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async i=>{const u=K("env.json");try{const e=JSON.parse(z.readFileSync(u,"utf-8"));for(const[t,o]of Object.entries(e))process.env[t]||(process.env[t]=o);pe()}catch{}Oe(Ne(process.env,m()));const v=Do();ie()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(v),process.exit(0));const l=Ve(),C=ko({lockPath:st,instanceId:l});C.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(C.ownerPid?` (PID ${C.ownerPid})`:"")+", skipping duplicate start"),clearInterval(v),process.exit(0));try{const e=ct();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),C.release(),process.exit(0)}catch{}}catch{}const Q=Be(process.env,ve)?[]:je(process.pid);Q.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${Q[0]}), skipping duplicate start`),C.release(),process.exit(0)),ce(process.pid,l,{version:T}),de(process.pid,void 0,l),process.on("exit",()=>{re(process.pid,l),ae(l)}),process.on("exit",C.release);let V=null;try{V=yo()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const M=await Io();if(M){V||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{wo({fromVersion:T,targetVersion:M.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:M.jobId},{readiness:V}),console.error(`[upgrade] New version crashed ${M.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{nt()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const d=m(),p=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??d.serverUrl??fo.cn.url,f=le(),c=await me({serverUrl:p,authToken:d.machineToken??d.accessToken}),S=c.map(e=>e.type);let j=L(c);const h=new $o,U=new jo,k=new Zo(h),y=new Lo(p),Se=new Qo({actionClient:y}),ye=new Yo({actionClient:y});let w=null,r;const Y=Xo({authority:k,actionClient:y,attachmentCache:Se,attachmentUploader:ye,observations:U,getMachineCredentials:()=>({machineToken:m().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),onSendOutcome:e=>r.noteManagedRoomSendOutcome(e),getActiveRunId:(e,t)=>r.getManagedRoomActiveRunId(e,t),scheduleExecutor:(e,t,o)=>ne({serverUrl:p,machineToken:m().machineToken,sessionId:e,action:t,args:o}),onPaused:({registryKey:e,sessionId:t})=>{const n=h.getByRegistryKey(e)?.binding;n&&h.setBinding({registryKey:e,bindingId:n.bindingId,roomId:n.roomId,agentIdentityId:n.agentIdentityId,agentMembershipId:n.agentMembershipId,status:"paused",activationMode:"paused"}),k.revokeSession(e),r?.discardPendingManagedRoomMessages(t)}});let F=null,H=null,B=null,W=null,Z=!1;const b=await ue({paths:Mo(),handlers:{..._o({daemonVersion:f,protocolVersion:xo,getStatus:()=>se(),getAgents:()=>c,requestShutdown:()=>{W?W():Z=!0},completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),bindManagedRoom:e=>r.bindManagedRoomFromLocal(e),stewardSay:e=>r.stewardSayFromLocal(e),startUpgrade:async e=>{if(!F)throw new Error("upgrade_unavailable");return F(e)},prepareExternalUpgrade:e=>{if(!H)throw new Error("external_upgrade_unavailable");return H(e)},cancelExternalUpgrade:()=>{if(!B)throw new Error("external_upgrade_unavailable");return B()}}),...No({getStatus:()=>se(),getSnapshot:()=>L(c).map(e=>{const t=c.find(o=>o.type===e.type);return{...e,runtimePlatform:t?.runtimePlatform,runtimeIsWsl:t?.runtimeIsWsl}}),getUnavailable:io,discover:async e=>{if(!r)throw new Error("daemon_starting");const t=await ge(!0,e);if(e){const n=c.filter(g=>g.type!==e);c.splice(0,c.length,...n,...t.detectedAgents)}else c.splice(0,c.length,...t.detectedAgents);const o=L(c);return s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:c.map(n=>n.type),agents:o}}),t.agents.map(n=>{const g=t.detectedAgents.find(q=>q.type===n.type);return{...n,runtimePlatform:g?.runtimePlatform,runtimeIsWsl:g?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return Oo(e,{ignoreNativeSession:(t,o)=>P?.ignoreNativeSource(t,o)})}})}});let A;try{A=await ue({paths:Uo(),handlers:{"managed-room.execute":e=>Y(e),"schedule.personal":async e=>{const t=e,o=ke(t?.context);if(h.getByNianSessionId(o)?.binding||!be(o))throw new Error("schedule_personal_context_required");return await ne({serverUrl:p,machineToken:m().machineToken,sessionId:o,action:t.operation,args:t})}}})}catch(e){throw await b.close(),e}let X=!1;const _=()=>{X||(X=!0,Promise.allSettled([b.close(),A.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",_),process.once("SIGTERM",_),!d.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([b.close(),A.close()]),process.exitCode=1;return}process.removeListener("SIGINT",_),process.removeListener("SIGTERM",_);const ee=`${dt(p)}/relay/machine`,N=d.machineToken;if(!N)return;try{await tt({serverUrl:p,machineToken:N,machineId:d.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([b.close(),A.close()]),process.exit(1)}d.machineId&&Ao(p,d.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${ee}... (v${f}) agents: ${S.join(",")}`),D({level:"info",wsEvent:"daemon.start",metadata:{version:f,agents:S}});let P=null,E=null,R=0,G=!1,I=vo();const oe=Ue(d.autoUpgrade),O=d.machineId?new Ro({serverUrl:p,machineId:d.machineId,getMachineToken:()=>m().machineToken,getDetectedAgents:()=>me({serverUrl:p,authToken:m().machineToken}),onRuntimeChanged:async()=>{const e=R,t=await ge(!0);if(c.splice(0,c.length,...t.detectedAgents),S.splice(0,S.length,...t.agentList),j=t.agents,!(await s.sendReq({type:"req",id:De(),method:"machine.agents.report",params:{agents:t.agents}},2e4)).ok)throw new Error("machine_capability_report_rejected");e===R&&s.getState()==="connected"&&O?.start()},onError:()=>console.warn("[public-agent] delivery attempt failed")}):null,s=new _e({serverUrl:ee,machineToken:N,cliVersion:f,agentList:S,autoUpgradePolicy:oe,sessionSyncProtocolVersion:fe,sessionSyncCapabilities:he,daemonInstallationId:et(),dataEpoch:Ie,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),D({level:"info",wsEvent:"daemon.connected"}),s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:S,agents:j}}),bo(c,{serverUrl:d.serverUrl??p,authToken:d.machineToken??d.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(j)&&s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:S,agents:o}})}).catch(()=>{}),I&&s.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:I.from,to:I.to,...I.jobId?{jobId:I.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),x.start(),E?.start();const e=++R,t=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),I){const o=I;I=null,o.jobId&&Co(o.jobId,o.to),ho(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),Po({kind:"upgrade",result:o.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),s.sendEvent({type:"event",event:"upgrade",payload:{state:o.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:o.from,to:o.to,...o.jobId?{jobId:o.jobId}:{}}}),o.operation!=="rollback"&&s.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:o.from,to:o.to}})}G||(G=!0,ro({clientVersion:f}).then(o=>{const n=o.filter(g=>!g.ok||!["current","registered","updated"].includes(g.result.status));n.length>0&&console.warn(`[skill] ${n.length} installed Skill copies need attention; run shennian setup for details`)}).catch(()=>console.warn("[skill] Official Skill refresh failed; Client remains available")).finally(()=>{G=!1})),e===R&&s.getState()==="connected"&&(P?.handleConnected(),O?.start())}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===R&&s.getState()==="connected"){if(o instanceof at)return;const n=o instanceof rt?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{t()},n).unref?.()}}};t()},onDisconnected:e=>{R+=1,r?.revokeProjectFsHandles(),O?.stop(),E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${lt(e)}`),D({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||r?.revokeProjectFsHandles()},onReq:e=>{if(console.log(`[${new Date().toISOString()}] [req] ${e.method}`),D({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),e.method==="room.message.deliver"){Ho(s,E,e);return}r.handleReq(e)}});P=Eo()?new To(s):null,E=new Fo({registry:h,observations:U,actionClient:y,getMachineCredentials:()=>({machineToken:m().machineToken}),isSessionDeleted:e=>new Bo().hasSession(e),onMessages:async(e,t,o,n)=>{await w?.processMessages(e,t,o,n)},onBindingPaused:e=>{e.lifecycleState==="closed"?(k.revokeSession(e.registryKey),r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")})):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const x=new So({currentVersion:f,machineId:d.machineId??"unknown-machine",serverUrl:d.serverUrl??p,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:fe,dataEpoch:Ie,advertisedCapabilities:he,updaterProtocolVersion:1,startUpgrade:async(e,t)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(s,"auto-upgrade",e,{currentVersion:f,prepareForUpgrade:n=>r.prepareForUpgrade(n),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:t?void 0:()=>r.getUpgradeIdleState().idle})}});x.setPolicy(oe),r=new uo(s,P,f,x,new Vo({registry:h,observations:U,bindingClient:y,getMachineCredentials:()=>{const e=m();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}),{prepare:()=>Fe(),isDisabled:()=>ie(),shutdownAfterResponse:()=>{setTimeout(()=>{He(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>k.revokeToken(e),Y,null,go(N),()=>L(c)),F=async e=>{const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof t.targetVersion=="string"?t.targetVersion:void 0,n=t.confirmedMajor===!0;return await Xe(s,`local-upgrade-${Date.now()}`,o,{currentVersion:f,confirmedMajor:n,prepareForUpgrade:q=>r.prepareForUpgrade(q),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},H=e=>{const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},n=`desktop-${(typeof t.targetVersion=="string"?t.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:n,...r.prepareForUpgrade(n)}},B=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),w=new qo({registry:h,observations:U,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const t=m().machineToken?.trim(),o=e.binding;if(!t||!o)throw new Error("managed_room_context_unavailable");const n=await y.status({machineToken:t,roomId:o.roomId,bindingId:o.bindingId});if(!Go(h,e)||!Wo(e,n))throw new Error("managed_room_binding_unavailable");return{roomName:n.room.name,memberCount:n.room.memberCount,members:n.room.members,agentsByIdentityId:n.agent?{[n.agentIdentityId]:n.agent}:{},effectiveModelsBySessionId:n.effectiveModelId!==void 0?{[e.nianSessionId]:n.effectiveModelId}:void 0,agentSystemPromptsByIdentityId:n.agent?{[n.agentIdentityId]:n.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,t,o,n)=>{const g=m().machineToken;if(!g)throw new Error("machine_not_authorized");return k.issue({registryKey:e,machineCredential:g,activationCauseMessageId:t,allowedActions:o,propagateWorkerRoomOrigin:n})},audit:new Jo,prepareUnboundDirectTurn:Ko,resolveManagedAgentPolicy:e=>zo({...e,runtime:c.find(t=>t.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>Ae({serverUrl:p,machineToken:m().machineToken,req:e,client:s,queue:r.getScheduleQueue(),registry:h}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(h.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await y.status({machineToken:m().machineToken,roomId:e.roomId,bindingId:e.bindingId});return o.status==="active"&&o.room.status==="active"?"ready":"ended"},r.setManagedRoomTurnPreparer(e=>w.prepareConversationTurn(e)),r.setManagedAgentDirectTurnPreparer((e,t)=>w.prepareDirectConversationTurn(e,t)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?w.prepareDirectConversationTurn(e.sessionId,ot):e.source==="manager_event"?w.prepareDirectConversationTurn(e.sessionId,{allowedRoomActions:[],managerEvent:!0}):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:w.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),z.mkdirSync(ve,{recursive:!0}),ce(process.pid,l,{version:f}),de(process.pid,void 0,l),s.connect(),process.stdin.resume();let te=!1;const $=async()=>{if(!te){te=!0,console.log(Ee.gray(`
3
+ Disconnecting...`)),D({level:"info",wsEvent:"daemon.stop"}),clearInterval(v),O?.stop();try{await r.cleanup(),x.stop(),P?.stop(),E?.stop(),s.disconnect(),await Promise.allSettled([b.close(),A.close()]),re(process.pid,l),ae(l)}finally{process.exit(0)}}};W=$,Z&&$(),process.on("SIGINT",()=>{$()}),process.on("SIGTERM",()=>{$()})}),a.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>J()),a.command("room-session-hook",{hidden:!0}).description("(internal) Authorize the official Room tool for one trusted Agent Session").argument("<runtime>","Trusted runtime adapter").allowUnknownOption(!0).action(()=>J()),a.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>J()),we(a),ao(a),xe(a),Le(a),We(a),Ce(a),Ge(a),qe(a,{clientVersion:T}),ze(a),Ke(a),Je(a),Qe(a),Ye(a),Ze(a),eo(a),oo(a),to(a),no(a),so(a,T),a.parse();
@@ -0,0 +1 @@
1
+ import t from"node:fs";import D from"node:os";import o from"node:path";import{createHash as E,randomUUID as O}from"node:crypto";import{getShennianDir as a}from"../config/index.js";import{assertPathsSeparate as N}from"../steward/workspace.js";const j=e=>{if(typeof e!="string"||!/^[\w-]{1,100}$/.test(e))throw new Error("recording_invalid_id");return e},S=e=>E("sha256").update(e).digest("hex"),y=e=>{if(!t.existsSync(e))return null;if(t.lstatSync(e).isSymbolicLink())return r("path_forbidden");const n=t.openSync(e,t.constants.O_RDONLY|(t.constants.O_NOFOLLOW??0));try{return t.fstatSync(n).isFile()?t.readFileSync(n):r("path_forbidden")}finally{t.closeSync(n)}},r=e=>{throw new Error(`recording_${e}`)},_=()=>o.join(a(),"personal-recordings.json");let m=null;const z=()=>{if(process.env.SHENNIAN_RECORDINGS_DIR)return process.env.SHENNIAN_RECORDINGS_DIR;if(m)return m;try{const e=JSON.parse(t.readFileSync(_(),"utf8"));return typeof e.directory!="string"||!o.isAbsolute(e.directory)?r("directory_invalid"):(m=e.directory,m)}catch(e){if(e.code==="ENOENT")return m=o.join(D.homedir(),"shennian_recordings"),m;throw e}};function H(){return k()}function M(e){if(process.env.SHENNIAN_RECORDINGS_DIR)return r("directory_env_override");if(!o.isAbsolute(e)||/[\u0000-\u001f]/.test(e))return r("directory_invalid");const n=o.resolve(e);N(n,a());const c=process.env.SHENNIAN_RECORDINGS_DIR;try{process.env.SHENNIAN_RECORDINGS_DIR=n,k()}finally{c===void 0?delete process.env.SHENNIAN_RECORDINGS_DIR:process.env.SHENNIAN_RECORDINGS_DIR=c}t.mkdirSync(a(),{recursive:!0,mode:448});const s=`${_()}.${O()}.tmp`;try{t.writeFileSync(s,JSON.stringify({directory:n}),{mode:384,flag:"wx"}),t.renameSync(s,_())}finally{try{t.unlinkSync(s)}catch{}}return n}function k(){const e=z();if(!o.isAbsolute(e))return r("directory_invalid");const n=o.resolve(e);N(n,a());let c=n;for(;;){try{if(t.lstatSync(c).isSymbolicLink())return r("path_forbidden")}catch(l){if(l.code!=="ENOENT")throw l}const f=o.dirname(c);if(f===c)break;c=f}t.mkdirSync(n,{recursive:!0,mode:448});const s=t.realpathSync(n),u=t.statSync(s);if(!u.isDirectory())return r("directory_invalid");if(process.platform!=="win32"){if(typeof process.getuid=="function"&&u.uid!==process.getuid())return r("directory_owner");u.mode&63&&t.chmodSync(s,448)}return N(s,t.existsSync(a())?t.realpathSync(a()):a()),s}function P(e){let n=k();for(const c of e){n=o.join(n,j(c));let s=null;try{s=t.lstatSync(n)}catch(f){if(f.code!=="ENOENT")throw f}if(s?.isSymbolicLink())return r("path_forbidden");s||t.mkdirSync(n,{mode:448});const u=t.lstatSync(n);if(!u.isDirectory())return r("path_forbidden");if(process.platform!=="win32"){if(typeof process.getuid=="function"&&u.uid!==process.getuid())return r("directory_owner");u.mode&63&&t.chmodSync(n,448)}}return n}function I(e,n,c){const s=o.join(e,`${O()}.tmp`);try{const u=t.openSync(s,"wx",384);try{t.writeFileSync(u,c),t.fsyncSync(u)}finally{t.closeSync(u)}if(t.renameSync(s,o.join(e,n)),process.platform!=="win32"){const f=t.openSync(e,"r");try{t.fsyncSync(f)}finally{t.closeSync(f)}}}finally{try{t.unlinkSync(s)}catch{}}}function G(e){try{if(!e||!["chunk","commit"].includes(e.action)||typeof e.initialMachineId!="string"||!/^[\w-]{1,100}$/.test(e.initialMachineId)||!Number.isSafeInteger(e.initialPrimaryRevision)||e.initialPrimaryRevision<0||!(e.confirmedPrimaryRevision===null||Number.isSafeInteger(e.confirmedPrimaryRevision)&&e.confirmedPrimaryRevision>=0))return r("invalid_request");const n=P([e.userId,e.sessionKey,e.batchKey]),c=o.join(n,"manifest.json");if(e.action==="chunk"){if(!Number.isInteger(e.index)||e.index<0||e.index>=400||typeof e.base64!="string"||e.base64.length>18e4||!/^[A-Za-z0-9+/]*={0,2}$/.test(e.base64)||!Number.isInteger(e.size)||e.size<1||e.size>128e3||!/^[a-f0-9]{64}$/.test(e.sha256??""))return r("invalid_chunk");const i=Buffer.from(e.base64,"base64");if(i.length!==e.size||S(i)!==e.sha256)return r("chunk_mismatch");const d=`${e.index}.chunk`,p=o.join(n,d),v=y(p);if(v){if(!v.equals(i))return r("chunk_conflict")}else{const b=y(c);if(b){const h=JSON.parse(b.toString("utf8")),g=y(o.join(n,"audio.pcm"));return h.initialMachineId!==e.initialMachineId||h.initialPrimaryRevision!==e.initialPrimaryRevision||h.chunks[e.index]?.size!==e.size||h.chunks[e.index]?.sha256!==e.sha256||!g||g.length!==h.audioSize||S(g)!==h.audioSha256?r("chunk_conflict"):{persisted:!0,complete:!0}}I(n,d,i)}return{persisted:!0,complete:t.existsSync(c)}}if(!Array.isArray(e.chunks)||e.chunks.length<1||e.chunks.length>400||!Array.isArray(e.transcript)||e.transcript.length>1e3||JSON.stringify(e.transcript).length>2e5||typeof e.startedAt!="string"||typeof e.endedAt!="string"||e.chunks.some(i=>!Number.isInteger(i.size)||i.size<1||i.size>128e3||!/^[a-f0-9]{64}$/.test(i.sha256)))return r("invalid_request");const s=e.transcript;if(s.some(i=>!i||typeof i!="object"||typeof i.text!="string"))return r("invalid_request");const u=[];for(let i=0;i<e.chunks.length;i++){const d=y(o.join(n,`${i}.chunk`));if(d)u.push(d);else if(!t.existsSync(c))return r("missing_chunk")}const f=u.length===e.chunks.length?Buffer.concat(u):null,l={sessionKey:e.sessionKey,batchKey:e.batchKey,initialMachineId:e.initialMachineId,initialPrimaryRevision:e.initialPrimaryRevision,startedAt:e.startedAt,endedAt:e.endedAt,audioFormat:{encoding:"pcm16le",sampleRate:16e3,channels:1},chunks:e.chunks,audioSize:f?.length??e.chunks.reduce((i,d)=>i+d.size,0),audioSha256:f?S(f):null,transcript:s},A=JSON.stringify(l),R=y(c);if(R){const i=JSON.parse(R.toString("utf8")),d=y(o.join(n,"audio.pcm"));return i.sessionKey!==l.sessionKey||i.batchKey!==l.batchKey||i.initialMachineId!==l.initialMachineId||i.initialPrimaryRevision!==l.initialPrimaryRevision||i.startedAt!==l.startedAt||i.endedAt!==l.endedAt||JSON.stringify(i.chunks)!==JSON.stringify(l.chunks)||JSON.stringify(i.transcript)!==JSON.stringify(l.transcript)||!d||d.length!==i.audioSize||S(d)!==i.audioSha256?r("batch_conflict"):{persisted:!0,complete:!0}}for(let i=0;i<e.chunks.length;i++){const d=o.join(n,`${i}.chunk`),p=y(d);if(!p)return r("missing_chunk");if(p.length!==e.chunks[i].size||S(p)!==e.chunks[i].sha256)return r("chunk_mismatch")}if(!f)return r("missing_chunk");I(n,"audio.pcm",f),I(n,"manifest.json",Buffer.from(A));for(let i=0;i<e.chunks.length;i++)t.unlinkSync(o.join(n,`${i}.chunk`));return{persisted:!0,complete:!0}}catch(n){if(["ENOSPC","EDQUOT"].includes(n.code??""))return r("storage_full");throw n}}export{M as configureRecordingDirectory,G as receivePersonalRecording,H as recordingDirectory};
@@ -0,0 +1 @@
1
+ import{receivePersonalRecording as a}from"../../personal-workspace/recordings.js";function i(r,e){try{r.client.sendRes({type:"res",id:e.id,ok:!0,payload:a(e.params)})}catch(o){const s=o instanceof Error?o.message:"";r.client.sendRes({type:"res",id:e.id,ok:!1,error:/^recording_[a-z_]+$/.test(s)?s:"recording_unavailable"})}}export{i as handlePersonalRecording};
@@ -0,0 +1 @@
1
+ import{handlePersonalWorkspace as e}from"./personal-workspace.js";import{handlePersonalRecording as n}from"./personal-recording.js";import{handleLocalApps as a}from"./local-apps.js";async function t(r,o){return o.method==="personal.workspace"?e(r,o):o.method==="personal.recording"?n(r,o):a(r,o)}export{t as handlePersonalRequest};
@@ -1 +1 @@
1
- import b from"node:crypto";import{getRegisteredAgents as S,unregisterAgent as k}from"../agents/adapter.js";import{resetCommandSpecCache as w}from"../agents/command-spec.js";import{loadConfig as I}from"../config/index.js";import{handleUpgradeStart as A,handleUpgradeStatus as T}from"../commands/upgrade.js";import{handleAgentsRefresh as P,handleModelsRefresh as C,refreshMachineAgents as M}from"./handlers/agents.js";import{AcpDiscoveryWatcher as x}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as D}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as F,handleAgentConfigGet as E,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleCodexSettings as z}from"./handlers/codex-settings.js";import{handleChatAbort as O,handleChatSend as B}from"./handlers/chat.js";import{recoverJournaledRun as H}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as _}from"./handlers/tool-detail.js";import{handleSessionTitleSet as U}from"./handlers/title.js";import{handleSessionMessageStatus as J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as $}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as L}from"./handlers/voice-window.js";import{commitStewardSay as V,commitTerminalStewardSay as N}from"./handlers/steward.js";import{handlePersonalWorkspace as G}from"./handlers/personal-workspace.js";import{handleLocalApps as K}from"./handlers/local-apps.js";import{handleRemoteAccessPause as X}from"./handlers/remote-access.js";import{cleanupPendingTransfers as Z,handleFsLs as Y,handleFsRead as q,handleFsRename as ee,handleFsWrite as se,handleFsTransferAbort as te,handleFsTransferChunk as ae,handleFsTransferFinish as re,handleFsTransferStart as ne,handleFsExportMarkdownPdf as ie,handleFsExportMarkdownPdfSetup as oe,handleFsArchiveZip as ce}from"./handlers/fs.js";import{handleRegionProbe as le,handleRegionSwitch as ue,handleUpgradeSetPolicy as he}from"./handlers/control.js";import{ManagerRuntimeService as de,setManagerRuntimeService as d}from"../manager/runtime.js";import{ChatQueueManager as me}from"./queue.js";import{createAuthorizedFsRoot as pe,createAuthorizedFsRootAsync as ge,resolveAuthorizedPath as fe,resolveAuthorizedPathAsync as ve,resolveSessionWorkDir as ye}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as Re}from"../agents/custom.js";import{listNodeAdapters as be}from"../adapter-kit/registry.js";import{syncNodeAdapterAgents as Se}from"../agents/node-adapter.js";import{bindManagedRoom as ke,handleManagedRoomBind as we,handleManagedRoomRestart as Ie,discardPreBindingSession as Ae}from"./handlers/room-managed.js";import{getDaemonInstallationId as m,listSessionRecords as u,purgeCanonicalSession as Te,purgeSessionRecord as Pe,recordSession as Ce,upsertMessage as Me}from"./store.js";import{requestSessionIndexPublish as p}from"./index-publisher.js";import{checkRunStalls as xe}from"./run-stall.js";import{reportUpgradeAggregateMetric as De}from"../log-reporter.js";import{PersonalHistorySubscriptions as Fe}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Ee}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Qe}from"../native-fusion/native-source-deletions.js";import{collectLocalNativeSources as je}from"../native-fusion/session-native-sources.js";import{purgeToolDetails as ze}from"./tool-detail-store.js";import{NativeSessionCleanupOutbox as Oe}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Be}from"./run-recovery/journal.js";import{RunRecoveryBarrier as He}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as We}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as _e}from"./project-fs-store.js";import{handleProjectFsRequest as Ue}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as Je,handleAcpAgentRequest as $e}from"./handlers/agent-control.js";import{SessionDeletionSynchronizer as Le}from"./deletion-synchronizer.js";import{dispatchManagedChat as Ve,dispatchQueuedChat as Ne,interruptQueuedChat as Ge}from"./queued-chat-dispatch.js";const Ke=50;import{resolveSessionWorkDir as nt}from"../fs/boundary.js";function Xe(){return"\u795E\u5FF5\u5347\u7EA7\u4E2D\u65AD\u4E86\u672C\u6B21\u8FD0\u884C\u3002\u5DF2\u5B8C\u6210\u7684\u56DE\u590D\u6216\u64CD\u4F5C\u4ECD\u7136\u6709\u6548\uFF0C\u672A\u5B8C\u6210\u90E8\u5206\u53EF\u91CD\u8BD5\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\u3002"}class tt{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;getAgentSnapshot;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new He;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new _e;deletionSynchronizer;constructor(e,t=null,s,r=null,n=null,o=null,h=null,g=null,f=null,v=null,y=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=r,this.managedRoomBinder=n,this.remoteAccessPauseController=o,this.managedRoomContextRevoker=h,this.managedRoomExecutor=g,this.trustedProjectFsRequestResolver=v,this.getAgentSnapshot=y,this.runJournal=f??new Be(m());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new We({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>H(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=u().find(R=>R.sessionId===a.sessionId),l=`terminal:${b.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>De({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new de({getRuntime:()=>this.getRuntime(),getAgentSnapshot:this.getAgentSnapshot??void 0,dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new me({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Ve(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ne(this.getRuntime(),a,i),interruptQueuedSession:a=>Ge(this.getRuntime(),a)}),this.deletionSynchronizer=new Le(e,a=>this.applySessionDeletion(a)),this.historySubscriptions=new Fe(this.client),this.nativeCleanupOutbox=new Oe({logger:console.info}),this.acpDiscoveryWatcher=new x(async()=>{w(),await M(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeFusion?.setExternalClaimHandler?.((a,i)=>{this.chatQueue.noteExternalClaim(a,i)}),this.nativeCleanupOutbox.start(),d(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{xe(this.sessions.entries(),()=>p(this.client)),this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...u().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Ee(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}noteManagedRoomSendOutcome(e){for(const t of this.sessions.values()){if(t.managedRoomContextToken!==e.token)continue;const s=t.roomSendOutcome??(t.roomSendOutcome={successes:0,failureCodes:[]});e.ok?s.successes+=1:s.failureCodes.length<20&&s.failureCodes.push(e.errorCode??"managed_room_action_failed");return}}getManagedRoomActiveRunId(e,t){const s=this.sessions.get(t);if(s?.currentRunId)return s.currentRunId;for(const r of this.sessions.values())if(r.managedRoomContextToken===e)return r.currentRunId??null;return null}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),getAgentSnapshot:this.getAgentSnapshot??void 0,resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}bindManagedRoomFromLocal(e){return ke(this.getRuntime(),this.managedRoomBinder,e)}stewardSayFromLocal(e){const t=typeof e.sessionId=="string"?e.sessionId:"",s=typeof e.text=="string"?e.text:"";return t?V(this.getRuntime(),t,s):N(this.getRuntime(),s)}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const r=Xe();Me(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:r,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),Ce({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:r}),p(this.client);const n=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:n,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:n,reason:t.reason,...t.message?{message:t.message}:{}},seq:n,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const r=u().find(n=>n.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:r?.modelId??s.params.modelId,sessionMode:r?.sessionMode??s.params.sessionMode,managerConfig:r?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:r?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await Ae(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){await this.deletionSynchronizer.synchronize()}async applySessionDeletion(e){const t=new Qe({daemonInstallationId:m()}),s=u().find(o=>o.sessionId===e.sessionId)?.codexSettings?.codexHome;let r=[];try{r=je(e.sessionId,{records:u()})}catch(o){console.warn("[session.deletions] local native source lookup failed",{error:o instanceof Error?o.message:String(o)})}t.recordSession(e);for(const o of[...e.sources,...r]){const h=t.find(o.agentType,o.sourceSessionKey);h&&h.sessionId!==e.sessionId||t.record({...e,...o})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const n=this.sessions.get(e.sessionId);if(n){this.revokeManagedRoomToken(n);try{await n.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),ze(e.sessionId),Te(e.sessionId),Pe(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e,s),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const r=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:r,canStop:s.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:n,runPhase:s.runPhase,canStop:s.canStop??!0},seq:n,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of S())t.startsWith("custom:")&&k(t);const e=I();for(const[t,s]of Object.entries(e.customAgents??{}))Re(t,s);Se(be(),new Set(Object.keys(e.customAgents??{})))}async handleReq(e,t={}){const s=this.getRuntime();let r;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?r={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await B(s,e);break;case"chat.enqueue":c(e.params),r={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.codex.settings.get":case"chat.codex.settings.set":z(s,e);break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await O(s,e);break;case"session.refresh":c(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":J(s,e);break;case"session.tool.detail":await _(s,e);break;case"voice.session.body.window":L(s,e);break;case"session.title.set":await U(s,e);break;case"room.agent.bind-managed":await we(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await Ie(s,this.managedRoomBinder,e);break;case"personal.workspace":await G(s,e);break;case"personal.apps.list":case"personal.apps.register":case"personal.apps.remove":case"personal.service":await K(s,e);break;case"fs.ls":await Y(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await Ue(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await q(s,e);break;case"fs.write":await se(s,e);break;case"fs.export.markdown-pdf":await ie(s,e);break;case"fs.export.markdown-pdf.setup":await oe(s,e);break;case"fs.archive.zip":await ce(s,e);break;case"fs.rename":await ee(s,e);break;case"fs.transfer.start":await ne(s,e);break;case"fs.transfer.chunk":await ae(s,e);break;case"fs.transfer.finish":await re(s,e);break;case"fs.transfer.abort":await te(s,e);break;case"region.probe":await le(s,e);break;case"region.switch":await ue(s,e);break;case"upgrade.start":await A(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:n=>this.prepareForUpgrade(n),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await T(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await he(s,e);break;case"machine.remote-access.pause":await X(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await P(s,e);break;case"agent.permission.respond":await Je(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await $e(s,e);break;case"models.refresh":await C(s,e);break;case"agent.config.get":await E(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await F(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await $(s,e);break;case"agent.capabilities.list":await D(s,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(n){if(t.propagateErrors)throw n;this.client.sendRes({type:"res",id:e.id,ok:!1,error:n instanceof Error?n.message:String(n)})}finally{this.activeRequests--}return r}evictIdleSessions(){if(this.sessions.size<Ke)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return ye(e)}resolveAuthorizedPath(e,t){return fe(e,pe(t))}async resolveAuthorizedPathAsync(e,t){return ve(e,await ge(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),Z(this.getRuntime()),await this.managerRuntime.stop(),d(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{tt as SessionManager,nt as resolveSessionWorkDir,Xe as upgradeRecoveryVisibleMessage};
1
+ import b from"node:crypto";import{getRegisteredAgents as S,unregisterAgent as k}from"../agents/adapter.js";import{resetCommandSpecCache as w}from"../agents/command-spec.js";import{loadConfig as I}from"../config/index.js";import{handleUpgradeStart as A,handleUpgradeStatus as T}from"../commands/upgrade.js";import{handleAgentsRefresh as P,handleModelsRefresh as C,refreshMachineAgents as M}from"./handlers/agents.js";import{AcpDiscoveryWatcher as x}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as D}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as F,handleAgentConfigGet as E,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleCodexSettings as z}from"./handlers/codex-settings.js";import{handleChatAbort as O,handleChatSend as B}from"./handlers/chat.js";import{recoverJournaledRun as H}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as _}from"./handlers/tool-detail.js";import{handleSessionTitleSet as U}from"./handlers/title.js";import{handleSessionMessageStatus as J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as $}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as V}from"./handlers/voice-window.js";import{commitStewardSay as L,commitTerminalStewardSay as N}from"./handlers/steward.js";import{handlePersonalRequest as G}from"./handlers/personal.js";import{handleRemoteAccessPause as K}from"./handlers/remote-access.js";import{cleanupPendingTransfers as X,handleFsLs as Z,handleFsRead as Y,handleFsRename as q,handleFsWrite as ee,handleFsTransferAbort as se,handleFsTransferChunk as te,handleFsTransferFinish as ae,handleFsTransferStart as re,handleFsExportMarkdownPdf as ne,handleFsExportMarkdownPdfSetup as ie,handleFsArchiveZip as oe}from"./handlers/fs.js";import{handleRegionProbe as ce,handleRegionSwitch as le,handleUpgradeSetPolicy as ue}from"./handlers/control.js";import{ManagerRuntimeService as he,setManagerRuntimeService as d}from"../manager/runtime.js";import{ChatQueueManager as de}from"./queue.js";import{createAuthorizedFsRoot as me,createAuthorizedFsRootAsync as pe,resolveAuthorizedPath as ge,resolveAuthorizedPathAsync as fe,resolveSessionWorkDir as ve}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as ye}from"../agents/custom.js";import{listNodeAdapters as Re}from"../adapter-kit/registry.js";import{syncNodeAdapterAgents as be}from"../agents/node-adapter.js";import{bindManagedRoom as Se,handleManagedRoomBind as ke,handleManagedRoomRestart as we,discardPreBindingSession as Ie}from"./handlers/room-managed.js";import{getDaemonInstallationId as m,listSessionRecords as u,purgeCanonicalSession as Ae,purgeSessionRecord as Te,recordSession as Pe,upsertMessage as Ce}from"./store.js";import{requestSessionIndexPublish as p}from"./index-publisher.js";import{checkRunStalls as Me}from"./run-stall.js";import{reportUpgradeAggregateMetric as xe}from"../log-reporter.js";import{PersonalHistorySubscriptions as De}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Fe}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Ee}from"../native-fusion/native-source-deletions.js";import{collectLocalNativeSources as Qe}from"../native-fusion/session-native-sources.js";import{purgeToolDetails as je}from"./tool-detail-store.js";import{NativeSessionCleanupOutbox as ze}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Oe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as Be}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as He}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as We}from"./project-fs-store.js";import{handleProjectFsRequest as _e}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as Ue,handleAcpAgentRequest as Je}from"./handlers/agent-control.js";import{SessionDeletionSynchronizer as $e}from"./deletion-synchronizer.js";import{dispatchManagedChat as Ve,dispatchQueuedChat as Le,interruptQueuedChat as Ne}from"./queued-chat-dispatch.js";const Ge=50;import{resolveSessionWorkDir as at}from"../fs/boundary.js";function Ke(){return"\u795E\u5FF5\u5347\u7EA7\u4E2D\u65AD\u4E86\u672C\u6B21\u8FD0\u884C\u3002\u5DF2\u5B8C\u6210\u7684\u56DE\u590D\u6216\u64CD\u4F5C\u4ECD\u7136\u6709\u6548\uFF0C\u672A\u5B8C\u6210\u90E8\u5206\u53EF\u91CD\u8BD5\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\u3002"}class et{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;getAgentSnapshot;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new Be;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new We;deletionSynchronizer;constructor(e,t=null,s,r=null,n=null,o=null,h=null,g=null,f=null,v=null,y=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=r,this.managedRoomBinder=n,this.remoteAccessPauseController=o,this.managedRoomContextRevoker=h,this.managedRoomExecutor=g,this.trustedProjectFsRequestResolver=v,this.getAgentSnapshot=y,this.runJournal=f??new Oe(m());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new He({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>H(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=u().find(R=>R.sessionId===a.sessionId),l=`terminal:${b.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>xe({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new he({getRuntime:()=>this.getRuntime(),getAgentSnapshot:this.getAgentSnapshot??void 0,dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new de({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Ve(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Le(this.getRuntime(),a,i),interruptQueuedSession:a=>Ne(this.getRuntime(),a)}),this.deletionSynchronizer=new $e(e,a=>this.applySessionDeletion(a)),this.historySubscriptions=new De(this.client),this.nativeCleanupOutbox=new ze({logger:console.info}),this.acpDiscoveryWatcher=new x(async()=>{w(),await M(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeFusion?.setExternalClaimHandler?.((a,i)=>{this.chatQueue.noteExternalClaim(a,i)}),this.nativeCleanupOutbox.start(),d(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{Me(this.sessions.entries(),()=>p(this.client)),this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...u().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Fe(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}noteManagedRoomSendOutcome(e){for(const t of this.sessions.values()){if(t.managedRoomContextToken!==e.token)continue;const s=t.roomSendOutcome??(t.roomSendOutcome={successes:0,failureCodes:[]});e.ok?s.successes+=1:s.failureCodes.length<20&&s.failureCodes.push(e.errorCode??"managed_room_action_failed");return}}getManagedRoomActiveRunId(e,t){const s=this.sessions.get(t);if(s?.currentRunId)return s.currentRunId;for(const r of this.sessions.values())if(r.managedRoomContextToken===e)return r.currentRunId??null;return null}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),getAgentSnapshot:this.getAgentSnapshot??void 0,resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}bindManagedRoomFromLocal(e){return Se(this.getRuntime(),this.managedRoomBinder,e)}stewardSayFromLocal(e){const t=typeof e.sessionId=="string"?e.sessionId:"",s=typeof e.text=="string"?e.text:"";return t?L(this.getRuntime(),t,s):N(this.getRuntime(),s)}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const r=Ke();Ce(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:r,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),Pe({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:r}),p(this.client);const n=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:n,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:n,reason:t.reason,...t.message?{message:t.message}:{}},seq:n,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const r=u().find(n=>n.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:r?.modelId??s.params.modelId,sessionMode:r?.sessionMode??s.params.sessionMode,managerConfig:r?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:r?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await Ie(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){await this.deletionSynchronizer.synchronize()}async applySessionDeletion(e){const t=new Ee({daemonInstallationId:m()}),s=u().find(o=>o.sessionId===e.sessionId)?.codexSettings?.codexHome;let r=[];try{r=Qe(e.sessionId,{records:u()})}catch(o){console.warn("[session.deletions] local native source lookup failed",{error:o instanceof Error?o.message:String(o)})}t.recordSession(e);for(const o of[...e.sources,...r]){const h=t.find(o.agentType,o.sourceSessionKey);h&&h.sessionId!==e.sessionId||t.record({...e,...o})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const n=this.sessions.get(e.sessionId);if(n){this.revokeManagedRoomToken(n);try{await n.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),je(e.sessionId),Ae(e.sessionId),Te(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e,s),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const r=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:r,canStop:s.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:n,runPhase:s.runPhase,canStop:s.canStop??!0},seq:n,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of S())t.startsWith("custom:")&&k(t);const e=I();for(const[t,s]of Object.entries(e.customAgents??{}))ye(t,s);be(Re(),new Set(Object.keys(e.customAgents??{})))}async handleReq(e,t={}){const s=this.getRuntime();let r;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?r={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await B(s,e);break;case"chat.enqueue":c(e.params),r={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.codex.settings.get":case"chat.codex.settings.set":z(s,e);break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await O(s,e);break;case"session.refresh":c(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":J(s,e);break;case"session.tool.detail":await _(s,e);break;case"voice.session.body.window":V(s,e);break;case"session.title.set":await U(s,e);break;case"room.agent.bind-managed":await ke(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await we(s,this.managedRoomBinder,e);break;case"personal.recording":case"personal.workspace":case"personal.apps.list":case"personal.apps.register":case"personal.apps.remove":case"personal.service":await G(s,e);break;case"fs.ls":await Z(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await _e(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await Y(s,e);break;case"fs.write":await ee(s,e);break;case"fs.export.markdown-pdf":await ne(s,e);break;case"fs.export.markdown-pdf.setup":await ie(s,e);break;case"fs.archive.zip":await oe(s,e);break;case"fs.rename":await q(s,e);break;case"fs.transfer.start":await re(s,e);break;case"fs.transfer.chunk":await te(s,e);break;case"fs.transfer.finish":await ae(s,e);break;case"fs.transfer.abort":await se(s,e);break;case"region.probe":await ce(s,e);break;case"region.switch":await le(s,e);break;case"upgrade.start":await A(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:n=>this.prepareForUpgrade(n),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await T(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ue(s,e);break;case"machine.remote-access.pause":await K(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await P(s,e);break;case"agent.permission.respond":await Ue(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await Je(s,e);break;case"models.refresh":await C(s,e);break;case"agent.config.get":await E(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await F(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await $(s,e);break;case"agent.capabilities.list":await D(s,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(n){if(t.propagateErrors)throw n;this.client.sendRes({type:"res",id:e.id,ok:!1,error:n instanceof Error?n.message:String(n)})}finally{this.activeRequests--}return r}evictIdleSessions(){if(this.sessions.size<Ge)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return ve(e)}resolveAuthorizedPath(e,t){return ge(e,me(t))}async resolveAuthorizedPathAsync(e,t){return fe(e,await pe(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),X(this.getRuntime()),await this.managerRuntime.stop(),d(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{et as SessionManager,at as resolveSessionWorkDir,Ke as upgradeRecoveryVisibleMessage};
@@ -1 +1 @@
1
- import o from"node:fs";import a from"node:path";import{getShennianDir as s}from"../config/index.js";import{assertPathsSeparate as d}from"./workspace.js";import{readPersonalPaths as l,savePersonalPaths as y}from"./settings.js";function f(e){if(!a.isAbsolute(e)||/[\u0000-\u001f]/.test(e))throw new Error("personal_absolute_directory_required");const r=a.resolve(e);d(r,s());let t=r;for(;;){try{if(o.lstatSync(t).isSymbolicLink())throw new Error("personal_symlink_forbidden")}catch(c){if(c.code!=="ENOENT")throw c}const n=a.dirname(t);if(n===t)break;t=n}if(o.existsSync(r)&&!o.statSync(r).isDirectory())throw new Error("personal_directory_required");o.mkdirSync(r,{recursive:!0,mode:448});const i=o.realpathSync(r);return d(i,o.existsSync(s())?o.realpathSync(s()):s()),i}function _(e){if(!e.workspace&&!e.diary)throw new Error("personal_directory_required");const r={...l()};return e.workspace&&(r.workspace=f(e.workspace)),e.diary&&(r.diary=f(e.diary)),y(r),r}export{_ as configurePersonalPaths,f as validatePersonalDirectory};
1
+ import o from"node:fs";import i from"node:path";import{getShennianDir as t}from"../config/index.js";import{assertPathsSeparate as y}from"./workspace.js";import{readPersonalPaths as d,savePersonalPaths as f}from"./settings.js";function l(r){if(!i.isAbsolute(r)||/[\u0000-\u001f]/.test(r))throw new Error("personal_absolute_directory_required");const e=i.resolve(r);y(e,t());let a=e;for(;;){try{if(o.lstatSync(a).isSymbolicLink())throw new Error("personal_symlink_forbidden")}catch(n){if(n.code!=="ENOENT")throw n}const c=i.dirname(a);if(c===a)break;a=c}if(o.existsSync(e)&&!o.statSync(e).isDirectory())throw new Error("personal_directory_required");o.mkdirSync(e,{recursive:!0,mode:448});const s=o.realpathSync(e);return y(s,o.existsSync(t())?o.realpathSync(t()):t()),s}function _(r){if(!r.workspace&&!r.diary&&!r.clearDiary||r.diary&&r.clearDiary)throw new Error("personal_directory_required");const e={...d()};return r.workspace&&(e.workspace=l(r.workspace)),r.clearDiary&&delete e.diary,r.diary&&(e.diary=l(r.diary)),f(e),e}export{_ as configurePersonalPaths,l as validatePersonalDirectory};
@@ -0,0 +1 @@
1
+ import{loadConfig as a}from"../config/index.js";import{SERVERS as i}from"../region.js";async function s(e,n=fetch){const r=a();if(!r.machineToken||!r.machineId)throw new Error("not_paired");const o=await n(`${(r.serverUrl??i.cn.url).replace(/\/$/,"")}/api/personal-workspace/primary-machine-cli`,{method:e?"PUT":"GET",redirect:"error",signal:AbortSignal.timeout(3e4),headers:{authorization:`Bearer ${r.machineToken}`,"content-type":"application/json"},...e?{body:JSON.stringify({...e,machineId:r.machineId})}:{}});if(!o.ok)throw new Error(o.status===409?"personal_primary_conflict":"personal_primary_request_failed");return o.json()}export{s as primaryMachineRequest};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.5.37",
3
+ "version": "0.5.39",
4
4
  "description": "Shennian \u2014 AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {