shennian 0.4.26 → 0.4.27

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.
@@ -496,8 +496,8 @@
496
496
  },
497
497
  {
498
498
  "file": "src/native-fusion/local-repository.js",
499
- "beforeBytes": 25725,
500
- "afterBytes": 12677
499
+ "beforeBytes": 25938,
500
+ "afterBytes": 12778
501
501
  },
502
502
  {
503
503
  "file": "src/native-fusion/native-source-deletions.js",
@@ -841,8 +841,8 @@
841
841
  },
842
842
  {
843
843
  "file": "src/session/store.js",
844
- "beforeBytes": 29803,
845
- "afterBytes": 15174
844
+ "beforeBytes": 32176,
845
+ "afterBytes": 16319
846
846
  },
847
847
  {
848
848
  "file": "src/session/tool-detail-store.js",
@@ -1,2 +1,2 @@
1
- import p from"node:crypto";import l from"node:fs";import f from"node:path";import{sessionPreviewFromPayload as L}from"@shennian/wire";import{resolvePersonalSyncV1Path as R}from"../personal-sync/paths.js";import{getCanonicalSessionStore as P,getDaemonInstallationId as H,listSessionRecords as x,recordSession as w}from"../session/store.js";import{readToolDetail as U,writeToolDetail as J}from"../session/tool-detail-store.js";import{NativeSourceDeletionStore as V}from"./native-source-deletions.js";import{recordPersonalSyncLocalMetric as v}from"../personal-sync/metrics.js";const I=1;class q extends Error{code="missing_user_boundary";constructor(e){super(`native source ${e} does not start at a visible user boundary`),this.name="MissingUserBoundaryError"}}class W extends Error{code="native_source_deleted";constructor(e){super(`native source ${e} is blocked by a durable deletion tombstone`),this.name="NativeSourceDeletedError"}}class z extends Error{sourceEventKey;code="native_event_identity_conflict";constructor(e){super(`native event identity conflict: ${e}`),this.sourceEventKey=e,this.name="NativeEventIdentityConflictError"}}class de{options;constructor(e={}){this.options=e}commitEvents(e){return[...e].sort((s,o)=>s.ts-o.ts).map(s=>this.commitEvent(s))}updateMessageDeliveryState(e,s,o){if(!this.canonicalStore().updateMessageDeliveryState(e,s,o))return;const i=(this.options.listLocalSessions??x)().find(a=>a.sessionId===e);if(!i)return;(this.options.recordLocalSession??w)({...i})}commitEvent(e){if(G(e),this.isSourceDeleted(e.agentType,e.sourceSessionKey))throw new W(e.sourceSessionKey);const s=this.installationId(),o=this.readSources(),n=b(e.agentType,e.sourceSessionKey),i=o.sources[n],c=Y(e),a=this.ledgerFile(e.agentType,e.sourceEventKey),r=l.existsSync(a)?D(a):null;if(r&&r.daemonInstallationId!==s)throw new Error("native event ledger belongs to another daemon installation");if(r&&r.eventFingerprint!==c)throw new z(e.sourceEventKey);if(!i&&!r&&e.role!=="user")throw new q(e.sourceSessionKey);const m=e.claimSessionId??null,d=i?.sessionId??r?.sessionId??m??Q(s,e.agentType,e.sourceSessionKey);if(m&&i&&i.sessionId!==m)throw new Error(`managed claim session conflicts with source binding ${e.sourceSessionKey}`);const h=this.canonicalStore(),y=e.localDisposition==="managed_echo_suppressed"||r?.mappedBy==="managed_echo_suppressed",u=r?.canonicalMessageId??(y?null:e.claimCanonicalMessageId??X(s,e.agentType,e.canonicalMessageKey??e.sourceEventKey));let S=h.getManifest(d)?.bodyRevision??0,T=!!r;const E=!y&&!!e.claimCanonicalMessageId;if(E){if(!u)throw new Error("managed echo claim requires a canonical message");const M=h.getMessageState(d,u);if(!M||M.tombstoned)throw new Error(`managed echo claim target is not durable: ${u}`)}if(!r&&!E&&!y){if(!u)throw new Error("native event requires a canonical message");const M=e.canonicalMessageKey?h.getMessageState(d,u):null,F=e.canonicalMutation==="upsert"||!!M,$=F?M??h.getMessageState(d,u):null,_={id:u,sessionId:d,role:e.role,ts:$?.message?.ts??e.ts,payload:Z($?.message?.payload,e.payload)},C=F?h.upsert(d,_):h.append(d,_);if(S=C.bodyRevision,T=C.duplicate,e.localToolDetail){const N=this.options.writeLocalToolDetail??J,j=this.options.readLocalToolDetail??U,B=ee(j(d,e.localToolDetail.toolCallId),e.localToolDetail);N({sessionId:d,...B,ts:e.ts,detailRef:{toolIndex:0}})}}e.terminal&&(S=h.completeStartedUserMessages(d,e.ts).at(-1)?.bodyRevision??S),(!r||e.terminal)&&!y&&this.recordIndex(e,d,u,S);const K=new Date().toISOString();return r||g(a,{schemaVersion:I,daemonInstallationId:s,sessionId:d,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceEventKey:e.sourceEventKey,eventFingerprint:c,canonicalMessageId:u,canonicalRevision:S,cursor:e.cursor??null,mappedBy:y?"managed_echo_suppressed":E?"managed_echo_claim":e.sourceMode,eventTs:e.ts,createdAt:K}),o.sources[n]={schemaVersion:I,daemonInstallationId:s,sessionId:d,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceMode:r?i?.sourceMode??e.sourceMode:e.sourceMode,lastCursor:r?i?.lastCursor??r.cursor:e.cursor??i?.lastCursor??null,bodyRevision:S,createdAt:i?.createdAt??K,updatedAt:K},g(this.sourcesFile(),o),!r&&e.cursor&&v("sourceCursorAdvanced"),!r&&!E&&!y&&!T&&v("canonicalCommits"),{sessionId:d,messageId:u,bodyRevision:S,duplicate:T,claimed:E,suppressed:y}}repairMissingUserBoundaries(){const e=this.options.listLocalSessions??x,s=this.options.recordLocalSession??w,o=this.canonicalStore();let n=0;for(const i of e()){if(i.localReady)continue;const a=o.getManifest(i.sessionId)?.firstAvailableSeq;if(a==null)continue;const r=o.readPage(i.sessionId,{limit:1,beforeSequence:a+1}).entries[0];!r||r.sequence!==a||r.message.role!=="user"||(s({sessionId:i.sessionId,agentType:i.agentType,sessionMode:i.sessionMode,managerConfig:i.managerConfig,workDir:i.workDir,agentSessionId:i.agentSessionId,modelId:i.modelId,managerDefaultWorkerAgentType:i.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:i.managerDefaultWorkerModelId,status:i.status,lastActivityAt:i.lastActivityAt,lastMessagePreview:i.lastMessagePreview,localReady:!0,firstUserMessageId:r.message.id,firstUserBodyRevision:r.revision}),n+=1)}return n}listManagedClaims(){return Object.values(this.readManagedEchoState().claims)}listManagedSuppressions(){return Object.values(this.readManagedEchoState().suppressions)}upsertManagedClaim(e){A(e);const s=this.readManagedEchoState();s.claims[e.canonicalMessageId]=e,g(this.managedEchoStateFile(),s)}updateManagedClaimSource(e,s,o){const n=this.readManagedEchoState();let i=!1;for(const c of Object.values(n.claims))c.sessionId!==e||c.sourceAgentType!==s||(c.sourceSessionKey=o,i=!0);i&&g(this.managedEchoStateFile(),n)}removeManagedClaim(e){const s=this.readManagedEchoState();s.claims[e]&&(delete s.claims[e],g(this.managedEchoStateFile(),s))}completeManagedClaim(e,s){const o=this.readManagedEchoState();delete o.claims[e],s&&(k(s),o.suppressions[b(s.agentType,s.sourceSessionKey)]=s),g(this.managedEchoStateFile(),o)}removeManagedSuppression(e,s){const o=this.readManagedEchoState(),n=b(e,s);o.suppressions[n]&&(delete o.suppressions[n],g(this.managedEchoStateFile(),o))}listSourceBindings(){return Object.values(this.readSources().sources).filter(e=>!this.isSourceDeleted(e.agentType,e.sourceSessionKey))}purgeSession(e){if(!e)throw new Error("sessionId is required");const s=this.readSources();let o=!1;for(const[a,r]of Object.entries(s.sources))r.sessionId===e&&(delete s.sources[a],o=!0);o&&g(this.sourcesFile(),s);const n=this.readManagedEchoState();let i=!1;for(const[a,r]of Object.entries(n.claims))r.sessionId===e&&(delete n.claims[a],i=!0);for(const[a,r]of Object.entries(n.suppressions))r.sessionId===e&&(delete n.suppressions[a],i=!0);i&&g(this.managedEchoStateFile(),n);const c=f.join(this.rootDir(),"ledger");if(l.existsSync(c))for(const a of l.readdirSync(c,{withFileTypes:!0})){if(!a.isFile()||!a.name.endsWith(".json"))continue;const r=f.join(c,a.name),m=D(r);if(m.daemonInstallationId!==this.installationId())throw new Error("native event ledger belongs to another daemon installation");m.sessionId===e&&l.unlinkSync(r)}}isSourceDeleted(e,s){return(this.options.deletionStore??new V({rootDir:f.basename(this.rootDir())==="native-fusion"?f.dirname(this.rootDir()):this.rootDir(),daemonInstallationId:this.installationId()})).has(e,s)}observeNativeTitle(e,s,o){const n=o.trim().slice(0,120);if(!n)return!1;const i=this.readSources().sources[b(e,s)];if(!i||this.isSourceDeleted(e,s))return!1;const c=(this.options.listLocalSessions??x)().find(m=>m.sessionId===i.sessionId);if(c?.titleLockedByUser||c?.titleSource==="agent_native"&&c.title===n)return!1;const a=p.createHash("sha256").update(`${e}\0${s}\0${n}`).digest("hex");return(this.options.recordLocalSession??w)({sessionId:i.sessionId,agentType:i.agentType,workDir:c?.workDir??"",agentSessionId:s,title:n,titleSource:"agent_native",titleOriginEventId:`agent-native:${a}`}),!0}recordIndex(e,s,o,n){const i=this.options.recordLocalSession??w,c=e.terminal?`terminal:${p.createHash("sha256").update(e.sourceEventKey).digest("hex")}`:void 0,a=e.role==="user"||e.role==="agent"?O(e.payload):null,r=a&&o?{lastMessagePreview:a,lastMessagePreviewMessageId:o,lastMessagePreviewAt:new Date(e.ts).toISOString()}:{};i({sessionId:s,agentType:e.agentType,workDir:e.workDir??"",agentSessionId:e.sourceSessionKey,modelId:e.modelId??null,status:e.terminal?e.terminalState==="failed"||e.terminalState==="aborted"?"failed":"completed":"active",attentionId:c,lastActivityAt:new Date(e.ts).toISOString(),...r,...e.role==="user"&&o?{localReady:!0,firstUserMessageId:o,firstUserBodyRevision:n}:{},title:e.title?.trim()||(e.role==="user"?O(e.payload)??"":void 0),titleSource:e.title?.trim()?e.titleSource??"first_user_fallback":"first_user_fallback",titleOriginEventId:e.sourceEventKey})}readSources(){const e=this.sourcesFile();if(!l.existsSync(e))return{schemaVersion:I,daemonInstallationId:this.installationId(),sources:{}};const s=D(e);if(s.schemaVersion!==I||s.daemonInstallationId!==this.installationId()||!s.sources)throw new Error("invalid native source binding store");for(const o of Object.values(s.sources))if(o.daemonInstallationId!==this.installationId())throw new Error("native source binding belongs to another daemon installation");return s}installationId(){return this.options.daemonInstallationId??H()}canonicalStore(){return this.options.canonicalStore??P()}rootDir(){return this.options.rootDir??R("native-fusion")}sourcesFile(){return f.join(this.rootDir(),"sources.json")}managedEchoStateFile(){return f.join(this.rootDir(),"managed-echo-state.json")}readManagedEchoState(){const e=this.managedEchoStateFile();if(!l.existsSync(e))return{schemaVersion:I,daemonInstallationId:this.installationId(),claims:{},suppressions:{}};const s=D(e);if(s.schemaVersion!==I||s.daemonInstallationId!==this.installationId()||!s.claims||!s.suppressions)throw new Error("invalid managed echo state");for(const o of Object.values(s.claims))A(o);for(const o of Object.values(s.suppressions))k(o);return s}ledgerFile(e,s){const o=p.createHash("sha256").update(`${e}\0${s}`).digest("hex");return f.join(this.rootDir(),"ledger",`${o}.json`)}}function G(t){if(!t.agentType||!t.sourceSessionKey||!t.sourceEventKey||!t.payload)throw new Error("invalid native event");if(!Number.isFinite(t.ts))throw new Error("invalid native event timestamp")}function b(t,e){return p.createHash("sha256").update(`${t}\0${e}`).digest("hex")}function Q(t,e,s){return`native-session-${p.createHash("sha256").update(`${t}\0${e}\0${s}`).digest("hex").slice(0,32)}`}function X(t,e,s){return`native-${p.createHash("sha256").update(`${t}\0${e}\0${s}`).digest("hex").slice(0,32)}`}function Y(t){return p.createHash("sha256").update(JSON.stringify({agentType:t.agentType,sourceSessionKey:t.sourceSessionKey,sourceEventKey:t.sourceEventKey,role:t.role,ts:t.ts,payload:t.payload,canonicalMessageKey:t.canonicalMessageKey??null,canonicalMutation:t.canonicalMutation??"append"})).digest("hex")}function A(t){if(!t.sessionId||!t.canonicalMessageId||!t.textHash||!Number.isFinite(t.createdAt)||!["codex","claude","opencode"].includes(t.sourceAgentType)||!["suppress_following","import_following"].includes(t.managedEchoPolicy))throw new Error("invalid managed echo claim")}function k(t){if(!t.sessionId||!t.sourceSessionKey||!t.claimSourceEventKey||!["codex","claude","opencode"].includes(t.agentType)||!Number.isFinite(t.startedAt)||!Number.isFinite(t.endsAt)||t.endsAt<t.startedAt)throw new Error("invalid managed echo suppression")}function Z(t,e){if(!t)return e;try{const s=JSON.parse(t),o=JSON.parse(e);if(s.type!=="tool"||o.type!=="tool"||s.toolCallId!==o.toolCallId)return e;const n=typeof o.name=="string"?o.name:"",i=/(?:_output|_result)$/.test(n);return JSON.stringify({...s,...o,...i&&typeof s.name=="string"?{name:s.name}:{}})}catch{return e}}function ee(t,e){if(!t||t.toolCallId!==e.toolCallId)return e;const s=/(?:_output|_result)$/.test(e.name);return{...e,name:s?t.name:e.name,...e.args===void 0&&t.args!==void 0?{args:t.args}:{},...e.result===void 0&&t.result!==void 0?{result:t.result}:{}}}function O(t){return L(t,120)}function g(t,e){const s=f.dirname(t);l.mkdirSync(s,{recursive:!0,mode:448});const o=`${t}.tmp-${process.pid}-${p.randomBytes(6).toString("hex")}`;let n;try{n=l.openSync(o,"wx",384),l.writeFileSync(n,`${JSON.stringify(e,null,2)}
2
- `,"utf8"),l.fsyncSync(n),l.closeSync(n),n=void 0,l.renameSync(o,t)}finally{n!==void 0&&l.closeSync(n);try{l.unlinkSync(o)}catch{}}}function D(t){return JSON.parse(l.readFileSync(t,"utf8"))}export{q as MissingUserBoundaryError,z as NativeEventIdentityConflictError,de as NativeFusionLocalRepository,W as NativeSourceDeletedError};
1
+ import p from"node:crypto";import l from"node:fs";import f from"node:path";import{isToolPayload as L,sessionPreviewFromPayload as R}from"@shennian/wire";import{resolvePersonalSyncV1Path as P}from"../personal-sync/paths.js";import{getCanonicalSessionStore as H,getDaemonInstallationId as U,listSessionRecords as x,recordSession as w}from"../session/store.js";import{readToolDetail as V,writeToolDetail as J}from"../session/tool-detail-store.js";import{NativeSourceDeletionStore as q}from"./native-source-deletions.js";import{recordPersonalSyncLocalMetric as v}from"../personal-sync/metrics.js";const I=1;class W extends Error{code="missing_user_boundary";constructor(e){super(`native source ${e} does not start at a visible user boundary`),this.name="MissingUserBoundaryError"}}class z extends Error{code="native_source_deleted";constructor(e){super(`native source ${e} is blocked by a durable deletion tombstone`),this.name="NativeSourceDeletedError"}}class G extends Error{sourceEventKey;code="native_event_identity_conflict";constructor(e){super(`native event identity conflict: ${e}`),this.sourceEventKey=e,this.name="NativeEventIdentityConflictError"}}class ue{options;constructor(e={}){this.options=e}commitEvents(e){return[...e].sort((s,o)=>s.ts-o.ts).map(s=>this.commitEvent(s))}updateMessageDeliveryState(e,s,o){if(!this.canonicalStore().updateMessageDeliveryState(e,s,o))return;const i=(this.options.listLocalSessions??x)().find(a=>a.sessionId===e);if(!i)return;(this.options.recordLocalSession??w)({...i})}commitEvent(e){if(Q(e),this.isSourceDeleted(e.agentType,e.sourceSessionKey))throw new z(e.sourceSessionKey);const s=this.installationId(),o=this.readSources(),n=b(e.agentType,e.sourceSessionKey),i=o.sources[n],c=Z(e),a=this.ledgerFile(e.agentType,e.sourceEventKey),r=l.existsSync(a)?D(a):null;if(r&&r.daemonInstallationId!==s)throw new Error("native event ledger belongs to another daemon installation");if(r&&r.eventFingerprint!==c)throw new G(e.sourceEventKey);if(!i&&!r&&e.role!=="user")throw new W(e.sourceSessionKey);const u=e.claimSessionId??null,d=i?.sessionId??r?.sessionId??u??X(s,e.agentType,e.sourceSessionKey);if(u&&i&&i.sessionId!==u)throw new Error(`managed claim session conflicts with source binding ${e.sourceSessionKey}`);const h=this.canonicalStore(),y=e.localDisposition==="managed_echo_suppressed"||r?.mappedBy==="managed_echo_suppressed",g=r?.canonicalMessageId??(y?null:e.claimCanonicalMessageId??Y(s,e.agentType,e.canonicalMessageKey??e.sourceEventKey));let S=h.getManifest(d)?.bodyRevision??0,T=!!r;const E=!y&&!!e.claimCanonicalMessageId;if(E){if(!g)throw new Error("managed echo claim requires a canonical message");const M=h.getMessageState(d,g);if(!M||M.tombstoned)throw new Error(`managed echo claim target is not durable: ${g}`)}if(!r&&!E&&!y){if(!g)throw new Error("native event requires a canonical message");const M=e.canonicalMessageKey?h.getMessageState(d,g):null,F=e.canonicalMutation==="upsert"||!!M,$=F?M??h.getMessageState(d,g):null,_={id:g,sessionId:d,role:e.role,ts:$?.message?.ts??e.ts,payload:ee($?.message?.payload,e.payload)},C=F?h.upsert(d,_):h.append(d,_);if(S=C.bodyRevision,T=C.duplicate,e.localToolDetail){const N=this.options.writeLocalToolDetail??J,j=this.options.readLocalToolDetail??V,B=se(j(d,e.localToolDetail.toolCallId),e.localToolDetail);N({sessionId:d,...B,ts:e.ts,detailRef:{toolIndex:0}})}}e.terminal&&(S=h.completeStartedUserMessages(d,e.ts).at(-1)?.bodyRevision??S),(!r||e.terminal)&&!y&&this.recordIndex(e,d,g,S);const K=new Date().toISOString();return r||m(a,{schemaVersion:I,daemonInstallationId:s,sessionId:d,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceEventKey:e.sourceEventKey,eventFingerprint:c,canonicalMessageId:g,canonicalRevision:S,cursor:e.cursor??null,mappedBy:y?"managed_echo_suppressed":E?"managed_echo_claim":e.sourceMode,eventTs:e.ts,createdAt:K}),o.sources[n]={schemaVersion:I,daemonInstallationId:s,sessionId:d,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceMode:r?i?.sourceMode??e.sourceMode:e.sourceMode,lastCursor:r?i?.lastCursor??r.cursor:e.cursor??i?.lastCursor??null,bodyRevision:S,createdAt:i?.createdAt??K,updatedAt:K},m(this.sourcesFile(),o),!r&&e.cursor&&v("sourceCursorAdvanced"),!r&&!E&&!y&&!T&&v("canonicalCommits"),{sessionId:d,messageId:g,bodyRevision:S,duplicate:T,claimed:E,suppressed:y}}repairMissingUserBoundaries(){const e=this.options.listLocalSessions??x,s=this.options.recordLocalSession??w,o=this.canonicalStore();let n=0;for(const i of e()){if(i.localReady)continue;const a=o.getManifest(i.sessionId)?.firstAvailableSeq;if(a==null)continue;const r=o.readPage(i.sessionId,{limit:1,beforeSequence:a+1}).entries[0];!r||r.sequence!==a||r.message.role!=="user"||(s({sessionId:i.sessionId,agentType:i.agentType,sessionMode:i.sessionMode,managerConfig:i.managerConfig,workDir:i.workDir,agentSessionId:i.agentSessionId,modelId:i.modelId,managerDefaultWorkerAgentType:i.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:i.managerDefaultWorkerModelId,status:i.status,lastActivityAt:i.lastActivityAt,lastMessagePreview:i.lastMessagePreview,localReady:!0,firstUserMessageId:r.message.id,firstUserBodyRevision:r.revision}),n+=1)}return n}listManagedClaims(){return Object.values(this.readManagedEchoState().claims)}listManagedSuppressions(){return Object.values(this.readManagedEchoState().suppressions)}upsertManagedClaim(e){A(e);const s=this.readManagedEchoState();s.claims[e.canonicalMessageId]=e,m(this.managedEchoStateFile(),s)}updateManagedClaimSource(e,s,o){const n=this.readManagedEchoState();let i=!1;for(const c of Object.values(n.claims))c.sessionId!==e||c.sourceAgentType!==s||(c.sourceSessionKey=o,i=!0);i&&m(this.managedEchoStateFile(),n)}removeManagedClaim(e){const s=this.readManagedEchoState();s.claims[e]&&(delete s.claims[e],m(this.managedEchoStateFile(),s))}completeManagedClaim(e,s){const o=this.readManagedEchoState();delete o.claims[e],s&&(O(s),o.suppressions[b(s.agentType,s.sourceSessionKey)]=s),m(this.managedEchoStateFile(),o)}removeManagedSuppression(e,s){const o=this.readManagedEchoState(),n=b(e,s);o.suppressions[n]&&(delete o.suppressions[n],m(this.managedEchoStateFile(),o))}listSourceBindings(){return Object.values(this.readSources().sources).filter(e=>!this.isSourceDeleted(e.agentType,e.sourceSessionKey))}purgeSession(e){if(!e)throw new Error("sessionId is required");const s=this.readSources();let o=!1;for(const[a,r]of Object.entries(s.sources))r.sessionId===e&&(delete s.sources[a],o=!0);o&&m(this.sourcesFile(),s);const n=this.readManagedEchoState();let i=!1;for(const[a,r]of Object.entries(n.claims))r.sessionId===e&&(delete n.claims[a],i=!0);for(const[a,r]of Object.entries(n.suppressions))r.sessionId===e&&(delete n.suppressions[a],i=!0);i&&m(this.managedEchoStateFile(),n);const c=f.join(this.rootDir(),"ledger");if(l.existsSync(c))for(const a of l.readdirSync(c,{withFileTypes:!0})){if(!a.isFile()||!a.name.endsWith(".json"))continue;const r=f.join(c,a.name),u=D(r);if(u.daemonInstallationId!==this.installationId())throw new Error("native event ledger belongs to another daemon installation");u.sessionId===e&&l.unlinkSync(r)}}isSourceDeleted(e,s){return(this.options.deletionStore??new q({rootDir:f.basename(this.rootDir())==="native-fusion"?f.dirname(this.rootDir()):this.rootDir(),daemonInstallationId:this.installationId()})).has(e,s)}observeNativeTitle(e,s,o){const n=o.trim().slice(0,120);if(!n)return!1;const i=this.readSources().sources[b(e,s)];if(!i||this.isSourceDeleted(e,s))return!1;const c=(this.options.listLocalSessions??x)().find(u=>u.sessionId===i.sessionId);if(c?.titleLockedByUser||c?.titleSource==="agent_native"&&c.title===n)return!1;const a=p.createHash("sha256").update(`${e}\0${s}\0${n}`).digest("hex");return(this.options.recordLocalSession??w)({sessionId:i.sessionId,agentType:i.agentType,workDir:c?.workDir??"",agentSessionId:s,title:n,titleSource:"agent_native",titleOriginEventId:`agent-native:${a}`}),!0}recordIndex(e,s,o,n){const i=this.options.recordLocalSession??w,c=e.terminal?`terminal:${p.createHash("sha256").update(e.sourceEventKey).digest("hex")}`:void 0,a=e.role==="user"||e.role==="agent"?k(e.payload):null,r=a&&o?{lastMessagePreview:a,lastMessagePreviewMessageId:o,lastMessagePreviewAt:new Date(e.ts).toISOString()}:{},u=o&&(a||L(e.payload))?new Date(e.ts).toISOString():void 0;i({sessionId:s,agentType:e.agentType,workDir:e.workDir??"",agentSessionId:e.sourceSessionKey,modelId:e.modelId??null,status:e.terminal?e.terminalState==="failed"||e.terminalState==="aborted"?"failed":"completed":"active",attentionId:c,lastActivityAt:new Date(e.ts).toISOString(),lastVisibleEventAt:u,...r,...e.role==="user"&&o?{localReady:!0,firstUserMessageId:o,firstUserBodyRevision:n}:{},title:e.title?.trim()||(e.role==="user"?k(e.payload)??"":void 0),titleSource:e.title?.trim()?e.titleSource??"first_user_fallback":"first_user_fallback",titleOriginEventId:e.sourceEventKey})}readSources(){const e=this.sourcesFile();if(!l.existsSync(e))return{schemaVersion:I,daemonInstallationId:this.installationId(),sources:{}};const s=D(e);if(s.schemaVersion!==I||s.daemonInstallationId!==this.installationId()||!s.sources)throw new Error("invalid native source binding store");for(const o of Object.values(s.sources))if(o.daemonInstallationId!==this.installationId())throw new Error("native source binding belongs to another daemon installation");return s}installationId(){return this.options.daemonInstallationId??U()}canonicalStore(){return this.options.canonicalStore??H()}rootDir(){return this.options.rootDir??P("native-fusion")}sourcesFile(){return f.join(this.rootDir(),"sources.json")}managedEchoStateFile(){return f.join(this.rootDir(),"managed-echo-state.json")}readManagedEchoState(){const e=this.managedEchoStateFile();if(!l.existsSync(e))return{schemaVersion:I,daemonInstallationId:this.installationId(),claims:{},suppressions:{}};const s=D(e);if(s.schemaVersion!==I||s.daemonInstallationId!==this.installationId()||!s.claims||!s.suppressions)throw new Error("invalid managed echo state");for(const o of Object.values(s.claims))A(o);for(const o of Object.values(s.suppressions))O(o);return s}ledgerFile(e,s){const o=p.createHash("sha256").update(`${e}\0${s}`).digest("hex");return f.join(this.rootDir(),"ledger",`${o}.json`)}}function Q(t){if(!t.agentType||!t.sourceSessionKey||!t.sourceEventKey||!t.payload)throw new Error("invalid native event");if(!Number.isFinite(t.ts))throw new Error("invalid native event timestamp")}function b(t,e){return p.createHash("sha256").update(`${t}\0${e}`).digest("hex")}function X(t,e,s){return`native-session-${p.createHash("sha256").update(`${t}\0${e}\0${s}`).digest("hex").slice(0,32)}`}function Y(t,e,s){return`native-${p.createHash("sha256").update(`${t}\0${e}\0${s}`).digest("hex").slice(0,32)}`}function Z(t){return p.createHash("sha256").update(JSON.stringify({agentType:t.agentType,sourceSessionKey:t.sourceSessionKey,sourceEventKey:t.sourceEventKey,role:t.role,ts:t.ts,payload:t.payload,canonicalMessageKey:t.canonicalMessageKey??null,canonicalMutation:t.canonicalMutation??"append"})).digest("hex")}function A(t){if(!t.sessionId||!t.canonicalMessageId||!t.textHash||!Number.isFinite(t.createdAt)||!["codex","claude","opencode"].includes(t.sourceAgentType)||!["suppress_following","import_following"].includes(t.managedEchoPolicy))throw new Error("invalid managed echo claim")}function O(t){if(!t.sessionId||!t.sourceSessionKey||!t.claimSourceEventKey||!["codex","claude","opencode"].includes(t.agentType)||!Number.isFinite(t.startedAt)||!Number.isFinite(t.endsAt)||t.endsAt<t.startedAt)throw new Error("invalid managed echo suppression")}function ee(t,e){if(!t)return e;try{const s=JSON.parse(t),o=JSON.parse(e);if(s.type!=="tool"||o.type!=="tool"||s.toolCallId!==o.toolCallId)return e;const n=typeof o.name=="string"?o.name:"",i=/(?:_output|_result)$/.test(n);return JSON.stringify({...s,...o,...i&&typeof s.name=="string"?{name:s.name}:{}})}catch{return e}}function se(t,e){if(!t||t.toolCallId!==e.toolCallId)return e;const s=/(?:_output|_result)$/.test(e.name);return{...e,name:s?t.name:e.name,...e.args===void 0&&t.args!==void 0?{args:t.args}:{},...e.result===void 0&&t.result!==void 0?{result:t.result}:{}}}function k(t){return R(t,120)}function m(t,e){const s=f.dirname(t);l.mkdirSync(s,{recursive:!0,mode:448});const o=`${t}.tmp-${process.pid}-${p.randomBytes(6).toString("hex")}`;let n;try{n=l.openSync(o,"wx",384),l.writeFileSync(n,`${JSON.stringify(e,null,2)}
2
+ `,"utf8"),l.fsyncSync(n),l.closeSync(n),n=void 0,l.renameSync(o,t)}finally{n!==void 0&&l.closeSync(n);try{l.unlinkSync(o)}catch{}}}function D(t){return JSON.parse(l.readFileSync(t,"utf8"))}export{W as MissingUserBoundaryError,G as NativeEventIdentityConflictError,ue as NativeFusionLocalRepository,z as NativeSourceDeletedError};
@@ -21,6 +21,7 @@ export type LocalSessionRecord = {
21
21
  lastMessagePreview?: string | null;
22
22
  lastMessagePreviewMessageId: string | null;
23
23
  lastMessagePreviewAt: string | null;
24
+ lastVisibleEventAt?: string | null;
24
25
  localReady: boolean;
25
26
  firstUserMessageId: string | null;
26
27
  firstUserBodyRevision: number | null;
@@ -70,6 +71,7 @@ export declare function recordSession(input: {
70
71
  lastMessagePreview?: string | null;
71
72
  lastMessagePreviewMessageId?: string | null;
72
73
  lastMessagePreviewAt?: string | null;
74
+ lastVisibleEventAt?: string | null;
73
75
  localReady?: boolean;
74
76
  firstUserMessageId?: string | null;
75
77
  firstUserBodyRevision?: number | null;
@@ -1,2 +1,2 @@
1
- import b from"node:crypto";import d from"node:fs";import x from"node:path";import{SESSION_SYNC_PROTOCOL_VERSION as A,SESSION_SYNC_DATA_EPOCH as I,SESSION_TITLE_SOURCE_PRIORITY as v,sessionPreviewFromPayload as C}from"@shennian/wire";import{PERSONAL_SYNC_V1_ROOT_NAME as k,resolvePersonalSyncV1Path as T}from"../personal-sync/paths.js";import{CanonicalSessionStore as N}from"./canonical-store.js";import{getDaemonInstallationId as u}from"../personal-sync/identity.js";import{NativeSourceDeletionStore as B}from"../native-fusion/native-source-deletions.js";const P=120;function p(t){if(t.length<=P)return t;let e=t.slice(0,P);const n=e.charCodeAt(e.length-1);return n>=55296&&n<=56319&&(e=e.slice(0,-1)),e}let w=null,O=null;function R(){return T()}function g(){const t=x.join(R(),"canonical");return(!w||O!==t)&&(w=new N(t,u()),O=t),w}function h(){return x.join(R(),"session-index.json")}function c(){const t=h();if(!d.existsSync(t))return{};const e=JSON.parse(d.readFileSync(t,"utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`invalid personal session index: ${t}`);const n=u();for(const o of Object.values(e))if(o.daemonInstallationId!==n)throw new Error(`personal session index belongs to another daemon installation: ${t}`);return e}function S(t){W(h(),t)}function E(t){return C(t.payload,120)}function y(t){if(new B({rootDir:R(),daemonInstallationId:u()}).hasSession(t))throw new Error(`session_deleted:${t}`)}function U(t){y(t.sessionId),u();const e=c(),n=e[t.sessionId],o=new Date().toISOString(),i=g().getManifest(t.sessionId)?.bodyRevision??n?.bodyRevision??0,s=g().getManifest(t.sessionId),a=j(n,t),l=t.attentionId?.trim()||null,r=Array.from(new Set([...n?.seenAttentionIds??[],...n?.lastAttentionId?[n.lastAttentionId]:[]])),f=!!(l&&!r.includes(l)),m=t.lastMessagePreview===null?{preview:null,messageId:null,at:null}:t.lastMessagePreview!==void 0&&t.lastMessagePreviewMessageId&&t.lastMessagePreviewAt?{preview:t.lastMessagePreview,messageId:t.lastMessagePreviewMessageId,at:t.lastMessagePreviewAt}:{preview:n?.lastMessagePreview??null,messageId:n?.lastMessagePreviewMessageId??null,at:n?.lastMessagePreviewAt??null},M={daemonInstallationId:u(),sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode??n?.sessionMode,managerConfig:t.managerConfig??n?.managerConfig??null,workDir:t.workDir,agentSessionId:t.agentSessionId??n?.agentSessionId??null,modelId:t.modelId??n?.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType??n?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId??n?.managerDefaultWorkerModelId??null,status:t.status??n?.status??"active",createdAt:n?.createdAt??o,updatedAt:o,lastActivityAt:t.lastActivityAt??n?.lastActivityAt??o,lastMessagePreview:m.preview,lastMessagePreviewMessageId:m.messageId,lastMessagePreviewAt:m.at,localReady:n?.localReady===!0||t.localReady===!0,firstUserMessageId:n?.firstUserMessageId??t.firstUserMessageId??null,firstUserBodyRevision:n?.firstUserBodyRevision??t.firstUserBodyRevision??null,bodyRevision:i,indexRevision:(n?.indexRevision??0)+1,...a,firstAvailableSeq:s?.firstAvailableSeq??n?.firstAvailableSeq??null,visibleMessageCount:s?.visibleMessageCount??n?.visibleMessageCount??0,lastVisibleMessageId:s?.lastVisibleMessageId??n?.lastVisibleMessageId??null,attentionCount:(n?.attentionCount??0)+(f?1:0),lastAttentionId:f?l:n?.lastAttentionId??null,seenAttentionIds:f&&l?[...r,l]:r,lastBodyCommittedAt:s?.lastBodyCommittedAt??n?.lastBodyCommittedAt??null,deletionRevision:n?.deletionRevision??0,deletedAt:t.deletedAt??n?.deletedAt??null,syncedIndexRevision:n?.syncedIndexRevision??0,indexSyncState:"pending",indexSyncStateRevision:(n?.indexRevision??0)+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,titleGenerationAttemptedAt:n?.titleGenerationAttemptedAt&&n.titleGenerationNextAttemptAt!==void 0?n.titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:n?.titleGenerationNextAttemptAt??null,titleGenerationAttempts:n?.titleGenerationAttempts??0};return e[t.sessionId]=M,S(e),M}function G(){return Object.values(c())}function K(t){if(!t)throw new Error("sessionId is required");const e=c();e[t]&&(delete e[t],S(e))}function Z(t){g().purgeSession(t)}function L(){const t=c();let e=!1;const n=new Date().toISOString();for(const[o,i]of Object.entries(t)){const s=p(i.title);if(s===i.title)continue;const a=i.indexRevision+1;t[o]={...i,title:s,indexRevision:a,indexSyncState:"pending",indexSyncStateRevision:a,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,updatedAt:n},e=!0}e&&S(t)}function ee(){const t=u();return V(),L(),G().filter(e=>{const n=e.indexSyncStateRevision===e.indexRevision;return e.indexQuarantineCode||n&&(e.indexSyncState==="quarantined"||e.indexSyncState==="terminal")||n&&e.indexSyncNextAttemptAt&&Date.parse(e.indexSyncNextAttemptAt)>Date.now()?!1:e.indexRevision>e.syncedIndexRevision&&e.localReady&&!!e.firstUserMessageId&&e.firstUserBodyRevision!=null}).sort((e,n)=>e.indexRevision-n.indexRevision).map(e=>{const n=!!(e.lastMessagePreview&&e.lastMessagePreviewMessageId&&e.lastMessagePreviewAt);return{protocolVersion:A,dataEpoch:I,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:n?e.lastMessagePreview:null,lastMessagePreviewMessageId:n?e.lastMessagePreviewMessageId:null,lastMessagePreviewAt:n?e.lastMessagePreviewAt:null,bodyStorageMode:"machine_local",localReady:!0,firstUserBoundary:{role:"user",messageId:e.firstUserMessageId,bodyRevision:e.firstUserBodyRevision},bodyRevision:e.bodyRevision,indexRevision:e.indexRevision,firstAvailableSeq:e.firstAvailableSeq,visibleMessageCount:e.visibleMessageCount,lastVisibleMessageId:e.lastVisibleMessageId,attentionCount:e.attentionCount??0,lastAttentionId:e.lastAttentionId??null,lastBodyCommittedAt:e.lastBodyCommittedAt,deletionRevision:e.deletionRevision,lastActivityAt:e.lastActivityAt,createdAt:e.createdAt,updatedAt:e.updatedAt,deletedAt:e.deletedAt}}})}function te(t,e){const n=c(),o=n[t];if(!(!o||e<=o.syncedIndexRevision)){if(e>o.indexRevision)throw new Error(`cannot acknowledge future index revision ${e} for ${t}`);n[t]={...o,syncedIndexRevision:e,indexSyncState:"applied",indexSyncStateRevision:e,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null},S(n)}}function ne(){const t=c();let e=0;const n=new Date().toISOString();for(const[o,i]of Object.entries(t)){if(i.deletedAt||i.indexQuarantineCode||!i.localReady)continue;const s=i.indexRevision+1;t[o]={...i,indexRevision:s,indexSyncState:"pending",indexSyncStateRevision:s,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e+=1}return e>0&&S(t),e}function ie(t){const e=c(),n=e[t.sessionId];if(!n||n.indexRevision!==t.indexRevision)return"terminal";const i=(n.indexSyncStateRevision===t.indexRevision?n.indexSyncAttempts??0:0)+1;let s=t.disposition;s==="retry"&&i>=(t.maxAttempts??8)&&(s="terminal");const a=t.now??Date.now(),l=Math.min(5e3*2**Math.max(0,i-1),360*60*1e3),r=Math.round(l*.2*(Math.random()*2-1));return e[t.sessionId]={...n,indexSyncState:s==="retry"?"pending":s,indexSyncStateRevision:t.indexRevision,indexSyncAttempts:i,indexSyncNextAttemptAt:s==="retry"?new Date(a+l+r).toISOString():null,indexSyncErrorCode:t.code,indexQuarantineCode:s==="quarantined"?t.code:n.indexQuarantineCode??null},S(e),s}const q=2*6e4;function se(t=Date.now(),e=q){const n=c(),o=[],i=new Date(t).toISOString();for(const s of Object.values(n)){if(s.titleSource!=="first_user_fallback"||s.titleLockedByUser||s.titleGenerationAttemptedAt||!s.title.trim()||s.syncedIndexRevision<s.indexRevision||s.titleGenerationNextAttemptAt&&Date.parse(s.titleGenerationNextAttemptAt)>t)continue;const a=s.status==="completed"||s.status==="failed",l=s.visibleMessageCount>=2;let r=null;if(s.agentType==="claude"&&l?r="agent_native_unavailable":a?r="terminal":l&&t-Date.parse(s.createdAt)>=e&&(r="grace_elapsed"),!r)continue;const f=C(s.title,240);if(!f)continue;const m=b.randomUUID();n[s.sessionId]={...s,titleGenerationAttemptedAt:i,titleGenerationNextAttemptAt:null,titleGenerationAttempts:(s.titleGenerationAttempts??0)+1},o.push({sessionId:s.sessionId,requestId:m,titleSeed:f,baseTitleRevision:s.titleRevision,eligibility:r})}return o.length>0&&S(n),o}function oe(t,e=Date.now()){const n=c(),o=n[t];if(!o?.titleGenerationAttemptedAt||o.titleSource!=="first_user_fallback")return null;const i=Math.max(1,o.titleGenerationAttempts??1),s=Math.min(10*6e4,3e4*2**Math.min(i-1,5)),a=new Date(e+s).toISOString();return n[t]={...o,titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:a},S(n),a}function ae(t,e){const o=c()[t];return!o||o.titleLockedByUser||v[o.titleSource]>=v.shennian_generated||e.titleRevision<=o.titleRevision?!1:(U({sessionId:t,agentType:o.agentType,sessionMode:o.sessionMode,managerConfig:o.managerConfig,workDir:o.workDir,agentSessionId:o.agentSessionId,modelId:o.modelId,status:o.status,title:e.title,titleSource:"shennian_generated",titleRevision:e.titleRevision,titleLockedByUser:!1,titleOriginEventId:e.titleOriginEventId}),!0)}function le(t,e,n){y(t),u();const o=g().append(t,e,n);return D(t,e,o.bodyRevision),o.bodyRevision}function re(t,e,n){y(t),u();const o=g().upsert(t,e,n);return D(t,e,o.bodyRevision),o.bodyRevision}function de(t,e){const n=g().getMessageState(t,e);return!n||n.tombstoned||!n.message||!n.deliveryState?{protocolVersion:A,dataEpoch:I,daemonInstallationId:u(),state:"not_found",sessionId:t,clientMessageId:e}:{protocolVersion:A,dataEpoch:I,daemonInstallationId:u(),state:n.deliveryState,sessionId:t,clientMessageId:e,messageId:n.message.id,deliveryState:n.deliveryState,bodyRevision:n.lastRevision,committedAt:new Date(n.message.ts).toISOString()}}function ce(t,e){y(t),u();const n=g().tombstone(t,e),o=c(),i=o[t];if(i){const s=e===i.lastMessagePreviewMessageId?_(t):{preview:i.lastMessagePreview??null,messageId:i.lastMessagePreviewMessageId??null,at:i.lastMessagePreviewAt??null};o[t]={...i,bodyRevision:n.bodyRevision,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastMessagePreview:s.preview,lastMessagePreviewMessageId:s.messageId,lastMessagePreviewAt:s.at},S(o)}return n.bodyRevision}function D(t,e,n){const o=c(),i=o[t];if(!i)return;const s=E(e),a=s?{lastMessagePreview:s,lastMessagePreviewMessageId:e.id,lastMessagePreviewAt:new Date(e.ts).toISOString()}:null,l=g().getManifest(t),r=e.role==="user"&&s&&!i.title?{title:p(s),titleSource:"first_user_fallback",titleRevision:i.titleRevision+1,titleLockedByUser:!1,titleOriginEventId:e.id}:null,f=e.role==="user"&&!i.localReady?{localReady:!0,firstUserMessageId:e.id,firstUserBodyRevision:n}:null;o[t]={...i,...r??{},...f??{},bodyRevision:n,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastActivityAt:new Date(e.ts).toISOString(),...a??{},firstAvailableSeq:l?.firstAvailableSeq??i.firstAvailableSeq,visibleMessageCount:l?.visibleMessageCount??i.visibleMessageCount,lastVisibleMessageId:l?.lastVisibleMessageId??i.lastVisibleMessageId,attentionCount:i.attentionCount??0,lastAttentionId:i.lastAttentionId??null,lastBodyCommittedAt:l?.lastBodyCommittedAt??i.lastBodyCommittedAt},S(o)}function _(t){let e;do{const n=g().readPage(t,{limit:500,beforeSequence:e});for(let o=n.entries.length-1;o>=0;o-=1){const i=n.entries[o],s=E(i.message);if(s)return{preview:s,messageId:i.message.id,at:new Date(i.message.ts).toISOString()}}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return{preview:null,messageId:null,at:null}}function V(){const t=c();let e=!1;const n=new Date().toISOString();for(const[o,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewMessageId")&&Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewAt"))continue;const s=_(o);t[o]={...i,lastMessagePreview:s.preview,lastMessagePreviewMessageId:s.messageId,lastMessagePreviewAt:s.at,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function j(t,e){const n={title:t?.title??"",titleSource:t?.titleSource??"first_user_fallback",titleRevision:t?.titleRevision??0,titleLockedByUser:t?.titleLockedByUser??!1,titleOriginEventId:t?.titleOriginEventId??null},o=p(e.title?.trim()??"");if(!o)return n;if(!e.titleSource)throw new Error("titleSource is required with title");if(n.title&&n.titleSource==="first_user_fallback"&&e.titleSource==="first_user_fallback")return n;const i=e.titleSource==="shennian_manual";if(e.titleLockedByUser!==void 0&&e.titleLockedByUser!==i)throw new Error("titleLockedByUser conflicts with titleSource");const s=o===n.title&&e.titleSource===n.titleSource,a=e.titleRevision??n.titleRevision+(s?0:1);if(!Number.isSafeInteger(a)||a<0)throw new Error("invalid titleRevision");const l=v[e.titleSource],r=v[n.titleSource];return l<r||a<n.titleRevision||s&&a===n.titleRevision||a===n.titleRevision&&!s?n:{title:o,titleSource:e.titleSource,titleRevision:a,titleLockedByUser:i,titleOriginEventId:e.titleOriginEventId??n.titleOriginEventId}}function ue(t,e){const n=e?.limit&&e.limit>0?Math.min(e.limit,500):500;let i=g().readRecent(t,n).messages;return e?.before!==void 0&&(i=i.filter(s=>s.ts<e.before)),[...i].sort((s,a)=>a.ts-s.ts)}function ge(){return g().listSessionIds()}function Se(){return g()}function W(t,e){const n=x.dirname(t);d.mkdirSync(n,{recursive:!0,mode:448});const o=`${t}.tmp-${process.pid}-${b.randomBytes(6).toString("hex")}`;let i;try{if(i=d.openSync(o,"wx",384),d.writeFileSync(i,`${JSON.stringify(e,null,2)}
2
- `,"utf8"),d.fsyncSync(i),d.closeSync(i),i=void 0,d.renameSync(o,t),process.platform!=="win32"){const s=d.openSync(n,"r");try{d.fsyncSync(s)}finally{d.closeSync(s)}}}finally{i!==void 0&&d.closeSync(i);try{d.unlinkSync(o)}catch{}}}export{k as PERSONAL_SYNC_V1_ROOT_NAME,te as acknowledgeSessionIndexUpdate,le as appendMessage,ae as applyGeneratedSessionTitle,se as claimSessionTitleGenerationCandidates,oe as deferSessionTitleGeneration,Se as getCanonicalSessionStore,u as getDaemonInstallationId,de as getMessageDeliveryStatus,ee as listPendingSessionIndexUpdates,G as listSessionRecords,ge as listSessions,ne as markAllSessionIndexesForRepublish,Z as purgeCanonicalSession,K as purgeSessionRecord,ue as readMessages,U as recordSession,ie as recordSessionIndexRejection,ce as tombstoneMessage,re as upsertMessage};
1
+ import O from"node:crypto";import c from"node:fs";import A from"node:path";import{SESSION_SYNC_PROTOCOL_VERSION as x,SESSION_SYNC_DATA_EPOCH as I,SESSION_TITLE_SOURCE_PRIORITY as m,isToolPayload as P,sessionPreviewFromPayload as h}from"@shennian/wire";import{PERSONAL_SYNC_V1_ROOT_NAME as V,resolvePersonalSyncV1Path as G}from"../personal-sync/paths.js";import{CanonicalSessionStore as L}from"./canonical-store.js";import{getDaemonInstallationId as g}from"../personal-sync/identity.js";import{NativeSourceDeletionStore as q}from"../native-fusion/native-source-deletions.js";const D=120;function p(t){if(t.length<=D)return t;let e=t.slice(0,D);const n=e.charCodeAt(e.length-1);return n>=55296&&n<=56319&&(e=e.slice(0,-1)),e}let w=null,_=null;function R(){return G()}function u(){const t=A.join(R(),"canonical");return(!w||_!==t)&&(w=new L(t,g()),_=t),w}function k(){return A.join(R(),"session-index.json")}function d(){const t=k();if(!c.existsSync(t))return{};const e=JSON.parse(c.readFileSync(t,"utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`invalid personal session index: ${t}`);const n=g();for(const s of Object.values(e))if(s.daemonInstallationId!==n)throw new Error(`personal session index belongs to another daemon installation: ${t}`);return e}function S(t){J(k(),t)}function M(t){return h(t.payload,120)}function y(t){if(new q({rootDir:R(),daemonInstallationId:g()}).hasSession(t))throw new Error(`session_deleted:${t}`)}function j(t){y(t.sessionId),g();const e=d(),n=e[t.sessionId],s=new Date().toISOString(),i=u().getManifest(t.sessionId)?.bodyRevision??n?.bodyRevision??0,o=u().getManifest(t.sessionId),a=z(n,t),r=t.attentionId?.trim()||null,l=Array.from(new Set([...n?.seenAttentionIds??[],...n?.lastAttentionId?[n.lastAttentionId]:[]])),f=!!(r&&!l.includes(r)),v=t.lastMessagePreview===null?{preview:null,messageId:null,at:null}:t.lastMessagePreview!==void 0&&t.lastMessagePreviewMessageId&&t.lastMessagePreviewAt?{preview:t.lastMessagePreview,messageId:t.lastMessagePreviewMessageId,at:t.lastMessagePreviewAt}:{preview:n?.lastMessagePreview??null,messageId:n?.lastMessagePreviewMessageId??null,at:n?.lastMessagePreviewAt??null},b=Date.parse(t.lastVisibleEventAt??""),E=Date.parse(n?.lastVisibleEventAt??""),U=Number.isFinite(b)&&(!Number.isFinite(E)||b>=E)?t.lastVisibleEventAt:n?.lastVisibleEventAt??null,C={daemonInstallationId:g(),sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode??n?.sessionMode,managerConfig:t.managerConfig??n?.managerConfig??null,workDir:t.workDir,agentSessionId:t.agentSessionId??n?.agentSessionId??null,modelId:t.modelId??n?.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType??n?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId??n?.managerDefaultWorkerModelId??null,status:t.status??n?.status??"active",createdAt:n?.createdAt??s,updatedAt:s,lastActivityAt:t.lastActivityAt??n?.lastActivityAt??s,lastMessagePreview:v.preview,lastMessagePreviewMessageId:v.messageId,lastMessagePreviewAt:v.at,lastVisibleEventAt:U,localReady:n?.localReady===!0||t.localReady===!0,firstUserMessageId:n?.firstUserMessageId??t.firstUserMessageId??null,firstUserBodyRevision:n?.firstUserBodyRevision??t.firstUserBodyRevision??null,bodyRevision:i,indexRevision:(n?.indexRevision??0)+1,...a,firstAvailableSeq:o?.firstAvailableSeq??n?.firstAvailableSeq??null,visibleMessageCount:o?.visibleMessageCount??n?.visibleMessageCount??0,lastVisibleMessageId:o?.lastVisibleMessageId??n?.lastVisibleMessageId??null,attentionCount:(n?.attentionCount??0)+(f?1:0),lastAttentionId:f?r:n?.lastAttentionId??null,seenAttentionIds:f&&r?[...l,r]:l,lastBodyCommittedAt:o?.lastBodyCommittedAt??n?.lastBodyCommittedAt??null,deletionRevision:n?.deletionRevision??0,deletedAt:t.deletedAt??n?.deletedAt??null,syncedIndexRevision:n?.syncedIndexRevision??0,indexSyncState:"pending",indexSyncStateRevision:(n?.indexRevision??0)+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,titleGenerationAttemptedAt:n?.titleGenerationAttemptedAt&&n.titleGenerationNextAttemptAt!==void 0?n.titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:n?.titleGenerationNextAttemptAt??null,titleGenerationAttempts:n?.titleGenerationAttempts??0};return e[t.sessionId]=C,S(e),C}function F(){return Object.values(d())}function se(t){if(!t)throw new Error("sessionId is required");const e=d();e[t]&&(delete e[t],S(e))}function oe(t){u().purgeSession(t)}function W(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){const o=p(i.title);if(o===i.title)continue;const a=i.indexRevision+1;t[s]={...i,title:o,indexRevision:a,indexSyncState:"pending",indexSyncStateRevision:a,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,updatedAt:n},e=!0}e&&S(t)}function ae(){const t=g();return Y(),Q(),W(),F().filter(e=>{const n=e.indexSyncStateRevision===e.indexRevision;return e.indexQuarantineCode||n&&(e.indexSyncState==="quarantined"||e.indexSyncState==="terminal")||n&&e.indexSyncNextAttemptAt&&Date.parse(e.indexSyncNextAttemptAt)>Date.now()?!1:e.indexRevision>e.syncedIndexRevision&&e.localReady&&!!e.firstUserMessageId&&e.firstUserBodyRevision!=null}).sort((e,n)=>e.indexRevision-n.indexRevision).map(e=>{const n=!!(e.lastMessagePreview&&e.lastMessagePreviewMessageId&&e.lastMessagePreviewAt);return{protocolVersion:x,dataEpoch:I,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:n?e.lastMessagePreview:null,lastMessagePreviewMessageId:n?e.lastMessagePreviewMessageId:null,lastMessagePreviewAt:n?e.lastMessagePreviewAt:null,lastVisibleEventAt:e.lastVisibleEventAt??e.lastMessagePreviewAt??null,bodyStorageMode:"machine_local",localReady:!0,firstUserBoundary:{role:"user",messageId:e.firstUserMessageId,bodyRevision:e.firstUserBodyRevision},bodyRevision:e.bodyRevision,indexRevision:e.indexRevision,firstAvailableSeq:e.firstAvailableSeq,visibleMessageCount:e.visibleMessageCount,lastVisibleMessageId:e.lastVisibleMessageId,attentionCount:e.attentionCount??0,lastAttentionId:e.lastAttentionId??null,lastBodyCommittedAt:e.lastBodyCommittedAt,deletionRevision:e.deletionRevision,lastActivityAt:e.lastActivityAt,createdAt:e.createdAt,updatedAt:e.updatedAt,deletedAt:e.deletedAt}}})}function le(t,e){const n=d(),s=n[t];if(!(!s||e<=s.syncedIndexRevision)){if(e>s.indexRevision)throw new Error(`cannot acknowledge future index revision ${e} for ${t}`);n[t]={...s,syncedIndexRevision:e,indexSyncState:"applied",indexSyncStateRevision:e,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null},S(n)}}function re(){const t=d();let e=0;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(i.deletedAt||i.indexQuarantineCode||!i.localReady)continue;const o=i.indexRevision+1;t[s]={...i,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e+=1}return e>0&&S(t),e}function de(t){const e=d(),n=e[t.sessionId];if(!n||n.indexRevision!==t.indexRevision)return"terminal";const i=(n.indexSyncStateRevision===t.indexRevision?n.indexSyncAttempts??0:0)+1;let o=t.disposition;o==="retry"&&i>=(t.maxAttempts??8)&&(o="terminal");const a=t.now??Date.now(),r=Math.min(5e3*2**Math.max(0,i-1),360*60*1e3),l=Math.round(r*.2*(Math.random()*2-1));return e[t.sessionId]={...n,indexSyncState:o==="retry"?"pending":o,indexSyncStateRevision:t.indexRevision,indexSyncAttempts:i,indexSyncNextAttemptAt:o==="retry"?new Date(a+r+l).toISOString():null,indexSyncErrorCode:t.code,indexQuarantineCode:o==="quarantined"?t.code:n.indexQuarantineCode??null},S(e),o}const $=2*6e4;function ce(t=Date.now(),e=$){const n=d(),s=[],i=new Date(t).toISOString();for(const o of Object.values(n)){if(o.titleSource!=="first_user_fallback"||o.titleLockedByUser||o.titleGenerationAttemptedAt||!o.title.trim()||o.syncedIndexRevision<o.indexRevision||o.titleGenerationNextAttemptAt&&Date.parse(o.titleGenerationNextAttemptAt)>t)continue;const a=o.status==="completed"||o.status==="failed",r=o.visibleMessageCount>=2;let l=null;if(o.agentType==="claude"&&r?l="agent_native_unavailable":a?l="terminal":r&&t-Date.parse(o.createdAt)>=e&&(l="grace_elapsed"),!l)continue;const f=h(o.title,240);if(!f)continue;const v=O.randomUUID();n[o.sessionId]={...o,titleGenerationAttemptedAt:i,titleGenerationNextAttemptAt:null,titleGenerationAttempts:(o.titleGenerationAttempts??0)+1},s.push({sessionId:o.sessionId,requestId:v,titleSeed:f,baseTitleRevision:o.titleRevision,eligibility:l})}return s.length>0&&S(n),s}function ue(t,e=Date.now()){const n=d(),s=n[t];if(!s?.titleGenerationAttemptedAt||s.titleSource!=="first_user_fallback")return null;const i=Math.max(1,s.titleGenerationAttempts??1),o=Math.min(10*6e4,3e4*2**Math.min(i-1,5)),a=new Date(e+o).toISOString();return n[t]={...s,titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:a},S(n),a}function ge(t,e){const s=d()[t];return!s||s.titleLockedByUser||m[s.titleSource]>=m.shennian_generated||e.titleRevision<=s.titleRevision?!1:(j({sessionId:t,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:s.agentSessionId,modelId:s.modelId,status:s.status,title:e.title,titleSource:"shennian_generated",titleRevision:e.titleRevision,titleLockedByUser:!1,titleOriginEventId:e.titleOriginEventId}),!0)}function Se(t,e,n){y(t),g();const s=u().append(t,e,n);return T(t,e,s.bodyRevision),s.bodyRevision}function fe(t,e,n){y(t),g();const s=u().upsert(t,e,n);return T(t,e,s.bodyRevision),s.bodyRevision}function ve(t,e){const n=u().getMessageState(t,e);return!n||n.tombstoned||!n.message||!n.deliveryState?{protocolVersion:x,dataEpoch:I,daemonInstallationId:g(),state:"not_found",sessionId:t,clientMessageId:e}:{protocolVersion:x,dataEpoch:I,daemonInstallationId:g(),state:n.deliveryState,sessionId:t,clientMessageId:e,messageId:n.message.id,deliveryState:n.deliveryState,bodyRevision:n.lastRevision,committedAt:new Date(n.message.ts).toISOString()}}function me(t,e){y(t),g();const n=u().tombstone(t,e),s=d(),i=s[t];if(i){const o=e===i.lastMessagePreviewMessageId?N(t):{preview:i.lastMessagePreview??null,messageId:i.lastMessagePreviewMessageId??null,at:i.lastMessagePreviewAt??null};s[t]={...i,bodyRevision:n.bodyRevision,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,lastVisibleEventAt:B(t)},S(s)}return n.bodyRevision}function T(t,e,n){const s=d(),i=s[t];if(!i)return;const o=M(e),a=o?{lastMessagePreview:o,lastMessagePreviewMessageId:e.id,lastMessagePreviewAt:new Date(e.ts).toISOString()}:null,r=o||P(e.payload)?new Date(e.ts).toISOString():i.lastVisibleEventAt,l=u().getManifest(t),f=e.role==="user"&&o&&!i.title?{title:p(o),titleSource:"first_user_fallback",titleRevision:i.titleRevision+1,titleLockedByUser:!1,titleOriginEventId:e.id}:null,v=e.role==="user"&&!i.localReady?{localReady:!0,firstUserMessageId:e.id,firstUserBodyRevision:n}:null;s[t]={...i,...f??{},...v??{},bodyRevision:n,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastActivityAt:new Date(e.ts).toISOString(),lastVisibleEventAt:r,...a??{},firstAvailableSeq:l?.firstAvailableSeq??i.firstAvailableSeq,visibleMessageCount:l?.visibleMessageCount??i.visibleMessageCount,lastVisibleMessageId:l?.lastVisibleMessageId??i.lastVisibleMessageId,attentionCount:i.attentionCount??0,lastAttentionId:i.lastAttentionId??null,lastBodyCommittedAt:l?.lastBodyCommittedAt??i.lastBodyCommittedAt},S(s)}function N(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s],o=M(i.message);if(o)return{preview:o,messageId:i.message.id,at:new Date(i.message.ts).toISOString()}}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return{preview:null,messageId:null,at:null}}function B(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s].message;if(!(!M(i)&&!P(i.payload)))return new Date(i.ts).toISOString()}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return null}function Q(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastVisibleEventAt"))continue;const o=i.indexRevision+1;t[s]={...i,lastVisibleEventAt:B(s)??i.lastMessagePreviewAt??null,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function Y(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewMessageId")&&Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewAt"))continue;const o=N(s);t[s]={...i,lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function z(t,e){const n={title:t?.title??"",titleSource:t?.titleSource??"first_user_fallback",titleRevision:t?.titleRevision??0,titleLockedByUser:t?.titleLockedByUser??!1,titleOriginEventId:t?.titleOriginEventId??null},s=p(e.title?.trim()??"");if(!s)return n;if(!e.titleSource)throw new Error("titleSource is required with title");if(n.title&&n.titleSource==="first_user_fallback"&&e.titleSource==="first_user_fallback")return n;const i=e.titleSource==="shennian_manual";if(e.titleLockedByUser!==void 0&&e.titleLockedByUser!==i)throw new Error("titleLockedByUser conflicts with titleSource");const o=s===n.title&&e.titleSource===n.titleSource,a=e.titleRevision??n.titleRevision+(o?0:1);if(!Number.isSafeInteger(a)||a<0)throw new Error("invalid titleRevision");const r=m[e.titleSource],l=m[n.titleSource];return r<l||a<n.titleRevision||o&&a===n.titleRevision||a===n.titleRevision&&!o?n:{title:s,titleSource:e.titleSource,titleRevision:a,titleLockedByUser:i,titleOriginEventId:e.titleOriginEventId??n.titleOriginEventId}}function ye(t,e){const n=e?.limit&&e.limit>0?Math.min(e.limit,500):500;let i=u().readRecent(t,n).messages;return e?.before!==void 0&&(i=i.filter(o=>o.ts<e.before)),[...i].sort((o,a)=>a.ts-o.ts)}function Ae(){return u().listSessionIds()}function xe(){return u()}function J(t,e){const n=A.dirname(t);c.mkdirSync(n,{recursive:!0,mode:448});const s=`${t}.tmp-${process.pid}-${O.randomBytes(6).toString("hex")}`;let i;try{if(i=c.openSync(s,"wx",384),c.writeFileSync(i,`${JSON.stringify(e,null,2)}
2
+ `,"utf8"),c.fsyncSync(i),c.closeSync(i),i=void 0,c.renameSync(s,t),process.platform!=="win32"){const o=c.openSync(n,"r");try{c.fsyncSync(o)}finally{c.closeSync(o)}}}finally{i!==void 0&&c.closeSync(i);try{c.unlinkSync(s)}catch{}}}export{V as PERSONAL_SYNC_V1_ROOT_NAME,le as acknowledgeSessionIndexUpdate,Se as appendMessage,ge as applyGeneratedSessionTitle,ce as claimSessionTitleGenerationCandidates,ue as deferSessionTitleGeneration,xe as getCanonicalSessionStore,g as getDaemonInstallationId,ve as getMessageDeliveryStatus,ae as listPendingSessionIndexUpdates,F as listSessionRecords,Ae as listSessions,re as markAllSessionIndexesForRepublish,oe as purgeCanonicalSession,se as purgeSessionRecord,ye as readMessages,j as recordSession,de as recordSessionIndexRejection,me as tombstoneMessage,fe as upsertMessage};
@@ -332,6 +332,8 @@ export type DaemonSessionIndexProjection = {
332
332
  /** Stable identity and canonical timestamp of lastMessagePreview. */
333
333
  lastMessagePreviewMessageId: string | null;
334
334
  lastMessagePreviewAt: string | null;
335
+ /** Latest canonical user-visible text or tool event; optional for older daemons. */
336
+ lastVisibleEventAt?: string | null;
335
337
  bodyStorageMode: SessionBodyStorageMode;
336
338
  /**
337
339
  * Set only after the daemon has durably committed the first canonical user
@@ -296,6 +296,8 @@ export type NianSession = {
296
296
  /** Stable identity and canonical timestamp of the displayed list preview. */
297
297
  lastMessagePreviewMessageId?: string | null;
298
298
  lastMessagePreviewAt?: string | null;
299
+ /** Latest canonical timeline event visible to the user, including tool activity. */
300
+ lastVisibleEventAt?: string | null;
299
301
  bodyStorageMode?: SessionBodyStorageMode;
300
302
  /**
301
303
  * False only for a Server-created shell that has not yet committed its first
@@ -328,7 +330,7 @@ export type NianSession = {
328
330
  activity?: SessionActivitySnapshot | null;
329
331
  externalChannel?: ExternalChannelSessionStatus | null;
330
332
  };
331
- export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'titleSource' | 'titleRevision' | 'titleLockedByUser' | 'titleOriginEventId' | 'status' | 'workDir' | 'lastMessagePreview' | 'lastMessagePreviewMessageId' | 'lastMessagePreviewAt' | 'bodyStorageMode' | 'bodyRevision' | 'indexRevision' | 'dataEpoch' | 'firstAvailableSeq' | 'visibleMessageCount' | 'lastVisibleMessageId' | 'attentionCount' | 'lastAttentionId' | 'lastBodyCommittedAt' | 'deletionRevision' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
333
+ export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'titleSource' | 'titleRevision' | 'titleLockedByUser' | 'titleOriginEventId' | 'status' | 'workDir' | 'lastMessagePreview' | 'lastMessagePreviewMessageId' | 'lastMessagePreviewAt' | 'lastVisibleEventAt' | 'bodyStorageMode' | 'bodyRevision' | 'indexRevision' | 'dataEpoch' | 'firstAvailableSeq' | 'visibleMessageCount' | 'lastVisibleMessageId' | 'attentionCount' | 'lastAttentionId' | 'lastBodyCommittedAt' | 'deletionRevision' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
332
334
  export type ChatSendParams = PersonalSyncIdentity & {
333
335
  sessionId: string;
334
336
  text: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.26",
3
+ "version": "0.4.27",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {