shennian 0.5.36 → 0.5.38

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": 294,
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": 3628,
600
- "afterBytes": 1852
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,16 @@
884
889
  "beforeBytes": 910,
885
890
  "afterBytes": 479
886
891
  },
892
+ {
893
+ "file": "src/personal-workspace/recordings.js",
894
+ "beforeBytes": 10606,
895
+ "afterBytes": 5756
896
+ },
897
+ {
898
+ "file": "src/personal-workspace/service.js",
899
+ "beforeBytes": 6845,
900
+ "afterBytes": 3885
901
+ },
887
902
  {
888
903
  "file": "src/region.js",
889
904
  "beforeBytes": 3029,
@@ -1194,6 +1209,21 @@
1194
1209
  "beforeBytes": 676,
1195
1210
  "afterBytes": 392
1196
1211
  },
1212
+ {
1213
+ "file": "src/session/handlers/personal-recording.js",
1214
+ "beforeBytes": 522,
1215
+ "afterBytes": 362
1216
+ },
1217
+ {
1218
+ "file": "src/session/handlers/personal-workspace.js",
1219
+ "beforeBytes": 519,
1220
+ "afterBytes": 366
1221
+ },
1222
+ {
1223
+ "file": "src/session/handlers/personal.js",
1224
+ "beforeBytes": 582,
1225
+ "afterBytes": 332
1226
+ },
1197
1227
  {
1198
1228
  "file": "src/session/handlers/project-fs.js",
1199
1229
  "beforeBytes": 3778,
@@ -1251,8 +1281,8 @@
1251
1281
  },
1252
1282
  {
1253
1283
  "file": "src/session/manager.js",
1254
- "beforeBytes": 42449,
1255
- "afterBytes": 22329
1284
+ "beforeBytes": 42545,
1285
+ "afterBytes": 22383
1256
1286
  },
1257
1287
  {
1258
1288
  "file": "src/session/native-cleanup-outbox.js",
@@ -1384,6 +1414,11 @@
1384
1414
  "beforeBytes": 19384,
1385
1415
  "afterBytes": 9616
1386
1416
  },
1417
+ {
1418
+ "file": "src/steward/configure.js",
1419
+ "beforeBytes": 1912,
1420
+ "afterBytes": 1094
1421
+ },
1387
1422
  {
1388
1423
  "file": "src/steward/failover.js",
1389
1424
  "beforeBytes": 4394,
@@ -1394,20 +1429,30 @@
1394
1429
  "beforeBytes": 3176,
1395
1430
  "afterBytes": 5735
1396
1431
  },
1432
+ {
1433
+ "file": "src/steward/primary-machine.js",
1434
+ "beforeBytes": 1085,
1435
+ "afterBytes": 669
1436
+ },
1397
1437
  {
1398
1438
  "file": "src/steward/session.js",
1399
1439
  "beforeBytes": 3433,
1400
1440
  "afterBytes": 2758
1401
1441
  },
1442
+ {
1443
+ "file": "src/steward/settings.js",
1444
+ "beforeBytes": 1649,
1445
+ "afterBytes": 1015
1446
+ },
1402
1447
  {
1403
1448
  "file": "src/steward/templates.js",
1404
- "beforeBytes": 5392,
1405
- "afterBytes": 9262
1449
+ "beforeBytes": 6079,
1450
+ "afterBytes": 10546
1406
1451
  },
1407
1452
  {
1408
1453
  "file": "src/steward/workspace.js",
1409
- "beforeBytes": 3881,
1410
- "afterBytes": 1828
1454
+ "beforeBytes": 3740,
1455
+ "afterBytes": 1903
1411
1456
  },
1412
1457
  {
1413
1458
  "file": "src/support/support-client.js",
@@ -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,3 +1,8 @@
1
- import c from"node:fs";import{callDaemonIpc as u}from"../daemon-ipc/client.js";import{DaemonIpcError as r}from"../daemon-ipc/protocol.js";import{STEWARD_SAY_MAX_CHARS as m,STEWARD_SESSION_ID_ENV as h}from"../steward/session.js";const y={write:a=>process.stdout.write(a),fail:()=>{process.exitCode=1}};function x(a,e={}){const o=e.io??y,d=e.callDaemon??u,t=e.env??process.env,l=e.readStdin??(()=>c.readFileSync(0,"utf8"));a.command("steward").description("Talk to the user as the Shennian steward").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(f,w)=>{try{const n=t[h]?.trim(),s=p(f,w,l),i=await d({method:"steward.say",params:n?{sessionId:n,text:s}:{text:s}});o.write(`${JSON.stringify({ok:!0,command:"steward.say",result:i})}
2
- `)}catch(n){const s=n instanceof r,i=!s&&n?.code==="ENOENT";o.write(`${JSON.stringify({ok:!1,error:s?n.code:i?"daemon_unavailable":"steward_command_failed",message:s?n.message:i?"Shennian is not running on this computer.":"Shennian steward command failed.",nextAction:null})}
3
- `),o.fail()}})}function p(a,e,o){if([a!==void 0,e.file!==void 0,e.stdin===!0].filter(Boolean).length!==1)throw new r("steward_say_invalid","Provide exactly one of: text, --file, --stdin.");let t;if(e.file!==void 0)try{t=c.readFileSync(e.file,"utf8")}catch{throw new r("steward_say_invalid","The message file could not be read.")}else if(e.stdin)try{t=o()}catch{throw new r("steward_say_invalid","Standard input could not be read.")}else t=a??"";if(t=t.trim(),!t||t.length>m)throw new r("steward_say_invalid",`Provide a non-empty message of at most ${m} characters.`);return t}export{x 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 v from"node:os";import c from"node:path";import{createHash as D,randomUUID as A}from"node:crypto";import{getShennianDir as y}from"../config/index.js";import{assertPathsSeparate as m}from"../steward/workspace.js";const E=e=>{if(typeof e!="string"||!/^[\w-]{1,100}$/.test(e))throw new Error("recording_invalid_id");return e},S=e=>D("sha256").update(e).digest("hex"),p=e=>{if(!t.existsSync(e))return null;if(t.lstatSync(e).isSymbolicLink())return i("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):i("path_forbidden")}finally{t.closeSync(n)}},i=e=>{throw new Error(`recording_${e}`)},g=()=>c.join(y(),"personal-recordings.json");let h=null;const x=()=>{if(process.env.SHENNIAN_RECORDINGS_DIR)return process.env.SHENNIAN_RECORDINGS_DIR;if(h)return h;try{const e=JSON.parse(t.readFileSync(g(),"utf8"));return typeof e.directory!="string"||!c.isAbsolute(e.directory)?i("directory_invalid"):(h=e.directory,h)}catch(e){if(e.code==="ENOENT")return h=c.join(v.homedir(),"shennian_recordings"),h;throw e}};function J(){return N()}function G(e){if(process.env.SHENNIAN_RECORDINGS_DIR)return i("directory_env_override");if(!c.isAbsolute(e)||/[\u0000-\u001f]/.test(e))return i("directory_invalid");const n=c.resolve(e);m(n,y());const o=process.env.SHENNIAN_RECORDINGS_DIR;try{process.env.SHENNIAN_RECORDINGS_DIR=n,N()}finally{o===void 0?delete process.env.SHENNIAN_RECORDINGS_DIR:process.env.SHENNIAN_RECORDINGS_DIR=o}t.mkdirSync(y(),{recursive:!0,mode:448});const s=`${g()}.${A()}.tmp`;try{t.writeFileSync(s,JSON.stringify({directory:n}),{mode:384,flag:"wx"}),t.renameSync(s,g())}finally{try{t.unlinkSync(s)}catch{}}return n}function N(){const e=x();if(!c.isAbsolute(e))return i("directory_invalid");const n=c.resolve(e);m(n,y());let o=n;for(;;){try{if(t.lstatSync(o).isSymbolicLink())return i("path_forbidden")}catch(d){if(d.code!=="ENOENT")throw d}const f=c.dirname(o);if(f===o)break;o=f}t.mkdirSync(n,{recursive:!0,mode:448});const s=t.realpathSync(n),u=t.statSync(s);if(!u.isDirectory())return i("directory_invalid");if(process.platform!=="win32"){if(typeof process.getuid=="function"&&u.uid!==process.getuid())return i("directory_owner");u.mode&63&&t.chmodSync(s,448)}return m(s,t.existsSync(y())?t.realpathSync(y()):y()),s}function j(e){let n=N();for(const o of e){n=c.join(n,E(o));let s=null;try{s=t.lstatSync(n)}catch(f){if(f.code!=="ENOENT")throw f}if(s?.isSymbolicLink())return i("path_forbidden");s||t.mkdirSync(n,{mode:448});const u=t.lstatSync(n);if(!u.isDirectory())return i("path_forbidden");if(process.platform!=="win32"){if(typeof process.getuid=="function"&&u.uid!==process.getuid())return i("directory_owner");u.mode&63&&t.chmodSync(n,448)}}return n}function _(e,n,o){const s=c.join(e,`${A()}.tmp`);try{const u=t.openSync(s,"wx",384);try{t.writeFileSync(u,o),t.fsyncSync(u)}finally{t.closeSync(u)}if(t.renameSync(s,c.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 L(e){try{if(!e||!["chunk","commit"].includes(e.action))return i("invalid_request");const n=j([e.userId,e.sessionKey,e.batchKey]),o=c.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 i("invalid_chunk");const r=Buffer.from(e.base64,"base64");if(r.length!==e.size||S(r)!==e.sha256)return i("chunk_mismatch");const l=`${e.index}.chunk`,a=c.join(n,l),b=p(a);if(b){if(!b.equals(r))return i("chunk_conflict")}else{const I=p(o);if(I){const O=JSON.parse(I.toString("utf8"));return O.chunks[e.index]?.size!==e.size||O.chunks[e.index]?.sha256!==e.sha256?i("chunk_conflict"):{persisted:!0,complete:!0}}_(n,l,r)}return{persisted:!0,complete:t.existsSync(o)}}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(r=>!Number.isInteger(r.size)||r.size<1||r.size>128e3||!/^[a-f0-9]{64}$/.test(r.sha256)))return i("invalid_request");const s=e.transcript;if(s.some(r=>!r||typeof r!="object"||typeof r.text!="string"))return i("invalid_request");const u=[];for(let r=0;r<e.chunks.length;r++){const l=p(c.join(n,`${r}.chunk`));if(l)u.push(l);else if(!t.existsSync(o))return i("missing_chunk")}const f=u.length===e.chunks.length?Buffer.concat(u):null,d={sessionKey:e.sessionKey,batchKey:e.batchKey,startedAt:e.startedAt,endedAt:e.endedAt,audioFormat:{encoding:"pcm16le",sampleRate:16e3,channels:1},chunks:e.chunks,audioSize:f?.length??e.chunks.reduce((r,l)=>r+l.size,0),audioSha256:f?S(f):null,transcript:s},R=JSON.stringify(d),k=p(o);if(k){const r=JSON.parse(k.toString("utf8"));return r.sessionKey!==d.sessionKey||r.batchKey!==d.batchKey||r.startedAt!==d.startedAt||r.endedAt!==d.endedAt||JSON.stringify(r.chunks)!==JSON.stringify(d.chunks)?i("batch_conflict"):{persisted:!0,complete:!0}}for(let r=0;r<e.chunks.length;r++){const l=c.join(n,`${r}.chunk`),a=p(l);if(!a)return i("missing_chunk");if(a.length!==e.chunks[r].size||S(a)!==e.chunks[r].sha256)return i("chunk_mismatch")}if(!f)return i("missing_chunk");_(n,"audio.pcm",f),_(n,"manifest.json",Buffer.from(R));for(let r=0;r<e.chunks.length;r++)t.unlinkSync(c.join(n,`${r}.chunk`));return{persisted:!0,complete:!0}}catch(n){if(["ENOSPC","EDQUOT"].includes(n.code??""))return i("storage_full");throw n}}export{G as configureRecordingDirectory,L as receivePersonalRecording,J as recordingDirectory};
@@ -0,0 +1 @@
1
+ import a from"node:fs";import p from"node:path";import{getStewardDir as b,assertPathsSeparate as k}from"../steward/workspace.js";import{readPersonalPaths as x}from"../steward/settings.js";import{getShennianDir as h}from"../config/index.js";const S=512*1024,O=/\.(md|txt|json|yaml|yml|csv|tsv|log)$/i,$=t=>!t||t.startsWith(".")||/(?:^|[-_])(credentials?|secrets?|tokens?|passwords?|private[-_]?key)(?:[._-]|$)/i.test(t)||/\.(pem|key|p12|pfx|keystore)$/i.test(t),r=t=>{throw new Error(`personal_${t}`)};function N(t){return t===void 0||t===""?"":typeof t!="string"||t.length>2e3||/[\\\u0000-\u001f:]/.test(t)||t.startsWith("/")||t.split("/").some($)?r("path_forbidden"):t}function F(t){const e=t==="memory"?b():t==="diary"?x().diary:void 0;if(!e)return r("directory_not_configured");k(e,h());let n=e;for(;;){if(a.lstatSync(n).isSymbolicLink())return r("path_forbidden");const o=p.dirname(n);if(o===n)break;n=o}const s=a.realpathSync(e);return k(s,a.existsSync(h())?a.realpathSync(h()):h()),a.statSync(s).isDirectory()?s:r("directory_unavailable")}function _(t,e){let n=t;for(const f of e?e.split("/"):[])if(n=p.join(n,f),a.lstatSync(n).isSymbolicLink())return r("path_forbidden");const s=a.realpathSync(n),o=p.relative(t,s);return o.startsWith("..")||p.isAbsolute(o)?r("path_forbidden"):s}function D(t,e){if(!O.test(e))return r("text_only");const n=_(t,e),s=a.openSync(n,a.constants.O_RDONLY|(a.constants.O_NOFOLLOW??0));try{const o=a.fstatSync(s);if(!o.isFile())return r("text_only");if(o.size>S)return r("file_too_large");const f=Buffer.alloc(S+1),d=a.readSync(s,f,0,f.length,0);if(d>S)return r("file_too_large");if(_(t,e)!==n||a.statSync(n).ino!==o.ino)return r("file_changed");const i=f.subarray(0,d).toString("utf8");return i.includes("\0")?r("text_only"):i}finally{a.closeSync(s)}}function T(t){return t===void 0?0:!Number.isSafeInteger(t)||Number(t)<0||Number(t)>1e5?r("invalid_request"):Number(t)}function g(t){const e=/^(\d{4})\/(\d{4}-\d{2}-\d{2})\.md$/.exec(t);if(!e||e[1]!==e[2].slice(0,4))return null;const n=new Date(`${e[2]}T00:00:00Z`);return Number.isNaN(n.getTime())||n.toISOString().slice(0,10)!==e[2]?null:e[2]}function v(t){if(!t||typeof t!="object"||Array.isArray(t))return r("invalid_request");const e=t;if(Object.keys(e).some(i=>!["action","kind","path","offset"].includes(i)))return r("invalid_request");if(e.action==="info")return{workspace:b(),diary:x().diary??null,readOnly:!0};if(!["list","read","diary"].includes(String(e.action))||e.kind!=="memory"&&e.kind!=="diary")return r("invalid_request");const n=F(e.kind),s=N(e.path),o=T(e.offset);if(e.action==="read")return e.kind==="diary"&&!g(s)?r("path_forbidden"):{path:s,content:D(n,s)};if(e.action==="diary"){if(e.kind!=="diary"||s)return r("invalid_request");const i=a.readdirSync(n,{withFileTypes:!0}).filter(c=>c.isDirectory()&&/^\d{4}$/.test(c.name));if(i.length>300)return r("directory_too_large");const l=[];for(const c of i){const u=a.readdirSync(_(n,c.name),{withFileTypes:!0});if(u.length>500)return r("directory_too_large");for(const y of u){const m=`${c.name}/${y.name}`;y.isFile()&&g(m)&&l.push(m)}}return l.sort().reverse(),{entries:l.slice(o,o+30).map(c=>{let u="",y="";try{const m=D(n,c);u=/^#\s+(.+)$/m.exec(m)?.[1]?.slice(0,200)??"",y=/^>\s*概要[::]\s*(.+)$/m.exec(m)?.[1]?.slice(0,300)??""}catch{}return{path:c,date:g(c),title:u,summary:y}}),nextOffset:o+30<l.length?o+30:null}}if(e.kind!=="memory")return r("invalid_request");const f=a.readdirSync(_(n,s),{withFileTypes:!0});if(f.length>1e4)return r("directory_too_large");const d=f.filter(i=>!$(i.name)&&!i.isSymbolicLink()&&(i.isDirectory()||i.isFile())).sort((i,l)=>Number(l.isDirectory())-Number(i.isDirectory())||i.name.localeCompare(l.name));return{path:s,entries:d.slice(o,o+100).map(i=>({name:i.name,path:s?`${s}/${i.name}`:i.name,isDir:i.isDirectory()})),nextOffset:o+100<d.length?o+100:null}}export{v as personalWorkspace};
@@ -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{personalWorkspace as o}from"../../personal-workspace/service.js";async function t(r,e){try{r.client.sendRes({type:"res",id:e.id,ok:!0,payload:o(e.params)})}catch(s){const a=s instanceof Error?s.message:"";r.client.sendRes({type:"res",id:e.id,ok:!1,error:/^personal_[a-z_]+$/.test(a)?a:"personal_directory_unavailable"})}}export{t as handlePersonalWorkspace};
@@ -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{handleLocalApps as G}from"./handlers/local-apps.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 Le,dispatchQueuedChat as Ve,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)=>Le(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ve(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?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=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":L(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.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
+ 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};
@@ -0,0 +1 @@
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};
@@ -0,0 +1,2 @@
1
+ import o from"node:fs";import s from"node:os";import n from"node:path";import{randomUUID as a}from"node:crypto";import{getShennianDir as t}from"../config/index.js";const i=()=>n.join(t(),"personal-paths.json");function m(){try{const r=JSON.parse(o.readFileSync(i(),"utf8"));if(!r||typeof r!="object"||Array.isArray(r))throw new Error;for(const e of["workspace","diary"])if(r[e]!==void 0&&(typeof r[e]!="string"||!n.isAbsolute(r[e])))throw new Error;return{workspace:r.workspace,diary:r.diary}}catch(r){if(r.code==="ENOENT")return{};throw new Error("personal_settings_invalid")}}function d(){const r=`${t()}-steward`;return o.existsSync(r)||process.env.SHENNIAN_HOME||process.env.VITEST?r:n.join(s.homedir(),"shennian_agent")}function u(r){o.mkdirSync(t(),{recursive:!0,mode:448});const e=`${i()}.${a()}.tmp`;try{o.writeFileSync(e,JSON.stringify(r,null,2)+`
2
+ `,{mode:384,flag:"wx"}),o.renameSync(e,i())}finally{try{o.unlinkSync(e)}catch{}}}export{d as defaultWorkspace,m as readPersonalPaths,u as savePersonalPaths};
@@ -45,6 +45,13 @@ import{STEWARD_INDEX_ONBOARDING as n}from"./onboarding.js";const e=4,s=`<!-- she
45
45
 
46
46
  ${n}
47
47
 
48
+ ## \u65E5\u8BB0\u4E0E\u8BB0\u5FC6
49
+
50
+ - Personal Agent \u5DE5\u4F5C\u533A\u4E0E\u65E5\u8BB0\u76EE\u5F55\u7531 Client \u5206\u522B\u914D\u7F6E\u3002\u7528 shennian steward paths \u67E5\u770B\u5B9E\u9645\u8DEF\u5F84\uFF0C\u4E0D\u5199\u6B7B\u7528\u6237\u76EE\u5F55\uFF0C\u4E0D\u628A\u672A\u914D\u7F6E\u89E3\u91CA\u4E3A\u7A7A\u65E5\u8BB0\u3002
51
+ - \u53EA\u6709\u7528\u6237\u660E\u786E\u8981\u6C42\u8BB0\u65E5\u8BB0\u3001\u8865\u8BB0\u6216\u7FFB\u770B\u65F6\u624D\u8FDB\u5165\u65E5\u8BB0\u76EE\u5F55\uFF1B\u4E00\u5929\u4E00\u7BC7\uFF0C\u4EE5\u7528\u6237\u8BBE\u5B9A\u7684\u65F6\u533A\uFF08\u672A\u8BBE\u65F6\u5148\u786E\u8BA4\uFF09\u4FDD\u5B58\u4E3A YYYY/YYYY-MM-DD.md\u3002
52
+ - \u6B63\u6587\u4F7F\u7528 # \u65E5\u671F\uFF5C\u4E00\u53E5\u8BDD\u5C0F\u6807\u9898\uFF0C\u4E0B\u4E00\u884C > \u6982\u8981\uFF1A\u2026\uFF1B\u53EA\u4F9D\u636E\u7528\u6237\u63D0\u4F9B\u7684\u7ECF\u5386\u8BB0\u5F55\uFF0C\u4E0D\u7F16\u9020\uFF0C\u5DF2\u6709\u6B63\u6587\u5148\u8BFB\u518D\u8865\u5145\uFF0C\u4E0D\u8986\u76D6\u3002
53
+ - \u65E5\u8BB0\u6807\u9898\u3001\u6982\u8981\u548C\u6B63\u6587\u4E0D\u8FDB\u5165\u5168\u5C40\u8D44\u6599\u7D22\u5F15\u3002\u624B\u673A\u65E5\u8BB0\u548C\u8BB0\u5FC6\u9996\u7248\u53EA\u8BFB\uFF0C\u4E0D\u56E0\u6D4F\u89C8\u8BF7\u6C42\u7F16\u8F91\u6216\u81EA\u52A8\u751F\u6210\u6587\u4EF6\u3002
54
+
48
55
  ## \u8BB0\u5F55
49
56
 
50
57
  - \u53EA\u5728\u7528\u6237\u8981\u6C42\uFF0C\u6216\u51FA\u73B0\u957F\u671F\u6709\u7528\u7684\u4FE1\u606F\uFF08\u65B0\u9879\u76EE\u7684\u7528\u9014\u3001\u5E38\u7528\u7FA4\u7684\u7EA6\u5B9A\uFF09\u65F6\uFF0C\u624D\u66F4\u65B0 index.md \u7B49\u6587\u4EF6\u3002\u4E0D\u8981\u5199\u6D88\u606F\u6570\u3001\u5728\u7EBF\u72B6\u6001\u3001\u6210\u5458\u540D\u5355\u8FD9\u7C7B\u5B9E\u65F6\u5185\u5BB9\u3002
@@ -1 +1 @@
1
- import o from"node:fs";import n from"node:path";import{getShennianDir as c}from"../config/index.js";import{STEWARD_AGENTS_MD as u,STEWARD_CLAUDE_MD as h,STEWARD_INDEX_MD as l}from"./templates.js";class a extends Error{code;constructor(r,t){super(t),this.code=r}}function m(){return`${c()}-steward`}const S=[["AGENTS.md",u],["index.md",l],["CLAUDE.md",h]];function v(){const e=m();w(e,c()),y(e),w(o.realpathSync.native(e),E(c()));const r=[];for(const[t,s]of S){const f=n.join(e,t);try{o.writeFileSync(f,s,{encoding:"utf8",mode:384,flag:"wx"}),r.push(t)}catch(i){if(i.code!=="EEXIST")throw i}}return{dir:o.realpathSync.native(e),created:r}}function y(e){let r=null;try{r=o.lstatSync(e)}catch(s){if(s.code!=="ENOENT")throw s}if(r?.isSymbolicLink())throw new a("steward_workspace_symlink","The steward workspace path must not be a symbolic link.");if(r&&!r.isDirectory())throw new a("steward_workspace_not_directory","The steward workspace path is not a directory.");if(r||o.mkdirSync(e,{mode:448}),process.platform==="win32")return;const t=o.lstatSync(e);if(typeof process.getuid=="function"&&t.uid!==process.getuid())throw new a("steward_workspace_owner","The steward workspace is owned by another user.");(t.mode&63)!==0&&o.chmodSync(e,448)}function E(e){try{return o.realpathSync.native(e)}catch{return n.resolve(e)}}function p(e){const r=n.resolve(e);return process.platform==="win32"||process.platform==="darwin"?r.toLowerCase():r}function d(e,r){const t=n.relative(p(r),p(e));return t===""||!t.startsWith("..")&&!n.isAbsolute(t)}function w(e,r){if(d(e,r)||d(r,e))throw new a("steward_workspace_overlaps_credentials","The steward workspace must be separate from the Shennian credential directory.")}export{S as STEWARD_FILES,a as StewardWorkspaceError,w as assertPathsSeparate,v as ensureStewardWorkspace,m as getStewardDir};
1
+ import o from"node:fs";import n from"node:path";import{getShennianDir as i}from"../config/index.js";import{readPersonalPaths as u,defaultWorkspace as h}from"./settings.js";import{STEWARD_AGENTS_MD as l,STEWARD_CLAUDE_MD as m,STEWARD_INDEX_MD as S}from"./templates.js";class a extends Error{code;constructor(r,t){super(t),this.code=r}}function y(){return u().workspace??h()}const E=[["AGENTS.md",l],["index.md",S],["CLAUDE.md",m]];function W(){const e=y();w(e,i()),_(e),w(o.realpathSync.native(e),k(i()));const r=[];for(const[t,s]of E){const f=n.join(e,t);try{o.writeFileSync(f,s,{encoding:"utf8",mode:384,flag:"wx"}),r.push(t)}catch(c){if(c.code!=="EEXIST")throw c}}return{dir:o.realpathSync.native(e),created:r}}function _(e){let r=null;try{r=o.lstatSync(e)}catch(s){if(s.code!=="ENOENT")throw s}if(r?.isSymbolicLink())throw new a("steward_workspace_symlink","The steward workspace path must not be a symbolic link.");if(r&&!r.isDirectory())throw new a("steward_workspace_not_directory","The steward workspace path is not a directory.");if(r||o.mkdirSync(e,{mode:448}),process.platform==="win32")return;const t=o.lstatSync(e);if(typeof process.getuid=="function"&&t.uid!==process.getuid())throw new a("steward_workspace_owner","The steward workspace is owned by another user.");(t.mode&63)!==0&&o.chmodSync(e,448)}function k(e){try{return o.realpathSync.native(e)}catch{return n.resolve(e)}}function p(e){const r=n.resolve(e);return process.platform==="win32"||process.platform==="darwin"?r.toLowerCase():r}function d(e,r){const t=n.relative(p(r),p(e));return t===""||!t.startsWith("..")&&!n.isAbsolute(t)}function w(e,r){if(d(e,r)||d(r,e))throw new a("steward_workspace_overlaps_credentials","The steward workspace must be separate from the Shennian credential directory.")}export{E as STEWARD_FILES,a as StewardWorkspaceError,w as assertPathsSeparate,W as ensureStewardWorkspace,y as getStewardDir};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.5.36",
3
+ "version": "0.5.38",
4
4
  "description": "Shennian \u2014 AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {