shennian 0.3.41 → 0.3.43
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 +93 -43
- package/dist/src/agents/adapter.d.ts +1 -0
- package/dist/src/commands/daemon.d.ts +6 -0
- package/dist/src/commands/daemon.js +9 -9
- package/dist/src/index.js +3 -3
- package/dist/src/native-fusion/codex-parser.d.ts +1 -0
- package/dist/src/native-fusion/codex-parser.js +4 -4
- package/dist/src/native-fusion/file-watcher.d.ts +18 -0
- package/dist/src/native-fusion/file-watcher.js +1 -0
- package/dist/src/native-fusion/local-repository.d.ts +52 -0
- package/dist/src/native-fusion/local-repository.js +2 -0
- package/dist/src/native-fusion/opencode-parser.js +2 -2
- package/dist/src/native-fusion/parser-common.d.ts +7 -1
- package/dist/src/native-fusion/parser-common.js +4 -4
- package/dist/src/native-fusion/parsers.d.ts +2 -1
- package/dist/src/native-fusion/parsers.js +2 -2
- package/dist/src/native-fusion/service.d.ts +10 -2
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/session-header.d.ts +9 -0
- package/dist/src/native-fusion/session-header.js +2 -0
- package/dist/src/native-fusion/state.d.ts +1 -1
- package/dist/src/native-fusion/state.js +2 -1
- package/dist/src/native-fusion/types.d.ts +29 -5
- package/dist/src/native-fusion/types.js +1 -1
- package/dist/src/personal-sync/paths.d.ts +2 -0
- package/dist/src/personal-sync/paths.js +1 -0
- package/dist/src/relay/client.d.ts +4 -1
- package/dist/src/relay/client.js +1 -1
- package/dist/src/session/attachment-reference.d.ts +2 -0
- package/dist/src/session/attachment-reference.js +1 -0
- package/dist/src/session/attachment-transfer-store.d.ts +38 -0
- package/dist/src/session/attachment-transfer-store.js +2 -0
- package/dist/src/session/canonical-store.d.ts +101 -0
- package/dist/src/session/canonical-store.js +5 -0
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/fs.d.ts +0 -1
- package/dist/src/session/handlers/fs.js +1 -1
- package/dist/src/session/handlers/message-status.d.ts +3 -0
- package/dist/src/session/handlers/message-status.js +1 -0
- package/dist/src/session/handlers/title.js +1 -1
- package/dist/src/session/handlers/tool-detail.js +1 -1
- package/dist/src/session/handlers/voice-window.d.ts +3 -0
- package/dist/src/session/handlers/voice-window.js +1 -0
- package/dist/src/session/history-subscriptions.d.ts +17 -0
- package/dist/src/session/history-subscriptions.js +1 -0
- package/dist/src/session/index-publisher.d.ts +3 -0
- package/dist/src/session/index-publisher.js +1 -0
- package/dist/src/session/manager.d.ts +2 -0
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/queue.d.ts +1 -1
- package/dist/src/session/queue.js +4 -3
- package/dist/src/session/store.d.ts +33 -3
- package/dist/src/session/store.js +2 -3
- package/dist/src/session/tool-detail-store.d.ts +16 -0
- package/dist/src/session/tool-detail-store.js +2 -0
- package/dist/src/session/types.d.ts +3 -13
- package/node_modules/@shennian/wire/dist/events.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/fs.d.ts +45 -0
- package/node_modules/@shennian/wire/dist/fs.js +7 -1
- package/node_modules/@shennian/wire/dist/index.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/index.js +1 -0
- package/node_modules/@shennian/wire/dist/machine.d.ts +6 -0
- package/node_modules/@shennian/wire/dist/message-payload.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/message-payload.js +15 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/session-sync.d.ts +197 -0
- package/node_modules/@shennian/wire/dist/session-sync.js +49 -0
- package/node_modules/@shennian/wire/dist/session.d.ts +24 -13
- package/node_modules/@shennian/wire/dist/tool-detail.d.ts +18 -11
- package/node_modules/@shennian/wire/dist/tool-detail.js +7 -1
- package/package.json +1 -1
- package/dist/src/session/remote-attachments.d.ts +0 -15
- package/dist/src/session/remote-attachments.js +0 -1
- package/dist/src/session/tool-summary.d.ts +0 -1
- package/dist/src/session/tool-summary.js +0 -1
|
@@ -25,9 +25,54 @@ export type FsChunk = {
|
|
|
25
25
|
export type FsTransferManifestEntry = {
|
|
26
26
|
relativePath: string;
|
|
27
27
|
size: number;
|
|
28
|
+
sha256: string;
|
|
28
29
|
mimeType?: string;
|
|
29
30
|
modifiedAt?: number;
|
|
30
31
|
};
|
|
32
|
+
export type FsTransferStartParams = {
|
|
33
|
+
transferId: string;
|
|
34
|
+
rootPath: string;
|
|
35
|
+
name: string;
|
|
36
|
+
totalSize: number;
|
|
37
|
+
sha256: string;
|
|
38
|
+
mimeType: string;
|
|
39
|
+
kind: 'file' | 'folder';
|
|
40
|
+
manifest?: FsTransferManifestEntry[];
|
|
41
|
+
};
|
|
42
|
+
export type FsTransferStartResult = {
|
|
43
|
+
transferId: string;
|
|
44
|
+
path: string;
|
|
45
|
+
reused: boolean;
|
|
46
|
+
offsets: Record<string, number>;
|
|
47
|
+
attachment?: FsTransferFinishResult;
|
|
48
|
+
};
|
|
49
|
+
export type FsTransferChunkParams = {
|
|
50
|
+
transferId: string;
|
|
51
|
+
rootPath: string;
|
|
52
|
+
offset: number;
|
|
53
|
+
data: string;
|
|
54
|
+
relativePath?: string;
|
|
55
|
+
};
|
|
56
|
+
export type FsTransferFinishParams = {
|
|
57
|
+
transferId: string;
|
|
58
|
+
rootPath: string;
|
|
59
|
+
};
|
|
60
|
+
export type FsTransferFinishResult = {
|
|
61
|
+
transferId: string;
|
|
62
|
+
path: string;
|
|
63
|
+
name: string;
|
|
64
|
+
mimeType: string;
|
|
65
|
+
kind: 'file' | 'folder';
|
|
66
|
+
byteSize: number;
|
|
67
|
+
sha256: string;
|
|
68
|
+
reused: boolean;
|
|
69
|
+
};
|
|
70
|
+
export type FsTransferAbortParams = {
|
|
71
|
+
transferId: string;
|
|
72
|
+
rootPath: string;
|
|
73
|
+
};
|
|
74
|
+
/** Stable input for the aggregate hash of a folder transfer. */
|
|
75
|
+
export declare function serializeFsTransferManifest(entries: readonly FsTransferManifestEntry[]): string;
|
|
31
76
|
export type FsRenameResult = {
|
|
32
77
|
oldPath: string;
|
|
33
78
|
newPath: string;
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** Stable input for the aggregate hash of a folder transfer. */
|
|
2
|
+
export function serializeFsTransferManifest(entries) {
|
|
3
|
+
return [...entries]
|
|
4
|
+
.sort((left, right) => left.relativePath.localeCompare(right.relativePath))
|
|
5
|
+
.map((entry) => `${entry.relativePath}\0${entry.size}\0${entry.sha256.toLowerCase()}`)
|
|
6
|
+
.join('\n');
|
|
7
|
+
}
|
|
@@ -5,6 +5,7 @@ export * from './methods.ts';
|
|
|
5
5
|
export * from './frames.ts';
|
|
6
6
|
export * from './fs.ts';
|
|
7
7
|
export * from './session.ts';
|
|
8
|
+
export * from './session-sync.ts';
|
|
8
9
|
export * from './message-payload.ts';
|
|
9
10
|
export * from './external-message-format.ts';
|
|
10
11
|
export * from './native-session.ts';
|
|
@@ -5,6 +5,7 @@ export * from "./methods.js";
|
|
|
5
5
|
export * from "./frames.js";
|
|
6
6
|
export * from "./fs.js";
|
|
7
7
|
export * from "./session.js";
|
|
8
|
+
export * from "./session-sync.js";
|
|
8
9
|
export * from "./message-payload.js";
|
|
9
10
|
export * from "./external-message-format.js";
|
|
10
11
|
export * from "./native-session.js";
|
|
@@ -14,6 +14,12 @@ export type Machine = {
|
|
|
14
14
|
region?: string;
|
|
15
15
|
/** CLI version currently running on this machine */
|
|
16
16
|
cliVersion?: string;
|
|
17
|
+
/** Stable identity of the daemon data root. It is not the mobile installationId. */
|
|
18
|
+
daemonInstallationId?: string;
|
|
19
|
+
/** Personal Session sync protocol understood by this daemon. */
|
|
20
|
+
sessionSyncProtocolVersion?: import('./session-sync.ts').SessionSyncProtocolVersion;
|
|
21
|
+
/** Full capability set required by the hard-cutover personal Session protocol. */
|
|
22
|
+
sessionSyncCapabilities?: import('./session-sync.ts').SessionSyncCapability[];
|
|
17
23
|
/** Auto-upgrade policy configured on this machine */
|
|
18
24
|
autoUpgrade?: AutoUpgradePolicy;
|
|
19
25
|
/** Ownership role — absent means owner (backward-compatible) */
|
|
@@ -52,7 +52,21 @@ function parseAttachmentMeta(value) {
|
|
|
52
52
|
if (!path || !name || !mimeType || !kind)
|
|
53
53
|
return null;
|
|
54
54
|
const previewData = typeof entry.previewData === 'string' && entry.previewData.trim() ? entry.previewData.trim() : undefined;
|
|
55
|
-
|
|
55
|
+
const byteSize = typeof entry.byteSize === 'number' && Number.isSafeInteger(entry.byteSize) && entry.byteSize >= 0
|
|
56
|
+
? entry.byteSize
|
|
57
|
+
: undefined;
|
|
58
|
+
const sha256 = typeof entry.sha256 === 'string' && /^[a-f0-9]{64}$/i.test(entry.sha256)
|
|
59
|
+
? entry.sha256.toLowerCase()
|
|
60
|
+
: undefined;
|
|
61
|
+
return {
|
|
62
|
+
path,
|
|
63
|
+
name,
|
|
64
|
+
mimeType,
|
|
65
|
+
kind,
|
|
66
|
+
...(byteSize !== undefined ? { byteSize } : {}),
|
|
67
|
+
...(sha256 ? { sha256 } : {}),
|
|
68
|
+
...(previewData ? { previewData } : {}),
|
|
69
|
+
};
|
|
56
70
|
}
|
|
57
71
|
export function parseStructuredMessagePayload(payload) {
|
|
58
72
|
const parsed = parseObjectPayload(payload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type ReqMethod = 'chat.send' | 'chat.enqueue' | 'chat.queue.get' | 'chat.queue.edit' | 'chat.queue.delete' | 'chat.abort' | 'session.resume' | 'session.history' | 'session.refresh' | 'session.tool.detail' | 'session.title.set' | 'fs.ls' | 'fs.read' | 'fs.write' | 'fs.export.markdown-pdf' | 'fs.export.markdown-pdf.setup' | 'fs.archive.zip' | 'fs.transfer
|
|
1
|
+
export type ReqMethod = 'chat.send' | 'chat.enqueue' | 'chat.queue.get' | 'chat.queue.edit' | 'chat.queue.delete' | 'chat.abort' | 'session.resume' | 'session.history' | 'session.history.open' | 'session.history.page' | 'session.history.close' | 'session.index.update' | 'session.message.status' | 'voice.session.body.window' | 'session.refresh' | 'session.tool.detail' | 'session.title.set' | 'fs.ls' | 'fs.read' | 'fs.write' | 'fs.export.markdown-pdf' | 'fs.export.markdown-pdf.setup' | 'fs.archive.zip' | 'fs.transfer.start' | 'fs.transfer.chunk' | 'fs.transfer.finish' | 'fs.transfer.abort' | 'fs.rename' | 'skill.list' | 'skill.install' | 'skill.doctor' | 'skill.setup' | 'skill.use' | 'region.probe' | 'region.switch' | 'upgrade.start' | 'upgrade.status' | 'upgrade.set-policy' | 'agents.refresh' | 'models.refresh' | 'agent.config.get' | 'agent.config.upsert' | 'agent.config.clear' | 'agent.config.test' | 'agent.capabilities.list' | 'manager.channel.get' | 'manager.channel.upsert' | 'session.wechat-rpa.channel.get' | 'session.wechat-rpa.channel.upsert' | 'session.wechat-rpa.channel.sync' | 'session.wechat-rpa.outbound.cancel' | 'manager.wechat-rpa.channel.get' | 'manager.wechat-rpa.channel.upsert' | 'manager.wechat-rpa.channel.sync' | 'manager.wechat-rpa.outbound.cancel' | 'wechat-rpa.helper.runtime' | 'wecom.send' | 'external.send' | 'room.sync' | 'room.send' | 'room.bind' | 'room.agent.bind-managed' | 'room.agent.restart-managed' | 'room.unbind';
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { Envelope } from './envelope.ts';
|
|
2
|
+
import type { AgentType, ManagerConfig, SessionMode } from './session.ts';
|
|
3
|
+
export declare const SESSION_SYNC_PROTOCOL_VERSION: 1;
|
|
4
|
+
export type SessionSyncProtocolVersion = typeof SESSION_SYNC_PROTOCOL_VERSION;
|
|
5
|
+
export declare const SESSION_SYNC_RELEASE_GATE: {
|
|
6
|
+
readonly minCliVersion: "0.3.42";
|
|
7
|
+
readonly minAppBuild: {
|
|
8
|
+
readonly ios: 51;
|
|
9
|
+
readonly android: 12;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare const SESSION_SYNC_REQUIRED_CAPABILITIES: readonly ["session_index_v1", "session_body_revision_v1", "session_history_subscription_v1", "local_canonical_v1", "session_title_authority_v1", "session_tool_detail_v1", "voice_session_body_relay_v1", "native_source_tombstone_v1", "session_durable_send_v1", "daemon_installation_identity_v1"];
|
|
13
|
+
export declare const SESSION_SYNC_EVENT_NAMES: readonly ["session.index.updated", "session.body.delta"];
|
|
14
|
+
export declare const SESSION_HISTORY_LIMITS: {
|
|
15
|
+
readonly defaultSnapshotMessages: 100;
|
|
16
|
+
readonly maxSnapshotMessages: 500;
|
|
17
|
+
readonly defaultPageMessages: 100;
|
|
18
|
+
readonly maxPageMessages: 500;
|
|
19
|
+
readonly maxDeltaMutations: 200;
|
|
20
|
+
readonly maxMutationBytes: number;
|
|
21
|
+
readonly maxSubscriptionsPerClient: 4;
|
|
22
|
+
readonly maxSubscriptionsPerSession: 8;
|
|
23
|
+
};
|
|
24
|
+
export type SessionSyncCapability = (typeof SESSION_SYNC_REQUIRED_CAPABILITIES)[number];
|
|
25
|
+
export type SessionSyncEventName = (typeof SESSION_SYNC_EVENT_NAMES)[number];
|
|
26
|
+
export type SessionBodyStorageMode = 'machine_local';
|
|
27
|
+
export type SessionTitleSource = 'shennian_manual' | 'agent_native' | 'shennian_generated' | 'first_user_fallback';
|
|
28
|
+
export declare const SESSION_TITLE_SOURCE_PRIORITY: Readonly<Record<SessionTitleSource, number>>;
|
|
29
|
+
export declare function isSessionTitleSource(value: unknown): value is SessionTitleSource;
|
|
30
|
+
export type SessionTitleSetParams = {
|
|
31
|
+
sessionId: string;
|
|
32
|
+
agentType: AgentType;
|
|
33
|
+
agentSessionId: string | null;
|
|
34
|
+
workDir: string;
|
|
35
|
+
title: string;
|
|
36
|
+
titleSource: 'shennian_manual';
|
|
37
|
+
titleRevision: number;
|
|
38
|
+
titleOriginEventId: string;
|
|
39
|
+
};
|
|
40
|
+
export type SessionSyncErrorCode = 'upgrade_required' | 'revision_gap' | 'snapshot_compacted' | 'machine_offline' | 'history_unavailable' | 'subscription_not_found' | 'subscription_limit_exceeded' | 'response_too_large';
|
|
41
|
+
export type SessionSyncError = {
|
|
42
|
+
code: SessionSyncErrorCode;
|
|
43
|
+
message?: string;
|
|
44
|
+
requiredProtocolVersion?: SessionSyncProtocolVersion;
|
|
45
|
+
requiredCapabilities?: SessionSyncCapability[];
|
|
46
|
+
expectedRevision?: number;
|
|
47
|
+
actualRevision?: number;
|
|
48
|
+
retryable: boolean;
|
|
49
|
+
};
|
|
50
|
+
export type PersonalAttachmentReference = {
|
|
51
|
+
path: string;
|
|
52
|
+
name: string;
|
|
53
|
+
mimeType: string;
|
|
54
|
+
kind: 'file' | 'image' | 'folder';
|
|
55
|
+
byteSize: number;
|
|
56
|
+
sha256: string;
|
|
57
|
+
};
|
|
58
|
+
export type SessionDeliveryState = 'queued' | 'committed' | 'executing' | 'completed' | 'failed' | 'cancelled';
|
|
59
|
+
export type SessionDurableSendAck<TState extends SessionDeliveryState = SessionDeliveryState> = {
|
|
60
|
+
sessionId: string;
|
|
61
|
+
clientMessageId: string;
|
|
62
|
+
messageId: string;
|
|
63
|
+
deliveryState: TState;
|
|
64
|
+
bodyRevision: number;
|
|
65
|
+
committedAt: string;
|
|
66
|
+
};
|
|
67
|
+
export type SessionMessageStatusParams = {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
clientMessageId: string;
|
|
70
|
+
};
|
|
71
|
+
export type SessionMessageStatusResponse = {
|
|
72
|
+
state: 'not_found';
|
|
73
|
+
sessionId: string;
|
|
74
|
+
clientMessageId: string;
|
|
75
|
+
} | {
|
|
76
|
+
[TState in SessionDeliveryState]: {
|
|
77
|
+
state: TState;
|
|
78
|
+
} & SessionDurableSendAck<TState>;
|
|
79
|
+
}[SessionDeliveryState];
|
|
80
|
+
export declare function getMissingSessionSyncCapabilities(capabilities: readonly string[] | null | undefined): SessionSyncCapability[];
|
|
81
|
+
export declare function hasRequiredSessionSyncCapabilities(capabilities: readonly string[] | null | undefined): capabilities is readonly SessionSyncCapability[];
|
|
82
|
+
export type SessionHistoryOpenParams = {
|
|
83
|
+
sessionId: string;
|
|
84
|
+
subscriptionId: string;
|
|
85
|
+
cachedBodyRevision?: number;
|
|
86
|
+
limit?: number;
|
|
87
|
+
beforeSequence?: number;
|
|
88
|
+
};
|
|
89
|
+
export type SessionHistoryMessage = {
|
|
90
|
+
sequence: number;
|
|
91
|
+
revision: number;
|
|
92
|
+
message: Envelope;
|
|
93
|
+
};
|
|
94
|
+
export type SessionHistorySnapshot = {
|
|
95
|
+
sessionId: string;
|
|
96
|
+
subscriptionId: string;
|
|
97
|
+
storageMode: SessionBodyStorageMode;
|
|
98
|
+
snapshotRevision: number;
|
|
99
|
+
firstAvailableSeq: number | null;
|
|
100
|
+
lastAvailableSeq: number | null;
|
|
101
|
+
hasOlder: boolean;
|
|
102
|
+
messages: SessionHistoryMessage[];
|
|
103
|
+
};
|
|
104
|
+
export type SessionHistoryPageParams = {
|
|
105
|
+
sessionId: string;
|
|
106
|
+
subscriptionId: string;
|
|
107
|
+
beforeSequence: number;
|
|
108
|
+
limit?: number;
|
|
109
|
+
};
|
|
110
|
+
export type SessionHistoryPage = {
|
|
111
|
+
sessionId: string;
|
|
112
|
+
subscriptionId: string;
|
|
113
|
+
snapshotRevision: number;
|
|
114
|
+
firstAvailableSeq: number | null;
|
|
115
|
+
hasOlder: boolean;
|
|
116
|
+
messages: SessionHistoryMessage[];
|
|
117
|
+
};
|
|
118
|
+
export type VoiceSessionBodyWindowParams = {
|
|
119
|
+
sessionId: string;
|
|
120
|
+
callId: string;
|
|
121
|
+
bodyRevision?: number;
|
|
122
|
+
limit?: number;
|
|
123
|
+
maxBytes?: number;
|
|
124
|
+
};
|
|
125
|
+
export type VoiceSessionBodyWindow = {
|
|
126
|
+
sessionId: string;
|
|
127
|
+
callId: string;
|
|
128
|
+
bodyRevision: number;
|
|
129
|
+
messages: Envelope[];
|
|
130
|
+
truncated: boolean;
|
|
131
|
+
};
|
|
132
|
+
export type SessionHistoryCloseParams = {
|
|
133
|
+
sessionId: string;
|
|
134
|
+
subscriptionId: string;
|
|
135
|
+
};
|
|
136
|
+
export type SessionHistoryCloseResponse = {
|
|
137
|
+
sessionId: string;
|
|
138
|
+
subscriptionId: string;
|
|
139
|
+
closed: true;
|
|
140
|
+
};
|
|
141
|
+
export type SessionBodyMutation = {
|
|
142
|
+
sessionId: string;
|
|
143
|
+
subscriptionId: string;
|
|
144
|
+
revision: number;
|
|
145
|
+
mutation: 'append' | 'upsert' | 'tombstone';
|
|
146
|
+
messageId: string;
|
|
147
|
+
sequence: number;
|
|
148
|
+
message?: Envelope;
|
|
149
|
+
deliveryState?: SessionDeliveryState;
|
|
150
|
+
};
|
|
151
|
+
export type SessionBodyDeltaEvent = {
|
|
152
|
+
sessionId: string;
|
|
153
|
+
subscriptionId: string;
|
|
154
|
+
fromRevision: number;
|
|
155
|
+
toRevision: number;
|
|
156
|
+
mutations: SessionBodyMutation[];
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Machine-authored personal-session projection. Ownership, machine display
|
|
160
|
+
* fields and viewer permissions are server authority and therefore never
|
|
161
|
+
* accepted from a daemon payload.
|
|
162
|
+
*/
|
|
163
|
+
export type DaemonSessionIndexProjection = {
|
|
164
|
+
id: string;
|
|
165
|
+
agentType: AgentType;
|
|
166
|
+
sessionMode?: SessionMode;
|
|
167
|
+
managerConfig?: ManagerConfig | null;
|
|
168
|
+
agentSessionId: string | null;
|
|
169
|
+
modelId: string | null;
|
|
170
|
+
managerDefaultWorkerAgentType?: AgentType | null;
|
|
171
|
+
managerDefaultWorkerModelId?: string | null;
|
|
172
|
+
title: string;
|
|
173
|
+
titleSource: SessionTitleSource;
|
|
174
|
+
titleRevision: number;
|
|
175
|
+
titleLockedByUser: boolean;
|
|
176
|
+
titleOriginEventId: string | null;
|
|
177
|
+
status: 'active' | 'completed' | 'failed';
|
|
178
|
+
workDir: string;
|
|
179
|
+
lastMessagePreview: string | null;
|
|
180
|
+
bodyStorageMode: SessionBodyStorageMode;
|
|
181
|
+
bodyRevision: number;
|
|
182
|
+
indexRevision: number;
|
|
183
|
+
firstAvailableSeq: number | null;
|
|
184
|
+
visibleMessageCount: number;
|
|
185
|
+
lastVisibleMessageId: string | null;
|
|
186
|
+
lastBodyCommittedAt: string | null;
|
|
187
|
+
deletionRevision: number;
|
|
188
|
+
lastActivityAt: string;
|
|
189
|
+
createdAt: string;
|
|
190
|
+
updatedAt: string;
|
|
191
|
+
deletedAt: string | null;
|
|
192
|
+
};
|
|
193
|
+
export type SessionIndexUpdate = {
|
|
194
|
+
protocolVersion: SessionSyncProtocolVersion;
|
|
195
|
+
daemonInstallationId: string;
|
|
196
|
+
session: DaemonSessionIndexProjection;
|
|
197
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @arch docs/architecture/data-sync.md#目标架构-v3
|
|
2
|
+
// @test src/__tests__/session-sync.test.ts
|
|
3
|
+
export const SESSION_SYNC_PROTOCOL_VERSION = 1;
|
|
4
|
+
export const SESSION_SYNC_RELEASE_GATE = {
|
|
5
|
+
minCliVersion: '0.3.42',
|
|
6
|
+
minAppBuild: { ios: 51, android: 12 },
|
|
7
|
+
};
|
|
8
|
+
export const SESSION_SYNC_REQUIRED_CAPABILITIES = [
|
|
9
|
+
'session_index_v1',
|
|
10
|
+
'session_body_revision_v1',
|
|
11
|
+
'session_history_subscription_v1',
|
|
12
|
+
'local_canonical_v1',
|
|
13
|
+
'session_title_authority_v1',
|
|
14
|
+
'session_tool_detail_v1',
|
|
15
|
+
'voice_session_body_relay_v1',
|
|
16
|
+
'native_source_tombstone_v1',
|
|
17
|
+
'session_durable_send_v1',
|
|
18
|
+
'daemon_installation_identity_v1',
|
|
19
|
+
];
|
|
20
|
+
export const SESSION_SYNC_EVENT_NAMES = [
|
|
21
|
+
'session.index.updated',
|
|
22
|
+
'session.body.delta',
|
|
23
|
+
];
|
|
24
|
+
export const SESSION_HISTORY_LIMITS = {
|
|
25
|
+
defaultSnapshotMessages: 100,
|
|
26
|
+
maxSnapshotMessages: 500,
|
|
27
|
+
defaultPageMessages: 100,
|
|
28
|
+
maxPageMessages: 500,
|
|
29
|
+
maxDeltaMutations: 200,
|
|
30
|
+
maxMutationBytes: 256 * 1024,
|
|
31
|
+
maxSubscriptionsPerClient: 4,
|
|
32
|
+
maxSubscriptionsPerSession: 8,
|
|
33
|
+
};
|
|
34
|
+
export const SESSION_TITLE_SOURCE_PRIORITY = {
|
|
35
|
+
first_user_fallback: 0,
|
|
36
|
+
shennian_generated: 1,
|
|
37
|
+
agent_native: 2,
|
|
38
|
+
shennian_manual: 3,
|
|
39
|
+
};
|
|
40
|
+
export function isSessionTitleSource(value) {
|
|
41
|
+
return typeof value === 'string' && value in SESSION_TITLE_SOURCE_PRIORITY;
|
|
42
|
+
}
|
|
43
|
+
export function getMissingSessionSyncCapabilities(capabilities) {
|
|
44
|
+
const available = new Set(capabilities ?? []);
|
|
45
|
+
return SESSION_SYNC_REQUIRED_CAPABILITIES.filter((capability) => !available.has(capability));
|
|
46
|
+
}
|
|
47
|
+
export function hasRequiredSessionSyncCapabilities(capabilities) {
|
|
48
|
+
return getMissingSessionSyncCapabilities(capabilities).length === 0;
|
|
49
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { NativeSessionSourceMode } from './native-session.js';
|
|
2
|
+
import type { PersonalAttachmentReference, SessionBodyStorageMode, SessionTitleSource } from './session-sync.js';
|
|
2
3
|
export type BuiltinAgentType = 'claude' | 'codex' | 'workbuddy' | 'gemini' | 'cursor' | 'openclaw' | 'opencode' | 'pi' | 'manager';
|
|
3
4
|
export type CustomAgentType = `custom:${string}`;
|
|
4
5
|
export type AgentType = BuiltinAgentType | CustomAgentType;
|
|
@@ -70,6 +71,10 @@ export type SessionUserState = {
|
|
|
70
71
|
sessionId: string;
|
|
71
72
|
pinnedAt?: string | null;
|
|
72
73
|
lastReadAt?: string | null;
|
|
74
|
+
/** Index watermark captured atomically when the user marks this session read. */
|
|
75
|
+
lastReadBodyRevision?: number;
|
|
76
|
+
lastReadVisibleMessageCount?: number;
|
|
77
|
+
lastReadVisibleMessageId?: string | null;
|
|
73
78
|
manualUnread?: boolean;
|
|
74
79
|
updatedAt: string;
|
|
75
80
|
};
|
|
@@ -184,9 +189,21 @@ export type NianSession = {
|
|
|
184
189
|
managerDefaultWorkerAgentType?: AgentType | null;
|
|
185
190
|
managerDefaultWorkerModelId?: string | null;
|
|
186
191
|
title: string;
|
|
192
|
+
titleSource?: SessionTitleSource;
|
|
193
|
+
titleRevision?: number;
|
|
194
|
+
titleLockedByUser?: boolean;
|
|
195
|
+
titleOriginEventId?: string | null;
|
|
187
196
|
status: 'active' | 'completed' | 'failed';
|
|
188
197
|
workDir: string;
|
|
189
198
|
lastMessagePreview?: string | null;
|
|
199
|
+
bodyStorageMode?: SessionBodyStorageMode;
|
|
200
|
+
bodyRevision?: number;
|
|
201
|
+
indexRevision?: number;
|
|
202
|
+
firstAvailableSeq?: number | null;
|
|
203
|
+
visibleMessageCount?: number;
|
|
204
|
+
lastVisibleMessageId?: string | null;
|
|
205
|
+
lastBodyCommittedAt?: string | null;
|
|
206
|
+
deletionRevision?: number;
|
|
190
207
|
lastActivityAt: string;
|
|
191
208
|
createdAt: string;
|
|
192
209
|
updatedAt: string;
|
|
@@ -201,7 +218,7 @@ export type NianSession = {
|
|
|
201
218
|
activity?: SessionActivitySnapshot | null;
|
|
202
219
|
externalChannel?: ExternalChannelSessionStatus | null;
|
|
203
220
|
};
|
|
204
|
-
export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'status' | 'workDir' | 'lastMessagePreview' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
|
|
221
|
+
export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'titleSource' | 'titleRevision' | 'titleLockedByUser' | 'titleOriginEventId' | 'status' | 'workDir' | 'lastMessagePreview' | 'bodyStorageMode' | 'bodyRevision' | 'indexRevision' | 'firstAvailableSeq' | 'visibleMessageCount' | 'lastVisibleMessageId' | 'lastBodyCommittedAt' | 'deletionRevision' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
|
|
205
222
|
export type ChatSendParams = {
|
|
206
223
|
sessionId: string;
|
|
207
224
|
text: string;
|
|
@@ -217,10 +234,8 @@ export type ChatSendParams = {
|
|
|
217
234
|
reasoningEffort?: string | null;
|
|
218
235
|
clientMessageId?: string;
|
|
219
236
|
sessionListProjection?: SessionListProjection[];
|
|
220
|
-
attachments?: Array<{
|
|
221
|
-
|
|
222
|
-
name: string;
|
|
223
|
-
mimeType: string;
|
|
237
|
+
attachments?: Array<PersonalAttachmentReference & {
|
|
238
|
+
/** @deprecated Removed by the hard-cutover attachment migration. */
|
|
224
239
|
previewData?: string;
|
|
225
240
|
}>;
|
|
226
241
|
externalChannel?: ExternalChannelSessionStatus | null;
|
|
@@ -241,10 +256,8 @@ export type QueuedChatMessage = {
|
|
|
241
256
|
managerDefaultWorkerModelId?: string | null;
|
|
242
257
|
reasoningEffort?: string | null;
|
|
243
258
|
clientMessageId?: string | null;
|
|
244
|
-
attachments?: Array<{
|
|
245
|
-
|
|
246
|
-
name: string;
|
|
247
|
-
mimeType: string;
|
|
259
|
+
attachments?: Array<PersonalAttachmentReference & {
|
|
260
|
+
/** @deprecated Removed by the hard-cutover attachment migration. */
|
|
248
261
|
previewData?: string;
|
|
249
262
|
}>;
|
|
250
263
|
externalChannel?: ExternalChannelSessionStatus | null;
|
|
@@ -268,10 +281,8 @@ export type ChatQueueEditParams = {
|
|
|
268
281
|
sessionId: string;
|
|
269
282
|
queueMessageId: string;
|
|
270
283
|
text: string;
|
|
271
|
-
attachments?: Array<{
|
|
272
|
-
|
|
273
|
-
name: string;
|
|
274
|
-
mimeType: string;
|
|
284
|
+
attachments?: Array<PersonalAttachmentReference & {
|
|
285
|
+
/** @deprecated Removed by the hard-cutover attachment migration. */
|
|
275
286
|
previewData?: string;
|
|
276
287
|
}>;
|
|
277
288
|
};
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
export declare const SESSION_TOOL_DETAIL_LIMITS: {
|
|
2
|
+
readonly defaultMaxBytes: number;
|
|
3
|
+
readonly minMaxBytes: number;
|
|
4
|
+
readonly maxMaxBytes: number;
|
|
5
|
+
readonly responseTtlMs: number;
|
|
6
|
+
readonly relayTimeoutMs: number;
|
|
7
|
+
};
|
|
1
8
|
export type ToolDetailStatus = 'available' | 'not_found' | 'unsupported' | 'unavailable';
|
|
9
|
+
export type ToolDetailUnavailableReason = 'not_found' | 'revision_mismatch' | 'machine_offline' | 'request_timeout' | 'response_too_large' | 'unsupported';
|
|
2
10
|
export type ToolDetailSource = 'local-session-store' | 'local-tool-index' | 'native-local-index' | 'unavailable';
|
|
3
11
|
export type ToolDetailRef = {
|
|
4
12
|
runId?: string;
|
|
@@ -7,24 +15,23 @@ export type ToolDetailRef = {
|
|
|
7
15
|
};
|
|
8
16
|
export type SessionToolDetailRequest = {
|
|
9
17
|
sessionId: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
runId?: string;
|
|
14
|
-
sourceSeq?: number;
|
|
15
|
-
detailRef?: ToolDetailRef | string | null;
|
|
16
|
-
maxChars?: number;
|
|
18
|
+
toolCallId: string;
|
|
19
|
+
detailRevision: number;
|
|
20
|
+
maxBytes?: number;
|
|
17
21
|
};
|
|
18
22
|
export type SessionToolDetailResponse = {
|
|
23
|
+
sessionId: string;
|
|
24
|
+
toolCallId: string;
|
|
25
|
+
detailRevision: number;
|
|
19
26
|
detailStatus: ToolDetailStatus;
|
|
20
|
-
messageId?: string;
|
|
21
|
-
toolIndex?: number;
|
|
22
|
-
name?: string;
|
|
23
27
|
status?: 'running' | 'completed' | 'failed';
|
|
24
28
|
command?: string;
|
|
25
29
|
argsSummary?: unknown;
|
|
26
30
|
result?: string;
|
|
27
31
|
resultOmitted: boolean;
|
|
32
|
+
redacted: boolean;
|
|
33
|
+
byteSize: number;
|
|
34
|
+
expiresAt: string;
|
|
28
35
|
source: ToolDetailSource;
|
|
29
|
-
reason?:
|
|
36
|
+
reason?: ToolDetailUnavailableReason;
|
|
30
37
|
};
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
// @arch docs/architecture/data-retention-and-sync-policy.md#tool-结果
|
|
2
2
|
// @test src/__tests__/types.test.ts
|
|
3
|
-
export {
|
|
3
|
+
export const SESSION_TOOL_DETAIL_LIMITS = {
|
|
4
|
+
defaultMaxBytes: 32 * 1024,
|
|
5
|
+
minMaxBytes: 4 * 1024,
|
|
6
|
+
maxMaxBytes: 64 * 1024,
|
|
7
|
+
responseTtlMs: 5 * 60 * 1_000,
|
|
8
|
+
relayTimeoutMs: 15 * 1_000,
|
|
9
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type ChatAttachmentInput = {
|
|
2
|
-
path: string;
|
|
3
|
-
name: string;
|
|
4
|
-
mimeType: string;
|
|
5
|
-
previewData?: string;
|
|
6
|
-
};
|
|
7
|
-
export declare function materializeRemoteChatAttachments(input: {
|
|
8
|
-
text: string;
|
|
9
|
-
attachments?: ChatAttachmentInput[];
|
|
10
|
-
workDir: string;
|
|
11
|
-
}): Promise<{
|
|
12
|
-
text: string;
|
|
13
|
-
attachments?: ChatAttachmentInput[];
|
|
14
|
-
localized: boolean;
|
|
15
|
-
}>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import f from"node:crypto";import i from"node:fs";import o from"node:path";const l=Number(process.env.SHENNIAN_REMOTE_ATTACHMENT_MAX_BYTES||50*1024*1024);function m(t){return o.basename(t||"attachment").normalize("NFKC").replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").replace(/[\r\n\t]+/g," ").replace(/\s+/g," ").replace(/_+/g,"_").replace(/^[ ._]+|[ ._]+$/g,"")||"attachment"}function u(t,a,e){const r=m(a),n=o.extname(r),c=n?r.slice(0,-n.length):r,s=o.join(t,r);return i.existsSync(s)?o.join(t,`${c}-${e.slice(0,8)}${n}`):s}function p(t){return/^https?:\/\//i.test(t)}async function d(t,a){if(!p(t.path))return t;const e=await fetch(t.path);if(!e.ok||Number(e.headers.get("content-length")||0)>l)return t;const n=Buffer.from(await e.arrayBuffer());if(!n.byteLength||n.byteLength>l)return t;const c=f.createHash("sha256").update(n).digest("hex"),s=o.join(a,".uploads");i.mkdirSync(s,{recursive:!0});const h=u(s,t.name,c);return i.existsSync(h)||i.writeFileSync(h,n),{...t,path:h,mimeType:t.mimeType||e.headers.get("content-type")||"application/octet-stream"}}function g(t,a,e){return a.path===e.path||!a.path||!e.path?t:t.split(a.path).join(e.path)}async function _(t){if(!t.attachments?.length)return{text:t.text,attachments:t.attachments,localized:!1};const a=[];let e=t.text,r=!1;for(const n of t.attachments){const c=await d(n,t.workDir).catch(()=>n);c.path!==n.path&&p(n.path)&&(r=!0),e=g(e,n,c),a.push(c)}return{text:e,attachments:a,localized:r}}export{_ as materializeRemoteChatAttachments};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function buildToolArgsSummary(value: unknown): unknown;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const o=240;function c(t){if(t==null)return;if(!t||typeof t!="object"||Array.isArray(t))return r(t);const n={};for(const[i,e]of Object.entries(t))if(!(e==null||e==="")&&(n[i]=r(e),Object.keys(n).length===2))break;return Object.keys(n).length?n:void 0}function r(t){if(typeof t=="string")return s(t)?"[SYSTEM CONTEXT REDACTED]":t.replace(/\s+/g," ").trim().slice(0,240);const n=JSON.stringify(t);return String(n??t).replace(/\s+/g," ").slice(0,240)}function s(t){const n=t.trim();return/^<environment_context>[\s\S]*<\/environment_context>$/i.test(n)||/^# AGENTS\.md instructions for [^\n]+[\s\S]*<INSTRUCTIONS>[\s\S]*<\/INSTRUCTIONS>/i.test(n)||/^<turn_aborted>[\s\S]*<\/turn_aborted>$/i.test(n)}export{c as buildToolArgsSummary};
|