shennian 0.5.16 → 0.5.18

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": 279,
5
+ "fileCount": 280,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian-adapter-host.js",
@@ -434,6 +434,11 @@
434
434
  "beforeBytes": 963,
435
435
  "afterBytes": 465
436
436
  },
437
+ {
438
+ "file": "src/commands/contact.js",
439
+ "beforeBytes": 2049,
440
+ "afterBytes": 1217
441
+ },
437
442
  {
438
443
  "file": "src/commands/daemon-instance-lock.js",
439
444
  "beforeBytes": 4507,
@@ -661,8 +666,8 @@
661
666
  },
662
667
  {
663
668
  "file": "src/index.js",
664
- "beforeBytes": 45702,
665
- "afterBytes": 22628
669
+ "beforeBytes": 46996,
670
+ "afterBytes": 23133
666
671
  },
667
672
  {
668
673
  "file": "src/log-redaction.js",
@@ -931,8 +936,8 @@
931
936
  },
932
937
  {
933
938
  "file": "src/room/public-room-client.js",
934
- "beforeBytes": 6945,
935
- "afterBytes": 4002
939
+ "beforeBytes": 7119,
940
+ "afterBytes": 4117
936
941
  },
937
942
  {
938
943
  "file": "src/room/registration-authority.js",
@@ -1091,8 +1096,8 @@
1091
1096
  },
1092
1097
  {
1093
1098
  "file": "src/session/handlers/chat-events.js",
1094
- "beforeBytes": 20196,
1095
- "afterBytes": 8099
1099
+ "beforeBytes": 20267,
1100
+ "afterBytes": 8130
1096
1101
  },
1097
1102
  {
1098
1103
  "file": "src/session/handlers/chat-recovery.js",
@@ -1146,8 +1151,8 @@
1146
1151
  },
1147
1152
  {
1148
1153
  "file": "src/session/handlers/steward.js",
1149
- "beforeBytes": 7468,
1150
- "afterBytes": 3596
1154
+ "beforeBytes": 8421,
1155
+ "afterBytes": 3939
1151
1156
  },
1152
1157
  {
1153
1158
  "file": "src/session/handlers/title.js",
@@ -1306,18 +1311,18 @@
1306
1311
  },
1307
1312
  {
1308
1313
  "file": "src/skill/hosts.js",
1309
- "beforeBytes": 3462,
1310
- "afterBytes": 1577
1314
+ "beforeBytes": 4285,
1315
+ "afterBytes": 1940
1311
1316
  },
1312
1317
  {
1313
1318
  "file": "src/skill/updater.js",
1314
- "beforeBytes": 18411,
1315
- "afterBytes": 9229
1319
+ "beforeBytes": 19384,
1320
+ "afterBytes": 9616
1316
1321
  },
1317
1322
  {
1318
1323
  "file": "src/steward/failover.js",
1319
- "beforeBytes": 3819,
1320
- "afterBytes": 2378
1324
+ "beforeBytes": 4394,
1325
+ "afterBytes": 2607
1321
1326
  },
