shennian 0.3.42 → 0.3.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/publish-build-manifest.json +91 -41
- package/dist/src/agents/adapter.d.ts +1 -0
- package/dist/src/index.js +3 -3
- package/dist/src/native-fusion/codex-parser.d.ts +1 -0
- package/dist/src/native-fusion/codex-parser.js +4 -4
- package/dist/src/native-fusion/file-watcher.d.ts +18 -0
- package/dist/src/native-fusion/file-watcher.js +1 -0
- package/dist/src/native-fusion/local-repository.d.ts +53 -0
- package/dist/src/native-fusion/local-repository.js +2 -0
- package/dist/src/native-fusion/opencode-parser.js +2 -2
- package/dist/src/native-fusion/parser-common.d.ts +7 -1
- package/dist/src/native-fusion/parser-common.js +4 -4
- package/dist/src/native-fusion/parsers.d.ts +2 -1
- package/dist/src/native-fusion/parsers.js +2 -2
- package/dist/src/native-fusion/service.d.ts +10 -2
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/session-header.d.ts +9 -0
- package/dist/src/native-fusion/session-header.js +2 -0
- package/dist/src/native-fusion/state.d.ts +1 -1
- package/dist/src/native-fusion/state.js +2 -1
- package/dist/src/native-fusion/types.d.ts +31 -5
- package/dist/src/native-fusion/types.js +1 -1
- package/dist/src/personal-sync/paths.d.ts +2 -0
- package/dist/src/personal-sync/paths.js +1 -0
- package/dist/src/relay/client.d.ts +4 -1
- package/dist/src/relay/client.js +1 -1
- package/dist/src/session/attachment-reference.d.ts +2 -0
- package/dist/src/session/attachment-reference.js +1 -0
- package/dist/src/session/attachment-transfer-store.d.ts +38 -0
- package/dist/src/session/attachment-transfer-store.js +2 -0
- package/dist/src/session/canonical-store.d.ts +101 -0
- package/dist/src/session/canonical-store.js +5 -0
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/fs.d.ts +0 -1
- package/dist/src/session/handlers/fs.js +1 -1
- package/dist/src/session/handlers/message-status.d.ts +3 -0
- package/dist/src/session/handlers/message-status.js +1 -0
- package/dist/src/session/handlers/title.js +1 -1
- package/dist/src/session/handlers/tool-detail.js +1 -1
- package/dist/src/session/handlers/voice-window.d.ts +3 -0
- package/dist/src/session/handlers/voice-window.js +1 -0
- package/dist/src/session/history-subscriptions.d.ts +17 -0
- package/dist/src/session/history-subscriptions.js +1 -0
- package/dist/src/session/index-publisher.d.ts +3 -0
- package/dist/src/session/index-publisher.js +1 -0
- package/dist/src/session/manager.d.ts +2 -0
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/queue.d.ts +1 -1
- package/dist/src/session/queue.js +4 -3
- package/dist/src/session/store.d.ts +33 -3
- package/dist/src/session/store.js +2 -3
- package/dist/src/session/tool-detail-store.d.ts +16 -0
- package/dist/src/session/tool-detail-store.js +2 -0
- package/dist/src/session/types.d.ts +3 -13
- package/node_modules/@shennian/wire/dist/events.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/fs.d.ts +45 -0
- package/node_modules/@shennian/wire/dist/fs.js +7 -1
- package/node_modules/@shennian/wire/dist/index.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/index.js +1 -0
- package/node_modules/@shennian/wire/dist/machine.d.ts +6 -0
- package/node_modules/@shennian/wire/dist/message-payload.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/message-payload.js +15 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/session-sync.d.ts +197 -0
- package/node_modules/@shennian/wire/dist/session-sync.js +49 -0
- package/node_modules/@shennian/wire/dist/session.d.ts +24 -13
- package/node_modules/@shennian/wire/dist/tool-detail.d.ts +18 -11
- package/node_modules/@shennian/wire/dist/tool-detail.js +7 -1
- package/package.json +1 -1
- package/dist/src/session/remote-attachments.d.ts +0 -15
- package/dist/src/session/remote-attachments.js +0 -1
- package/dist/src/session/tool-summary.d.ts +0 -1
- package/dist/src/session/tool-summary.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createAgent as
|
|
1
|
+
import{createAgent as y}from"../../agents/adapter.js";import{buildManagedAgentEnv as g}from"../../agents/config-status.js";import{recordSession as f}from"../store.js";import{requestSessionIndexPublish as S}from"../index-publisher.js";function o(e){return typeof e=="string"?e.trim():""}async function w(e,i){const t=i.params,r=o(t.sessionId),d=o(t.title),n=o(t.agentSessionId),c=o(t.agentType),l=o(t.workDir)||process.cwd(),u=o(t.titleOriginEventId),p=t.titleRevision;if(!r||!d||!c||t.titleSource!=="shennian_manual"||!Number.isSafeInteger(p)||Number(p)<1||!u){e.client.sendRes({type:"res",id:i.id,ok:!1,error:"explicit shennian_manual title authority is required"});return}if(f({sessionId:r,agentType:c,workDir:l,agentSessionId:n||null,title:d,titleSource:"shennian_manual",titleRevision:Number(p),titleLockedByUser:!0,titleOriginEventId:u}),S(e.client),c!=="codex"||!n){e.client.sendRes({type:"res",id:i.id,ok:!0,payload:{localApplied:!0,nativeWriteback:"unsupported"}});return}const s=e.sessions.get(r);if(s?.agentType==="codex"&&s.adapter.setTitle){await s.adapter.setTitle(n,d,s.workDir||l),s.agentSessionId=n,s.lastActiveAt=Date.now(),e.client.sendRes({type:"res",id:i.id,ok:!0,payload:{synced:!0}});return}const a=y("codex");if(!a?.setTitle){e.client.sendRes({type:"res",id:i.id,ok:!1,error:"Codex adapter does not support title sync"});return}a.configure?.({sessionId:r,env:g("codex")});try{await a.start(r,l,n),await a.setTitle(n,d,l),e.client.sendRes({type:"res",id:i.id,ok:!0,payload:{synced:!0}})}finally{await a.stop().catch(()=>{})}}export{w as handleSessionTitleSet};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isSystemControlPayload as
|
|
1
|
+
import{isSystemControlPayload as I,SESSION_TOOL_DETAIL_LIMITS as l}from"@shennian/wire";import{readToolDetail as g}from"../tool-detail-store.js";const A=/(?:token|api[-_]?key|password|passwd|pwd|secret|authorization|cookie|credential|private[-_]?key)/i,_=/\b([A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|PWD|AUTH)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi,T=/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi,D=/\bsk-[A-Za-z0-9_-]{12,}\b/g;function O(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function M(e){const n=typeof e=="number"?e:Number(e);return!Number.isFinite(n)||n<=0?l.defaultMaxBytes:Math.min(Math.max(l.minMaxBytes,Math.floor(n)),l.maxMaxBytes)}function u(e,n){if(I(e))return"[SYSTEM CONTEXT REDACTED]";const t=e.replace(_,"$1=[REDACTED]").replace(T,"Bearer [REDACTED]").replace(D,"sk-[REDACTED]");return t.length>n?`${t.slice(0,n)}\u2026`:t}function f(e,n,t=0){if(e==null)return e;if(typeof e=="string")return u(e,n);if(typeof e=="number"||typeof e=="boolean")return e;if(t>=4)return"[Truncated]";if(Array.isArray(e))return e.slice(0,20).map(r=>f(r,n,t+1));if(typeof e=="object"){const r={};for(const[o,a]of Object.entries(e).slice(0,50))r[o]=A.test(o)?"[REDACTED]":f(a,n,t+1);return r}return String(e)}function z(e,n){const t=O(e)?.command;if(typeof t=="string")return u(t,n);if(Array.isArray(t))return u(t.map(String).join(" "),n)}function N(e){return Buffer.byteLength(JSON.stringify(e),"utf8")}function p(e){for(let n=0;n<3;n++){const t=N(e);if(t===e.byteSize)break;e.byteSize=t}return e}function E(e,n){const t={sessionId:e.sessionId,toolCallId:e.toolCallId,detailRevision:e.detailRevision,detailStatus:n==="not_found"?"not_found":"unavailable",resultOmitted:!0,redacted:!0,byteSize:0,expiresAt:new Date(Date.now()+l.responseTtlMs).toISOString(),source:"unavailable",reason:n};return p(t)}async function C(e,n){const t=n.params,r=typeof t.sessionId=="string"?t.sessionId:"",o=typeof t.toolCallId=="string"?t.toolCallId:"",a=typeof t.detailRevision=="number"&&Number.isSafeInteger(t.detailRevision)?t.detailRevision:-1;if(!r||!o||a<0){e.client.sendRes({type:"res",id:n.id,ok:!1,error:"upgrade_required: sessionId, toolCallId and detailRevision are required"});return}const c=M(t.maxBytes),y={sessionId:r,toolCallId:o,detailRevision:a,maxBytes:c},i=g(r,o);if(!i){e.client.sendRes({type:"res",id:n.id,ok:!0,payload:E(y,"not_found")});return}if(i.detailRevision!==a){e.client.sendRes({type:"res",id:n.id,ok:!0,payload:E(y,"revision_mismatch")});return}const d=Math.max(512,Math.floor(c/4)),m=i.args==null?void 0:f(i.args,d),b=z(i.args,d),S=typeof i.result=="string"?u(i.result,d):i.result==null?void 0:u(JSON.stringify(f(i.result,d)),d),R=new Date(Date.now()+l.responseTtlMs).toISOString();let s={sessionId:r,toolCallId:o,detailRevision:a,detailStatus:"available",status:i.status,...b?{command:b}:{},...m!==void 0?{argsSummary:m}:{},...S!==void 0?{result:S}:{},resultOmitted:S===void 0,redacted:!0,byteSize:0,expiresAt:R,source:"local-tool-index"};p(s),s.byteSize>c&&(delete s.result,s.resultOmitted=!0,p(s)),s.byteSize>c&&(s=E(y,"response_too_large")),e.client.sendRes({type:"res",id:n.id,ok:!0,payload:s})}export{C as handleSessionToolDetail};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{extractPayloadText as m,isAgentHiddenPayload as h,isSystemControlPayload as g,isToolPayload as p}from"@shennian/wire";import{getCanonicalSessionStore as I}from"../store.js";const S=8,y=32*1024;function M(e,i){const t=i.params;if(!t?.sessionId?.trim()||!t.callId?.trim())throw new Error("sessionId and callId are required");const d=u(t.limit,4,S),l=u(t.maxBytes,y,y),o=I().readRecent(t.sessionId,Math.min(d*6,48)),s=o.messages.filter(b),n=[];let c=0;for(let r=s.length-1;r>=0&&n.length<d;r-=1){const f=s[r],a=Buffer.byteLength(JSON.stringify(f),"utf8");if(n.length>0&&c+a>l)break;a>l||(n.push(f),c+=a)}n.reverse(),e.client.sendRes({type:"res",id:i.id,ok:!0,payload:{sessionId:t.sessionId,callId:t.callId,bodyRevision:o.bodyRevision,messages:n,truncated:o.hasOlder||n.length<s.length}})}function b(e){return e.role!=="user"&&e.role!=="agent"||p(e.payload)||g(e.payload)||h(e.payload)?!1:m(e.payload).trim().length>0}function u(e,i,t){if(e===void 0)return i;if(!Number.isSafeInteger(e)||e<1)throw new Error("invalid voice window limit");return Math.min(e,t)}export{M as handleVoiceSessionBodyWindow};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReqFrame } from '@shennian/wire';
|
|
2
|
+
import type { CliRelayClient } from '../relay/client.js';
|
|
3
|
+
import type { CanonicalSessionStore } from './canonical-store.js';
|
|
4
|
+
export declare class PersonalHistorySubscriptions {
|
|
5
|
+
private client;
|
|
6
|
+
private store;
|
|
7
|
+
private subscriptions;
|
|
8
|
+
private unsubscribeStore;
|
|
9
|
+
constructor(client: Pick<CliRelayClient, 'sendRes' | 'sendEvent'>, store?: CanonicalSessionStore);
|
|
10
|
+
handleOpen(req: ReqFrame): void;
|
|
11
|
+
handlePage(req: ReqFrame): void;
|
|
12
|
+
handleClose(req: ReqFrame): void;
|
|
13
|
+
closeAll(): void;
|
|
14
|
+
private handleMutation;
|
|
15
|
+
private publishMutation;
|
|
16
|
+
private requireSubscription;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SESSION_HISTORY_LIMITS as r}from"@shennian/wire";import{getCanonicalSessionStore as u}from"./store.js";class b{client;store;subscriptions=new Map;unsubscribeStore;constructor(i,s=u()){this.client=i,this.store=s,this.unsubscribeStore=s.subscribe(o=>this.handleMutation(o))}handleOpen(i){const s=i.params;if(a(s.sessionId,s.subscriptionId),this.subscriptions.has(s.subscriptionId))throw new Error("subscription already exists");if([...this.subscriptions.values()].filter(t=>t.sessionId===s.sessionId).length>=r.maxSubscriptionsPerSession)throw new Error("subscription_limit_exceeded");const e={sessionId:s.sessionId,subscriptionId:s.subscriptionId,snapshotRevision:0,lastSentRevision:0,active:!1,buffered:[]};this.subscriptions.set(s.subscriptionId,e);try{const t=this.store.readPage(s.sessionId,{limit:d(s.limit,r.defaultSnapshotMessages),...s.beforeSequence===void 0?{}:{beforeSequence:s.beforeSequence}});e.snapshotRevision=t.bodyRevision,e.lastSentRevision=t.bodyRevision,this.client.sendRes({type:"res",id:i.id,ok:!0,payload:{sessionId:s.sessionId,subscriptionId:s.subscriptionId,storageMode:"machine_local",snapshotRevision:t.bodyRevision,firstAvailableSeq:t.firstAvailableSeq,lastAvailableSeq:t.lastAvailableSeq,hasOlder:t.hasOlder,messages:t.entries}}),e.active=!0;for(const c of e.buffered)this.publishMutation(e,c);e.buffered=[]}catch(t){throw this.subscriptions.delete(s.subscriptionId),t}}handlePage(i){const s=i.params,o=this.requireSubscription(s.sessionId,s.subscriptionId);let e;try{e=this.store.readPageAtRevision(s.sessionId,{beforeSequence:s.beforeSequence,limit:d(s.limit,r.defaultPageMessages),revision:o.snapshotRevision})}catch{throw new Error("snapshot_compacted")}this.client.sendRes({type:"res",id:i.id,ok:!0,payload:{sessionId:s.sessionId,subscriptionId:s.subscriptionId,snapshotRevision:o.snapshotRevision,firstAvailableSeq:e.firstAvailableSeq,hasOlder:e.hasOlder,messages:e.entries}})}handleClose(i){const s=i.params;a(s.sessionId,s.subscriptionId),this.subscriptions.get(s.subscriptionId)?.sessionId===s.sessionId&&this.subscriptions.delete(s.subscriptionId),this.client.sendRes({type:"res",id:i.id,ok:!0,payload:{sessionId:s.sessionId,subscriptionId:s.subscriptionId,closed:!0}})}closeAll(){this.subscriptions.clear(),this.unsubscribeStore()}handleMutation(i){for(const s of this.subscriptions.values())s.sessionId===i.sessionId&&(s.active?this.publishMutation(s,i):s.buffered.push(i))}publishMutation(i,s){s.revision<=i.lastSentRevision||(this.client.sendEvent({type:"event",event:"session.body.delta",payload:{sessionId:i.sessionId,subscriptionId:i.subscriptionId,fromRevision:i.lastSentRevision,toRevision:s.revision,mutations:[{...s,subscriptionId:i.subscriptionId}]}}),i.lastSentRevision=s.revision)}requireSubscription(i,s){a(i,s);const o=this.subscriptions.get(s);if(!o||o.sessionId!==i)throw new Error("subscription_not_found");return o}}function a(n,i){if(typeof n!="string"||!n||typeof i!="string"||!i)throw new Error("invalid history subscription identity")}function d(n,i){const s=n??i;if(!Number.isSafeInteger(s)||s<1||s>r.maxPageMessages)throw new Error("invalid history limit");return s}export{b as PersonalHistorySubscriptions};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CliRelayClient } from '../relay/client.js';
|
|
2
|
+
export declare function publishPendingSessionIndexes(client: Pick<CliRelayClient, 'sendBufferedEvent'>): Promise<void>;
|
|
3
|
+
export declare function requestSessionIndexPublish(client: Pick<CliRelayClient, 'sendBufferedEvent'>): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{acknowledgeSessionIndexUpdate as d,listPendingSessionIndexUpdates as r}from"./store.js";const i=new WeakMap,t=new WeakSet;function a(s){const e=s,n=i.get(e);if(n)return t.add(e),n;const o=c(s).finally(()=>{i.get(e)===o&&i.delete(e),t.delete(e)&&f(s)});return i.set(e,o),o}async function c(s){const e=r();for(const n of e)await s.sendBufferedEvent({type:"event",event:"session.index.updated",id:`session-index-${n.daemonInstallationId}-${n.session.id}-${n.session.indexRevision}`,payload:n},6e4),d(n.session.id,n.session.indexRevision)}function f(s){a(s).catch(e=>{console.error("[session-index] sync failed; dirty revisions retained for retry",e)})}export{a as publishPendingSessionIndexes,f as requestSessionIndexPublish};
|
|
@@ -27,7 +27,9 @@ export declare class SessionManager {
|
|
|
27
27
|
private pendingTransfers;
|
|
28
28
|
private managerRuntime;
|
|
29
29
|
private chatQueue;
|
|
30
|
+
private historySubscriptions;
|
|
30
31
|
private activityProbeTimer;
|
|
32
|
+
private attachmentCleanupTimer;
|
|
31
33
|
private activeRequests;
|
|
32
34
|
constructor(client: CliRelayClient, nativeFusion?: NativeSessionFusionService | null, cliVersion?: string | undefined, upgradePolicyController?: UpgradePolicyController | null, managedRoomBinder?: ManagedRoomBinder | null);
|
|
33
35
|
private getRuntime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import u from"node:crypto";import{getRegisteredAgents as m,unregisterAgent as p}from"../agents/adapter.js";import{loadConfig as f}from"../config/index.js";import{handleUpgradeStart as g,handleUpgradeStatus as b}from"../commands/upgrade.js";import{handleAgentsRefresh as w,handleModelsRefresh as v}from"./handlers/agents.js";import{handleAgentCapabilitiesList as k}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as R,handleAgentConfigGet as y,handleAgentConfigTest as S,handleAgentConfigUpsert as A}from"./handlers/agent-config.js";import{handleChatAbort as c,handleChatSend as l}from"./handlers/chat.js";import{handleSessionRefresh as I}from"./handlers/session-refresh.js";import{handleSessionToolDetail as T}from"./handlers/tool-detail.js";import{handleSessionTitleSet as P}from"./handlers/title.js";import{cleanupPendingTransfers as C,handleFsLs as M,handleFsRead as F,handleFsRename as x,handleFsWrite as D,handleFsTransfer as E,handleFsTransferAbort as Q,handleFsTransferChunk as z,handleFsTransferFinish as U,handleFsTransferStart as W,handleFsExportMarkdownPdf as _,handleFsExportMarkdownPdfSetup as O,handleFsArchiveZip as V}from"./handlers/fs.js";import{handleRegionProbe as B,handleRegionSwitch as $,handleUpgradeSetPolicy as j}from"./handlers/control.js";import{ManagerRuntimeService as L,setManagerRuntimeService as h}from"../manager/runtime.js";import{ChatQueueManager as G}from"./queue.js";import{createAuthorizedFsRoot as N,resolveAuthorizedPath as X,resolveSessionWorkDir as Z}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/manager.js";import{registerCustomAgent as H}from"../agents/custom.js";import{handleManagedRoomBind as J,handleManagedRoomRestart as K}from"./handlers/room-managed.js";import{listSessionRecords as Y}from"./store.js";const q=50;import{resolveSessionWorkDir as Fe}from"../fs/boundary.js";class Pe{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;activityProbeTimer=null;activeRequests=0;constructor(e,t=null,a,i=null,n=null){this.client=e,this.nativeFusion=t,this.cliVersion=a,this.upgradePolicyController=i,this.managedRoomBinder=n,this.managerRuntime=new L({getRuntime:()=>this.getRuntime(),dispatchReq:s=>this.handleReq(s)}),this.chatQueue=new G({getRuntime:()=>this.getRuntime(),dispatchReq:s=>this.handleReq(s)}),h(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents(),this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(s=>{console.error("[session.activity] managed probe failed",s)})},15e3),this.activityProbeTimer.unref?.()}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController}}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}async activateRoomSession(e){const t=Y().find(s=>s.sessionId===e.sessionId),a=t?.agentType===e.agentType?t.modelId??void 0:void 0,i={value:null},n=new Proxy(this.client,{get:(s,o)=>{if(o==="sendRes")return d=>{i.value=d};const r=Reflect.get(s,o,s);return typeof r=="function"?r.bind(s):r}});return await l({...this.getRuntime(),client:n},{type:"req",id:e.clientMessageId,method:"chat.send",params:{...e,modelId:a,sessionMode:t?.sessionMode??(t?.agentType==="manager"?"manager":"standard"),managerConfig:t?.managerConfig??null,managerDefaultWorkerAgentType:t?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t?.managerDefaultWorkerModelId??null,waitForDispatch:!0,suppressExternalOwnerEcho:!0}},{source:"room_activation"}),{externalOwnerQueued:i.value?.ok===!0&&i.value.payload?.deliveryMode==="external_owner_queue"}}async abortRoomSession(e){const t=new Proxy(this.client,{get:(a,i)=>{if(i==="sendRes")return()=>{};const n=Reflect.get(a,i,a);return typeof n=="function"?n.bind(a):n}});await c({...this.getRuntime(),client:t},{type:"req",id:`room-activation-abort-${u.randomUUID()}`,method:"chat.abort",params:{sessionId:e.sessionId}})}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const a=await t.adapter.getStatus().catch(()=>null);if(!a?.active||!a.runPhase)continue;const i=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:a.runId||t.currentRunId,runPhase:a.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:i,canStop:a.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:a.runId||t.currentRunId,seq:n,runPhase:a.runPhase,canStop:a.canStop??!0},seq:n,id:`agent-status-${a.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of m())t.startsWith("custom:")&&p(t);const e=f();for(const[t,a]of Object.entries(e.customAgents??{}))H(t,a)}async handleReq(e){const t=this.getRuntime();this.activeRequests++;try{switch(e.method){case"chat.send":await l(t,e);break;case"chat.enqueue":await this.chatQueue.handleEnqueue(e);break;case"chat.queue.get":await this.chatQueue.handleGet(e);break;case"chat.queue.edit":await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":await this.chatQueue.handleDelete(e);break;case"chat.abort":await c(t,e);break;case"session.refresh":await I(t,e);break;case"session.tool.detail":await T(t,e);break;case"session.title.set":await P(t,e);break;case"room.agent.bind-managed":await J(t,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await K(t,this.managedRoomBinder,e);break;case"fs.ls":await M(t,e);break;case"fs.read":await F(t,e);break;case"fs.write":await D(t,e);break;case"fs.export.markdown-pdf":await _(t,e);break;case"fs.export.markdown-pdf.setup":await O(t,e);break;case"fs.archive.zip":await V(t,e);break;case"fs.rename":await x(t,e);break;case"fs.transfer":await E(t,e);break;case"fs.transfer.start":await W(t,e);break;case"fs.transfer.chunk":await z(t,e);break;case"fs.transfer.finish":await U(t,e);break;case"fs.transfer.abort":await Q(t,e);break;case"region.probe":await B(t,e);break;case"region.switch":await $(t,e);break;case"upgrade.start":await g(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0});break;case"upgrade.status":await b(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await j(t,e);break;case"agents.refresh":await w(t,e);break;case"models.refresh":await v(t,e);break;case"agent.config.get":await y(t,e);break;case"agent.config.upsert":await A(t,e);break;case"agent.config.clear":await R(t,e);break;case"agent.config.test":await S(t,e);break;case"agent.capabilities.list":await k(t,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(a){this.client.sendRes({type:"res",id:e.id,ok:!1,error:a instanceof Error?a.message:String(a)})}finally{this.activeRequests--}}evictIdleSessions(){if(this.sessions.size<q)return;let e=null;for(const[t,a]of this.sessions)(!e||a.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:a});e&&(e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return Z(e)}resolveAuthorizedPath(e,t){return X(e,N(t))}async cleanup(){this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null);for(const[,e]of this.sessions)e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),C(this.getRuntime()),await this.managerRuntime.stop(),h(null)}}export{Pe as SessionManager,Fe as resolveSessionWorkDir};
|
|
1
|
+
import m from"node:crypto";import{getRegisteredAgents as p,unregisterAgent as f}from"../agents/adapter.js";import{loadConfig as g}from"../config/index.js";import{handleUpgradeStart as b,handleUpgradeStatus as w}from"../commands/upgrade.js";import{handleAgentsRefresh as v,handleModelsRefresh as k}from"./handlers/agents.js";import{handleAgentCapabilitiesList as y}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as R,handleAgentConfigGet as S,handleAgentConfigTest as A,handleAgentConfigUpsert as T}from"./handlers/agent-config.js";import{handleChatAbort as c,handleChatSend as l}from"./handlers/chat.js";import{handleSessionRefresh as I}from"./handlers/session-refresh.js";import{handleSessionToolDetail as P}from"./handlers/tool-detail.js";import{handleSessionTitleSet as C}from"./handlers/title.js";import{handleSessionMessageStatus as M}from"./handlers/message-status.js";import{handleVoiceSessionBodyWindow as F}from"./handlers/voice-window.js";import{cleanupPendingTransfers as D,handleFsLs as x,handleFsRead as E,handleFsRename as Q,handleFsWrite as W,handleFsTransferAbort as _,handleFsTransferChunk as z,handleFsTransferFinish as U,handleFsTransferStart as O,handleFsExportMarkdownPdf as V,handleFsExportMarkdownPdfSetup as B,handleFsArchiveZip as $}from"./handlers/fs.js";import{handleRegionProbe as j,handleRegionSwitch as L,handleUpgradeSetPolicy as G}from"./handlers/control.js";import{ManagerRuntimeService as H,setManagerRuntimeService as h}from"../manager/runtime.js";import{ChatQueueManager as N}from"./queue.js";import{createAuthorizedFsRoot as X,resolveAuthorizedPath as Z,resolveSessionWorkDir as J}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/manager.js";import{registerCustomAgent as K}from"../agents/custom.js";import{handleManagedRoomBind as Y,handleManagedRoomRestart as q}from"./handlers/room-managed.js";import{listSessionRecords as d}from"./store.js";import{PersonalHistorySubscriptions as ee}from"./history-subscriptions.js";import{sweepAttachmentTransfers as te}from"./attachment-transfer-store.js";const se=50;import{resolveSessionWorkDir as ze}from"../fs/boundary.js";class Qe{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;constructor(e,t=null,s,i=null,n=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=i,this.managedRoomBinder=n,this.managerRuntime=new H({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a)}),this.chatQueue=new N({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a)}),this.historySubscriptions=new ee(this.client),h(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents(),this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...d().map(r=>r.workDir),...Array.from(this.pendingTransfers.values()).map(r=>r.rootPath)]);for(const r of a)try{te(this.resolvePath(r))}catch(o){console.error("[attachment.cleanup] failed",o instanceof Error?o.message:String(o))}},6e4),this.attachmentCleanupTimer.unref?.()}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController}}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}async activateRoomSession(e){const t=d().find(a=>a.sessionId===e.sessionId),s=t?.agentType===e.agentType?t.modelId??void 0:void 0,i={value:null},n=new Proxy(this.client,{get:(a,r)=>{if(r==="sendRes")return u=>{i.value=u};const o=Reflect.get(a,r,a);return typeof o=="function"?o.bind(a):o}});return await l({...this.getRuntime(),client:n},{type:"req",id:e.clientMessageId,method:"chat.send",params:{...e,modelId:s,sessionMode:t?.sessionMode??(t?.agentType==="manager"?"manager":"standard"),managerConfig:t?.managerConfig??null,managerDefaultWorkerAgentType:t?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t?.managerDefaultWorkerModelId??null,waitForDispatch:!0,suppressExternalOwnerEcho:!0}},{source:"room_activation"}),{externalOwnerQueued:i.value?.ok===!0&&i.value.payload?.deliveryMode==="external_owner_queue"}}async abortRoomSession(e){const t=new Proxy(this.client,{get:(s,i)=>{if(i==="sendRes")return()=>{};const n=Reflect.get(s,i,s);return typeof n=="function"?n.bind(s):n}});await c({...this.getRuntime(),client:t},{type:"req",id:`room-activation-abort-${m.randomUUID()}`,method:"chat.abort",params:{sessionId:e.sessionId}})}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const i=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:i,canStop:s.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:n,runPhase:s.runPhase,canStop:s.canStop??!0},seq:n,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of p())t.startsWith("custom:")&&f(t);const e=g();for(const[t,s]of Object.entries(e.customAgents??{}))K(t,s)}async handleReq(e){const t=this.getRuntime();this.activeRequests++;try{switch(e.method){case"chat.send":await l(t,e);break;case"chat.enqueue":await this.chatQueue.handleEnqueue(e);break;case"chat.queue.get":await this.chatQueue.handleGet(e);break;case"chat.queue.edit":await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":await this.chatQueue.handleDelete(e);break;case"chat.abort":await c(t,e);break;case"session.refresh":await I(t,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":M(t,e);break;case"session.tool.detail":await P(t,e);break;case"voice.session.body.window":F(t,e);break;case"session.title.set":await C(t,e);break;case"room.agent.bind-managed":await Y(t,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await q(t,this.managedRoomBinder,e);break;case"fs.ls":await x(t,e);break;case"fs.read":await E(t,e);break;case"fs.write":await W(t,e);break;case"fs.export.markdown-pdf":await V(t,e);break;case"fs.export.markdown-pdf.setup":await B(t,e);break;case"fs.archive.zip":await $(t,e);break;case"fs.rename":await Q(t,e);break;case"fs.transfer.start":await O(t,e);break;case"fs.transfer.chunk":await z(t,e);break;case"fs.transfer.finish":await U(t,e);break;case"fs.transfer.abort":await _(t,e);break;case"region.probe":await j(t,e);break;case"region.switch":await L(t,e);break;case"upgrade.start":await b(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0});break;case"upgrade.status":await w(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await G(t,e);break;case"agents.refresh":await v(t,e);break;case"models.refresh":await k(t,e);break;case"agent.config.get":await S(t,e);break;case"agent.config.upsert":await T(t,e);break;case"agent.config.clear":await R(t,e);break;case"agent.config.test":await A(t,e);break;case"agent.capabilities.list":await y(t,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(s){this.client.sendRes({type:"res",id:e.id,ok:!1,error:s instanceof Error?s.message:String(s)})}finally{this.activeRequests--}}evictIdleSessions(){if(this.sessions.size<se)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return J(e)}resolveAuthorizedPath(e,t){return Z(e,X(t))}async cleanup(){this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),D(this.getRuntime()),await this.managerRuntime.stop(),h(null)}}export{Qe as SessionManager,ze as resolveSessionWorkDir};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ChatQueueSnapshot, type ReqFrame } from '@shennian/wire';
|
|
2
2
|
import type { LocalReqDispatcher } from '../manager/runtime.js';
|
|
3
3
|
import type { SessionManagerRuntime } from './types.js';
|
|
4
4
|
export declare class ChatQueueManager {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import c from"node:fs";import{randomUUID as p}from"node:crypto";import{buildUserMessagePayload as R}from"@shennian/wire";import{mergeProjectedSessions as T}from"./projection.js";import{parsePersonalAttachmentReferences as m}from"./attachment-reference.js";import{assertFinishedAttachmentReferences as k,markAttachmentReferences as q}from"./attachment-transfer-store.js";import{resolvePersonalSyncV1Path as w}from"../personal-sync/paths.js";import{appendMessage as b,getMessageDeliveryStatus as E,recordSession as v,tombstoneMessage as P,upsertMessage as D}from"./store.js";import{requestSessionIndexPublish as y}from"./index-publisher.js";const I=w("outbound-queue.json");function A(){return{sessions:{}}}function M(){return new Date().toISOString()}function Q(s){return`enqueue-send-${s}-${p()}`}function l(){try{const s=JSON.parse(c.readFileSync(I,"utf-8"));return{sessions:s.sessions&&typeof s.sessions=="object"?s.sessions:{}}}catch(s){if(s.code==="ENOENT"||s instanceof Error&&s.message.startsWith("ENOENT:"))return A();throw s}}function g(s){const e=w();c.mkdirSync(e,{recursive:!0,mode:448});const n=`${I}.tmp-${process.pid}-${p()}`;try{c.writeFileSync(n,`${JSON.stringify(s,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});const t=c.openSync(n,"r");if(typeof t=="number")try{c.fsyncSync(t)}finally{c.closeSync(t)}c.renameSync(n,I)}finally{try{c.unlinkSync(n)}catch{}}}function $(s){const e=M();return{id:s.queueMessageId||s.clientMessageId||`queue-${p()}`,sessionId:s.sessionId,text:s.text,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:s.agentSessionId??null,modelId:s.modelId??null,systemPrompt:s.systemPrompt??null,managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:s.managerDefaultWorkerModelId??null,reasoningEffort:s.reasoningEffort??null,clientMessageId:s.clientMessageId??null,attachments:m(s.attachments),externalChannel:s.externalChannel??null,replyTarget:s.replyTarget??null,origin:s.origin,createdAt:e,updatedAt:e}}function x(s){return{id:s.clientMessageId??s.id,sessionId:s.sessionId,role:"user",ts:Date.parse(s.createdAt),payload:R(s.text,s.attachments)}}class _{opts;draining=new Set;constructor(e){this.opts=e,setTimeout(()=>this.drainIdleQueues(),0).unref?.()}getSnapshot(e){return{sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:l().sessions[e]??[]}}async handleEnqueue(e){const n=this.opts.getRuntime(),t=e.params;if(T(t.sessionListProjection),!t.sessionId||!t.text||!t.agentType||!t.workDir){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"});return}const i=n.resolvePath(t.workDir),o=m(t.attachments);o?.length&&k(i,o);const r={text:t.text,attachments:o,localized:!1},d=await this.isSessionBusy(t.sessionId),u=l(),h=u.sessions[t.sessionId]??[];if(!d&&!h.length){await this.opts.dispatchReq({...e,id:Q(e.id),method:"chat.send",params:{...t,text:r.text,responseId:e.id,clientMessageId:t.clientMessageId??t.queueMessageId,waitForDispatch:!0,attachments:r.attachments}});return}const a=$({...t,text:r.text,attachments:r.attachments}),f=t.origin==="external"?C(h,a):null;f||(u.sessions[t.sessionId]=[...h,a],g(u),v({sessionId:a.sessionId,agentType:a.agentType,sessionMode:a.sessionMode,managerConfig:a.managerConfig,workDir:a.workDir,agentSessionId:a.agentSessionId,modelId:a.modelId}),b(a.sessionId,x(a),"queued"),q(i,a.attachments??[]),y(n.client)),this.broadcast(t.sessionId),n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:f?.id??a.id,...E(t.sessionId,f?.clientMessageId??f?.id??a.clientMessageId??a.id),queue:this.getSnapshot(t.sessionId),...r.localized?{localizedAttachments:!0}:{}}}),d||this.drainNext(t.sessionId)}async handleGet(e){const n=this.opts.getRuntime(),t=e.params;if(!t.sessionId){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}}),this.getSnapshot(t.sessionId).busy||this.drainNext(t.sessionId)}async handleEdit(e){const n=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const i=l(),o=i.sessions[t.sessionId]??[],r=o.findIndex(h=>h.id===t.queueMessageId);if(r<0){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}const d=m(t.attachments),u=n.resolvePath(o[r].workDir);d?.length&&k(u,d),o[r]={...o[r],text:t.text,attachments:d,updatedAt:M()},i.sessions[t.sessionId]=o,g(i),D(t.sessionId,x(o[r]),"queued"),o[r].attachments?.length&&q(u,o[r].attachments??[]),y(n.client),this.broadcast(t.sessionId),n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const n=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const i=l(),o=i.sessions[t.sessionId]??[],r=o.find(u=>u.id===t.queueMessageId),d=o.filter(u=>u.id!==t.queueMessageId);if(d.length===o.length){n.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}d.length?i.sessions[t.sessionId]=d:delete i.sessions[t.sessionId],g(i),P(t.sessionId,r?.clientMessageId??r?.id??t.queueMessageId),y(n.client),this.broadcast(t.sessionId),n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}noteTerminal(e){this.drainNext(e)}drainIdleQueues(){const e=l();for(const n of Object.keys(e.sessions))this.drainNext(n)}async drainNext(e){if(this.draining.has(e)||await this.isSessionBusy(e))return;const i=(l().sessions[e]??[])[0];if(!i){this.broadcast(e);return}const o=i;this.draining.add(e);try{D(e,x(o),"queued"),await this.dispatchQueuedMessage(o);const r=l(),d=(r.sessions[e]??[]).filter(u=>u.id!==i.id);d.length?r.sessions[e]=d:delete r.sessions[e],g(r),this.broadcast(e)}finally{this.draining.delete(e)}}mergeExternalMessages(e,n){const t=[e];for(;n[0]?.origin==="external";)t.push(n.shift());const i=W(t);return i.length===1?i[0]:{...e,id:`external-batch-${e.id}`,text:i.map(o=>o.text).filter(Boolean).join(`
|
|
2
3
|
|
|
3
|
-
`),attachments:
|
|
4
|
-
`)}function
|
|
4
|
+
`),attachments:B(i.flatMap(o=>o.attachments??[])),updatedAt:M()}}async dispatchQueuedMessage(e){await this.opts.dispatchReq({type:"req",id:`queue-send-${e.id}-${Date.now()}`,method:"chat.send",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??void 0,systemPrompt:e.systemPrompt??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId,reasoningEffort:e.reasoningEffort??void 0,clientMessageId:e.clientMessageId??e.id,attachments:e.attachments,externalChannel:e.externalChannel,replyTarget:e.replyTarget,waitForDispatch:!0}})}async isSessionBusy(e){const n=this.opts.getRuntime().sessions.get(e);if(!n)return!1;if(n.currentRunId)return!0;if(!n.adapter.getStatus)return!1;const t=await n.adapter.getStatus().catch(()=>null);return t?.active?(t.runId&&(n.currentRunId=t.runId,n.currentRunPhase=t.runPhase??n.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}function W(s){const e=new Set,n=[];for(const t of s){const i=S(t);e.has(i)||(e.add(i),n.push(t))}return n}function C(s,e){const n=S(e);return s.find(t=>S(t)===n)??null}function S(s){const e=N(s);return e?`id:${e}`:["body",j(s.text),...(s.attachments??[]).map(n=>n.path||`${n.name}:${n.mimeType}`)].join(`
|
|
5
|
+
`)}function N(s){const e=typeof s.clientMessageId=="string"?s.clientMessageId.trim():"";if(e)return e;const n=typeof s.id=="string"?s.id.trim():"";return n&&!n.startsWith("queue-")?n:""}function B(s){const e=new Set,n=[];for(const t of s){const i=t.path||`${t.name}:${t.mimeType}`;e.has(i)||(e.add(i),n.push(t))}return n.length?n:void 0}function j(s){return String(s||"").replace(/\s+/g," ").trim()}export{_ as ChatQueueManager};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AgentType, type Envelope, type ManagerConfig, type SessionIndexUpdate, type SessionDeliveryState, type SessionMessageStatusResponse, type SessionMode, type SessionTitleSource } from '@shennian/wire';
|
|
2
|
+
import { PERSONAL_SYNC_V1_ROOT_NAME } from '../personal-sync/paths.js';
|
|
3
|
+
import { CanonicalSessionStore } from './canonical-store.js';
|
|
4
|
+
export { PERSONAL_SYNC_V1_ROOT_NAME };
|
|
2
5
|
export type LocalSessionRecord = {
|
|
3
6
|
sessionId: string;
|
|
4
7
|
agentType: AgentType;
|
|
@@ -14,7 +17,22 @@ export type LocalSessionRecord = {
|
|
|
14
17
|
updatedAt: string;
|
|
15
18
|
lastActivityAt: string;
|
|
16
19
|
lastMessagePreview?: string | null;
|
|
20
|
+
bodyRevision: number;
|
|
21
|
+
indexRevision: number;
|
|
22
|
+
title: string;
|
|
23
|
+
titleSource: SessionTitleSource;
|
|
24
|
+
titleRevision: number;
|
|
25
|
+
titleLockedByUser: boolean;
|
|
26
|
+
titleOriginEventId: string | null;
|
|
27
|
+
firstAvailableSeq: number | null;
|
|
28
|
+
visibleMessageCount: number;
|
|
29
|
+
lastVisibleMessageId: string | null;
|
|
30
|
+
lastBodyCommittedAt: string | null;
|
|
31
|
+
deletionRevision: number;
|
|
32
|
+
deletedAt: string | null;
|
|
33
|
+
syncedIndexRevision: number;
|
|
17
34
|
};
|
|
35
|
+
export declare function getDaemonInstallationId(): string;
|
|
18
36
|
export declare function recordSession(input: {
|
|
19
37
|
sessionId: string;
|
|
20
38
|
agentType: AgentType;
|
|
@@ -28,11 +46,23 @@ export declare function recordSession(input: {
|
|
|
28
46
|
status?: 'active' | 'completed' | 'failed';
|
|
29
47
|
lastActivityAt?: string;
|
|
30
48
|
lastMessagePreview?: string | null;
|
|
31
|
-
|
|
49
|
+
title?: string;
|
|
50
|
+
titleSource?: SessionTitleSource;
|
|
51
|
+
titleRevision?: number;
|
|
52
|
+
titleLockedByUser?: boolean;
|
|
53
|
+
titleOriginEventId?: string | null;
|
|
54
|
+
deletedAt?: string | null;
|
|
55
|
+
}): LocalSessionRecord;
|
|
32
56
|
export declare function listSessionRecords(): LocalSessionRecord[];
|
|
33
|
-
export declare function
|
|
57
|
+
export declare function listPendingSessionIndexUpdates(): SessionIndexUpdate[];
|
|
58
|
+
export declare function acknowledgeSessionIndexUpdate(sessionId: string, indexRevision: number): void;
|
|
59
|
+
export declare function appendMessage(sessionId: string, envelope: Envelope, deliveryState?: SessionDeliveryState): number;
|
|
60
|
+
export declare function upsertMessage(sessionId: string, envelope: Envelope, deliveryState?: SessionDeliveryState): number;
|
|
61
|
+
export declare function getMessageDeliveryStatus(sessionId: string, clientMessageId: string): SessionMessageStatusResponse;
|
|
62
|
+
export declare function tombstoneMessage(sessionId: string, messageId: string): number;
|
|
34
63
|
export declare function readMessages(sessionId: string, opts?: {
|
|
35
64
|
limit?: number;
|
|
36
65
|
before?: number;
|
|
37
66
|
}): Envelope[];
|
|
38
67
|
export declare function listSessions(): string[];
|
|
68
|
+
export declare function getCanonicalSessionStore(): CanonicalSessionStore;
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
`).filter(o=>o.trim().length>0);let s=[];for(const o of a)try{s.push(JSON.parse(o))}catch{}return s.sort((o,y)=>y.ts-o.ts),t?.before!==void 0&&(s=s.filter(o=>o.ts<t.before)),t?.limit!==void 0&&t.limit>0&&(s=s.slice(0,t.limit)),s}function h(){return u(),i.readdirSync(l).filter(e=>e.endsWith(".jsonl")).map(e=>e.replace(/\.jsonl$/,""))}export{D as appendMessage,x as listSessionRecords,h as listSessions,M as readMessages,A as recordSession};
|
|
1
|
+
import v from"node:crypto";import l from"node:fs";import f from"node:path";import{SESSION_SYNC_PROTOCOL_VERSION as M,SESSION_TITLE_SOURCE_PRIORITY as y}from"@shennian/wire";import{PERSONAL_SYNC_V1_ROOT_NAME as w,resolvePersonalSyncV1Path as p}from"../personal-sync/paths.js";import{CanonicalSessionStore as k}from"./canonical-store.js";let S=null,I=null;function m(){return p()}function r(){const t=f.join(m(),"canonical");return(!S||I!==t)&&(S=new k(t,c()),I=t),S}function R(){return f.join(m(),"session-index.json")}function u(){const t=R();if(!l.existsSync(t))return{};const e=JSON.parse(l.readFileSync(t,"utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`invalid personal session index: ${t}`);return e}function g(t){b(R(),t)}function O(t){const e=t.payload.replace(/\s+/g," ").trim();return!e||e.startsWith('{"v":1,"type":"tool')?null:e.length>120?`${e.slice(0,120)}...`:e}function c(){const t=f.join(m(),"installation.json");if(l.existsSync(t)){const i=JSON.parse(l.readFileSync(t,"utf8"));if(i.schemaVersion!==1||!i.daemonInstallationId)throw new Error(`invalid daemon installation identity: ${t}`);return i.daemonInstallationId}const e={schemaVersion:1,daemonInstallationId:v.randomUUID(),createdAt:new Date().toISOString()};return b(t,e),e.daemonInstallationId}function U(t){c();const e=u(),i=e[t.sessionId],n=new Date().toISOString(),s=r().getManifest(t.sessionId)?.bodyRevision??i?.bodyRevision??0,o=r().getManifest(t.sessionId),a=D(i,t),d={sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode??i?.sessionMode,managerConfig:t.managerConfig??i?.managerConfig??null,workDir:t.workDir,agentSessionId:t.agentSessionId??i?.agentSessionId??null,modelId:t.modelId??i?.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType??i?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId??i?.managerDefaultWorkerModelId??null,status:t.status??i?.status??"active",createdAt:i?.createdAt??n,updatedAt:n,lastActivityAt:t.lastActivityAt??i?.lastActivityAt??n,lastMessagePreview:t.lastMessagePreview??i?.lastMessagePreview??null,bodyRevision:s,indexRevision:(i?.indexRevision??0)+1,...a,firstAvailableSeq:o?.firstAvailableSeq??i?.firstAvailableSeq??null,visibleMessageCount:o?.visibleMessageCount??i?.visibleMessageCount??0,lastVisibleMessageId:o?.lastVisibleMessageId??i?.lastVisibleMessageId??null,lastBodyCommittedAt:o?.lastBodyCommittedAt??i?.lastBodyCommittedAt??null,deletionRevision:i?.deletionRevision??0,deletedAt:t.deletedAt??i?.deletedAt??null,syncedIndexRevision:i?.syncedIndexRevision??0};return e[t.sessionId]=d,g(e),d}function C(){return Object.values(u())}function V(){const t=c();return C().filter(e=>e.indexRevision>e.syncedIndexRevision).sort((e,i)=>e.indexRevision-i.indexRevision).map(e=>({protocolVersion:M,daemonInstallationId:t,session:{id:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId??null,title:e.title,titleSource:e.titleSource,titleRevision:e.titleRevision,titleLockedByUser:e.titleLockedByUser,titleOriginEventId:e.titleOriginEventId,status:e.status??"active",workDir:e.workDir,lastMessagePreview:e.lastMessagePreview??null,bodyStorageMode:"machine_local",bodyRevision:e.bodyRevision,indexRevision:e.indexRevision,firstAvailableSeq:e.firstAvailableSeq,visibleMessageCount:e.visibleMessageCount,lastVisibleMessageId:e.lastVisibleMessageId,lastBodyCommittedAt:e.lastBodyCommittedAt,deletionRevision:e.deletionRevision,lastActivityAt:e.lastActivityAt,createdAt:e.createdAt,updatedAt:e.updatedAt,deletedAt:e.deletedAt}}))}function L(t,e){const i=u(),n=i[t];if(!(!n||e<=n.syncedIndexRevision)){if(e>n.indexRevision)throw new Error(`cannot acknowledge future index revision ${e} for ${t}`);i[t]={...n,syncedIndexRevision:e},g(i)}}function W(t,e,i){c();const n=r().append(t,e,i);return A(t,e,n.bodyRevision),n.bodyRevision}function N(t,e,i){c();const n=r().upsert(t,e,i);return A(t,e,n.bodyRevision),n.bodyRevision}function q(t,e){const i=r().getMessageState(t,e);return!i||i.tombstoned||!i.message||!i.deliveryState?{state:"not_found",sessionId:t,clientMessageId:e}:{state:i.deliveryState,sessionId:t,clientMessageId:e,messageId:i.message.id,deliveryState:i.deliveryState,bodyRevision:i.lastRevision,committedAt:new Date(i.message.ts).toISOString()}}function $(t,e){c();const i=r().tombstone(t,e),n=u(),s=n[t];return s&&(n[t]={...s,bodyRevision:i.bodyRevision,indexRevision:s.indexRevision+1,updatedAt:new Date().toISOString()},g(n)),i.bodyRevision}function A(t,e,i){const n=u(),s=n[t];if(!s)return;const o=O(e),a=r().getManifest(t),d=e.role==="user"&&o&&!s.title?{title:o,titleSource:"first_user_fallback",titleRevision:s.titleRevision+1,titleLockedByUser:!1,titleOriginEventId:e.id}:null;n[t]={...s,...d??{},bodyRevision:i,indexRevision:s.indexRevision+1,updatedAt:new Date().toISOString(),lastActivityAt:new Date(e.ts).toISOString(),lastMessagePreview:o??s.lastMessagePreview??null,firstAvailableSeq:a?.firstAvailableSeq??s.firstAvailableSeq,visibleMessageCount:a?.visibleMessageCount??s.visibleMessageCount,lastVisibleMessageId:a?.lastVisibleMessageId??s.lastVisibleMessageId,lastBodyCommittedAt:a?.lastBodyCommittedAt??s.lastBodyCommittedAt},g(n)}function D(t,e){const i={title:t?.title??"",titleSource:t?.titleSource??"first_user_fallback",titleRevision:t?.titleRevision??0,titleLockedByUser:t?.titleLockedByUser??!1,titleOriginEventId:t?.titleOriginEventId??null},n=e.title?.trim()??"";if(!n)return i;if(!e.titleSource)throw new Error("titleSource is required with title");const s=e.titleSource==="shennian_manual";if(e.titleLockedByUser!==void 0&&e.titleLockedByUser!==s)throw new Error("titleLockedByUser conflicts with titleSource");const o=n===i.title&&e.titleSource===i.titleSource,a=e.titleRevision??i.titleRevision+(o?0:1);if(!Number.isSafeInteger(a)||a<0)throw new Error("invalid titleRevision");const d=y[e.titleSource],x=y[i.titleSource];return d<x||a<i.titleRevision||a===i.titleRevision&&!o?i:{title:n,titleSource:e.titleSource,titleRevision:a,titleLockedByUser:s,titleOriginEventId:e.titleOriginEventId??i.titleOriginEventId}}function j(t,e){const i=e?.limit&&e.limit>0?Math.min(e.limit,500):500;let s=r().readRecent(t,i).messages;return e?.before!==void 0&&(s=s.filter(o=>o.ts<e.before)),[...s].sort((o,a)=>a.ts-o.ts)}function F(){return r().listSessionIds()}function J(){return r()}function b(t,e){const i=f.dirname(t);l.mkdirSync(i,{recursive:!0,mode:448});const n=`${t}.tmp-${process.pid}-${v.randomBytes(6).toString("hex")}`;let s;try{if(s=l.openSync(n,"wx",384),l.writeFileSync(s,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,"utf8"),l.fsyncSync(s),l.closeSync(s),s=void 0,l.renameSync(n,t),process.platform!=="win32"){const o=l.openSync(i,"r");try{l.fsyncSync(o)}finally{l.closeSync(o)}}}finally{s!==void 0&&l.closeSync(s);try{l.unlinkSync(n)}catch{}}}export{w as PERSONAL_SYNC_V1_ROOT_NAME,L as acknowledgeSessionIndexUpdate,W as appendMessage,J as getCanonicalSessionStore,c as getDaemonInstallationId,q as getMessageDeliveryStatus,V as listPendingSessionIndexUpdates,C as listSessionRecords,F as listSessions,j as readMessages,U as recordSession,$ as tombstoneMessage,N as upsertMessage};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolDetailRef } from '@shennian/wire';
|
|
2
|
+
export type LocalToolDetail = {
|
|
3
|
+
schemaVersion: 1;
|
|
4
|
+
sessionId: string;
|
|
5
|
+
toolCallId: string;
|
|
6
|
+
detailRevision: number;
|
|
7
|
+
ts: number;
|
|
8
|
+
name: string;
|
|
9
|
+
args?: unknown;
|
|
10
|
+
result?: unknown;
|
|
11
|
+
status: 'running' | 'completed' | 'failed';
|
|
12
|
+
durationMs?: number;
|
|
13
|
+
detailRef: ToolDetailRef;
|
|
14
|
+
};
|
|
15
|
+
export declare function writeToolDetail(detail: Omit<LocalToolDetail, 'schemaVersion'>): void;
|
|
16
|
+
export declare function readToolDetail(sessionId: string, toolCallId: string): LocalToolDetail | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import m from"node:crypto";import n from"node:fs";import r from"node:path";import{resolvePersonalSyncV1Path as a}from"../personal-sync/paths.js";const f=200,u=25*1024*1024;function I(e){const o=y(e.sessionId);n.mkdirSync(o,{recursive:!0,mode:448}),S(r.join(o,`${c(e.toolCallId)}.json`),{schemaVersion:1,...e}),d(o)}function j(e,o){const s=r.join(y(e),`${c(o)}.json`);if(!n.existsSync(s))return null;try{const t=JSON.parse(n.readFileSync(s,"utf8"));return t.schemaVersion===1&&t.sessionId===e&&t.toolCallId===o?t:null}catch{return null}}function y(e){return a("tool-details",c(e))}function c(e){return m.createHash("sha256").update(e).digest("hex")}function S(e,o){const s=`${e}.tmp-${process.pid}-${m.randomBytes(6).toString("hex")}`;let t;try{t=n.openSync(s,"wx",384),n.writeFileSync(t,`${JSON.stringify(o)}
|
|
2
|
+
`,"utf8"),n.fsyncSync(t),n.closeSync(t),t=void 0,n.renameSync(s,e)}finally{t!==void 0&&n.closeSync(t);try{n.unlinkSync(s)}catch{}}}function d(e){const o=n.readdirSync(e).filter(t=>t.endsWith(".json")).map(t=>{const i=r.join(e,t),l=n.statSync(i);return{file:i,bytes:l.size,mtimeMs:l.mtimeMs}}).sort((t,i)=>t.mtimeMs-i.mtimeMs);let s=o.reduce((t,i)=>t+i.bytes,0);for(;o.length>f||s>u;){const t=o.shift();if(!t)return;n.unlinkSync(t.file),s-=t.bytes}}export{j as readToolDetail,I as writeToolDetail};
|
|
@@ -27,19 +27,9 @@ export type ActiveSession = {
|
|
|
27
27
|
externalReplyTarget?: string | null;
|
|
28
28
|
};
|
|
29
29
|
export type PendingTransfer = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
kind?: 'file' | 'folder';
|
|
34
|
-
rootPath?: string;
|
|
35
|
-
targetDir?: string;
|
|
36
|
-
files?: Map<string, PendingTransferFile>;
|
|
37
|
-
};
|
|
38
|
-
export type PendingTransferFile = {
|
|
39
|
-
relativePath: string;
|
|
40
|
-
tempPath: string;
|
|
41
|
-
targetPath: string;
|
|
42
|
-
size: number;
|
|
30
|
+
transferId: string;
|
|
31
|
+
rootPath: string;
|
|
32
|
+
lastActivityAt: number;
|
|
43
33
|
};
|
|
44
34
|
export type ChatQueueService = {
|
|
45
35
|
handleEnqueue(req: import('@shennian/wire').ReqFrame): Promise<void>;
|
|
@@ -68,6 +68,7 @@ export type AgentEventPayload = {
|
|
|
68
68
|
name: string;
|
|
69
69
|
args?: Record<string, unknown>;
|
|
70
70
|
detailRef?: ToolDetailRef;
|
|
71
|
+
durationMs?: number;
|
|
71
72
|
} | {
|
|
72
73
|
state: 'tool-result';
|
|
73
74
|
sessionId?: string;
|
|
@@ -76,6 +77,7 @@ export type AgentEventPayload = {
|
|
|
76
77
|
name: string;
|
|
77
78
|
result?: string;
|
|
78
79
|
detailRef?: ToolDetailRef;
|
|
80
|
+
durationMs?: number;
|
|
79
81
|
} | {
|
|
80
82
|
state: 'notify';
|
|
81
83
|
source: string;
|
|
@@ -25,9 +25,54 @@ export type FsChunk = {
|
|
|
25
25
|
export type FsTransferManifestEntry = {
|
|
26
26
|
relativePath: string;
|
|
27
27
|
size: number;
|
|
28
|
+
sha256: string;
|
|
28
29
|
mimeType?: string;
|
|
29
30
|
modifiedAt?: number;
|
|
30
31
|
};
|
|
32
|
+
export type FsTransferStartParams = {
|
|
33
|
+
transferId: string;
|
|
34
|
+
rootPath: string;
|
|
35
|
+
name: string;
|
|
36
|
+
totalSize: number;
|
|
37
|
+
sha256: string;
|
|
38
|
+
mimeType: string;
|
|
39
|
+
kind: 'file' | 'folder';
|
|
40
|
+
manifest?: FsTransferManifestEntry[];
|
|
41
|
+
};
|
|
42
|
+
export type FsTransferStartResult = {
|
|
43
|
+
transferId: string;
|
|
44
|
+
path: string;
|
|
45
|
+
reused: boolean;
|
|
46
|
+
offsets: Record<string, number>;
|
|
47
|
+
attachment?: FsTransferFinishResult;
|
|
48
|
+
};
|
|
49
|
+
export type FsTransferChunkParams = {
|
|
50
|
+
transferId: string;
|
|
51
|
+
rootPath: string;
|
|
52
|
+
offset: number;
|
|
53
|
+
data: string;
|
|
54
|
+
relativePath?: string;
|
|
55
|
+
};
|
|
56
|
+
export type FsTransferFinishParams = {
|
|
57
|
+
transferId: string;
|
|
58
|
+
rootPath: string;
|
|
59
|
+
};
|
|
60
|
+
export type FsTransferFinishResult = {
|
|
61
|
+
transferId: string;
|
|
62
|
+
path: string;
|
|
63
|
+
name: string;
|
|
64
|
+
mimeType: string;
|
|
65
|
+
kind: 'file' | 'folder';
|
|
66
|
+
byteSize: number;
|
|
67
|
+
sha256: string;
|
|
68
|
+
reused: boolean;
|
|
69
|
+
};
|
|
70
|
+
export type FsTransferAbortParams = {
|
|
71
|
+
transferId: string;
|
|
72
|
+
rootPath: string;
|
|
73
|
+
};
|
|
74
|
+
/** Stable input for the aggregate hash of a folder transfer. */
|
|
75
|
+
export declare function serializeFsTransferManifest(entries: readonly FsTransferManifestEntry[]): string;
|
|
31
76
|
export type FsRenameResult = {
|
|
32
77
|
oldPath: string;
|
|
33
78
|
newPath: string;
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** Stable input for the aggregate hash of a folder transfer. */
|
|
2
|
+
export function serializeFsTransferManifest(entries) {
|
|
3
|
+
return [...entries]
|
|
4
|
+
.sort((left, right) => left.relativePath.localeCompare(right.relativePath))
|
|
5
|
+
.map((entry) => `${entry.relativePath}\0${entry.size}\0${entry.sha256.toLowerCase()}`)
|
|
6
|
+
.join('\n');
|
|
7
|
+
}
|
|
@@ -5,6 +5,7 @@ export * from './methods.ts';
|
|
|
5
5
|
export * from './frames.ts';
|
|
6
6
|
export * from './fs.ts';
|
|
7
7
|
export * from './session.ts';
|
|
8
|
+
export * from './session-sync.ts';
|
|
8
9
|
export * from './message-payload.ts';
|
|
9
10
|
export * from './external-message-format.ts';
|
|
10
11
|
export * from './native-session.ts';
|
|
@@ -5,6 +5,7 @@ export * from "./methods.js";
|
|
|
5
5
|
export * from "./frames.js";
|
|
6
6
|
export * from "./fs.js";
|
|
7
7
|
export * from "./session.js";
|
|
8
|
+
export * from "./session-sync.js";
|
|
8
9
|
export * from "./message-payload.js";
|
|
9
10
|
export * from "./external-message-format.js";
|
|
10
11
|
export * from "./native-session.js";
|
|
@@ -14,6 +14,12 @@ export type Machine = {
|
|
|
14
14
|
region?: string;
|
|
15
15
|
/** CLI version currently running on this machine */
|
|
16
16
|
cliVersion?: string;
|
|
17
|
+
/** Stable identity of the daemon data root. It is not the mobile installationId. */
|
|
18
|
+
daemonInstallationId?: string;
|
|
19
|
+
/** Personal Session sync protocol understood by this daemon. */
|
|
20
|
+
sessionSyncProtocolVersion?: import('./session-sync.ts').SessionSyncProtocolVersion;
|
|
21
|
+
/** Full capability set required by the hard-cutover personal Session protocol. */
|
|
22
|
+
sessionSyncCapabilities?: import('./session-sync.ts').SessionSyncCapability[];
|
|
17
23
|
/** Auto-upgrade policy configured on this machine */
|
|
18
24
|
autoUpgrade?: AutoUpgradePolicy;
|
|
19
25
|
/** Ownership role — absent means owner (backward-compatible) */
|
|
@@ -52,7 +52,21 @@ function parseAttachmentMeta(value) {
|
|
|
52
52
|
if (!path || !name || !mimeType || !kind)
|
|
53
53
|
return null;
|
|
54
54
|
const previewData = typeof entry.previewData === 'string' && entry.previewData.trim() ? entry.previewData.trim() : undefined;
|
|
55
|
-
|
|
55
|
+
const byteSize = typeof entry.byteSize === 'number' && Number.isSafeInteger(entry.byteSize) && entry.byteSize >= 0
|
|
56
|
+
? entry.byteSize
|
|
57
|
+
: undefined;
|
|
58
|
+
const sha256 = typeof entry.sha256 === 'string' && /^[a-f0-9]{64}$/i.test(entry.sha256)
|
|
59
|
+
? entry.sha256.toLowerCase()
|
|
60
|
+
: undefined;
|
|
61
|
+
return {
|
|
62
|
+
path,
|
|
63
|
+
name,
|
|
64
|
+
mimeType,
|
|
65
|
+
kind,
|
|
66
|
+
...(byteSize !== undefined ? { byteSize } : {}),
|
|
67
|
+
...(sha256 ? { sha256 } : {}),
|
|
68
|
+
...(previewData ? { previewData } : {}),
|
|
69
|
+
};
|
|
56
70
|
}
|
|
57
71
|
export function parseStructuredMessagePayload(payload) {
|
|
58
72
|
const parsed = parseObjectPayload(payload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type ReqMethod = 'chat.send' | 'chat.enqueue' | 'chat.queue.get' | 'chat.queue.edit' | 'chat.queue.delete' | 'chat.abort' | 'session.resume' | 'session.history' | 'session.refresh' | 'session.tool.detail' | 'session.title.set' | 'fs.ls' | 'fs.read' | 'fs.write' | 'fs.export.markdown-pdf' | 'fs.export.markdown-pdf.setup' | 'fs.archive.zip' | 'fs.transfer
|
|
1
|
+
export type ReqMethod = 'chat.send' | 'chat.enqueue' | 'chat.queue.get' | 'chat.queue.edit' | 'chat.queue.delete' | 'chat.abort' | 'session.resume' | 'session.history' | 'session.history.open' | 'session.history.page' | 'session.history.close' | 'session.index.update' | 'session.message.status' | 'voice.session.body.window' | 'session.refresh' | 'session.tool.detail' | 'session.title.set' | 'fs.ls' | 'fs.read' | 'fs.write' | 'fs.export.markdown-pdf' | 'fs.export.markdown-pdf.setup' | 'fs.archive.zip' | 'fs.transfer.start' | 'fs.transfer.chunk' | 'fs.transfer.finish' | 'fs.transfer.abort' | 'fs.rename' | 'skill.list' | 'skill.install' | 'skill.doctor' | 'skill.setup' | 'skill.use' | 'region.probe' | 'region.switch' | 'upgrade.start' | 'upgrade.status' | 'upgrade.set-policy' | 'agents.refresh' | 'models.refresh' | 'agent.config.get' | 'agent.config.upsert' | 'agent.config.clear' | 'agent.config.test' | 'agent.capabilities.list' | 'manager.channel.get' | 'manager.channel.upsert' | 'session.wechat-rpa.channel.get' | 'session.wechat-rpa.channel.upsert' | 'session.wechat-rpa.channel.sync' | 'session.wechat-rpa.outbound.cancel' | 'manager.wechat-rpa.channel.get' | 'manager.wechat-rpa.channel.upsert' | 'manager.wechat-rpa.channel.sync' | 'manager.wechat-rpa.outbound.cancel' | 'wechat-rpa.helper.runtime' | 'wecom.send' | 'external.send' | 'room.sync' | 'room.send' | 'room.bind' | 'room.agent.bind-managed' | 'room.agent.restart-managed' | 'room.unbind';
|