shennian 0.3.44 → 0.3.46
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 +18 -13
- package/dist/src/native-fusion/local-repository.d.ts +7 -0
- package/dist/src/native-fusion/local-repository.js +2 -2
- package/dist/src/native-fusion/native-source-deletions.d.ts +34 -0
- package/dist/src/native-fusion/native-source-deletions.js +2 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/session-header.d.ts +4 -0
- package/dist/src/native-fusion/session-header.js +2 -2
- package/dist/src/native-fusion/state.js +2 -2
- package/dist/src/native-fusion/types.d.ts +1 -0
- package/dist/src/session/index-publisher.js +1 -1
- package/dist/src/session/store.d.ts +1 -0
- package/dist/src/session/store.js +2 -2
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"jsMinified": true,
|
|
4
4
|
"minifier": "esbuild",
|
|
5
|
-
"fileCount":
|
|
5
|
+
"fileCount": 122,
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"file": "bin/shennian.js",
|
|
@@ -321,8 +321,13 @@
|
|
|
321
321
|
},
|
|
322
322
|
{
|
|
323
323
|
"file": "src/native-fusion/local-repository.js",
|
|
324
|
-
"beforeBytes":
|
|
325
|
-
"afterBytes":
|
|
324
|
+
"beforeBytes": 14775,
|
|
325
|
+
"afterBytes": 7655
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"file": "src/native-fusion/native-source-deletions.js",
|
|
329
|
+
"beforeBytes": 5283,
|
|
330
|
+
"afterBytes": 2839
|
|
326
331
|
},
|
|
327
332
|
{
|
|
328
333
|
"file": "src/native-fusion/opencode-parser.js",
|
|
@@ -341,18 +346,18 @@
|
|
|
341
346
|
},
|
|
342
347
|
{
|
|
343
348
|
"file": "src/native-fusion/service.js",
|
|
344
|
-
"beforeBytes":
|
|
345
|
-
"afterBytes":
|
|
349
|
+
"beforeBytes": 21206,
|
|
350
|
+
"afterBytes": 10005
|
|
346
351
|
},
|
|
347
352
|
{
|
|
348
353
|
"file": "src/native-fusion/session-header.js",
|
|
349
|
-
"beforeBytes":
|
|
350
|
-
"afterBytes":
|
|
354
|
+
"beforeBytes": 4283,
|
|
355
|
+
"afterBytes": 1996
|
|
351
356
|
},
|
|
352
357
|
{
|
|
353
358
|
"file": "src/native-fusion/state.js",
|
|
354
|
-
"beforeBytes":
|
|
355
|
-
"afterBytes":
|
|
359
|
+
"beforeBytes": 3489,
|
|
360
|
+
"afterBytes": 1745
|
|
356
361
|
},
|
|
357
362
|
{
|
|
358
363
|
"file": "src/native-fusion/types.js",
|
|
@@ -556,8 +561,8 @@
|
|
|
556
561
|
},
|
|
557
562
|
{
|
|
558
563
|
"file": "src/session/index-publisher.js",
|
|
559
|
-
"beforeBytes":
|
|
560
|
-
"afterBytes":
|
|
564
|
+
"beforeBytes": 1896,
|
|
565
|
+
"afterBytes": 838
|
|
561
566
|
},
|
|
562
567
|
{
|
|
563
568
|
"file": "src/session/manager.js",
|
|
@@ -576,8 +581,8 @@
|
|
|
576
581
|
},
|
|
577
582
|
{
|
|
578
583
|
"file": "src/session/store.js",
|
|
579
|
-
"beforeBytes":
|
|
580
|
-
"afterBytes":
|
|
584
|
+
"beforeBytes": 13523,
|
|
585
|
+
"afterBytes": 7535
|
|
581
586
|
},
|
|
582
587
|
{
|
|
583
588
|
"file": "src/session/tool-detail-store.js",
|
|
@@ -2,11 +2,16 @@ import type { CanonicalSessionStore } from '../session/canonical-store.js';
|
|
|
2
2
|
import { listSessionRecords, recordSession } from '../session/store.js';
|
|
3
3
|
import type { ParsedNativeEvent } from './types.js';
|
|
4
4
|
import { type LocalToolDetail } from '../session/tool-detail-store.js';
|
|
5
|
+
import { NativeSourceDeletionStore } from './native-source-deletions.js';
|
|
5
6
|
declare const SCHEMA_VERSION: 1;
|
|
6
7
|
export declare class MissingUserBoundaryError extends Error {
|
|
7
8
|
readonly code = "missing_user_boundary";
|
|
8
9
|
constructor(sourceSessionKey: string);
|
|
9
10
|
}
|
|
11
|
+
export declare class NativeSourceDeletedError extends Error {
|
|
12
|
+
readonly code = "native_source_deleted";
|
|
13
|
+
constructor(sourceSessionKey: string);
|
|
14
|
+
}
|
|
10
15
|
type SourceBinding = {
|
|
11
16
|
schemaVersion: typeof SCHEMA_VERSION;
|
|
12
17
|
daemonInstallationId: string;
|
|
@@ -37,10 +42,12 @@ export declare class NativeFusionLocalRepository {
|
|
|
37
42
|
listLocalSessions?: typeof listSessionRecords;
|
|
38
43
|
writeLocalToolDetail?: (detail: Omit<LocalToolDetail, 'schemaVersion'>) => void;
|
|
39
44
|
readLocalToolDetail?: (sessionId: string, toolCallId: string) => LocalToolDetail | null;
|
|
45
|
+
deletionStore?: Pick<NativeSourceDeletionStore, 'has'>;
|
|
40
46
|
});
|
|
41
47
|
commitEvents(events: readonly ParsedNativeEvent[]): NativeLocalCommitResult[];
|
|
42
48
|
commitEvent(event: ParsedNativeEvent): NativeLocalCommitResult;
|
|
43
49
|
listSourceBindings(): SourceBinding[];
|
|
50
|
+
isSourceDeleted(agentType: ParsedNativeEvent['agentType'], sourceSessionKey: string): boolean;
|
|
44
51
|
observeNativeTitle(agentType: ParsedNativeEvent['agentType'], sourceSessionKey: string, titleValue: string): boolean;
|
|
45
52
|
private recordIndex;
|
|
46
53
|
private readSources;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import d from"node:crypto";import
|
|
2
|
-
`,"utf8"),
|
|
1
|
+
import d from"node:crypto";import l from"node:fs";import h from"node:path";import{resolvePersonalSyncV1Path as F}from"../personal-sync/paths.js";import{getCanonicalSessionStore as O,getDaemonInstallationId as k,listSessionRecords as B,recordSession as b}from"../session/store.js";import{readToolDetail as H,writeToolDetail as J}from"../session/tool-detail-store.js";import{NativeSourceDeletionStore as L}from"./native-source-deletions.js";const I=1;class R extends Error{code="missing_user_boundary";constructor(e){super(`native source ${e} does not start at a visible user boundary`),this.name="MissingUserBoundaryError"}}class A extends Error{code="native_source_deleted";constructor(e){super(`native source ${e} is blocked by a durable deletion tombstone`),this.name="NativeSourceDeletedError"}}class ee{options;constructor(e={}){this.options=e}commitEvents(e){return[...e].sort((o,t)=>o.ts-t.ts).map(o=>this.commitEvent(o))}commitEvent(e){if(j(e),this.isSourceDeleted(e.agentType,e.sourceSessionKey))throw new A(e.sourceSessionKey);const o=this.installationId(),t=this.readSources(),r=K(e.agentType,e.sourceSessionKey),i=t.sources[r],c=P(e),m=this.ledgerFile(e.agentType,e.sourceEventKey),n=l.existsSync(m)?x(m):null;if(n&&n.daemonInstallationId!==o)throw new Error("native event ledger belongs to another daemon installation");if(n&&n.eventFingerprint!==c)throw new Error(`native event identity conflict: ${e.sourceEventKey}`);if(!i&&!n&&e.role!=="user")throw new R(e.sourceSessionKey);const g=e.claimSessionId??null,a=i?.sessionId??n?.sessionId??g??V(o,e.agentType,e.sourceSessionKey);if(g&&i&&i.sessionId!==g)throw new Error(`managed claim session conflicts with source binding ${e.sourceSessionKey}`);const p=this.canonicalStore(),u=e.claimCanonicalMessageId??U(o,e.agentType,e.canonicalMessageKey??e.sourceEventKey);let S=p.getManifest(a)?.bodyRevision??0,D=!!n;const f=!!e.claimCanonicalMessageId;if(f){const y=p.getMessageState(a,u);if(!y||y.tombstoned)throw new Error(`managed echo claim target is not durable: ${u}`)}if(!n&&!f){const y=e.canonicalMutation==="upsert"?p.getMessageState(a,u):null,E={id:u,sessionId:a,role:e.role,ts:y?.message?.ts??e.ts,payload:W(y?.message?.payload,e.payload)},$=e.canonicalMutation==="upsert"?p.upsert(a,E):p.append(a,E);if(S=$.bodyRevision,D=$.duplicate,e.localToolDetail){const _=this.options.writeLocalToolDetail??J,N=this.options.readLocalToolDetail??H,C=q(N(a,e.localToolDetail.toolCallId),e.localToolDetail);_({sessionId:a,...C,ts:e.ts,detailRef:{toolIndex:0}})}}n||this.recordIndex(e,a);const w=new Date().toISOString();return n||M(m,{schemaVersion:I,daemonInstallationId:o,sessionId:a,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceEventKey:e.sourceEventKey,eventFingerprint:c,canonicalMessageId:u,canonicalRevision:S,cursor:e.cursor??null,mappedBy:f?"managed_echo_claim":e.sourceMode,eventTs:e.ts,createdAt:w}),t.sources[r]={schemaVersion:I,daemonInstallationId:o,sessionId:a,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceMode:n?i?.sourceMode??e.sourceMode:e.sourceMode,lastCursor:n?i?.lastCursor??n.cursor:e.cursor??i?.lastCursor??null,bodyRevision:S,createdAt:i?.createdAt??w,updatedAt:w},M(this.sourcesFile(),t),{sessionId:a,messageId:u,bodyRevision:S,duplicate:D,claimed:f}}listSourceBindings(){return Object.values(this.readSources().sources).filter(e=>!this.isSourceDeleted(e.agentType,e.sourceSessionKey))}isSourceDeleted(e,o){return(this.options.deletionStore??new L({rootDir:h.basename(this.rootDir())==="native-fusion"?h.dirname(this.rootDir()):this.rootDir(),daemonInstallationId:this.installationId()})).has(e,o)}observeNativeTitle(e,o,t){const r=t.trim().slice(0,120);if(!r)return!1;const i=this.readSources().sources[K(e,o)];if(!i||this.isSourceDeleted(e,o))return!1;const c=(this.options.listLocalSessions??B)().find(g=>g.sessionId===i.sessionId);if(c?.titleLockedByUser||c?.titleSource==="agent_native"&&c.title===r)return!1;const m=d.createHash("sha256").update(`${e}\0${o}\0${r}`).digest("hex");return(this.options.recordLocalSession??b)({sessionId:i.sessionId,agentType:i.agentType,workDir:c?.workDir??"",agentSessionId:o,title:r,titleSource:"agent_native",titleOriginEventId:`agent-native:${m}`}),!0}recordIndex(e,o){(this.options.recordLocalSession??b)({sessionId:o,agentType:e.agentType,workDir:e.workDir??"",agentSessionId:e.sourceSessionKey,modelId:e.modelId??null,status:e.terminal?"completed":"active",lastActivityAt:new Date(e.ts).toISOString(),lastMessagePreview:e.role==="user"?T(e.payload):void 0,title:e.title?.trim()||(e.role==="user"?T(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 o=x(e);if(o.schemaVersion!==I||o.daemonInstallationId!==this.installationId()||!o.sources)throw new Error("invalid native source binding store");for(const t of Object.values(o.sources))if(t.daemonInstallationId!==this.installationId())throw new Error("native source binding belongs to another daemon installation");return o}installationId(){return this.options.daemonInstallationId??k()}canonicalStore(){return this.options.canonicalStore??O()}rootDir(){return this.options.rootDir??F("native-fusion")}sourcesFile(){return h.join(this.rootDir(),"sources.json")}ledgerFile(e,o){const t=d.createHash("sha256").update(`${e}\0${o}`).digest("hex");return h.join(this.rootDir(),"ledger",`${t}.json`)}}function j(s){if(!s.agentType||!s.sourceSessionKey||!s.sourceEventKey||!s.payload)throw new Error("invalid native event");if(!Number.isFinite(s.ts))throw new Error("invalid native event timestamp")}function K(s,e){return d.createHash("sha256").update(`${s}\0${e}`).digest("hex")}function V(s,e,o){return`native-session-${d.createHash("sha256").update(`${s}\0${e}\0${o}`).digest("hex").slice(0,32)}`}function U(s,e,o){return`native-${d.createHash("sha256").update(`${s}\0${e}\0${o}`).digest("hex").slice(0,32)}`}function P(s){return d.createHash("sha256").update(JSON.stringify({agentType:s.agentType,sourceSessionKey:s.sourceSessionKey,sourceEventKey:s.sourceEventKey,role:s.role,ts:s.ts,payload:s.payload,claimCanonicalMessageId:s.claimCanonicalMessageId??null,claimSessionId:s.claimSessionId??null,canonicalMessageKey:s.canonicalMessageKey??null,canonicalMutation:s.canonicalMutation??"append"})).digest("hex")}function W(s,e){if(!s)return e;try{const o=JSON.parse(s),t=JSON.parse(e);if(o.type!=="tool"||t.type!=="tool"||o.toolCallId!==t.toolCallId)return e;const r=typeof t.name=="string"?t.name:"",i=/(?:_output|_result)$/.test(r);return JSON.stringify({...o,...t,...i&&typeof o.name=="string"?{name:o.name}:{}})}catch{return e}}function q(s,e){if(!s||s.toolCallId!==e.toolCallId)return e;const o=/(?:_output|_result)$/.test(e.name);return{...e,name:o?s.name:e.name,...e.args===void 0&&s.args!==void 0?{args:s.args}:{},...e.result===void 0&&s.result!==void 0?{result:s.result}:{}}}function T(s){const e=s.replace(/\s+/g," ").trim();return e?e.length>120?`${e.slice(0,120)}...`:e:null}function M(s,e){const o=h.dirname(s);l.mkdirSync(o,{recursive:!0,mode:448});const t=`${s}.tmp-${process.pid}-${d.randomBytes(6).toString("hex")}`;let r;try{r=l.openSync(t,"wx",384),l.writeFileSync(r,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,"utf8"),l.fsyncSync(r),l.closeSync(r),r=void 0,l.renameSync(t,s)}finally{r!==void 0&&l.closeSync(r);try{l.unlinkSync(t)}catch{}}}function x(s){return JSON.parse(l.readFileSync(s,"utf8"))}export{R as MissingUserBoundaryError,ee as NativeFusionLocalRepository,A as NativeSourceDeletedError};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare const SCHEMA_VERSION: 1;
|
|
2
|
+
export type LocalNativeSourceDeletion = {
|
|
3
|
+
schemaVersion: typeof SCHEMA_VERSION;
|
|
4
|
+
daemonInstallationId: string;
|
|
5
|
+
deletionRevision: number;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
agentType: string;
|
|
8
|
+
sourceSessionKey: string;
|
|
9
|
+
sourceSessionKeyHash: string;
|
|
10
|
+
deletedAt: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class NativeSourceDeletionStore {
|
|
13
|
+
private options;
|
|
14
|
+
constructor(options?: {
|
|
15
|
+
rootDir?: string;
|
|
16
|
+
daemonInstallationId?: string;
|
|
17
|
+
});
|
|
18
|
+
record(input: {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
agentType: string;
|
|
21
|
+
sourceSessionKey: string;
|
|
22
|
+
deletionRevision: number;
|
|
23
|
+
deletedAt?: string;
|
|
24
|
+
}): LocalNativeSourceDeletion;
|
|
25
|
+
find(agentType: string, sourceSessionKey: string): LocalNativeSourceDeletion | null;
|
|
26
|
+
has(agentType: string, sourceSessionKey: string): boolean;
|
|
27
|
+
list(): LocalNativeSourceDeletion[];
|
|
28
|
+
private read;
|
|
29
|
+
private installationId;
|
|
30
|
+
private filePath;
|
|
31
|
+
private key;
|
|
32
|
+
}
|
|
33
|
+
export declare function hashSource(agentType: string, sourceSessionKey: string): string;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import d from"node:crypto";import i from"node:fs";import l from"node:path";import{resolvePersonalSyncV1Path as y}from"../personal-sync/paths.js";import{getDaemonInstallationId as h}from"../session/store.js";const a=1;class g{options;constructor(e={}){this.options=e}record(e){f(e);const o=this.read(),t=this.key(e.agentType,e.sourceSessionKey),n=o.deletions[t];if(n&&n.sessionId!==e.sessionId)throw new Error("native source deletion identity conflict");if(n&&n.deletionRevision>=e.deletionRevision)return n;const r={schemaVersion:a,daemonInstallationId:this.installationId(),deletionRevision:e.deletionRevision,sessionId:e.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,sourceSessionKeyHash:c(e.agentType,e.sourceSessionKey),deletedAt:e.deletedAt??new Date().toISOString()};return o.deletions[t]=r,u(this.filePath(),o),r}find(e,o){return!e||!o?null:this.read().deletions[this.key(e,o)]??null}has(e,o){return this.find(e,o)!==null}list(){return Object.values(this.read().deletions).sort((e,o)=>e.deletionRevision-o.deletionRevision)}read(){const e=this.installationId(),o=this.filePath();if(!i.existsSync(o))return{schemaVersion:a,daemonInstallationId:e,deletions:{}};const t=JSON.parse(i.readFileSync(o,"utf8"));if(t.schemaVersion!==a||t.daemonInstallationId!==e||!t.deletions||typeof t.deletions!="object"||Array.isArray(t.deletions))throw new Error("invalid native source deletion store");for(const n of Object.values(t.deletions))if(n.schemaVersion!==a||n.daemonInstallationId!==e||!n.sessionId||!n.agentType||!n.sourceSessionKey||n.sourceSessionKeyHash!==c(n.agentType,n.sourceSessionKey)||!Number.isSafeInteger(n.deletionRevision)||n.deletionRevision<1)throw new Error("invalid native source deletion record");return t}installationId(){return this.options.daemonInstallationId??h()}filePath(){return l.join(this.options.rootDir??y(),"native-source-deletions.json")}key(e,o){return d.createHash("sha256").update(`${this.installationId()}\0${e}\0${o}`).digest("hex")}}function c(s,e){return d.createHash("sha256").update(`${s}\0${e}`).digest("hex")}function f(s){if(!s.sessionId||!s.agentType||!s.sourceSessionKey)throw new Error("invalid native source deletion identity");if(!Number.isSafeInteger(s.deletionRevision)||s.deletionRevision<1)throw new Error("invalid native source deletion revision")}function u(s,e){const o=l.dirname(s);i.mkdirSync(o,{recursive:!0,mode:448});const t=`${s}.tmp-${process.pid}-${d.randomBytes(6).toString("hex")}`;let n;try{if(n=i.openSync(t,"wx",384),i.writeFileSync(n,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,"utf8"),i.fsyncSync(n),i.closeSync(n),n=void 0,i.renameSync(t,s),process.platform!=="win32"){const r=i.openSync(o,"r");try{i.fsyncSync(r)}finally{i.closeSync(r)}}}finally{n!==void 0&&i.closeSync(n);try{i.unlinkSync(t)}catch{}}}export{g as NativeSourceDeletionStore,c as hashSource};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import T from"node:fs";import{publishPendingSessionIndexes as E}from"../session/index-publisher.js";import{NativeFusionFileWatcher as
|
|
2
|
-
`).trim()}function
|
|
1
|
+
import T from"node:fs";import{publishPendingSessionIndexes as E}from"../session/index-publisher.js";import{NativeFusionFileWatcher as b}from"./file-watcher.js";import{NativeFusionLocalRepository as C}from"./local-repository.js";import{listClaudeTranscriptFiles as K,listCodexRolloutFiles as N,listOpenCodeSessionFiles as _,inspectNativeSessionFile as P,lookupCodexThreadName as R,parseClaudeTranscriptChunk as O,parseCodexRolloutChunk as k,parseOpenCodeSessionFile as q}from"./parsers.js";import{loadNativeScannerState as F,saveNativeScannerState as L}from"./state.js";const x=6e4,A=x*2,$=30*6e4,W=2e3,B=3e4,w=240*6e4;function M(u){return u.replace(/\r\n/g,`
|
|
2
|
+
`).trim()}function D(u){return u.split(/[\\/]+/).includes(".codex")}class J{client;repository;timer=null;activeTimer=null;scanPromise=null;queuedTargetFiles=new Set;fullScanQueued=!1;watchEnabled=!1;lifecycleRevision=0;watcher=new b(e=>{this.scanNow(e).catch(s=>{console.error("[native-fusion] watched file scan failed",s)})});pendingClaims=new Map;suppressionWindows=new Map;externalObservations=new Map;constructor(e,s=new C){this.client=e,this.repository=s}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},x))}stop(){this.lifecycleRevision+=1,this.timer&&clearInterval(this.timer),this.timer=null,this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null,this.watchEnabled=!1,this.watcher.stop()}handleConnected(){const e=++this.lifecycleRevision;this.watchEnabled=!0,this.scanNow().catch(s=>{console.error("[native-fusion] initial scan failed",s)}).finally(()=>{this.lifecycleRevision===e&&this.start()})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;if(s!=="codex"&&s!=="claude"&&s!=="opencode")return;const n=e.canonicalMessageId;if(this.pendingClaims.set(n,{sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,text:M(e.text),createdAt:Date.now(),expiresAt:Date.now()+(e.externalRunId?w:A),sourceSessionKey:e.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following",externalRunId:e.externalRunId??null}),e.externalRunId&&e.sourceSessionKey){const t=`${s}:${e.sourceSessionKey}`,r=this.externalObservations.get(t)??[];r.push({sessionId:e.sessionId,sourceSessionKey:e.sourceSessionKey,runId:e.externalRunId,canonicalMessageId:e.canonicalMessageId,state:"queued",createdAt:Date.now(),lastPublishedAt:Date.now()}),this.externalObservations.set(t,r),this.emitExternalActivity(r[r.length-1],"queued"),this.ensureActiveScanning()}}noteManagedSourceSession(e,s,n){if(n)for(const t of this.pendingClaims.values())t.sessionId===e&&t.sourceAgentType===s&&(t.sourceSessionKey=n)}ensureActiveScanning(){this.activeTimer||(this.activeTimer=setInterval(()=>{if(this.externalObservations.size===0){this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null;return}this.scanNow().catch(e=>{console.error("[native-fusion] active observation scan failed",e)})},W),this.scanNow().catch(()=>{}))}emitExternalActivity(e,s){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${s}-${e.lastPublishedAt}`,payload:{state:s==="queued"?"start":"heartbeat",sessionId:e.sessionId,runId:e.runId,seq:s==="queued"?0:1,runPhase:"thinking",canStop:!1,owner:"external",ownerLabel:"Codex Desktop",lifecycle:s}})}emitExternalTerminal(e){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-final`,payload:{state:"final",sessionId:e.sessionId,runId:e.runId,seq:2,owner:"external",ownerLabel:"Codex Desktop"}})}pruneState(){const e=Date.now();for(const[s,n]of this.pendingClaims.entries())n.expiresAt<=e&&this.pendingClaims.delete(s);for(const[s,n]of this.suppressionWindows.entries())n.endsAt<=e&&this.suppressionWindows.delete(s)}async scanNow(e){if(this.client.getState()==="connected"){if(this.scanPromise){const s=this.scanPromise;if(e)for(const n of e)this.queuedTargetFiles.add(n);else this.fullScanQueued=!0;if(await s,this.fullScanQueued)return this.fullScanQueued=!1,this.queuedTargetFiles.clear(),this.scanNow();if(this.queuedTargetFiles.size>0){const n=[...this.queuedTargetFiles];return this.queuedTargetFiles.clear(),this.scanNow(n)}return}return this.scanPromise=this.runScanLoop(e).finally(()=>{this.scanPromise=null}),this.scanPromise}}async runScanLoop(e){let s=e?[...new Set(e)]:void 0;for(;;){if(await this.runScan(s),this.fullScanQueued){this.fullScanQueued=!1,this.queuedTargetFiles.clear(),s=void 0;continue}if(this.queuedTargetFiles.size>0){s=[...this.queuedTargetFiles],this.queuedTargetFiles.clear();continue}return}}async runScan(e){this.pruneState(),this.refreshExternalObservations();const s=F(),n={...s.files},t=[],r=new Map,h=e?[...e]:[...N(),...K(),..._()];!e&&this.watchEnabled&&this.watcher.refresh(h);for(const i of h){if(!T.existsSync(i))continue;const l=T.statSync(i),v=D(i),f=i.endsWith(".opencode-session.json"),d=P(i);if(d.status==="pending")continue;let a=s.files[i];const c=`${String(l.dev)}:${String(l.ino)}:${String(l.birthtimeMs)}`;let y=!a;if(a&&!f&&(l.size<a.offset||a.fileIdentity&&a.fileIdentity!==c)&&(a=void 0,y=!0),!f&&d.sources.length>0&&d.sources.every(o=>this.repository.isSourceDeleted?.(o.agentType,o.sourceSessionKey))){n[i]={...a??{daemonInstallationId:s.daemonInstallationId,classification:d.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:d.createdAtMs,sourceBoundaryEstablished:{}},offset:l.size,mtimeMs:l.mtimeMs,fileIdentity:c};continue}if(!a)a={daemonInstallationId:s.daemonInstallationId,offset:0,mtimeMs:l.mtimeMs,classification:d.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:d.createdAtMs,sourceBoundaryEstablished:{}};else if(f&&a.mtimeMs===l.mtimeMs)continue;const m=f?0:a.offset,p=f?q(i,m):v?k(i,m):O(i,m);for(const o of p.events)this.repository.isSourceDeleted?.(o.agentType,o.sourceSessionKey)||o.title?.trim()&&o.titleSource==="agent_native"&&r.set(`${o.agentType}:${o.sourceSessionKey}`,o);let S,g;if(f){const o=z(p.events,a,s.fusionEpochMs,y,l.mtimeMs,p.nextOffset);S=o.events,g=o.cursor}else if(y&&a.classification==="historical")S=[],g={...a,offset:p.nextOffset,mtimeMs:l.mtimeMs,awaitingUserBoundary:!0};else{const o=U(p.events,a,p.nextOffset,l.mtimeMs);S=o.events,g=o.cursor}g.fileIdentity=c,n[i]=g;for(const o of S){if(this.repository.isSourceDeleted?.(o.agentType,o.sourceSessionKey))continue;const I=this.tryClaimManagedEcho(o);if(I){t.push(I);continue}this.isSuppressed(o)||t.push(o)}}this.repository.commitEvents(t);for(const i of r.values())this.repository.observeNativeTitle(i.agentType,i.sourceSessionKey,i.title??"");for(const i of this.repository.listSourceBindings()){if(i.agentType!=="codex")continue;const l=R(i.sourceSessionKey);l&&this.repository.observeNativeTitle("codex",i.sourceSessionKey,l)}for(const i of t)this.observeExternalLifecycle(i);s.files=n,L(s),await E(this.client).catch(i=>{console.error("[native-fusion] index projection sync failed; retained for retry",i)})}refreshExternalObservations(){const e=Date.now();for(const[s,n]of this.externalObservations.entries()){const t=n.filter(h=>e-h.createdAt<w);if(t.length===0){this.externalObservations.delete(s);continue}this.externalObservations.set(s,t);const r=t[0];e-r.lastPublishedAt<B||(r.lastPublishedAt=e,this.emitExternalActivity(r,r.state))}}tryClaimManagedEcho(e){const s=Date.now();for(const[n,t]of this.pendingClaims.entries()){if(t.sourceAgentType!==e.agentType||t.expiresAt<=s||e.role!=="user"||!t.sourceSessionKey||t.sourceSessionKey!==e.sourceSessionKey)continue;const r=t.externalRunId?w:A;if(!(Math.abs(e.ts-t.createdAt)>r)&&M(e.payload)===t.text)return this.pendingClaims.delete(n),t.managedEchoPolicy==="suppress_following"&&this.suppressionWindows.set(`${e.agentType}:${e.sourceSessionKey}`,{sessionId:t.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+$}),{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:t.canonicalMessageId,claimSessionId:t.sessionId,managedEchoPolicy:t.managedEchoPolicy}}return null}observeExternalLifecycle(e){const s=`${e.agentType}:${e.sourceSessionKey}`,n=this.externalObservations.get(s);if(!n?.length)return;const t=n[0];e.claimCanonicalMessageId===t.canonicalMessageId&&t.state==="queued"&&(t.state="running",t.lastPublishedAt=Date.now(),this.emitExternalActivity(t,"running")),!(!e.terminal||t.state!=="running")&&(this.emitExternalTerminal(t),n.shift(),n.length===0?this.externalObservations.delete(s):(this.externalObservations.set(s,n),n[0].lastPublishedAt=Date.now(),this.emitExternalActivity(n[0],"queued")))}isSuppressed(e){const s=`${e.agentType}:${e.sourceSessionKey}`,n=this.suppressionWindows.get(s);return!n||e.ts<n.startedAt?!1:e.ts>n.endsAt?(this.suppressionWindows.delete(s),!1):e.role==="user"?(this.suppressionWindows.delete(s),!1):!0}}function U(u,e,s,n){if(!e.awaitingUserBoundary)return{events:u,cursor:{...e,offset:s,mtimeMs:n}};if(u.length===0)return{events:[],cursor:{...e,offset:s,mtimeMs:n,awaitingUserBoundary:!0}};const t=u.findIndex(r=>r.role==="user");return t<0?{events:[],cursor:{...e,mtimeMs:n,awaitingUserBoundary:!0}}:{events:u.slice(t),cursor:{...e,offset:s,mtimeMs:n,awaitingUserBoundary:!1}}}function z(u,e,s,n,t,r){const h={...e.sourceBoundaryEstablished??{}},i=e.eventWatermarkTs??-1,l=new Set(e.eventKeysAtWatermark??[]),v=n?u:u.filter(c=>c.ts>i||c.ts===i&&!l.has(c.sourceEventKey)),f=[];for(const c of v){const y=c.sourceSessionKey;if(h[y]){f.push(c);continue}!(!n||(c.sourceSessionCreatedAtMs??0)>=s)||c.role!=="user"||(h[y]=!0,f.push(c))}const d=u.reduce((c,y)=>Math.max(c,y.ts),i),a=new Set(d===i?e.eventKeysAtWatermark??[]:[]);for(const c of u)c.ts===d&&a.add(c.sourceEventKey);return{events:f,cursor:{...e,offset:r,mtimeMs:t,eventWatermarkTs:d>=0?d:void 0,eventKeysAtWatermark:d>=0?[...a]:void 0,sourceBoundaryEstablished:h}}}export{J as NativeSessionFusionService};
|
|
@@ -4,6 +4,10 @@ export type NativeSessionFileInspection = {
|
|
|
4
4
|
status: 'ready';
|
|
5
5
|
createdAtMs: number;
|
|
6
6
|
sourceCreatedAtByKey?: Record<string, number>;
|
|
7
|
+
sources: Array<{
|
|
8
|
+
agentType: 'codex' | 'claude' | 'opencode';
|
|
9
|
+
sourceSessionKey: string;
|
|
10
|
+
}>;
|
|
7
11
|
};
|
|
8
12
|
export declare function inspectNativeSessionFile(filePath: string): NativeSessionFileInspection;
|
|
9
13
|
export declare function normalizeNativeTimestamp(value: unknown): number | null;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`).slice(0,
|
|
1
|
+
import a from"node:fs";import{readTimestamp as d,safeParse as g}from"./parser-common.js";const S=1024*1024,b=64;function j(t){if(t.endsWith(".opencode-session.json"))return h(t);const s=A(t);if(s.length===0)return{status:"pending"};const e=a.statSync(t);if(t.split(/[\\/]+/).includes(".codex")){const n=s.find(y=>y.type==="session_meta");if(!n)return{status:"pending"};const c=p(n.payload),u=d(n.timestamp)??d(c?.timestamp)??f(e.birthtimeMs),m=typeof c?.id=="string"?c.id:"";return u&&m?{status:"ready",createdAtMs:u,sources:[{agentType:"codex",sourceSessionKey:m}]}:{status:"pending"}}const o=s.map(n=>d(n.timestamp)).find(n=>n!=null)??f(e.birthtimeMs),r=M(t);return o&&r?{status:"ready",createdAtMs:o,sources:[{agentType:"claude",sourceSessionKey:r}]}:{status:"pending"}}function h(t){let s;try{s=JSON.parse(a.readFileSync(t,"utf8"))}catch{return{status:"pending"}}const e=p(s);if(!e||!Array.isArray(e.sessions)||e.sessions.length===0)return{status:"pending"};const i={};for(const r of e.sessions){const n=p(r),c=typeof n?.id=="string"?n.id:"",u=l(n?.time_created);c&&u&&(i[c]=u)}const o=Object.values(i);return o.length===0?{status:"pending"}:{status:"ready",createdAtMs:Math.min(...o),sourceCreatedAtByKey:i,sources:Object.keys(i).map(r=>({agentType:"opencode",sourceSessionKey:r}))}}function M(t){const s=t.replace(/\\/g,"/"),e=s.slice(s.lastIndexOf("/")+1);return e.endsWith(".jsonl")?e.slice(0,-6):e}function A(t){const s=a.openSync(t,"r");try{const e=Math.min(a.fstatSync(s).size,S);if(e===0)return[];const i=Buffer.allocUnsafe(e),o=a.readSync(s,i,0,e,0);return i.subarray(0,o).toString("utf8").split(`
|
|
2
|
+
`).slice(0,b).map(r=>g(r)).filter(r=>r!=null)}finally{a.closeSync(s)}}function p(t){return typeof t=="object"&&t!==null?t:null}function f(t){return Number.isFinite(t)&&t>0?t:null}function R(t){return l(t)}function l(t){return typeof t!="number"||!Number.isFinite(t)||t<=0?null:t<1e10?Math.round(t*1e3):Math.round(t)}export{j as inspectNativeSessionFile,R as normalizeNativeTimestamp};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`,"utf8"),
|
|
1
|
+
import y from"node:crypto";import o from"node:fs";import m from"node:path";import{resolvePersonalSyncV1Path as p}from"../personal-sync/paths.js";import{getDaemonInstallationId as a}from"../session/store.js";import{NATIVE_SCANNER_STATE_SCHEMA_VERSION as f}from"./types.js";function l(){return p("native-fusion-state.json")}function I(){const n=l(),t=a();if(!o.existsSync(n)){const r={schemaVersion:f,fusionEpochMs:Date.now(),daemonInstallationId:t,files:{}};return u(n,r),r}let e;try{e=JSON.parse(o.readFileSync(n,"utf8"))}catch(r){throw new Error(`native fusion v1 state is unreadable: ${n}`,{cause:r})}return s(e,t),e}function N(n){const t=a();s(n,t);const e=l();if(o.existsSync(e)){const r=JSON.parse(o.readFileSync(e,"utf8"));if(s(r,t),r.fusionEpochMs!==n.fusionEpochMs)throw new Error("native fusion epoch is immutable")}u(e,n)}function s(n,t){if(!n||n.schemaVersion!==f||!Number.isSafeInteger(n.fusionEpochMs)||n.fusionEpochMs<=0||n.daemonInstallationId!==t||!n.files||typeof n.files!="object"||Array.isArray(n.files))throw new Error("invalid native fusion v1 state");for(const e of Object.values(n.files))if(e.daemonInstallationId!==t)throw new Error("native fusion cursor belongs to another daemon installation")}function u(n,t){const e=m.dirname(n);o.mkdirSync(e,{recursive:!0,mode:448});const r=`${n}.tmp-${process.pid}-${y.randomBytes(6).toString("hex")}`;let i;try{if(i=o.openSync(r,"wx",384),o.writeFileSync(i,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,"utf8"),o.fsyncSync(i),o.closeSync(i),i=void 0,o.renameSync(r,n),process.platform!=="win32"){const c=o.openSync(e,"r");try{o.fsyncSync(c)}finally{o.closeSync(c)}}}finally{i!==void 0&&o.closeSync(i);try{o.unlinkSync(r)}catch{}}}export{I as loadNativeScannerState,N as saveNativeScannerState};
|
|
@@ -2,6 +2,7 @@ import type { NativeSessionEventPayload, SessionTitleSource } from '@shennian/wi
|
|
|
2
2
|
export type NativeRepairHint = 'codex_app_context_wrapper';
|
|
3
3
|
export declare const NATIVE_SCANNER_STATE_SCHEMA_VERSION: 1;
|
|
4
4
|
export type NativeFileCursor = {
|
|
5
|
+
daemonInstallationId?: string;
|
|
5
6
|
offset: number;
|
|
6
7
|
mtimeMs: number;
|
|
7
8
|
fileIdentity?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{acknowledgeSessionIndexUpdate as
|
|
1
|
+
import{acknowledgeSessionIndexUpdate as r,listPendingSessionIndexUpdates as a}from"./store.js";const o=new WeakMap,t=new WeakSet;function c(s){const e=s,i=o.get(e);if(i)return t.add(e),i;const n=f(s).finally(()=>{o.get(e)===n&&o.delete(e),t.delete(e)&&u(s)});return o.set(e,n),n}async function f(s){const e=a(),i=[];for(const n of e)try{await s.sendBufferedEvent({type:"event",event:"session.index.updated",id:`session-index-${n.daemonInstallationId}-${n.session.id}-${n.session.indexRevision}`,payload:n},6e4),r(n.session.id,n.session.indexRevision)}catch(d){i.push(d)}if(i.length>0)throw new AggregateError(i,"one or more session indexes failed")}function u(s){c(s).catch(e=>{console.error("[session-index] sync failed; dirty revisions retained for retry",e)})}export{c as publishPendingSessionIndexes,u as requestSessionIndexPublish};
|
|
@@ -3,6 +3,7 @@ import { PERSONAL_SYNC_V1_ROOT_NAME } from '../personal-sync/paths.js';
|
|
|
3
3
|
import { CanonicalSessionStore } from './canonical-store.js';
|
|
4
4
|
export { PERSONAL_SYNC_V1_ROOT_NAME };
|
|
5
5
|
export type LocalSessionRecord = {
|
|
6
|
+
daemonInstallationId: string;
|
|
6
7
|
sessionId: string;
|
|
7
8
|
agentType: AgentType;
|
|
8
9
|
sessionMode?: SessionMode;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
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{
|
|
1
|
+
import S from"node:crypto";import l from"node:fs";import f from"node:path";import{SESSION_SYNC_PROTOCOL_VERSION as w,SESSION_TITLE_SOURCE_PRIORITY as y}from"@shennian/wire";import{PERSONAL_SYNC_V1_ROOT_NAME as M,resolvePersonalSyncV1Path as p}from"../personal-sync/paths.js";import{CanonicalSessionStore as k}from"./canonical-store.js";let m=null,I=null;function v(){return p()}function r(){const t=f.join(v(),"canonical");return(!m||I!==t)&&(m=new k(t,d()),I=t),m}function R(){return f.join(v(),"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}`);const i=d();for(const n of Object.values(e))if(n.daemonInstallationId!==i)throw new Error(`personal session index belongs to another daemon installation: ${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 d(){const t=f.join(v(),"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:S.randomUUID(),createdAt:new Date().toISOString()};return b(t,e),e.daemonInstallationId}function U(t){d();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),c={daemonInstallationId: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]=c,g(e),c}function C(){return Object.values(u())}function V(){const t=d();return C().filter(e=>e.indexRevision>e.syncedIndexRevision).sort((e,i)=>e.indexRevision-i.indexRevision).map(e=>({protocolVersion:w,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){d();const n=r().append(t,e,i);return A(t,e,n.bodyRevision),n.bodyRevision}function N(t,e,i){d();const n=r().upsert(t,e,i);return A(t,e,n.bodyRevision),n.bodyRevision}function $(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 q(t,e){d();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),c=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,...c??{},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 c=y[e.titleSource],x=y[i.titleSource];return c<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}-${S.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{M as PERSONAL_SYNC_V1_ROOT_NAME,L as acknowledgeSessionIndexUpdate,W as appendMessage,J as getCanonicalSessionStore,d as getDaemonInstallationId,$ as getMessageDeliveryStatus,V as listPendingSessionIndexUpdates,C as listSessionRecords,F as listSessions,j as readMessages,U as recordSession,q as tombstoneMessage,N as upsertMessage};
|