1322
1327
  {
1323
1328
  "file": "src/steward/session.js",
@@ -0,0 +1,3 @@
1
+ import{PublicRoomClient as s,PublicRoomClientError as n}from"../room/public-room-client.js";import{MANAGED_ROOM_CONTEXT_ENV as m}from"../room/managed-context.js";function f(i,c={}){const r=c.client??new s,o=c.io??{write:a=>process.stdout.write(a),fail:()=>{process.exitCode=1}};i.command("contact").description("Read the paired user's saved contacts").command("list").description("List saved contacts and owned Agents; not inferred from Room chats").option("--query <name>","Filter by display name (up to 80 characters)").action(async a=>{try{if(process.env[m]?.trim())throw new n("managed_room_action_forbidden","Contacts are not available in managed Room context.",{type:"ask_user",message:"A managed Agent cannot use the paired human identity."});const t=a.query?.trim();if(t&&t.length>80)throw new n("invalid_contact_query","--query must be at most 80 characters.");const e=await r.listContacts(t);o.write(`${JSON.stringify({ok:!0,command:"contact.list",result:e})}
2
+ `)}catch(t){const e=t instanceof n?t:new n("contact_command_failed","Shennian contact command failed.");o.write(`${JSON.stringify({ok:!1,error:e.code,message:e.message,nextAction:e.nextAction})}
3
+ `),o.fail()}})}export{f as registerContactCommand};
package/dist/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{registerScheduleCommand as be}from"./commands/schedule.js";import{resolvePersonalScheduleContext as ke}from"./schedules/personal-context.js";import{executeServerSchedule as re,deliverServerSchedule as Ae}from"./schedules/server-client.js";import{Command as Pe}from"commander";import T from"chalk";import Ee from"node:os";import{randomUUID as Te}from"node:crypto";import z from"node:fs";import{loadConfig as p,saveConfig as Ue,getConfigPath as De,getShennianDir as Me,resolveShennianPath as J,normalizeAutoUpgradePolicy as _e}from"./config/index.js";import{CliRelayClient as Ne}from"./relay/client.js";import{collectKnownLogSecrets as ae,installCliLogRedaction as xe,sanitizeCliLogValue as Oe}from"./log-redaction.js";import{registerPairCommand as $e,runSmartStart as Le}from"./commands/pair.js";import{registerLogoutCommand as Ve}from"./commands/logout.js";import{clearDaemonPidIfOwner as ie,createDaemonInstanceId as je,clearDaemonLauncher as se,findRunningDaemonProcessIds as He,isRemoteAccessDisabled as ce,prepareRemoteAccessPause as Fe,stopPreparedRemoteAccessService as Be,isIsolatedDaemonE2eInstance as We,getDaemonStatus as de,registerDaemonCommand as Ge,writeDaemonPid as le,writeDaemonLauncher as me}from"./commands/daemon.js";import{registerRuntimeCommand as qe}from"./commands/runtime.js";import{registerAdapterCommand as ze}from"./commands/adapter.js";import{registerAgentCommand as Je}from"./commands/agent.js";import{registerManagerCommand as Ke}from"./commands/manager.js";import{registerWorkerCommand as Qe}from"./commands/worker.js";import{registerProjectCommand as Ye}from"./commands/project.js";import{registerStewardCommand as Ze}from"./commands/steward.js";import{handleUpgradeStart as Xe,registerUpgradeCommand as eo}from"./commands/upgrade.js";import{registerToolsCommand as oo}from"./commands/tools.js";import{registerQueueCommand as no}from"./commands/queue.js";import{registerSkillCommand as to}from"./commands/skill.js";import{registerSetupCommand as ro}from"./commands/setup.js";import{getUnavailableAcpAgents as ao}from"./agents/acp/discovery.js";import{registerCommandReference as io}from"./commands/command-reference.js";import{registerIntegrationCommand as so}from"./commands/integration.js";import{registerRoomCommand as co}from"./commands/room.js";import{registerSupportCommand as lo}from"./commands/support.js";import{SessionManager as mo}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as po}from"./session/handlers/project-fs.js";import{SERVERS as K,regionToUrl as go,urlToRegion as uo}from"./region.js";import{clearUpgradeAttempt as fo,getCurrentVersion as pe,handleStartupCrashCheck as ho,readUpgradeAttempt as vo}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Io}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as So}from"./upgrade/updater-bootstrap.js";import{launchUpdater as yo,markUpdaterHealthy as wo}from"./upgrade/updater-launcher.js";import{detectAgents as ge}from"./agents/detect.js";import{PublicAgentDeliveryWorker as Co}from"./agents/public-delivery-worker.js";import{augmentProcessPath as ue}from"./env-path.js";import{acquireDaemonInstanceLock as Ro}from"./commands/daemon-instance-lock.js";ue();const U=pe();import{getCachedAgentInfos as V,resolveAgentInfos as bo}from"./agents/model-registry.js";import{initCliLogReporter as ko,reportLog as D,reportUpgradeAggregateMetric as Ao}from"./log-reporter.js";import{isNativeFusionEnabled as Po}from"./native-fusion/config.js";import{NativeSessionFusionService as Eo}from"./native-fusion/service.js";import{startDaemonLogRetention as To}from"./daemon-log.js";import{startDaemonIpcServer as fe}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as Uo,resolveManagedRoomIpcPaths as Do}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as Mo}from"./daemon-ipc/control.js";import{createAgentReadinessHandlers as _o}from"./daemon-ipc/agent-readiness.js";import{scanMachineAgents as he}from"./session/handlers/agents.js";import{validateAgentWorkspaceConfiguration as No}from"./session/handlers/agent-workspace-validation.js";import{DAEMON_IPC_VERSION as xo}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as Oo}from"./room/session-registry.js";import{HttpRoomBindingClient as $o}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as Lo}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Vo}from"./room/host-session-observations.js";import{RoomMirrorSyncService as jo}from"./room/mirror-sync-service.js";import{handleLiveRoomDelivery as Ho}from"./room/live-delivery.js";import{NativeSourceDeletionStore as Fo}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as Bo,isCurrentRegistration as Wo}from"./room/registration-authority.js";import{RoomActivationService as Go,resolveManagedAgentPolicy as qo}from"./room/activation-service.js";import{RoomActivationAudit as zo}from"./room/activation-audit.js";import{RoomAttachmentCache as Jo}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Ko}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as Qo}from"./room/managed-context.js";import{createManagedRoomExecutor as Yo}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as ve,SESSION_SYNC_ADVERTISED_CAPABILITIES as Ie}from"@shennian/wire";import{getDaemonInstallationId as Zo}from"./session/store.js";import{OWNER_DIRECT_TURN_OPTIONS as Xo}from"./session/queue-helpers.js";import{synchronizeMachinePersonalAuthority as en}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as Se,ensurePersonalDataEpoch as on}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as nn,DeletionSyncTerminalError as tn}from"./session/deletion-sync-state.js";const ye=Me(),rn=J("daemon.pid"),an=J("daemon.instance.lock");function sn(){try{const i=z.readFileSync(rn,"utf-8").trim();if(i.startsWith("{")){const g=JSON.parse(i),d=Number(g.pid);return Number.isInteger(d)&&d>0?d:null}const c=parseInt(i,10);return Number.isInteger(c)&&c>0?c:null}catch{return null}}function cn(i){return i.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function Q(){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 dn(i){const c=[`trigger=${i.trigger??"unknown"}`,`phase=${i.phase}`,`code=${i.code??"unknown"}`,`attempt=${i.reconnectAttempt}`];return i.reason&&c.push(`reason=${i.reason}`),i.error&&c.push(`error=${i.error}`),c.join(" ")}const a=new Pe;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(U),a.enablePositionalOptions(),so(a),co(a),lo(a),be(a),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",Ee.hostname()).action(async i=>{const c=p(),g=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??c.serverUrl??void 0;await Le(g,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 c=J("env.json");try{const e=JSON.parse(z.readFileSync(c,"utf-8"));for(const[n,o]of Object.entries(e))process.env[n]||(process.env[n]=o);ue()}catch{}xe(ae(process.env,p()));const g=To();ce()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(g),process.exit(0));const d=je(),C=Ro({lockPath:an,instanceId:d});C.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(C.ownerPid?` (PID ${C.ownerPid})`:"")+", skipping duplicate start"),clearInterval(g),process.exit(0));try{const e=sn();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 Y=We(process.env,ye)?[]:He(process.pid);Y.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${Y[0]}), skipping duplicate start`),C.release(),process.exit(0)),le(process.pid,d,{version:U}),me(process.pid,void 0,d),process.on("exit",()=>{ie(process.pid,d),se(d)}),process.on("exit",C.release);let j=null;try{j=So()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const M=await ho();if(M){j||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{yo({fromVersion:U,targetVersion:M.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:M.jobId},{readiness:j}),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{on()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const m=p(),u=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??m.serverUrl??K.cn.url,h=pe(),l=await ge({serverUrl:u,authToken:m.machineToken??m.accessToken}),S=l.map(e=>e.type);let H=V(l);const f=new Oo,_=new Vo,b=new Qo(f),y=new $o(u),Ce=new Jo({actionClient:y}),Re=new Ko({actionClient:y});let w=null,r;const Z=Yo({authority:b,actionClient:y,attachmentCache:Ce,attachmentUploader:Re,observations:_,getMachineCredentials:()=>({machineToken:p().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),onSendOutcome:e=>r.noteManagedRoomSendOutcome(e),getActiveRunId:(e,n)=>r.getManagedRoomActiveRunId(e,n),scheduleExecutor:(e,n,o)=>re({serverUrl:u,machineToken:p().machineToken,sessionId:e,action:n,args:o}),onPaused:({registryKey:e,sessionId:n})=>{const t=f.getByRegistryKey(e)?.binding;t&&f.setBinding({registryKey:e,bindingId:t.bindingId,roomId:t.roomId,agentIdentityId:t.agentIdentityId,agentMembershipId:t.agentMembershipId,status:"paused",activationMode:"paused"}),b.revokeSession(e),r?.discardPendingManagedRoomMessages(n)}});let F=null,B=null,W=null,G=null,X=!1;const k=await fe({paths:Uo(),handlers:{...Mo({daemonVersion:h,protocolVersion:xo,getStatus:()=>de(),getAgents:()=>l,requestShutdown:()=>{G?G():X=!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(!B)throw new Error("external_upgrade_unavailable");return B(e)},cancelExternalUpgrade:()=>{if(!W)throw new Error("external_upgrade_unavailable");return W()}}),..._o({getStatus:()=>de(),getSnapshot:()=>V(l).map(e=>{const n=l.find(o=>o.type===e.type);return{...e,runtimePlatform:n?.runtimePlatform,runtimeIsWsl:n?.runtimeIsWsl}}),getUnavailable:ao,discover:async e=>{if(!r)throw new Error("daemon_starting");const n=await he(!0,e);if(e){const t=l.filter(I=>I.type!==e);l.splice(0,l.length,...t,...n.detectedAgents)}else l.splice(0,l.length,...n.detectedAgents);const o=V(l);return s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:l.map(t=>t.type),agents:o}}),n.agents.map(t=>{const I=n.detectedAgents.find(q=>q.type===t.type);return{...t,runtimePlatform:I?.runtimePlatform,runtimeIsWsl:I?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return No(e,{ignoreNativeSession:(n,o)=>P?.ignoreNativeSource(n,o)})}})}});let A;try{A=await fe({paths:Do(),handlers:{"managed-room.execute":e=>Z(e),"schedule.personal":async e=>{const n=e,o=ke(n?.context);if(f.getByNianSessionId(o)?.binding)throw new Error("schedule_personal_context_required");return await re({serverUrl:u,machineToken:p().machineToken,sessionId:o,action:n.operation,args:n})}}})}catch(e){throw await k.close(),e}let ee=!1;const N=()=>{ee||(ee=!0,Promise.allSettled([k.close(),A.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",N),process.once("SIGTERM",N),!m.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([k.close(),A.close()]),process.exitCode=1;return}process.removeListener("SIGINT",N),process.removeListener("SIGTERM",N);const oe=`${cn(u)}/relay/machine`,x=m.machineToken;if(!x)return;try{await en({serverUrl:u,machineToken:x,machineId:m.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([k.close(),A.close()]),process.exit(1)}m.machineId&&ko(u,m.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${oe}... (v${h}) agents: ${S.join(",")}`),D({level:"info",wsEvent:"daemon.start",metadata:{version:h,agents:S}});let P=null,E=null,R=0,v=vo();const ne=_e(m.autoUpgrade),O=m.machineId?new Co({serverUrl:u,machineId:m.machineId,getMachineToken:()=>p().machineToken,getDetectedAgents:()=>ge({serverUrl:u,authToken:p().machineToken}),onRuntimeChanged:async()=>{const e=R,n=await he(!0);if(l.splice(0,l.length,...n.detectedAgents),S.splice(0,S.length,...n.agentList),H=n.agents,!(await s.sendReq({type:"req",id:Te(),method:"machine.agents.report",params:{agents:n.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 Ne({serverUrl:oe,machineToken:x,cliVersion:h,agentList:S,autoUpgradePolicy:ne,sessionSyncProtocolVersion:ve,sessionSyncCapabilities:Ie,daemonInstallationId:Zo(),dataEpoch:Se,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:H}}),bo(l,{serverUrl:m.serverUrl??u,authToken:m.machineToken??m.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(H)&&s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:S,agents:o}})}).catch(()=>{}),v&&s.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:v.from,to:v.to,...v.jobId?{jobId:v.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),$.start(),E?.start();const e=++R,n=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),v){const o=v;v=null,o.jobId&&wo(o.jobId,o.to),fo(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),Ao({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}})}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 tn)return;const t=o instanceof nn?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{n()},t).unref?.()}}};n()},onDisconnected:e=>{R+=1,r?.revokeProjectFsHandles(),O?.stop(),E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${dn(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=Po()?new Eo(s):null,E=new jo({registry:f,observations:_,actionClient:y,getMachineCredentials:()=>({machineToken:p().machineToken}),isSessionDeleted:e=>new Fo().hasSession(e),onMessages:async(e,n,o,t)=>{await w?.processMessages(e,n,o,t)},onBindingPaused:e=>{e.lifecycleState==="closed"?(b.revokeSession(e.registryKey),r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")})):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const $=new Io({currentVersion:h,machineId:m.machineId??"unknown-machine",serverUrl:m.serverUrl??u,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:ve,dataEpoch:Se,advertisedCapabilities:Ie,updaterProtocolVersion:1,startUpgrade:async(e,n)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(s,"auto-upgrade",e,{currentVersion:h,prepareForUpgrade:t=>r.prepareForUpgrade(t),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:n?void 0:()=>r.getUpgradeIdleState().idle})}});$.setPolicy(ne),r=new mo(s,P,h,$,new Lo({registry:f,observations:_,bindingClient:y,getMachineCredentials:()=>{const e=p();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${d}`}),{prepare:()=>Fe(),isDisabled:()=>ce(),shutdownAfterResponse:()=>{setTimeout(()=>{Be(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>b.revokeToken(e),Z,null,po(x),()=>V(l)),F=async e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof n.targetVersion=="string"?n.targetVersion:void 0,t=n.confirmedMajor===!0;return await Xe(s,`local-upgrade-${Date.now()}`,o,{currentVersion:h,confirmedMajor:t,prepareForUpgrade:q=>r.prepareForUpgrade(q),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},B=e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=`desktop-${(typeof n.targetVersion=="string"?n.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:t,...r.prepareForUpgrade(t)}},W=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),w=new Go({registry:f,observations:_,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const n=p().machineToken?.trim(),o=e.binding;if(!n||!o)throw new Error("managed_room_context_unavailable");const t=await y.status({machineToken:n,roomId:o.roomId,bindingId:o.bindingId});if(!Wo(f,e)||!Bo(e,t))throw new Error("managed_room_binding_unavailable");return{roomName:t.room.name,memberCount:t.room.memberCount,members:t.room.members,agentsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent}:{},effectiveModelsBySessionId:t.effectiveModelId!==void 0?{[e.nianSessionId]:t.effectiveModelId}:void 0,agentSystemPromptsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,n,o,t)=>{const I=p().machineToken;if(!I)throw new Error("machine_not_authorized");return b.issue({registryKey:e,machineCredential:I,activationCauseMessageId:n,allowedActions:o,propagateWorkerRoomOrigin:t})},audit:new zo,resolveManagedAgentPolicy:e=>qo({...e,runtime:l.find(n=>n.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>Ae({serverUrl:u,machineToken:p().machineToken,req:e,client:s,queue:r.getScheduleQueue(),registry:f}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(f.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await y.status({machineToken:p().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,n)=>w.prepareDirectConversationTurn(e,n)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?w.prepareDirectConversationTurn(e.sessionId,Xo):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(ye,{recursive:!0}),le(process.pid,d,{version:h}),me(process.pid,void 0,d),s.connect(),process.stdin.resume();let te=!1;const L=async()=>{if(!te){te=!0,console.log(T.gray(`
3
- Disconnecting...`)),D({level:"info",wsEvent:"daemon.stop"}),clearInterval(g),O?.stop();try{await r.cleanup(),$.stop(),P?.stop(),E?.stop(),s.disconnect(),await Promise.allSettled([k.close(),A.close()]),ie(process.pid,d),se(d)}finally{process.exit(0)}}};G=L,X&&L(),process.on("SIGINT",()=>{L()}),process.on("SIGTERM",()=>{L()})}),a.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>Q()),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(()=>Q()),a.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>Q());const we=a.command("config").description("View or modify configuration");we.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${De()}`);const i=p(),c=Oe(i,ae(process.env,i));if(i.serverUrl){const g=uo(i.serverUrl);console.log(`Region: ${g} (${K[g].label})`)}console.log(JSON.stringify(c,null,2))}),we.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((i,c)=>{const g=p();if(i==="server"){c!=="cn"&&c!=="global"&&(console.error(T.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const d=c;g.serverUrl=go(d),Ue(g),console.log(T.green(`\u2713 Server set to ${K[d].label}`)),console.log(T.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(T.red(`\u2717 Unknown config key: ${i}. Supported: server`)),process.exit(1)}),ro(a),$e(a),Ve(a),Ge(a),qe(a),ze(a,{clientVersion:U}),Je(a),Ke(a),Qe(a),Ye(a),Ze(a),eo(a),oo(a),no(a),to(a),io(a,U),a.parse();
1
+ import{registerScheduleCommand as be}from"./commands/schedule.js";import{resolvePersonalScheduleContext as Ae}from"./schedules/personal-context.js";import{executeServerSchedule as ae,deliverServerSchedule as Pe}from"./schedules/server-client.js";import{Command as Ee}from"commander";import T from"chalk";import Te from"node:os";import{randomUUID as Ue}from"node:crypto";import J from"node:fs";import{loadConfig as p,saveConfig as De,getConfigPath as Me,getShennianDir as _e,resolveShennianPath as K,normalizeAutoUpgradePolicy as Ne}from"./config/index.js";import{CliRelayClient as xe}from"./relay/client.js";import{collectKnownLogSecrets as ie,installCliLogRedaction as Oe,sanitizeCliLogValue as $e}from"./log-redaction.js";import{registerPairCommand as Le,runSmartStart as Ve}from"./commands/pair.js";import{registerLogoutCommand as je}from"./commands/logout.js";import{clearDaemonPidIfOwner as se,createDaemonInstanceId as Fe,clearDaemonLauncher as ce,findRunningDaemonProcessIds as He,isRemoteAccessDisabled as de,prepareRemoteAccessPause as Be,stopPreparedRemoteAccessService as We,isIsolatedDaemonE2eInstance as Ge,getDaemonStatus as le,registerDaemonCommand as qe,writeDaemonPid as me,writeDaemonLauncher as pe}from"./commands/daemon.js";import{registerRuntimeCommand as ze}from"./commands/runtime.js";import{registerAdapterCommand as Je}from"./commands/adapter.js";import{registerAgentCommand as Ke}from"./commands/agent.js";import{registerManagerCommand as Qe}from"./commands/manager.js";import{registerWorkerCommand as Ye}from"./commands/worker.js";import{registerProjectCommand as Ze}from"./commands/project.js";import{registerStewardCommand as Xe}from"./commands/steward.js";import{handleUpgradeStart as eo,registerUpgradeCommand as oo}from"./commands/upgrade.js";import{registerToolsCommand as no}from"./commands/tools.js";import{registerQueueCommand as to}from"./commands/queue.js";import{registerSkillCommand as ro}from"./commands/skill.js";import{refreshExistingSkillForHosts as ao}from"./skill/hosts.js";import{registerSetupCommand as io}from"./commands/setup.js";import{getUnavailableAcpAgents as so}from"./agents/acp/discovery.js";import{registerCommandReference as co}from"./commands/command-reference.js";import{registerIntegrationCommand as lo}from"./commands/integration.js";import{registerRoomCommand as mo}from"./commands/room.js";import{registerContactCommand as po}from"./commands/contact.js";import{registerSupportCommand as go}from"./commands/support.js";import{SessionManager as uo}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as fo}from"./session/handlers/project-fs.js";import{SERVERS as Q,regionToUrl as ho,urlToRegion as vo}from"./region.js";import{clearUpgradeAttempt as Io,getCurrentVersion as ge,handleStartupCrashCheck as So,readUpgradeAttempt as yo}from"./upgrade/engine.js";import{AutoUpgradeScheduler as wo}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as Co}from"./upgrade/updater-bootstrap.js";import{launchUpdater as ko,markUpdaterHealthy as Ro}from"./upgrade/updater-launcher.js";import{detectAgents as ue}from"./agents/detect.js";import{PublicAgentDeliveryWorker as bo}from"./agents/public-delivery-worker.js";import{augmentProcessPath as fe}from"./env-path.js";import{acquireDaemonInstanceLock as Ao}from"./commands/daemon-instance-lock.js";fe();const U=ge();import{getCachedAgentInfos as V,resolveAgentInfos as Po}from"./agents/model-registry.js";import{initCliLogReporter as Eo,reportLog as D,reportUpgradeAggregateMetric as To}from"./log-reporter.js";import{isNativeFusionEnabled as Uo}from"./native-fusion/config.js";import{NativeSessionFusionService as Do}from"./native-fusion/service.js";import{startDaemonLogRetention as Mo}from"./daemon-log.js";import{startDaemonIpcServer as he}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as _o,resolveManagedRoomIpcPaths as No}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as xo}from"./daemon-ipc/control.js";import{createAgentReadinessHandlers as Oo}from"./daemon-ipc/agent-readiness.js";import{scanMachineAgents as ve}from"./session/handlers/agents.js";import{validateAgentWorkspaceConfiguration as $o}from"./session/handlers/agent-workspace-validation.js";import{DAEMON_IPC_VERSION as Lo}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as Vo}from"./room/session-registry.js";import{HttpRoomBindingClient as jo}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as Fo}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Ho}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Bo}from"./room/mirror-sync-service.js";import{handleLiveRoomDelivery as Wo}from"./room/live-delivery.js";import{NativeSourceDeletionStore as Go}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as qo,isCurrentRegistration as zo}from"./room/registration-authority.js";import{RoomActivationService as Jo,resolveManagedAgentPolicy as Ko}from"./room/activation-service.js";import{RoomActivationAudit as Qo}from"./room/activation-audit.js";import{RoomAttachmentCache as Yo}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Zo}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as Xo}from"./room/managed-context.js";import{createManagedRoomExecutor as en}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as Ie,SESSION_SYNC_ADVERTISED_CAPABILITIES as Se}from"@shennian/wire";import{getDaemonInstallationId as on}from"./session/store.js";import{OWNER_DIRECT_TURN_OPTIONS as nn}from"./session/queue-helpers.js";import{synchronizeMachinePersonalAuthority as tn}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as ye,ensurePersonalDataEpoch as rn}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as an,DeletionSyncTerminalError as sn}from"./session/deletion-sync-state.js";const we=_e(),cn=K("daemon.pid"),dn=K("daemon.instance.lock");function ln(){try{const i=J.readFileSync(cn,"utf-8").trim();if(i.startsWith("{")){const g=JSON.parse(i),d=Number(g.pid);return Number.isInteger(d)&&d>0?d:null}const c=parseInt(i,10);return Number.isInteger(c)&&c>0?c:null}catch{return null}}function mn(i){return i.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function Y(){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 pn(i){const c=[`trigger=${i.trigger??"unknown"}`,`phase=${i.phase}`,`code=${i.code??"unknown"}`,`attempt=${i.reconnectAttempt}`];return i.reason&&c.push(`reason=${i.reason}`),i.error&&c.push(`error=${i.error}`),c.join(" ")}const a=new Ee;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(U),a.enablePositionalOptions(),lo(a),mo(a),po(a),go(a),be(a),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",Te.hostname()).action(async i=>{const c=p(),g=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??c.serverUrl??void 0;await Ve(g,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 c=K("env.json");try{const e=JSON.parse(J.readFileSync(c,"utf-8"));for(const[n,o]of Object.entries(e))process.env[n]||(process.env[n]=o);fe()}catch{}Oe(ie(process.env,p()));const g=Mo();de()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(g),process.exit(0));const d=Fe(),C=Ao({lockPath:dn,instanceId:d});C.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(C.ownerPid?` (PID ${C.ownerPid})`:"")+", skipping duplicate start"),clearInterval(g),process.exit(0));try{const e=ln();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 Z=Ge(process.env,we)?[]:He(process.pid);Z.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${Z[0]}), skipping duplicate start`),C.release(),process.exit(0)),me(process.pid,d,{version:U}),pe(process.pid,void 0,d),process.on("exit",()=>{se(process.pid,d),ce(d)}),process.on("exit",C.release);let j=null;try{j=Co()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const M=await So();if(M){j||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{ko({fromVersion:U,targetVersion:M.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:M.jobId},{readiness:j}),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{rn()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const m=p(),u=i.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??m.serverUrl??Q.cn.url,h=ge(),l=await ue({serverUrl:u,authToken:m.machineToken??m.accessToken}),S=l.map(e=>e.type);let F=V(l);const v=new Vo,_=new Ho,R=new Xo(v),y=new jo(u),ke=new Yo({actionClient:y}),Re=new Zo({actionClient:y});let w=null,r;const X=en({authority:R,actionClient:y,attachmentCache:ke,attachmentUploader:Re,observations:_,getMachineCredentials:()=>({machineToken:p().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),onSendOutcome:e=>r.noteManagedRoomSendOutcome(e),getActiveRunId:(e,n)=>r.getManagedRoomActiveRunId(e,n),scheduleExecutor:(e,n,o)=>ae({serverUrl:u,machineToken:p().machineToken,sessionId:e,action:n,args:o}),onPaused:({registryKey:e,sessionId:n})=>{const t=v.getByRegistryKey(e)?.binding;t&&v.setBinding({registryKey:e,bindingId:t.bindingId,roomId:t.roomId,agentIdentityId:t.agentIdentityId,agentMembershipId:t.agentMembershipId,status:"paused",activationMode:"paused"}),R.revokeSession(e),r?.discardPendingManagedRoomMessages(n)}});let H=null,B=null,W=null,G=null,ee=!1;const b=await he({paths:_o(),handlers:{...xo({daemonVersion:h,protocolVersion:Lo,getStatus:()=>le(),getAgents:()=>l,requestShutdown:()=>{G?G():ee=!0},completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),bindManagedRoom:e=>r.bindManagedRoomFromLocal(e),stewardSay:e=>r.stewardSayFromLocal(e),startUpgrade:async e=>{if(!H)throw new Error("upgrade_unavailable");return H(e)},prepareExternalUpgrade:e=>{if(!B)throw new Error("external_upgrade_unavailable");return B(e)},cancelExternalUpgrade:()=>{if(!W)throw new Error("external_upgrade_unavailable");return W()}}),...Oo({getStatus:()=>le(),getSnapshot:()=>V(l).map(e=>{const n=l.find(o=>o.type===e.type);return{...e,runtimePlatform:n?.runtimePlatform,runtimeIsWsl:n?.runtimeIsWsl}}),getUnavailable:so,discover:async e=>{if(!r)throw new Error("daemon_starting");const n=await ve(!0,e);if(e){const t=l.filter(f=>f.type!==e);l.splice(0,l.length,...t,...n.detectedAgents)}else l.splice(0,l.length,...n.detectedAgents);const o=V(l);return s.sendEvent({type:"event",event:"machine.agents",payload:{agentList:l.map(t=>t.type),agents:o}}),n.agents.map(t=>{const f=n.detectedAgents.find(z=>z.type===t.type);return{...t,runtimePlatform:f?.runtimePlatform,runtimeIsWsl:f?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return $o(e,{ignoreNativeSession:(n,o)=>P?.ignoreNativeSource(n,o)})}})}});let A;try{A=await he({paths:No(),handlers:{"managed-room.execute":e=>X(e),"schedule.personal":async e=>{const n=e,o=Ae(n?.context);if(v.getByNianSessionId(o)?.binding)throw new Error("schedule_personal_context_required");return await ae({serverUrl:u,machineToken:p().machineToken,sessionId:o,action:n.operation,args:n})}}})}catch(e){throw await b.close(),e}let oe=!1;const N=()=>{oe||(oe=!0,Promise.allSettled([b.close(),A.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",N),process.once("SIGTERM",N),!m.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",N),process.removeListener("SIGTERM",N);const ne=`${mn(u)}/relay/machine`,x=m.machineToken;if(!x)return;try{await tn({serverUrl:u,machineToken:x,machineId:m.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)}m.machineId&&Eo(u,m.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${ne}... (v${h}) agents: ${S.join(",")}`),D({level:"info",wsEvent:"daemon.start",metadata:{version:h,agents:S}});let P=null,E=null,k=0,q=!1,I=yo();const te=Ne(m.autoUpgrade),O=m.machineId?new bo({serverUrl:u,machineId:m.machineId,getMachineToken:()=>p().machineToken,getDetectedAgents:()=>ue({serverUrl:u,authToken:p().machineToken}),onRuntimeChanged:async()=>{const e=k,n=await ve(!0);if(l.splice(0,l.length,...n.detectedAgents),S.splice(0,S.length,...n.agentList),F=n.agents,!(await s.sendReq({type:"req",id:Ue(),method:"machine.agents.report",params:{agents:n.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 xe({serverUrl:ne,machineToken:x,cliVersion:h,agentList:S,autoUpgradePolicy:te,sessionSyncProtocolVersion:Ie,sessionSyncCapabilities:Se,daemonInstallationId:on(),dataEpoch:ye,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:F}}),Po(l,{serverUrl:m.serverUrl??u,authToken:m.machineToken??m.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(F)&&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()}}),$.start(),E?.start();const e=++k,n=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),I){const o=I;I=null,o.jobId&&Ro(o.jobId,o.to),Io(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),To({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}})}q||(q=!0,ao({clientVersion:h}).then(o=>{const t=o.filter(f=>!f.ok||!["current","registered","updated"].includes(f.result.status));t.length>0&&console.warn(`[skill] ${t.length} installed Skill copies need attention; run shennian setup for details`)}).catch(()=>console.warn("[skill] Official Skill refresh failed; Client remains available")).finally(()=>{q=!1})),e===k&&s.getState()==="connected"&&(P?.handleConnected(),O?.start())}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===k&&s.getState()==="connected"){if(o instanceof sn)return;const t=o instanceof an?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{n()},t).unref?.()}}};n()},onDisconnected:e=>{k+=1,r?.revokeProjectFsHandles(),O?.stop(),E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${pn(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"){Wo(s,E,e);return}r.handleReq(e)}});P=Uo()?new Do(s):null,E=new Bo({registry:v,observations:_,actionClient:y,getMachineCredentials:()=>({machineToken:p().machineToken}),isSessionDeleted:e=>new Go().hasSession(e),onMessages:async(e,n,o,t)=>{await w?.processMessages(e,n,o,t)},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 $=new wo({currentVersion:h,machineId:m.machineId??"unknown-machine",serverUrl:m.serverUrl??u,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:Ie,dataEpoch:ye,advertisedCapabilities:Se,updaterProtocolVersion:1,startUpgrade:async(e,n)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(s,"auto-upgrade",e,{currentVersion:h,prepareForUpgrade:t=>r.prepareForUpgrade(t),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:n?void 0:()=>r.getUpgradeIdleState().idle})}});$.setPolicy(te),r=new uo(s,P,h,$,new Fo({registry:v,observations:_,bindingClient:y,getMachineCredentials:()=>{const e=p();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${d}`}),{prepare:()=>Be(),isDisabled:()=>de(),shutdownAfterResponse:()=>{setTimeout(()=>{We(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>R.revokeToken(e),X,null,fo(x),()=>V(l)),H=async e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof n.targetVersion=="string"?n.targetVersion:void 0,t=n.confirmedMajor===!0;return await eo(s,`local-upgrade-${Date.now()}`,o,{currentVersion:h,confirmedMajor:t,prepareForUpgrade:z=>r.prepareForUpgrade(z),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},B=e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=`desktop-${(typeof n.targetVersion=="string"?n.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:t,...r.prepareForUpgrade(t)}},W=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),w=new Jo({registry:v,observations:_,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const n=p().machineToken?.trim(),o=e.binding;if(!n||!o)throw new Error("managed_room_context_unavailable");const t=await y.status({machineToken:n,roomId:o.roomId,bindingId:o.bindingId});if(!zo(v,e)||!qo(e,t))throw new Error("managed_room_binding_unavailable");return{roomName:t.room.name,memberCount:t.room.memberCount,members:t.room.members,agentsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent}:{},effectiveModelsBySessionId:t.effectiveModelId!==void 0?{[e.nianSessionId]:t.effectiveModelId}:void 0,agentSystemPromptsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,n,o,t)=>{const f=p().machineToken;if(!f)throw new Error("machine_not_authorized");return R.issue({registryKey:e,machineCredential:f,activationCauseMessageId:n,allowedActions:o,propagateWorkerRoomOrigin:t})},audit:new Qo,resolveManagedAgentPolicy:e=>Ko({...e,runtime:l.find(n=>n.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>Pe({serverUrl:u,machineToken:p().machineToken,req:e,client:s,queue:r.getScheduleQueue(),registry:v}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(v.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await y.status({machineToken:p().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,n)=>w.prepareDirectConversationTurn(e,n)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?w.prepareDirectConversationTurn(e.sessionId,nn):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}])),J.mkdirSync(we,{recursive:!0}),me(process.pid,d,{version:h}),pe(process.pid,void 0,d),s.connect(),process.stdin.resume();let re=!1;const L=async()=>{if(!re){re=!0,console.log(T.gray(`
3
+ Disconnecting...`)),D({level:"info",wsEvent:"daemon.stop"}),clearInterval(g),O?.stop();try{await r.cleanup(),$.stop(),P?.stop(),E?.stop(),s.disconnect(),await Promise.allSettled([b.close(),A.close()]),se(process.pid,d),ce(d)}finally{process.exit(0)}}};G=L,ee&&L(),process.on("SIGINT",()=>{L()}),process.on("SIGTERM",()=>{L()})}),a.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>Y()),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(()=>Y()),a.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>Y());const Ce=a.command("config").description("View or modify configuration");Ce.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${Me()}`);const i=p(),c=$e(i,ie(process.env,i));if(i.serverUrl){const g=vo(i.serverUrl);console.log(`Region: ${g} (${Q[g].label})`)}console.log(JSON.stringify(c,null,2))}),Ce.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((i,c)=>{const g=p();if(i==="server"){c!=="cn"&&c!=="global"&&(console.error(T.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const d=c;g.serverUrl=ho(d),De(g),console.log(T.green(`\u2713 Server set to ${Q[d].label}`)),console.log(T.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(T.red(`\u2717 Unknown config key: ${i}. Supported: server`)),process.exit(1)}),io(a),Le(a),je(a),qe(a),ze(a),Je(a,{clientVersion:U}),Ke(a),Qe(a),Ye(a),Ze(a),Xe(a),oo(a),no(a),to(a),ro(a),co(a,U),a.parse();
@@ -1 +1 @@
1
- import{loadConfig as w}from"../config/index.js";import{SERVERS as R}from"../region.js";class n extends Error{code;nextAction;constructor(e,t,o=null){super(t),this.code=e,this.nextAction=o}}class b{fetchImpl;constructor(e=fetch){this.fetchImpl=e}create(e,t){return this.request("POST","/api/room-cli/create",{name:e,operationId:t},{retryNetworkOnce:!0})}list(){return this.request("GET","/api/room-cli/rooms")}get(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}`)}update(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/update`,t)}deleteRecord(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/delete`,{version:t})}getInvite(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/invite`)}resetInvite(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/invite/reset`,{version:t})}listMembers(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/members`)}removeMember(e,t,o){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/members/remove`,{memberRef:t,version:o})}join(e,t,o){return this.request("POST","/api/room-cli/join",{roomId:e,inviteToken:t,...o?{message:o}:{}})}open(e){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/open`,{})}status(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/status`)}read(e,t){const o=new URLSearchParams({limit:String(t.limit)});return t.before&&o.set("before",t.before),t.after&&o.set("after",t.after),this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/messages?${o}`)}send(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/messages`,t,{retryNetworkOnce:!0})}initializeAttachment(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/attachments/init`,t)}completeAttachment(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/attachments/${encodeURIComponent(t)}/complete`,{})}getAttachmentDownload(e,t){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/attachments/${encodeURIComponent(t)}/download`)}leave(e){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/leave`,{})}async upload(e,t,o){let s;try{s=await this.fetchImpl(e,{method:"PUT",headers:t,body:o,redirect:"error",signal:AbortSignal.timeout(12e4)})}catch{throw new n("attachment_upload_failed","Attachment upload failed.")}if(!s.ok)throw new n("attachment_upload_failed","Attachment upload failed.")}async download(e){try{const t=await this.fetchImpl(e,{redirect:"error",signal:AbortSignal.timeout(6e4)});if(!t.ok||!t.body)throw new n("attachment_download_failed","Attachment download failed.");return t}catch(t){throw t instanceof n?t:new n("attachment_download_failed","Attachment download failed.")}}async request(e,t,o,s={}){const l=w();if(!l.machineToken)throw new n("not_paired","Shennian CLI is not paired.",{type:"run_command",command:"shennian pair --browser"});const d=(l.serverUrl??R.cn.url).replace(/\/+$/,""),u=()=>this.fetchImpl(`${d}${t}`,{method:e,headers:{authorization:`Bearer ${l.machineToken}`,...o==null?{}:{"content-type":"application/json"}},...o==null?{}:{body:JSON.stringify(o)},signal:AbortSignal.timeout(2e4)});let a;try{a=await u()}catch{if(!s.retryNetworkOnce)throw new n("server_unavailable","Shennian service is unavailable.");try{a=await u()}catch{throw new n("server_unavailable","Shennian service is unavailable.")}}const c=await y(a);if(!a.ok){const i=m(c)?c:{},h=typeof i.error=="string"?i.error:`http_${a.status}`,p=typeof i.message=="string"?i.message:"Room request failed.",f=I(i.nextAction)?i.nextAction:null;throw new n(h,p,f)}if(!m(c))throw new n("invalid_server_response","Shennian returned an invalid Room response.");return c}}function I(r){return m(r)&&Object.values(r).every(e=>typeof e=="string")}async function y(r){try{return await r.json()}catch{return null}}function m(r){return!!r&&typeof r=="object"&&!Array.isArray(r)}export{b as PublicRoomClient,n as PublicRoomClientError};
1
+ import{loadConfig as w}from"../config/index.js";import{SERVERS as R}from"../region.js";class r extends Error{code;nextAction;constructor(e,t,o=null){super(t),this.code=e,this.nextAction=o}}class C{fetchImpl;constructor(e=fetch){this.fetchImpl=e}create(e,t){return this.request("POST","/api/room-cli/create",{name:e,operationId:t},{retryNetworkOnce:!0})}list(){return this.request("GET","/api/room-cli/rooms")}listContacts(e){const t=e?`?q=${encodeURIComponent(e)}`:"";return this.request("GET",`/api/room-cli/contacts${t}`)}get(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}`)}update(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/update`,t)}deleteRecord(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/delete`,{version:t})}getInvite(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/invite`)}resetInvite(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/invite/reset`,{version:t})}listMembers(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/members`)}removeMember(e,t,o){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/members/remove`,{memberRef:t,version:o})}join(e,t,o){return this.request("POST","/api/room-cli/join",{roomId:e,inviteToken:t,...o?{message:o}:{}})}open(e){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/open`,{})}status(e){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/status`)}read(e,t){const o=new URLSearchParams({limit:String(t.limit)});return t.before&&o.set("before",t.before),t.after&&o.set("after",t.after),this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/messages?${o}`)}send(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/messages`,t,{retryNetworkOnce:!0})}initializeAttachment(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/attachments/init`,t)}completeAttachment(e,t){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/attachments/${encodeURIComponent(t)}/complete`,{})}getAttachmentDownload(e,t){return this.request("GET",`/api/room-cli/${encodeURIComponent(e)}/attachments/${encodeURIComponent(t)}/download`)}leave(e){return this.request("POST",`/api/room-cli/${encodeURIComponent(e)}/leave`,{})}async upload(e,t,o){let s;try{s=await this.fetchImpl(e,{method:"PUT",headers:t,body:o,redirect:"error",signal:AbortSignal.timeout(12e4)})}catch{throw new r("attachment_upload_failed","Attachment upload failed.")}if(!s.ok)throw new r("attachment_upload_failed","Attachment upload failed.")}async download(e){try{const t=await this.fetchImpl(e,{redirect:"error",signal:AbortSignal.timeout(6e4)});if(!t.ok||!t.body)throw new r("attachment_download_failed","Attachment download failed.");return t}catch(t){throw t instanceof r?t:new r("attachment_download_failed","Attachment download failed.")}}async request(e,t,o,s={}){const l=w();if(!l.machineToken)throw new r("not_paired","Shennian CLI is not paired.",{type:"run_command",command:"shennian pair --browser"});const d=(l.serverUrl??R.cn.url).replace(/\/+$/,""),u=()=>this.fetchImpl(`${d}${t}`,{method:e,headers:{authorization:`Bearer ${l.machineToken}`,...o==null?{}:{"content-type":"application/json"}},...o==null?{}:{body:JSON.stringify(o)},signal:AbortSignal.timeout(2e4)});let a;try{a=await u()}catch{if(!s.retryNetworkOnce)throw new r("server_unavailable","Shennian service is unavailable.");try{a=await u()}catch{throw new r("server_unavailable","Shennian service is unavailable.")}}const c=await $(a);if(!a.ok){const i=m(c)?c:{},h=typeof i.error=="string"?i.error:`http_${a.status}`,p=typeof i.message=="string"?i.message:"Room request failed.",f=I(i.nextAction)?i.nextAction:null;throw new r(h,p,f)}if(!m(c))throw new r("invalid_server_response","Shennian returned an invalid Room response.");return c}}function I(n){return m(n)&&Object.values(n).every(e=>typeof e=="string")}async function $(n){try{return await n.json()}catch{return null}}function m(n){return!!n&&typeof n=="object"&&!Array.isArray(n)}export{C as PublicRoomClient,r as PublicRoomClientError};
@@ -1,2 +1,2 @@
1
- import{buildApprovalPendingPayload as M}from"@shennian/wire";import{createHash as R}from"node:crypto";import{AgentEventTerminalGate as D}from"../../agents/event-terminal-gate.js";import{recordAcpAgentModels as k}from"../../agents/model-registry.js";import{reportLog as _}from"../../log-reporter.js";import{registerInternalNativeSource as P}from"../../native-fusion/source-visibility.js";import{requestSessionIndexPublish as c}from"../index-publisher.js";import{noteRunActivity as j}from"../run-stall.js";import{appendMessage as s,recordSession as I,upsertMessage as O}from"../store.js";import{writeToolDetail as C}from"../tool-detail-store.js";import{refreshMachineAgents as F}from"./agents.js";import{roomReplyFailureNotice as N}from"../room-reply-notice.js";import{commitStewardFallback as S,tryStewardFailover as B}from"./steward.js";import{resetStewardChain as H}from"../../steward/failover.js";function J(a){const r=a.indexOf(`
2
- `),o=r>0?Math.min(r,80):Math.min(a.length,80);return a.slice(0,o)}function A(a,r,o){return`${a}:${R("sha256").update(`${r}\0${o??""}`).digest("hex")}`}function L(a,r,o={}){if(a.state==="tool-call"||a.state==="tool-result"){const l={runId:a.runId,sourceSeq:a.seq};return{state:a.state,runId:a.runId,seq:a.seq,sessionId:r,detailRef:l,status:a.state==="tool-call"?"running":"completed",detailAvailable:!0,...a.durationMs!==void 0?{durationMs:a.durationMs}:{},...a.name?{name:a.name}:{},...a.source?{source:a.source}:{},...a.agentSessionId?{agentSessionId:a.agentSessionId}:{},...o}}return{...a,sessionId:r,...o}}const V=3e4;function Q(a){return a.state==="heartbeat"?a.runPhase??null:a.state==="tool-call"||a.state==="tool-result"?"tool_running":a.state==="approval-pending"?"waiting_approval":a.state==="delta"?a.thinking?"thinking":"streaming_text":a.state==="init"||a.state==="start"?"thinking":null}function w(a,r){return a!=="manager"?a:r==="claude"?"claude":"codex"}function y(a,r,o,l){if(l.state!=="error"){S(a,r,o,l);return}B(a,r,o,l).catch(()=>!1).then(g=>{g||S(a,r,o,l)})}function ot(a,r,o,l){let g=null;const E=new D;function x(t,n={}){a.client.sendAgentEvent({type:"event",event:"agent",payload:L(t,r,n),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}o.startsWith("acp:")&&l.on("sessionOptions",()=>{try{const t=l.getSessionOptions?.().models??[];if(!k(o,t))return;const n=a.getAgentSnapshot?.();if(!n)return;a.client.sendEvent({type:"event",event:"machine.agents",payload:{agentList:n.map(e=>e.type),agents:n}})}catch{}});function $(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function b(t){if(!t.currentRunId||!t.currentRunPhase)return;const n=t.heartbeatSeq++;a.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:r,runId:t.currentRunId,seq:n,runPhase:t.currentRunPhase},seq:n,id:`agent-heartbeat-${t.currentRunId}-${n}-${Date.now()}`})}function T(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{b(t)},V),t.heartbeatTimer.unref?.())}function f(t){const n=t?.pendingTextEvent;!t||!n||!n.text||(s(r,{id:`agent-${n.runId}-${n.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:n.text}),c(a.client),x({state:"delta",runId:n.runId,seq:n.seq,text:n.text,thinking:n.thinking||void 0}),t.sessionScope==="steward"&&(t.stewardLastText=n.text),t.pendingTextEvent=null)}l.on("agentEvent",t=>{if(!E.accept(t))return;let n=!1;t.errorCode==="acp_auth_required"&&F(a).catch(()=>{});const e=a.sessions.get(r),h=Q(t),u=t.state==="final"||t.state==="error"||t.state==="aborted";if(e&&j(r,e,u),e&&(e.nextEventSeq=t.seq+1,!u&&e.currentRunId!==t.runId&&e.sessionScope==="steward"&&(e.stewardSay={count:0},e.stewardLastText=""),u||(e.currentRunId=t.runId),!u&&h&&(e.currentRunPhase=h,T(e)),t.agentSessionId&&(e.agentSessionId=t.agentSessionId),e.journalRunId)){const i={agentSessionId:t.agentSessionId??e.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...u?{}:{phase:h==="waiting_approval"?"waiting_approval":"running"}};a.runJournal?.update(r,e.journalRunId,i)}if(a.managerRuntime?.noteAgentEvent(r,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&_({level:"info",sessionId:r,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:o}});let p=!1;if(t.state==="tool-call"||t.state==="tool-result"){const i=t.toolCallId?`agent-tool-${R("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;C({sessionId:r,toolCallId:i,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?O:s)(r,{id:i,sessionId:r,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:i,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),p=!0}else t.state==="approval-pending"?(s(r,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:M({...t.approval,permission:t.permission})}),p=!0,e&&I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:e.agentSessionId,attentionId:A("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(s(r,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:t.message}),p=!0);p&&c(a.client);const d=`${r}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&a.runTextAcc.set(d,(a.runTextAcc.get(d)??"")+t.text),t.agentSessionId&&t.agentSessionId!==g&&(e?.nativeSessionVisibility==="internal"&&P(r,w(o,t.source)??o,t.agentSessionId),g=t.agentSessionId,a.nativeFusion?.noteManagedSourceSession(r,w(o,t.source),t.agentSessionId),e&&I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:t.agentSessionId}),a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:r,agentType:o,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const i=t.text??"";if(!i)return;e?.pendingTextEvent&&e.pendingTextEvent.runId!==t.runId&&f(e),e&&!e.pendingTextEvent&&(e.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),e?.pendingTextEvent&&(e.pendingTextEvent.text+=i,e.pendingTextEvent.seq=t.seq);return}let q={};if(t.state==="final"){f(e),e&&(S(a,r,e,t),H(r));const i=e?N(e):null;i&&(n=!0,s(r,{id:`room-reply-notice-${t.runId}`,sessionId:r,role:"agent",ts:Date.now(),payload:i}),c(a.client));const m=a.runTextAcc.get(d)??"";m&&(q={messageSummary:J(m)}),a.runTextAcc.delete(d)}else t.state==="error"||t.state==="aborted"?(f(e),e&&y(a,r,e,t),a.runTextAcc.delete(d)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&f(e);u&&e?.currentRunId===t.runId&&(e.currentRunId=null,e.currentRunPhase=null,e.nextEventSeq=0,$(e),a.chatQueue?.noteTerminal(r),I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:e.agentSessionId,status:t.state==="final"&&!n?"completed":"failed",attentionId:A("terminal",t.runId),lastActivityAt:new Date().toISOString()}),c(a.client),e.journalRunId&&(a.runJournal?.remove(r,e.journalRunId),a.recoveryBarrier?.end(r),e.journalRunId=null)),x(t,q)}),l.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${r} agentType=${o}: ${t.message}`);const n=a.sessions.get(r);n&&y(a,r,n,{state:"error",runId:n.currentRunId??"",message:t.message}),n?.journalRunId&&(a.runJournal?.update(r,n.journalRunId,{phase:"terminal"}),a.runJournal?.remove(r,n.journalRunId),a.recoveryBarrier?.end(r),n.journalRunId=null),a.sessions.delete(r),a.chatQueue?.noteTerminal(r),a.chatQueue?.isDispatching?.(r)||(s(r,{id:`agent-error-${r}-${Date.now()}`,sessionId:r,role:"agent",ts:Date.now(),payload:t.message}),c(a.client)),a.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:t.message,runId:"",seq:0}})})}export{ot as bindAdapterEvents,w as getNativeSourceAgentType};
1
+ import{buildApprovalPendingPayload as M}from"@shennian/wire";import{createHash as w}from"node:crypto";import{AgentEventTerminalGate as D}from"../../agents/event-terminal-gate.js";import{recordAcpAgentModels as k}from"../../agents/model-registry.js";import{reportLog as _}from"../../log-reporter.js";import{registerInternalNativeSource as P}from"../../native-fusion/source-visibility.js";import{requestSessionIndexPublish as c}from"../index-publisher.js";import{noteRunActivity as j}from"../run-stall.js";import{appendMessage as s,recordSession as I,upsertMessage as O}from"../store.js";import{writeToolDetail as C}from"../tool-detail-store.js";import{refreshMachineAgents as F}from"./agents.js";import{roomReplyFailureNotice as N}from"../room-reply-notice.js";import{commitStewardFallback as S,tryStewardFailover as B}from"./steward.js";import{clearStewardSwitched as H,resetStewardChain as J}from"../../steward/failover.js";function L(a){const r=a.indexOf(`
2
+ `),o=r>0?Math.min(r,80):Math.min(a.length,80);return a.slice(0,o)}function R(a,r,o){return`${a}:${w("sha256").update(`${r}\0${o??""}`).digest("hex")}`}function V(a,r,o={}){if(a.state==="tool-call"||a.state==="tool-result"){const l={runId:a.runId,sourceSeq:a.seq};return{state:a.state,runId:a.runId,seq:a.seq,sessionId:r,detailRef:l,status:a.state==="tool-call"?"running":"completed",detailAvailable:!0,...a.durationMs!==void 0?{durationMs:a.durationMs}:{},...a.name?{name:a.name}:{},...a.source?{source:a.source}:{},...a.agentSessionId?{agentSessionId:a.agentSessionId}:{},...o}}return{...a,sessionId:r,...o}}const Q=3e4;function G(a){return a.state==="heartbeat"?a.runPhase??null:a.state==="tool-call"||a.state==="tool-result"?"tool_running":a.state==="approval-pending"?"waiting_approval":a.state==="delta"?a.thinking?"thinking":"streaming_text":a.state==="init"||a.state==="start"?"thinking":null}function A(a,r){return a!=="manager"?a:r==="claude"?"claude":"codex"}function y(a,r,o,l){if(l.state!=="error"){S(a,r,o,l);return}B(a,r,o,l).catch(()=>!1).then(g=>{g||S(a,r,o,l)})}function lt(a,r,o,l){let g=null;const E=new D;function x(t,n={}){a.client.sendAgentEvent({type:"event",event:"agent",payload:V(t,r,n),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}o.startsWith("acp:")&&l.on("sessionOptions",()=>{try{const t=l.getSessionOptions?.().models??[];if(!k(o,t))return;const n=a.getAgentSnapshot?.();if(!n)return;a.client.sendEvent({type:"event",event:"machine.agents",payload:{agentList:n.map(e=>e.type),agents:n}})}catch{}});function $(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function b(t){if(!t.currentRunId||!t.currentRunPhase)return;const n=t.heartbeatSeq++;a.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:r,runId:t.currentRunId,seq:n,runPhase:t.currentRunPhase},seq:n,id:`agent-heartbeat-${t.currentRunId}-${n}-${Date.now()}`})}function T(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{b(t)},Q),t.heartbeatTimer.unref?.())}function f(t){const n=t?.pendingTextEvent;!t||!n||!n.text||(s(r,{id:`agent-${n.runId}-${n.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:n.text}),c(a.client),x({state:"delta",runId:n.runId,seq:n.seq,text:n.text,thinking:n.thinking||void 0}),t.sessionScope==="steward"&&(t.stewardLastText=n.text),t.pendingTextEvent=null)}l.on("agentEvent",t=>{if(!E.accept(t))return;let n=!1;t.errorCode==="acp_auth_required"&&F(a).catch(()=>{});const e=a.sessions.get(r),h=G(t),u=t.state==="final"||t.state==="error"||t.state==="aborted";if(e&&j(r,e,u),e&&(e.nextEventSeq=t.seq+1,!u&&e.currentRunId!==t.runId&&e.sessionScope==="steward"&&(e.stewardSay={count:0},e.stewardLastText="",H(r)),u||(e.currentRunId=t.runId),!u&&h&&(e.currentRunPhase=h,T(e)),t.agentSessionId&&(e.agentSessionId=t.agentSessionId),e.journalRunId)){const i={agentSessionId:t.agentSessionId??e.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...u?{}:{phase:h==="waiting_approval"?"waiting_approval":"running"}};a.runJournal?.update(r,e.journalRunId,i)}if(a.managerRuntime?.noteAgentEvent(r,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&_({level:"info",sessionId:r,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:o}});let p=!1;if(t.state==="tool-call"||t.state==="tool-result"){const i=t.toolCallId?`agent-tool-${w("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;C({sessionId:r,toolCallId:i,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?O:s)(r,{id:i,sessionId:r,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:i,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),p=!0}else t.state==="approval-pending"?(s(r,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:M({...t.approval,permission:t.permission})}),p=!0,e&&I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:e.agentSessionId,attentionId:R("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(s(r,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:r,role:"agent",ts:Date.now(),payload:t.message}),p=!0);p&&c(a.client);const d=`${r}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&a.runTextAcc.set(d,(a.runTextAcc.get(d)??"")+t.text),t.agentSessionId&&t.agentSessionId!==g&&(e?.nativeSessionVisibility==="internal"&&P(r,A(o,t.source)??o,t.agentSessionId),g=t.agentSessionId,a.nativeFusion?.noteManagedSourceSession(r,A(o,t.source),t.agentSessionId),e&&I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:t.agentSessionId}),a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:r,agentType:o,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const i=t.text??"";if(!i)return;e?.pendingTextEvent&&e.pendingTextEvent.runId!==t.runId&&f(e),e&&!e.pendingTextEvent&&(e.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),e?.pendingTextEvent&&(e.pendingTextEvent.text+=i,e.pendingTextEvent.seq=t.seq);return}let q={};if(t.state==="final"){f(e),e&&(S(a,r,e,t),J(r));const i=e?N(e):null;i&&(n=!0,s(r,{id:`room-reply-notice-${t.runId}`,sessionId:r,role:"agent",ts:Date.now(),payload:i}),c(a.client));const m=a.runTextAcc.get(d)??"";m&&(q={messageSummary:L(m)}),a.runTextAcc.delete(d)}else t.state==="error"||t.state==="aborted"?(f(e),e&&y(a,r,e,t),a.runTextAcc.delete(d)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&f(e);u&&e?.currentRunId===t.runId&&(e.currentRunId=null,e.currentRunPhase=null,e.nextEventSeq=0,$(e),a.chatQueue?.noteTerminal(r),I({sessionId:r,agentType:o,workDir:e.workDir,agentSessionId:e.agentSessionId,status:t.state==="final"&&!n?"completed":"failed",attentionId:R("terminal",t.runId),lastActivityAt:new Date().toISOString()}),c(a.client),e.journalRunId&&(a.runJournal?.remove(r,e.journalRunId),a.recoveryBarrier?.end(r),e.journalRunId=null)),x(t,q)}),l.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${r} agentType=${o}: ${t.message}`);const n=a.sessions.get(r);n&&y(a,r,n,{state:"error",runId:n.currentRunId??"",message:t.message}),n?.journalRunId&&(a.runJournal?.update(r,n.journalRunId,{phase:"terminal"}),a.runJournal?.remove(r,n.journalRunId),a.recoveryBarrier?.end(r),n.journalRunId=null),a.sessions.delete(r),a.chatQueue?.noteTerminal(r),a.chatQueue?.isDispatching?.(r)||(s(r,{id:`agent-error-${r}-${Date.now()}`,sessionId:r,role:"agent",ts:Date.now(),payload:t.message}),c(a.client)),a.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:t.message,runId:"",seq:0}})})}export{lt as bindAdapterEvents,A as getNativeSourceAgentType};
@@ -1 +1 @@
1
- import{createHash as T,randomUUID as m}from"node:crypto";import{buildStewardSayPayload as x,STEWARD_TERMINAL_OPEN_MESSAGE_ID_PREFIX as _}from"@shennian/wire";import{DaemonIpcError as $}from"../../daemon-ipc/protocol.js";import{STEWARD_SAY_MAX_CHARS as l,isStewardSessionId as p}from"../../steward/session.js";import{requestSessionIndexPublish as A}from"../index-publisher.js";import{appendMessage as y,getDaemonInstallationId as E,listSessionRecords as I,recordSession as g}from"../store.js";import{pinStewardWorkDir as h}from"../../steward/session.js";import{buildHandoverNote as D,carryStewardChain as M,classifyStewardFailure as R,lastStewardUserText as b,pickFailoverAgent as N,setStewardHandover as L,stewardFailureLabel as k,stewardTriedAgents as C}from"../../steward/failover.js";class c extends ${}function w(s,e,t,a="say",d){if(!p(e))throw new c("steward_session_required","This session is not a Shennian steward session.");const r=typeof t=="string"?t.trim():"";if(!r)throw new c("steward_say_empty","There is nothing to say.");if(r.length>l)throw new c("steward_say_too_long",`A message may hold at most ${l} characters.`);const n=d??`steward-say-${m()}`;y(e,{id:n,sessionId:e,role:"agent",ts:Date.now(),payload:x(r,a)});const o=s.sessions.get(e);return o&&a==="say"&&(o.stewardSay={count:(o.stewardSay?.count??0)+1}),A(s.client),{messageId:n}}function j(s,e,t,a){if(!p(e)||(t.stewardSay?.count??0)>0)return;const r=(t.stewardLastText?.trim()??"")||(a.state==="final"?"\u5DF2\u5904\u7406\uFF0C\u4F46\u6CA1\u6709\u53EF\u663E\u793A\u7684\u56DE\u590D\u3002":a.message?.trim()||"\u8FD9\u6B21\u5904\u7406\u6CA1\u6709\u5B8C\u6210\u3002");try{w(s,e,r.slice(0,l),"fallback",`steward-fallback-${a.runId||"run"}`)}catch{}}const F="\u6765\u81EA\u7EC8\u7AEF",q=new Set(["manager","pi"]);function W(s){const e=T("sha256").update(`${s}\0steward-terminal`).digest("hex"),t=(Number.parseInt(e[16],16)&3|8).toString(16);return`sess_${e.slice(0,8)}-${e.slice(8,12)}-4${e.slice(13,16)}-${t}${e.slice(17,20)}-${e.slice(20,32)}`}function z(s,e){const t=W(E()),a=I().find(d=>d.sessionId===t);if(a&&a.sessionScope!=="steward")throw new c("steward_scope_conflict","The terminal conversation id is already in use.");if(!a){const r=(s.getAgentSnapshot?.()??[]).find(n=>n.supportsStandardSession!==!1&&!q.has(n.type))?.type??"codex";g({sessionId:t,agentType:r,workDir:h(),sessionScope:"steward",sessionMode:"standard"}),y(t,{id:`${_}${t}`,sessionId:t,role:"user",ts:Date.now(),payload:F})}return{...w(s,t,e),sessionId:t}}const H={codex:"Codex",claude:"Claude Code",opencode:"OpenCode"},S=s=>H[s]??s.replace(/^acp:/,"");async function J(s,e,t,a,d){if(a.state!=="error"||!p(e)||(t.stewardSay?.count??0)>0||!s.chatQueue)return!1;const r=d||b(e);if(!r)return!1;const n=C(e,t.agentType),o=N(s.getAgentSnapshot?.()??[],n);if(!o)return!1;const f=R(a.message),i=`sess_${m()}`,u=h();g({sessionId:i,agentType:o,workDir:u,sessionScope:"steward",sessionMode:"standard"}),M(e,i,[...n,o]),L(i,D(S(t.agentType),f));try{if(!await s.chatQueue.handleEnqueue({type:"req",id:`steward-failover-${i}`,method:"chat.enqueue",params:{sessionId:i,text:r,agentType:o,workDir:u,sessionMode:"standard",sessionScope:"steward",clientMessageId:`steward-failover-user-${i}`}}))return!1}catch{return!1}return w(s,i,`\u5DF2\u81EA\u52A8\u5207\u6362\u5230 ${S(o)}\uFF08\u539F\u56E0\uFF1A${S(t.agentType)}${k(f)}\uFF09`,"say",`steward-failover-note-${i}`),!0}export{F as STEWARD_TERMINAL_TITLE,c as StewardSayError,j as commitStewardFallback,w as commitStewardSay,z as commitTerminalStewardSay,W as stewardTerminalSessionId,J as tryStewardFailover};
1
+ import{createHash as T,randomUUID as m}from"node:crypto";import{buildStewardSayPayload as x,parseStewardSayPayload as E,STEWARD_FAILOVER_USER_MESSAGE_ID_PREFIX as A,STEWARD_TERMINAL_OPEN_MESSAGE_ID_PREFIX as $}from"@shennian/wire";import{DaemonIpcError as D}from"../../daemon-ipc/protocol.js";import{STEWARD_SAY_MAX_CHARS as l,isStewardSessionId as S}from"../../steward/session.js";import{requestSessionIndexPublish as R}from"../index-publisher.js";import{appendMessage as y,getDaemonInstallationId as I,listSessionRecords as M,readMessages as L,recordSession as g}from"../store.js";import{pinStewardWorkDir as h}from"../../steward/session.js";import{buildHandoverNote as b,carryStewardChain as N,classifyStewardFailure as k,clearStewardSwitched as _,lastStewardUserText as F,markStewardSwitched as C,pickFailoverAgent as P,setStewardHandover as U,wasStewardJustSwitched as W,stewardFailureLabel as q,stewardTriedAgents as H}from"../../steward/failover.js";class c extends D{}function w(t,e,a,r="say",d){if(!S(e))throw new c("steward_session_required","This session is not a Shennian steward session.");const s=typeof a=="string"?a.trim():"";if(!s)throw new c("steward_say_empty","There is nothing to say.");if(s.length>l)throw new c("steward_say_too_long",`A message may hold at most ${l} characters.`);const n=d??`steward-say-${m()}`;y(e,{id:n,sessionId:e,role:"agent",ts:Date.now(),payload:x(s,r)});const o=t.sessions.get(e);return o&&r==="say"&&(o.stewardSay={count:(o.stewardSay?.count??0)+1}),R(t.client),{messageId:n}}function O(t){for(const e of L(t,{limit:40})){if(e.role==="user")return!1;if(e.role==="agent"&&E(String(e.payload))?.source==="say")return!0}return!1}function te(t,e,a,r){if(!S(e)||(a.stewardSay?.count??0)>0||W(e)||O(e))return;const s=(a.stewardLastText?.trim()??"")||(r.state==="final"?"\u5DF2\u5904\u7406\uFF0C\u4F46\u6CA1\u6709\u53EF\u663E\u793A\u7684\u56DE\u590D\u3002":r.message?.trim()||"\u8FD9\u6B21\u5904\u7406\u6CA1\u6709\u5B8C\u6210\u3002");try{w(t,e,s.slice(0,l),"fallback",`steward-fallback-${r.runId||"run"}`)}catch{}}const G="\u6765\u81EA\u7EC8\u7AEF",X=new Set(["manager","pi"]);function v(t){const e=T("sha256").update(`${t}\0steward-terminal`).digest("hex"),a=(Number.parseInt(e[16],16)&3|8).toString(16);return`sess_${e.slice(0,8)}-${e.slice(8,12)}-4${e.slice(13,16)}-${a}${e.slice(17,20)}-${e.slice(20,32)}`}function ae(t,e){const a=v(I()),r=M().find(d=>d.sessionId===a);if(r&&r.sessionScope!=="steward")throw new c("steward_scope_conflict","The terminal conversation id is already in use.");if(!r){const s=(t.getAgentSnapshot?.()??[]).find(n=>n.supportsStandardSession!==!1&&!X.has(n.type))?.type??"codex";g({sessionId:a,agentType:s,workDir:h(),sessionScope:"steward",sessionMode:"standard"}),y(a,{id:`${$}${a}`,sessionId:a,role:"user",ts:Date.now(),payload:G})}return{...w(t,a,e),sessionId:a}}const Q={codex:"Codex",claude:"Claude Code",opencode:"OpenCode"},p=t=>Q[t]??t.replace(/^acp:/,"");async function re(t,e,a,r,d){if(r.state!=="error"||!S(e)||(a.stewardSay?.count??0)>0||!t.chatQueue)return!1;const s=d||F(e);if(!s)return!1;const n=H(e,a.agentType),o=P(t.getAgentSnapshot?.()??[],n);if(!o)return!1;const u=k(r.message);C(e);const i=`sess_${m()}`,f=h();g({sessionId:i,agentType:o,workDir:f,sessionScope:"steward",sessionMode:"standard"}),N(e,i,[...n,o]),U(i,b(p(a.agentType),u));try{if(!await t.chatQueue.handleEnqueue({type:"req",id:`steward-failover-${i}`,method:"chat.enqueue",params:{sessionId:i,text:s,agentType:o,workDir:f,sessionMode:"standard",sessionScope:"steward",clientMessageId:`${A}${i}`}}))return _(e),!1}catch{return _(e),!1}return w(t,i,`\u5DF2\u81EA\u52A8\u5207\u6362\u5230 ${p(o)}\uFF08\u539F\u56E0\uFF1A${p(a.agentType)}${q(u)}\uFF09`,"say",`steward-failover-note-${i}`),!0}export{G as STEWARD_TERMINAL_TITLE,c as StewardSayError,te as commitStewardFallback,w as commitStewardSay,ae as commitTerminalStewardSay,v as stewardTerminalSessionId,re as tryStewardFailover};
@@ -1 +1 @@
1
- import c from"node:fs";import u from"node:os";import n from"node:path";import{installOfficialSkill as d}from"./updater.js";const f=[{id:"claude",names:["Claude Code"],markers:[".claude"],skillsDir:[".claude","skills"]},{id:"agents",names:["Codex","Cursor","OpenCode","Gemini CLI"],markers:[".codex",".cursor",n.join(".config","opencode"),".gemini"],skillsDir:[".agents","skills"]},{id:"qwen",names:["Qwen Code"],markers:[".qwen"],skillsDir:[".qwen","skills"]}];function m(t=u.homedir()){const i=[];for(const e of f){const r=e.markers.filter(s=>h(n.join(t,s)));if(r.length===0)continue;const l=e.id==="agents"?e.names.filter((s,o)=>r.includes(e.markers[o])):[...e.names];e.id==="claude"&&p(t)||i.push({id:e.id,names:l,path:n.join(t,...e.skillsDir,"shennian","SKILL.md")})}return i}async function C(t){const i=[];for(const e of m(t.home))try{const r=await d(e.path,{clientVersion:t.clientVersion,fetchImpl:t.fetchImpl,registryPath:t.registryPath});i.push({...e,ok:!0,result:r})}catch(r){i.push({...e,ok:!1,error:r instanceof Error?r.message:String(r)})}return i}function h(t){try{return c.statSync(t).isDirectory()}catch{return!1}}function p(t){const e=[{dir:n.join(t,".claude","plugins"),depth:0}];for(;e.length>0;){const{dir:r,depth:l}=e.pop();let s;try{s=c.readdirSync(r,{withFileTypes:!0})}catch{continue}for(const o of s){if(!o.isDirectory())continue;const a=n.join(r,o.name);if(o.name==="skills"&&c.existsSync(n.join(a,"shennian","SKILL.md")))return!0;l<5&&e.push({dir:a,depth:l+1})}}return!1}export{f as SKILL_HOSTS,m as detectSkillHostTargets,C as installSkillForHosts};
1
+ import l from"node:fs";import f from"node:os";import i from"node:path";import{installOfficialSkill as h,updateOfficialSkill as d}from"./updater.js";const m=[{id:"claude",names:["Claude Code"],markers:[".claude"],skillsDir:[".claude","skills"]},{id:"agents",names:["Codex","Cursor","OpenCode","Gemini CLI"],markers:[".codex",".cursor",i.join(".config","opencode"),".gemini"],skillsDir:[".agents","skills"]},{id:"qwen",names:["Qwen Code"],markers:[".qwen"],skillsDir:[".qwen","skills"]}];function u(t=f.homedir()){const s=[];for(const e of m){const r=e.markers.filter(n=>p(i.join(t,n)));if(r.length===0)continue;const c=e.id==="agents"?e.names.filter((n,o)=>r.includes(e.markers[o])):[...e.names];e.id==="claude"&&k(t)||s.push({id:e.id,names:c,path:i.join(t,...e.skillsDir,"shennian","SKILL.md")})}return s}async function w(t){const s=[];for(const e of u(t.home))try{const r=await h(e.path,{clientVersion:t.clientVersion,fetchImpl:t.fetchImpl,registryPath:t.registryPath});s.push({...e,ok:!0,result:r})}catch(r){s.push({...e,ok:!1,error:r instanceof Error?r.message:String(r)})}return s}async function C(t){const s=[];for(const e of u(t.home))if(l.existsSync(e.path))try{const r=await d(e.path,{clientVersion:t.clientVersion,fetchImpl:t.fetchImpl,registryPath:t.registryPath});s.push({...e,ok:!0,result:r})}catch(r){s.push({...e,ok:!1,error:r instanceof Error?r.message:String(r)})}return s}function p(t){try{return l.statSync(t).isDirectory()}catch{return!1}}function k(t){const e=[{dir:i.join(t,".claude","plugins"),depth:0}];for(;e.length>0;){const{dir:r,depth:c}=e.pop();let n;try{n=l.readdirSync(r,{withFileTypes:!0})}catch{continue}for(const o of n){if(!o.isDirectory())continue;const a=i.join(r,o.name);if(o.name==="skills"&&l.existsSync(i.join(a,"shennian","SKILL.md")))return!0;c<5&&e.push({dir:a,depth:c+1})}}return!1}export{m as SKILL_HOSTS,u as detectSkillHostTargets,w as installSkillForHosts,C as refreshExistingSkillForHosts};
@@ -1 +1 @@
1
- import S from"node:crypto";import a from"node:fs";import d from"node:path";import{resolveShennianPath as w}from"../config/index.js";const F="https://shennian.net/skill-manifest.json",m="https://shennian.net/skill.md",f=1440*6e4;async function $(i,t){const e=V(i),r=T(e),s=t.registryPath??w("skill-updates.json"),l=I(s),n=l.targets[e],h=l.checks[e],o=t.now??Date.now(),u=R(e);if(n&&r.sha256!==n.sha256&&!t.replace)return y("local_modified",e,r.version,u);if(h&&h.sha256===r.sha256&&h.clientVersion===t.clientVersion&&!t.forceCheck&&!t.replace&&o-h.lastCheckedAt<f)return{status:h.lastStatus,path:e,localVersion:r.version,remoteVersion:h.remoteVersion,checked:!1,nextCheckAt:h.lastCheckedAt+f,message:"The previous official Skill check is still fresh; the local file was not changed.",...h.lastStatus==="current"||h.lastStatus==="registered"?{}:{officialUrl:m,manualCommand:u}};if(n&&n.clientVersion===t.clientVersion&&!t.forceCheck&&!t.replace&&o-n.lastCheckedAt<f)return{status:n.lastStatus==="updated"?"current":n.lastStatus,path:e,localVersion:r.version,checked:!1,nextCheckAt:n.lastCheckedAt+f,message:n.lastStatus==="check_failed"?"The previous official Skill check failed; continuing with the registered local copy.":"Official Skill check is still fresh; using the registered local copy."};let c;try{c=await A(t.fetchImpl??fetch)}catch{return n?(n.lastCheckedAt=o,n.lastStatus="check_failed",n.clientVersion=t.clientVersion):v(l,e,r,o,"check_failed",t.clientVersion),k(s,l),{status:"check_failed",path:e,localVersion:r.version,checked:!0,nextCheckAt:o+f,message:"Could not verify the official Skill manifest; continuing with the local copy.",officialUrl:m}}if(!b(t.clientVersion,c.skill))return v(l,e,r,o,"client_incompatible",t.clientVersion,c.skill.version),k(s,l),{status:"client_incompatible",path:e,localVersion:r.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+f,message:"The official Skill is not compatible with this Shennian Client version.",officialUrl:m,manualCommand:u};if(!n&&r.sha256===c.skill.sha256)return l.targets[e]={path:e,version:r.version,sha256:r.sha256,lastCheckedAt:o,lastStatus:"registered",clientVersion:t.clientVersion},k(s,l),{status:"registered",path:e,localVersion:r.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+f,message:"Registered this exact official Skill copy for future safe updates."};const U=c.previousSkills?.some(_=>_.version===r.version&&_.sha256===r.sha256)??!1;if(!n&&!U&&!t.replace)return v(l,e,r,o,"manual_update_required",t.clientVersion,c.skill.version),k(s,l),y("manual_update_required",e,r.version,u,c.skill.version);if(n&&r.sha256!==n.sha256&&!t.replace)return y("local_modified",e,r.version,u,c.skill.version);if(r.sha256===c.skill.sha256)return l.targets[e]={path:e,version:r.version,sha256:r.sha256,lastCheckedAt:o,lastStatus:"current",clientVersion:t.clientVersion},k(s,l),{status:"current",path:e,localVersion:r.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+f,message:"The registered official Skill is current."};if(!K(e))return{...y("not_writable",e,r.version,u,c.skill.version),message:"The Skill file is read-only or not a regular file; use the host update mechanism."};let g;try{g=await x(t.fetchImpl??fetch,c)}catch{return n?(n.lastCheckedAt=o,n.lastStatus="check_failed",n.clientVersion=t.clientVersion):v(l,e,r,o,"check_failed",t.clientVersion,c.skill.version),k(s,l),{status:"check_failed",path:e,localVersion:r.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+f,message:"Could not verify the official Skill file; continuing with the local copy.",officialUrl:m}}return O(e,g),l.targets[e]={path:e,version:c.skill.version,sha256:c.skill.sha256,lastCheckedAt:o,lastStatus:"updated",clientVersion:t.clientVersion},k(s,l),{status:"updated",path:e,localVersion:c.skill.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+f,message:"Updated the verified official Skill atomically. Re-read this file now; start a new AI host session if it caches Skills."}}async function W(i,t){const e=V(i);if(j(e))return $(e,{...t,forceCheck:!0});const r=t.fetchImpl??fetch,s=await A(r);if(!b(t.clientVersion,s.skill))return{status:"client_incompatible",path:e,localVersion:s.skill.version,remoteVersion:s.skill.version,checked:!0,message:"The official Skill is not compatible with this Shennian Client version.",officialUrl:m};const l=await x(r,s),n=d.dirname(e);a.mkdirSync(n,{recursive:!0});const h=d.join(n,`.SKILL.md.shennian-${process.pid}-${S.randomUUID()}.tmp`);try{a.writeFileSync(h,l,{flag:"wx",mode:420}),a.renameSync(h,e)}finally{try{a.unlinkSync(h)}catch{}}const o=t.now??Date.now(),u=t.registryPath??w("skill-updates.json"),c=I(u);return c.targets[e]={path:e,version:s.skill.version,sha256:s.skill.sha256,lastCheckedAt:o,lastStatus:"registered",clientVersion:t.clientVersion},delete c.checks[e],k(u,c),{status:"installed",path:e,localVersion:s.skill.version,remoteVersion:s.skill.version,checked:!0,nextCheckAt:o+f,message:"Installed the verified official Skill."}}function j(i){try{return a.lstatSync(i),!0}catch{return!1}}function V(i){if(!d.isAbsolute(i))throw new Error("skill_path_must_be_absolute");const t=d.resolve(i);if(d.basename(t)!=="SKILL.md")throw new Error("skill_path_must_name_SKILL.md");return t}function T(i){const t=a.lstatSync(i);if(!t.isFile()||t.isSymbolicLink())throw new Error("skill_path_must_be_regular_file");const e=a.readFileSync(i);return{version:C(e.toString("utf8")).version,sha256:L(e)}}function C(i){const t=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(i)?.[1];if(!t||!/^name:\s*shennian\s*$/m.test(t))throw new Error("not_official_shennian_skill");const e=/^version:\s*([^\s]+)\s*$/m.exec(t)?.[1];if(!e||!p(e))throw new Error("invalid_skill_version");return{version:e}}async function A(i){const t=await i(F,{redirect:"error",headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!t.ok)throw new Error("skill_manifest_unavailable");const e=await t.json(),r=e.skill;if(e.schemaVersion!==1||e.product!=="shennian"||!r||r.name!=="shennian"||r.url!==m||!p(r.version)||!p(r.minimumClientVersion)||r.maximumClientVersion!==null&&!p(r.maximumClientVersion)||!/^[a-f0-9]{64}$/.test(r.sha256??"")||e.previousSkills!==void 0&&(!Array.isArray(e.previousSkills)||e.previousSkills.length>32||e.previousSkills.some(s=>!s||!p(s.version)||!/^[a-f0-9]{64}$/.test(s.sha256))))throw new Error("invalid_skill_manifest");return e}async function x(i,t){const e=await i(m,{redirect:"error",headers:{Accept:"text/markdown"},signal:AbortSignal.timeout(1e4)});if(!e.ok)throw new Error("skill_download_unavailable");const r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>512e3)throw new Error("skill_too_large");const s=Buffer.from(await e.arrayBuffer());if(s.length===0||s.length>512e3)throw new Error("skill_too_large");if(L(s)!==t.skill.sha256)throw new Error("skill_integrity_mismatch");if(C(s.toString("utf8")).version!==t.skill.version)throw new Error("skill_version_mismatch");return s}function b(i,t){return!p(i)||E(i,t.minimumClientVersion)<0?!1:t.maximumClientVersion===null||E(i,t.maximumClientVersion)<=0}function K(i){try{const t=a.lstatSync(i);return!t.isFile()||t.isSymbolicLink()?!1:(a.accessSync(i,a.constants.W_OK),a.accessSync(d.dirname(i),a.constants.W_OK),!0)}catch{return!1}}function O(i,t){const e=d.dirname(i),r=a.statSync(i).mode&511,s=d.join(e,`.SKILL.md.shennian-${process.pid}-${S.randomUUID()}.tmp`);let l=null;try{l=a.openSync(s,"wx",r),a.writeFileSync(l,t),a.fsyncSync(l),a.closeSync(l),l=null,a.renameSync(s,i);try{const n=a.openSync(e,"r");a.fsyncSync(n),a.closeSync(n)}catch{}}finally{l!==null&&a.closeSync(l);try{a.unlinkSync(s)}catch{}}}function I(i){try{const t=JSON.parse(a.readFileSync(i,"utf8"));if(t.schemaVersion===1&&t.targets&&typeof t.targets=="object")return{schemaVersion:1,targets:t.targets,checks:t.checks&&typeof t.checks=="object"?t.checks:{}}}catch{}return{schemaVersion:1,targets:{},checks:{}}}function k(i,t){a.mkdirSync(d.dirname(i),{recursive:!0,mode:448});const e=`${i}.${process.pid}.${S.randomUUID()}.tmp`;a.writeFileSync(e,JSON.stringify(t,null,2),{mode:384}),a.renameSync(e,i);try{a.chmodSync(i,384)}catch{}}function y(i,t,e,r,s){return{status:i,path:t,localVersion:e,remoteVersion:s,checked:!0,message:i==="local_modified"?"The local Skill differs from its registered official copy; it was not overwritten.":"This local Skill copy is not registered as the current official file; it was not overwritten.",officialUrl:m,manualCommand:r}}function v(i,t,e,r,s,l,n){i.checks[t]={sha256:e.sha256,version:e.version,lastCheckedAt:r,lastStatus:s,clientVersion:l,remoteVersion:n}}function R(i){return process.platform==="win32"?`shennian skill update --path ${JSON.stringify(i)} --replace --json`:`shennian skill update --path '${i.replaceAll("'","'\\''")}' --replace --json`}function L(i){return S.createHash("sha256").update(i).digest("hex")}function p(i){return typeof i=="string"&&/^\d+\.\d+\.\d+$/.test(i)}function E(i,t){const e=i.split(".").map(Number),r=t.split(".").map(Number);for(let s=0;s<3;s+=1)if(e[s]!==r[s])return e[s]-r[s];return 0}export{F as OFFICIAL_SKILL_MANIFEST_URL,m as OFFICIAL_SKILL_URL,f as SKILL_CHECK_INTERVAL_MS,W as installOfficialSkill,$ as updateOfficialSkill};
1
+ import y from"node:crypto";import a from"node:fs";import d from"node:path";import{resolveShennianPath as V}from"../config/index.js";const F="https://shennian.net/skill-manifest.json",k="https://shennian.net/skill.md",u=1440*6e4;async function $(r,t){const e=C(r),i=j(e),s=t.registryPath??V("skill-updates.json"),l=L(s),n=l.targets[e],h=l.checks[e],o=t.now??Date.now(),f=R(e);if(n&&i.sha256!==n.sha256&&!t.replace)return v("local_modified",e,i.version,f);if(h&&h.sha256===i.sha256&&h.clientVersion===t.clientVersion&&!t.forceCheck&&!t.replace&&o-h.lastCheckedAt<u)return{status:h.lastStatus,path:e,localVersion:i.version,remoteVersion:h.remoteVersion,checked:!1,nextCheckAt:h.lastCheckedAt+u,message:"The previous official Skill check is still fresh; the local file was not changed.",...h.lastStatus==="current"||h.lastStatus==="registered"?{}:{officialUrl:k,manualCommand:f}};if(n&&n.clientVersion===t.clientVersion&&!t.forceCheck&&!t.replace&&o-n.lastCheckedAt<u)return{status:n.lastStatus==="updated"?"current":n.lastStatus,path:e,localVersion:i.version,checked:!1,nextCheckAt:n.lastCheckedAt+u,message:n.lastStatus==="check_failed"?"The previous official Skill check failed; continuing with the registered local copy.":"Official Skill check is still fresh; using the registered local copy."};let c;try{c=await x(t.fetchImpl??fetch)}catch{return n?(n.lastCheckedAt=o,n.lastStatus="check_failed",n.clientVersion=t.clientVersion):S(l,e,i,o,"check_failed",t.clientVersion),m(s,l),{status:"check_failed",path:e,localVersion:i.version,checked:!0,nextCheckAt:o+u,message:"Could not verify the official Skill manifest; continuing with the local copy.",officialUrl:k}}if(!I(t.clientVersion,c.skill))return S(l,e,i,o,"client_incompatible",t.clientVersion,c.skill.version),m(s,l),{status:"client_incompatible",path:e,localVersion:i.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"The official Skill is not compatible with this Shennian Client version.",officialUrl:k,manualCommand:f};if(g(i.version,c.skill.version)>0)return n?(n.lastCheckedAt=o,n.lastStatus="remote_older",n.clientVersion=t.clientVersion):S(l,e,i,o,"remote_older",t.clientVersion,c.skill.version),m(s,l),{status:"remote_older",path:e,localVersion:i.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"The public official Skill is older than this local copy; it was not replaced."};if(!n&&i.sha256===c.skill.sha256)return l.targets[e]={path:e,version:i.version,sha256:i.sha256,lastCheckedAt:o,lastStatus:"registered",clientVersion:t.clientVersion},m(s,l),{status:"registered",path:e,localVersion:i.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"Registered this exact official Skill copy for future safe updates."};const U=c.previousSkills?.some(w=>w.version===i.version&&w.sha256===i.sha256)??!1;if(!n&&!U&&!t.replace)return S(l,e,i,o,"manual_update_required",t.clientVersion,c.skill.version),m(s,l),v("manual_update_required",e,i.version,f,c.skill.version);if(n&&i.sha256!==n.sha256&&!t.replace)return v("local_modified",e,i.version,f,c.skill.version);if(i.sha256===c.skill.sha256)return l.targets[e]={path:e,version:i.version,sha256:i.sha256,lastCheckedAt:o,lastStatus:"current",clientVersion:t.clientVersion},m(s,l),{status:"current",path:e,localVersion:i.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"The registered official Skill is current."};if(!K(e))return{...v("not_writable",e,i.version,f,c.skill.version),message:"The Skill file is read-only or not a regular file; use the host update mechanism."};let _;try{_=await b(t.fetchImpl??fetch,c)}catch{return n?(n.lastCheckedAt=o,n.lastStatus="check_failed",n.clientVersion=t.clientVersion):S(l,e,i,o,"check_failed",t.clientVersion,c.skill.version),m(s,l),{status:"check_failed",path:e,localVersion:i.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"Could not verify the official Skill file; continuing with the local copy.",officialUrl:k}}return O(e,_),l.targets[e]={path:e,version:c.skill.version,sha256:c.skill.sha256,lastCheckedAt:o,lastStatus:"updated",clientVersion:t.clientVersion},m(s,l),{status:"updated",path:e,localVersion:c.skill.version,remoteVersion:c.skill.version,checked:!0,nextCheckAt:o+u,message:"Updated the verified official Skill atomically. Re-read this file now; start a new AI host session if it caches Skills."}}async function W(r,t){const e=C(r);if(T(e))return $(e,{...t,forceCheck:!0});const i=t.fetchImpl??fetch,s=await x(i);if(!I(t.clientVersion,s.skill))return{status:"client_incompatible",path:e,localVersion:s.skill.version,remoteVersion:s.skill.version,checked:!0,message:"The official Skill is not compatible with this Shennian Client version.",officialUrl:k};const l=await b(i,s),n=d.dirname(e);a.mkdirSync(n,{recursive:!0});const h=d.join(n,`.SKILL.md.shennian-${process.pid}-${y.randomUUID()}.tmp`);try{a.writeFileSync(h,l,{flag:"wx",mode:420}),a.renameSync(h,e)}finally{try{a.unlinkSync(h)}catch{}}const o=t.now??Date.now(),f=t.registryPath??V("skill-updates.json"),c=L(f);return c.targets[e]={path:e,version:s.skill.version,sha256:s.skill.sha256,lastCheckedAt:o,lastStatus:"registered",clientVersion:t.clientVersion},delete c.checks[e],m(f,c),{status:"installed",path:e,localVersion:s.skill.version,remoteVersion:s.skill.version,checked:!0,nextCheckAt:o+u,message:"Installed the verified official Skill."}}function T(r){try{return a.lstatSync(r),!0}catch{return!1}}function C(r){if(!d.isAbsolute(r))throw new Error("skill_path_must_be_absolute");const t=d.resolve(r);if(d.basename(t)!=="SKILL.md")throw new Error("skill_path_must_name_SKILL.md");return t}function j(r){const t=a.lstatSync(r);if(!t.isFile()||t.isSymbolicLink())throw new Error("skill_path_must_be_regular_file");const e=a.readFileSync(r);return{version:A(e.toString("utf8")).version,sha256:E(e)}}function A(r){const t=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(r)?.[1];if(!t||!/^name:\s*shennian\s*$/m.test(t))throw new Error("not_official_shennian_skill");const e=/^version:\s*([^\s]+)\s*$/m.exec(t)?.[1];if(!e||!p(e))throw new Error("invalid_skill_version");return{version:e}}async function x(r){const t=await r(F,{redirect:"error",headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!t.ok)throw new Error("skill_manifest_unavailable");const e=await t.json(),i=e.skill;if(e.schemaVersion!==1||e.product!=="shennian"||!i||i.name!=="shennian"||i.url!==k||!p(i.version)||!p(i.minimumClientVersion)||i.maximumClientVersion!==null&&!p(i.maximumClientVersion)||!/^[a-f0-9]{64}$/.test(i.sha256??"")||e.previousSkills!==void 0&&(!Array.isArray(e.previousSkills)||e.previousSkills.length>32||e.previousSkills.some(s=>!s||!p(s.version)||!/^[a-f0-9]{64}$/.test(s.sha256))))throw new Error("invalid_skill_manifest");return e}async function b(r,t){const e=await r(k,{redirect:"error",headers:{Accept:"text/markdown"},signal:AbortSignal.timeout(1e4)});if(!e.ok)throw new Error("skill_download_unavailable");const i=Number(e.headers.get("content-length"));if(Number.isFinite(i)&&i>512e3)throw new Error("skill_too_large");const s=Buffer.from(await e.arrayBuffer());if(s.length===0||s.length>512e3)throw new Error("skill_too_large");if(E(s)!==t.skill.sha256)throw new Error("skill_integrity_mismatch");if(A(s.toString("utf8")).version!==t.skill.version)throw new Error("skill_version_mismatch");return s}function I(r,t){return!p(r)||g(r,t.minimumClientVersion)<0?!1:t.maximumClientVersion===null||g(r,t.maximumClientVersion)<=0}function K(r){try{const t=a.lstatSync(r);return!t.isFile()||t.isSymbolicLink()?!1:(a.accessSync(r,a.constants.W_OK),a.accessSync(d.dirname(r),a.constants.W_OK),!0)}catch{return!1}}function O(r,t){const e=d.dirname(r),i=a.statSync(r).mode&511,s=d.join(e,`.SKILL.md.shennian-${process.pid}-${y.randomUUID()}.tmp`);let l=null;try{l=a.openSync(s,"wx",i),a.writeFileSync(l,t),a.fsyncSync(l),a.closeSync(l),l=null,a.renameSync(s,r);try{const n=a.openSync(e,"r");a.fsyncSync(n),a.closeSync(n)}catch{}}finally{l!==null&&a.closeSync(l);try{a.unlinkSync(s)}catch{}}}function L(r){try{const t=JSON.parse(a.readFileSync(r,"utf8"));if(t.schemaVersion===1&&t.targets&&typeof t.targets=="object")return{schemaVersion:1,targets:t.targets,checks:t.checks&&typeof t.checks=="object"?t.checks:{}}}catch{}return{schemaVersion:1,targets:{},checks:{}}}function m(r,t){a.mkdirSync(d.dirname(r),{recursive:!0,mode:448});const e=`${r}.${process.pid}.${y.randomUUID()}.tmp`;a.writeFileSync(e,JSON.stringify(t,null,2),{mode:384}),a.renameSync(e,r);try{a.chmodSync(r,384)}catch{}}function v(r,t,e,i,s){return{status:r,path:t,localVersion:e,remoteVersion:s,checked:!0,message:r==="local_modified"?"The local Skill differs from its registered official copy; it was not overwritten.":"This local Skill copy is not registered as the current official file; it was not overwritten.",officialUrl:k,manualCommand:i}}function S(r,t,e,i,s,l,n){r.checks[t]={sha256:e.sha256,version:e.version,lastCheckedAt:i,lastStatus:s,clientVersion:l,remoteVersion:n}}function R(r){return process.platform==="win32"?`shennian skill update --path ${JSON.stringify(r)} --replace --json`:`shennian skill update --path '${r.replaceAll("'","'\\''")}' --replace --json`}function E(r){return y.createHash("sha256").update(r).digest("hex")}function p(r){return typeof r=="string"&&/^\d+\.\d+\.\d+$/.test(r)}function g(r,t){const e=r.split(".").map(Number),i=t.split(".").map(Number);for(let s=0;s<3;s+=1)if(e[s]!==i[s])return e[s]-i[s];return 0}export{F as OFFICIAL_SKILL_MANIFEST_URL,k as OFFICIAL_SKILL_URL,u as SKILL_CHECK_INTERVAL_MS,W as installOfficialSkill,$ as updateOfficialSkill};
@@ -1 +1 @@
1
- const s={not_installed:"\u6CA1\u6709\u5B89\u88C5\u6216\u627E\u4E0D\u5230\u7A0B\u5E8F",not_logged_in:"\u6CA1\u6709\u767B\u5F55\u6216\u6388\u6743\u5931\u6548",quota:"\u989D\u5EA6\u7528\u5B8C\u6216\u88AB\u9650\u6D41",crashed:"\u542F\u52A8\u5931\u8D25\u6216\u8FD0\u884C\u4E2D\u65AD"};function f(e){return s[e]}function p(e){const t=(e??"").toLowerCase();return/enoent|command not found|not installed|command_unavailable|runtime_unavailable|no such file|未找到|未安装/.test(t)?"not_installed":/log ?in|logged in|sign in|unauthori[sz]ed|\b401\b|\b403\b|auth(?:entication|_required)?\b|api key|credential|未登录|登录/.test(t)?"not_logged_in":/quota|usage limit|rate limit|too many requests|\b429\b|insufficient|credit|billing|exceeded|额度|用完|限流/.test(t)?"quota":"crashed"}const d=new Set(["manager","pi","pi-coding-agent"]);function x(e,t){const n=new Set(t);return e.find(r=>r.supportsStandardSession!==!1&&!d.has(r.type)&&r.authState!=="required"&&r.authState!=="error"&&!n.has(r.type))?.type??null}function w(e,t){return[`\u8FD9\u6BB5\u5BF9\u8BDD\u662F\u4ECE\u300C${e}\u300D\u81EA\u52A8\u5207\u6362\u8FC7\u6765\u7684\uFF08\u539F\u56E0\uFF1A${s[t]}\uFF09\u3002`,"\u4E0A\u4E00\u4E2A AI \u53EF\u80FD\u5DF2\u7ECF\u505A\u4E86\u4E00\u90E8\u5206\u64CD\u4F5C\uFF1A\u52A8\u624B\u524D\u5148\u6838\u5BF9\u73B0\u72B6\uFF08\u4F8B\u5982 shennian project task list \u770B\u5DF2\u5EFA\u7684\u4EFB\u52A1\uFF09\uFF0C","\u4E0D\u8981\u91CD\u590D\u6267\u884C\u6709\u526F\u4F5C\u7528\u7684\u64CD\u4F5C\uFF0C\u4E5F\u4E0D\u8981\u91CD\u590D\u521B\u5EFA\u5DF2\u5B58\u5728\u7684\u4EFB\u52A1\uFF1B\u6838\u5BF9\u540E\u518D\u7EE7\u7EED\u56DE\u5E94\u7528\u6237\u7684\u8FD9\u6761\u6D88\u606F\u3002"].join("")}const u=new Map,o=new Map,i=new Map,l=200;function a(e){for(;e.size>l;)e.delete(e.keys().next().value);return e}function h(e,t){a(u).set(e,t)}function S(e){return u.get(e)??""}function b(e,t){const n=o.get(e)??[];return n.includes(t)?n:[...n,t]}function g(e,t,n){a(o).set(t,[...n]),o.delete(e)}function _(e,t){a(i).set(e,t)}function y(e){const t=i.get(e)??"";return i.delete(e),t}function A(e){o.delete(e)}export{w as buildHandoverNote,g as carryStewardChain,p as classifyStewardFailure,S as lastStewardUserText,x as pickFailoverAgent,h as rememberStewardTurn,A as resetStewardChain,_ as setStewardHandover,f as stewardFailureLabel,b as stewardTriedAgents,y as takeStewardHandover};
1
+ const d={not_installed:"\u6CA1\u6709\u5B89\u88C5\u6216\u627E\u4E0D\u5230\u7A0B\u5E8F",not_logged_in:"\u6CA1\u6709\u767B\u5F55\u6216\u6388\u6743\u5931\u6548",quota:"\u989D\u5EA6\u7528\u5B8C\u6216\u88AB\u9650\u6D41",crashed:"\u542F\u52A8\u5931\u8D25\u6216\u8FD0\u884C\u4E2D\u65AD"};function p(e){return d[e]}function S(e){const t=(e??"").toLowerCase();return/enoent|command not found|not installed|command_unavailable|runtime_unavailable|no such file|未找到|未安装/.test(t)?"not_installed":/log ?in|logged in|sign in|unauthori[sz]ed|\b401\b|\b403\b|auth(?:entication|_required)?\b|api key|credential|未登录|登录/.test(t)?"not_logged_in":/quota|usage limit|rate limit|too many requests|\b429\b|insufficient|credit|billing|exceeded|额度|用完|限流/.test(t)?"quota":"crashed"}const c=new Set(["manager","pi","pi-coding-agent"]);function x(e,t){const n=new Set(t);return e.find(r=>r.supportsStandardSession!==!1&&!c.has(r.type)&&r.authState!=="required"&&r.authState!=="error"&&!n.has(r.type))?.type??null}function h(e,t){return[`\u8FD9\u6BB5\u5BF9\u8BDD\u662F\u4ECE\u300C${e}\u300D\u81EA\u52A8\u5207\u6362\u8FC7\u6765\u7684\uFF08\u539F\u56E0\uFF1A${d[t]}\uFF09\u3002`,"\u4E0A\u4E00\u4E2A AI \u53EF\u80FD\u5DF2\u7ECF\u505A\u4E86\u4E00\u90E8\u5206\u64CD\u4F5C\uFF1A\u52A8\u624B\u524D\u5148\u6838\u5BF9\u73B0\u72B6\uFF08\u4F8B\u5982 shennian project task list \u770B\u5DF2\u5EFA\u7684\u4EFB\u52A1\uFF09\uFF0C","\u4E0D\u8981\u91CD\u590D\u6267\u884C\u6709\u526F\u4F5C\u7528\u7684\u64CD\u4F5C\uFF0C\u4E5F\u4E0D\u8981\u91CD\u590D\u521B\u5EFA\u5DF2\u5B58\u5728\u7684\u4EFB\u52A1\uFF1B\u6838\u5BF9\u540E\u518D\u7EE7\u7EED\u56DE\u5E94\u7528\u6237\u7684\u8FD9\u6761\u6D88\u606F\u3002"].join("")}const u=new Map,o=new Map,a=new Map,l=200;function i(e){for(;e.size>l;)e.delete(e.keys().next().value);return e}function _(e,t){i(u).set(e,t)}function g(e){return u.get(e)??""}function b(e,t){const n=o.get(e)??[];return n.includes(t)?n:[...n,t]}function A(e,t,n){i(o).set(t,[...n]),o.delete(e)}function T(e,t){i(a).set(e,t)}function m(e){const t=a.get(e)??"";return a.delete(e),t}function y(e){o.delete(e)}const s=new Map,w=6e4;function v(e){i(s).set(e,Date.now())}function k(e){const t=s.get(e);return t!==void 0&&Date.now()-t<w}function E(e){s.delete(e)}export{h as buildHandoverNote,A as carryStewardChain,S as classifyStewardFailure,E as clearStewardSwitched,g as lastStewardUserText,v as markStewardSwitched,x as pickFailoverAgent,_ as rememberStewardTurn,y as resetStewardChain,T as setStewardHandover,p as stewardFailureLabel,b as stewardTriedAgents,m as takeStewardHandover,k as wasStewardJustSwitched};
@@ -1,8 +1,8 @@
1
- const E=/^\s*::git-[a-z-]+\{[^\n]*\}\s*$/gm,g=/^\s*\{\s*"v"\s*:\s*1\s*,\s*"type"\s*:\s*"(tool|tool_use|tool_result)"/,x=/^\s*<environment_context>\s*[^]*?<\/environment_context>\s*$/i,R=/<(cwd|shell|current_date|timezone)>[^<]*<\/\1>/gi,b=/^\s*<recommended_plugins>[^]*?<\/recommended_plugins>\s*/i,P=/^\s*<turn_aborted>[^]*?<\/turn_aborted>\s*$/i,S=/^\s*<codex_internal_context\b[^>]*>[^]*?<\/codex_internal_context>\s*$/i,T=/^\s*# AGENTS\.md instructions for [^\n]+\n+\s*<INSTRUCTIONS>\s*[^]*?<\/INSTRUCTIONS>\s*(?:<environment_context>[^]*?<\/environment_context>)?\s*$/i,h=/^\s*\{\s*"v"\s*:\s*1\s*,\s*"type"\s*:\s*"approval_pending"/,N=/(?:<\/?(?:environment_context|instructions|system|developer|codex_internal_context|recommended_plugins)\b|#\s*AGENTS\.md instructions\b)/i,A=/\bdata:[a-z0-9.+-]+\/[a-z0-9.+-]+;base64,[a-z0-9+/=\s]+/i,I=/(?:^|\s)(?=[A-Za-z0-9+/]{80,}={0,2}(?=\s|$))(?=[A-Za-z0-9+/]*[A-Z])(?=[A-Za-z0-9+/]*[a-z])(?=[A-Za-z0-9+/]*[0-9])[A-Za-z0-9+/]{80,}={0,2}(?=\s|$)/,v=new Set(["tool","tool_use","tool_result","thinking","system","developer","context","environment_context","channel_delivery_status"]),L="steward-terminal-open-";function O(e){return e.replace(/[[\]\\]/g,"\\$&")}function C(e){const t=O(e.name);return e.kind==="image"?`![${t}](<${e.path}>)`:`[${t}](<${e.path}>)`}function w(e,t){if(!t?.length)return e;const n=new Set(t.map(C));return e.split(`
1
+ const E=/^\s*::git-[a-z-]+\{[^\n]*\}\s*$/gm,g=/^\s*\{\s*"v"\s*:\s*1\s*,\s*"type"\s*:\s*"(tool|tool_use|tool_result)"/,R=/^\s*<environment_context>\s*[^]*?<\/environment_context>\s*$/i,S=/<(cwd|shell|current_date|timezone)>[^<]*<\/\1>/gi,x=/^\s*<recommended_plugins>[^]*?<\/recommended_plugins>\s*/i,P=/^\s*<turn_aborted>[^]*?<\/turn_aborted>\s*$/i,b=/^\s*<codex_internal_context\b[^>]*>[^]*?<\/codex_internal_context>\s*$/i,T=/^\s*# AGENTS\.md instructions for [^\n]+\n+\s*<INSTRUCTIONS>\s*[^]*?<\/INSTRUCTIONS>\s*(?:<environment_context>[^]*?<\/environment_context>)?\s*$/i,A=/^\s*\{\s*"v"\s*:\s*1\s*,\s*"type"\s*:\s*"approval_pending"/,I=/(?:<\/?(?:environment_context|instructions|system|developer|codex_internal_context|recommended_plugins)\b|#\s*AGENTS\.md instructions\b)/i,h=/\bdata:[a-z0-9.+-]+\/[a-z0-9.+-]+;base64,[a-z0-9+/=\s]+/i,N=/(?:^|\s)(?=[A-Za-z0-9+/]{80,}={0,2}(?=\s|$))(?=[A-Za-z0-9+/]*[A-Z])(?=[A-Za-z0-9+/]*[a-z])(?=[A-Za-z0-9+/]*[0-9])[A-Za-z0-9+/]{80,}={0,2}(?=\s|$)/,v=new Set(["tool","tool_use","tool_result","thinking","system","developer","context","environment_context","channel_delivery_status"]),L="steward-terminal-open-",G="steward-failover-user-";function O(e){return e.replace(/[[\]\\]/g,"\\$&")}function C(e){const t=O(e.name);return e.kind==="image"?`![${t}](<${e.path}>)`:`[${t}](<${e.path}>)`}function w(e,t){if(!t?.length)return e;const n=new Set(t.map(C));return e.split(`
2
2
  `).filter(s=>!n.has(s.trim())).join(`
3
3
  `).replace(/\n{3,}/g,`
4
4
 
5
- `).trim()}function u(e){if(!e||e[0]!=="{")return null;try{const t=JSON.parse(e);if(typeof t=="object"&&t!==null)return t}catch{}return null}function D(e){if(typeof e!="object"||e===null)return null;const t=e,n=typeof t.path=="string"?t.path:"",r=typeof t.name=="string"?t.name:"",s=typeof t.mimeType=="string"?t.mimeType:"",l=t.kind==="image"||t.kind==="file"||t.kind==="folder"?t.kind:null;if(!n||!r||!s||!l)return null;const f=typeof t.previewData=="string"&&t.previewData.trim()?t.previewData.trim():void 0,p=typeof t.byteSize=="number"&&Number.isSafeInteger(t.byteSize)&&t.byteSize>=0?t.byteSize:void 0,d=typeof t.sha256=="string"&&/^[a-f0-9]{64}$/i.test(t.sha256)?t.sha256.toLowerCase():void 0;return{path:n,name:r,mimeType:s,kind:l,...p!==void 0?{byteSize:p}:{},...d?{sha256:d}:{},...f?{previewData:f}:{}}}function o(e){const t=u(e);if(!t||t.v!==1)return null;if(t.type==="user"&&typeof t.content=="string"){const n=Array.isArray(t.attachments)?t.attachments.map(D).filter(r=>r!=null):void 0;return{v:1,type:"user",content:t.content,...n?.length?{attachments:n}:{}}}return t}function z(e){const t=o(e);return t?.type==="user"?t:null}function G(e,t){return t?.length?JSON.stringify({v:1,type:"user",content:e,attachments:t}):e}function $(e){if(g.test(e))return!0;const t=o(e);return!t||typeof t!="object"?!1:t.type==="tool"||t.type==="tool_use"||t.type==="tool_result"}function k(e){return h.test(e)?!0:o(e)?.type==="approval_pending"}function j(e,t="say"){return JSON.stringify({v:1,type:"steward_say",content:e,source:t})}function J(e){const t=o(e);if(!t||t.type!=="steward_say")return null;const n=t;return typeof n.content!="string"||!n.content.trim()?null:{v:1,type:"steward_say",content:n.content,source:n.source==="fallback"?"fallback":"say"}}function F(e){return V(e)?.agentVisible===!1}function V(e){const t=o(e);if(!t||t.type!=="channel_delivery_status")return null;const n=t;if(n.v!==1||n.channel!=="wechat"||n.agentVisible!==!1)return null;const r=typeof n.status=="string"&&n.status.trim()?n.status.trim():"";if(!r)return null;const s=typeof n.content=="string"&&n.content.trim()?n.content:r==="manual_review"?"\u53D1\u9001\u72B6\u6001\u4E0D\u786E\u5B9A\uFF0C\u8BF7\u68C0\u67E5\u5FAE\u4FE1":"\u672A\u80FD\u81EA\u52A8\u53D1\u9001\u5230\u5FAE\u4FE1";return{v:1,type:"channel_delivery_status",channel:"wechat",status:r,agentVisible:!1,content:s,replyId:i(n.replyId),idempotencyKey:i(n.idempotencyKey),bindingId:i(n.bindingId),reasonCode:i(n.reasonCode),copyText:i(n.copyText),copyableContentRef:i(n.copyableContentRef),errorSummary:i(n.errorSummary)}}function X(e){const t=e?.trim();return`${!t||t==="codex"?"Codex":t==="workbuddy"?"WorkBuddy":t} \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002`}function W(e){return JSON.stringify({v:1,type:"approval_pending",title:e?.title?.trim()||"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:e?.content?.trim()||X(e?.source),source:e?.source?.trim()||"codex",actionHint:e?.permission?e?.actionHint?.trim():e?.actionHint?.trim()||"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002",...e?.permission?{permission:e.permission}:{}})}function _(e){if(!x.test(e))return!1;const t=new Set;for(const n of e.matchAll(R))n[1]&&t.add(n[1].toLowerCase());return t.has("current_date")&&t.has("timezone")&&e.includes("<workspace_roots>")?!0:t.has("cwd")&&t.has("shell")&&t.has("current_date")&&t.has("timezone")}function M(e){return P.test(e)}function y(e){return T.test(e)}function U(e){const t=e.match(b);if(t){const n=e.slice(t[0].length).trim();return!n||_(n)||y(n)}return _(e)||M(e)||S.test(e)||y(e)}function c(e){if(!e)return"";const t=e.replace(/\r\n/g,`
5
+ `).trim()}function u(e){if(!e||e[0]!=="{")return null;try{const t=JSON.parse(e);if(typeof t=="object"&&t!==null)return t}catch{}return null}function D(e){if(typeof e!="object"||e===null)return null;const t=e,n=typeof t.path=="string"?t.path:"",r=typeof t.name=="string"?t.name:"",s=typeof t.mimeType=="string"?t.mimeType:"",l=t.kind==="image"||t.kind==="file"||t.kind==="folder"?t.kind:null;if(!n||!r||!s||!l)return null;const f=typeof t.previewData=="string"&&t.previewData.trim()?t.previewData.trim():void 0,p=typeof t.byteSize=="number"&&Number.isSafeInteger(t.byteSize)&&t.byteSize>=0?t.byteSize:void 0,d=typeof t.sha256=="string"&&/^[a-f0-9]{64}$/i.test(t.sha256)?t.sha256.toLowerCase():void 0;return{path:n,name:r,mimeType:s,kind:l,...p!==void 0?{byteSize:p}:{},...d?{sha256:d}:{},...f?{previewData:f}:{}}}function o(e){const t=u(e);if(!t||t.v!==1)return null;if(t.type==="user"&&typeof t.content=="string"){const n=Array.isArray(t.attachments)?t.attachments.map(D).filter(r=>r!=null):void 0;return{v:1,type:"user",content:t.content,...n?.length?{attachments:n}:{}}}return t}function z(e){const t=o(e);return t?.type==="user"?t:null}function F(e,t){return t?.length?JSON.stringify({v:1,type:"user",content:e,attachments:t}):e}function $(e){if(g.test(e))return!0;const t=o(e);return!t||typeof t!="object"?!1:t.type==="tool"||t.type==="tool_use"||t.type==="tool_result"}function k(e){return A.test(e)?!0:o(e)?.type==="approval_pending"}function j(e,t="say"){return JSON.stringify({v:1,type:"steward_say",content:e,source:t})}function J(e){const t=o(e);if(!t||t.type!=="steward_say")return null;const n=t;return typeof n.content!="string"||!n.content.trim()?null:{v:1,type:"steward_say",content:n.content,source:n.source==="fallback"?"fallback":"say"}}function W(e){return V(e)?.agentVisible===!1}function V(e){const t=o(e);if(!t||t.type!=="channel_delivery_status")return null;const n=t;if(n.v!==1||n.channel!=="wechat"||n.agentVisible!==!1)return null;const r=typeof n.status=="string"&&n.status.trim()?n.status.trim():"";if(!r)return null;const s=typeof n.content=="string"&&n.content.trim()?n.content:r==="manual_review"?"\u53D1\u9001\u72B6\u6001\u4E0D\u786E\u5B9A\uFF0C\u8BF7\u68C0\u67E5\u5FAE\u4FE1":"\u672A\u80FD\u81EA\u52A8\u53D1\u9001\u5230\u5FAE\u4FE1";return{v:1,type:"channel_delivery_status",channel:"wechat",status:r,agentVisible:!1,content:s,replyId:i(n.replyId),idempotencyKey:i(n.idempotencyKey),bindingId:i(n.bindingId),reasonCode:i(n.reasonCode),copyText:i(n.copyText),copyableContentRef:i(n.copyableContentRef),errorSummary:i(n.errorSummary)}}function X(e){const t=e?.trim();return`${!t||t==="codex"?"Codex":t==="workbuddy"?"WorkBuddy":t} \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002`}function Z(e){return JSON.stringify({v:1,type:"approval_pending",title:e?.title?.trim()||"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:e?.content?.trim()||X(e?.source),source:e?.source?.trim()||"codex",actionHint:e?.permission?e?.actionHint?.trim():e?.actionHint?.trim()||"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002",...e?.permission?{permission:e.permission}:{}})}function _(e){if(!R.test(e))return!1;const t=new Set;for(const n of e.matchAll(S))n[1]&&t.add(n[1].toLowerCase());return t.has("current_date")&&t.has("timezone")&&e.includes("<workspace_roots>")?!0:t.has("cwd")&&t.has("shell")&&t.has("current_date")&&t.has("timezone")}function M(e){return P.test(e)}function y(e){return T.test(e)}function U(e){const t=e.match(x);if(t){const n=e.slice(t[0].length).trim();return!n||_(n)||y(n)}return _(e)||M(e)||b.test(e)||y(e)}function c(e){if(!e)return"";const t=e.replace(/\r\n/g,`
6
6
  `);if(!/(^|\n)\s*::git-[a-z-]+\{[^\n]*\}\s*(?=\n|$)/.test(t))return t;const r=t.replace(E,"");return r.trim()?r.replace(/[ \t]+\n/g,`
7
7
  `).replace(/\n+$/g,""):""}function m(e){if(!e)return"";const t=z(e);if(t)return w(t.content,t.attachments);const n=o(e);if(n){if(typeof n.content=="string")return c(n.content);if("text"in n&&typeof n.text=="string")return c(n.text)}try{const r=JSON.parse(e);if(typeof r=="string")return r;if(typeof r=="object"&&r!==null){const s=r;if(typeof s.content=="string")return c(s.content);if(typeof s.text=="string")return c(s.text)}}catch{}return c(e)}function a(e,t=160){if(typeof e!="string"||!Number.isSafeInteger(t)||t<1)return null;const n=e.replace(/\r\n/g,`
8
- `).trim();if(!n||N.test(n)||A.test(n)||I.test(n)||u(n))return null;const r=n.replace(/\s+/g," ");return r.length>t?`${r.slice(0,t)}\u2026`:r}function Z(e,t=160){if(!e||$(e)||U(e))return null;if(k(e))return a("\u9700\u8981\u7528\u6237\u786E\u8BA4",t);const n=o(e);if(n){const r=typeof n.type=="string"?n.type.toLowerCase():"";return!r||v.has(r)?null:a(m(e),t)}return u(e)?null:a(m(e),t)}function i(e){return typeof e=="string"&&e.trim()?e:void 0}export{L as STEWARD_TERMINAL_OPEN_MESSAGE_ID_PREFIX,W as buildApprovalPendingPayload,j as buildStewardSayPayload,G as buildUserMessagePayload,m as extractPayloadText,F as isAgentHiddenPayload,k as isApprovalPendingPayload,y as isCodexProjectInstructionsPayload,M as isCodexTurnAbortedPayload,U as isSystemControlPayload,_ as isSystemEnvironmentContextPayload,$ as isToolPayload,V as parseChannelDeliveryStatusPayload,J as parseStewardSayPayload,o as parseStructuredMessagePayload,z as parseUserMessagePayload,a as sanitizeSessionPreview,Z as sessionPreviewFromPayload,c as stripGitDirectiveArtifacts};
8
+ `).trim();if(!n||I.test(n)||h.test(n)||N.test(n)||u(n))return null;const r=n.replace(/\s+/g," ");return r.length>t?`${r.slice(0,t)}\u2026`:r}function B(e,t=160){if(!e||$(e)||U(e))return null;if(k(e))return a("\u9700\u8981\u7528\u6237\u786E\u8BA4",t);const n=o(e);if(n){const r=typeof n.type=="string"?n.type.toLowerCase():"";return!r||v.has(r)?null:a(m(e),t)}return u(e)?null:a(m(e),t)}function i(e){return typeof e=="string"&&e.trim()?e:void 0}export{G as STEWARD_FAILOVER_USER_MESSAGE_ID_PREFIX,L as STEWARD_TERMINAL_OPEN_MESSAGE_ID_PREFIX,Z as buildApprovalPendingPayload,j as buildStewardSayPayload,F as buildUserMessagePayload,m as extractPayloadText,W as isAgentHiddenPayload,k as isApprovalPendingPayload,y as isCodexProjectInstructionsPayload,M as isCodexTurnAbortedPayload,U as isSystemControlPayload,_ as isSystemEnvironmentContextPayload,$ as isToolPayload,V as parseChannelDeliveryStatusPayload,J as parseStewardSayPayload,o as parseStructuredMessagePayload,z as parseUserMessagePayload,a as sanitizeSessionPreview,B as sessionPreviewFromPayload,c as stripGitDirectiveArtifacts};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Shennian \u2014 AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {