@deepseek-ai/dsh-api-workspace-files 0.1.5-alpha.1
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +154 -0
- package/README.zh.md +154 -0
- package/lib/client.js +522 -0
- package/lib/index.js +551 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +853 -0
- package/lib/typert.remote-client.d.ts +38 -0
- package/lib/typert.remote-client.js +287 -0
- package/lib/types/changes.d.ts +26 -0
- package/lib/types/changes.js +109 -0
- package/lib/types/client/change-feed.d.ts +105 -0
- package/lib/types/client/change-feed.js +296 -0
- package/lib/types/client/index.d.ts +18 -0
- package/lib/types/client/index.js +26 -0
- package/lib/types/client/provider.d.ts +45 -0
- package/lib/types/client/provider.js +129 -0
- package/lib/types/client/remote.d.ts +44 -0
- package/lib/types/client/remote.js +2 -0
- package/lib/types/client/types.d.ts +65 -0
- package/lib/types/client/types.js +2 -0
- package/lib/types/index.d.ts +143 -0
- package/lib/types/index.js +368 -0
- package/lib/types/types.d.ts +163 -0
- package/lib/types/types.js +17 -0
- package/package.json +86 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */
|
|
2
|
+
import type {
|
|
3
|
+
RemoteResult,
|
|
4
|
+
TypertRemoteContribution,
|
|
5
|
+
} from '@deepseek-ai/dsh-typert-protocol'
|
|
6
|
+
import type { WorkspaceByteRange, WorkspaceDirectoryListing, WorkspaceFileBytes, WorkspaceFileRange, WorkspaceFileStat, WorkspaceFileText, WorkspaceFileWatchFrame } from '@deepseek-ai/dsh-api-workspace-files/types'
|
|
7
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
|
8
|
+
|
|
9
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
10
|
+
interface TypertRemoteNamespace$776f726b737061636546696c6573 {
|
|
11
|
+
changes: (agentId: SessionId, signal?: AbortSignal) => AsyncIterable<WorkspaceFileWatchFrame>
|
|
12
|
+
list: (agentId: SessionId, path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceDirectoryListing>>
|
|
13
|
+
read: (agentId: SessionId, path: string, range: WorkspaceFileRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileText>>
|
|
14
|
+
readBytes: (agentId: SessionId, path: string, range: WorkspaceByteRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileBytes>>
|
|
15
|
+
stat: (agentId: SessionId, path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileStat>>
|
|
16
|
+
}
|
|
17
|
+
interface TypertRemoteMap {
|
|
18
|
+
'workspaceFiles/changes': (agentId: SessionId, signal?: AbortSignal) => AsyncIterable<WorkspaceFileWatchFrame>
|
|
19
|
+
'workspaceFiles/list': (agentId: SessionId, path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceDirectoryListing>>
|
|
20
|
+
'workspaceFiles/read': (agentId: SessionId, path: string, range: WorkspaceFileRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileText>>
|
|
21
|
+
'workspaceFiles/readBytes': (agentId: SessionId, path: string, range: WorkspaceByteRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileBytes>>
|
|
22
|
+
'workspaceFiles/stat': (agentId: SessionId, path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileStat>>
|
|
23
|
+
}
|
|
24
|
+
interface TypertRemoteNamespaceMap {
|
|
25
|
+
'workspaceFiles': TypertRemoteNamespace$776f726b737061636546696c6573
|
|
26
|
+
}
|
|
27
|
+
interface TypertRemoteScopeMap {
|
|
28
|
+
'agent:workspaceFiles/changes': (signal?: AbortSignal) => AsyncIterable<WorkspaceFileWatchFrame>
|
|
29
|
+
'agent:workspaceFiles/list': (path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceDirectoryListing>>
|
|
30
|
+
'agent:workspaceFiles/read': (path: string, range: WorkspaceFileRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileText>>
|
|
31
|
+
'agent:workspaceFiles/readBytes': (path: string, range: WorkspaceByteRange, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileBytes>>
|
|
32
|
+
'agent:workspaceFiles/stat': (path: string, signal?: AbortSignal) => Promise<RemoteResult<WorkspaceFileStat>>
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export declare const TYPERT_REMOTE: TypertRemoteContribution
|
|
37
|
+
export default TYPERT_REMOTE
|
|
38
|
+
//# sourceMappingURL=typert.remote-client.d.ts.map
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_parameter_0$schema = z.intersection(z.string(), z.unknown())
|
|
5
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_result$schema = z.union([z.object({
|
|
6
|
+
'kind': z.literal("ready").readonly(),
|
|
7
|
+
}), z.object({
|
|
8
|
+
'kind': z.literal("change").readonly(),
|
|
9
|
+
'change': z.union([z.object({
|
|
10
|
+
'absolutePath': z.string().readonly(),
|
|
11
|
+
'version': z.string().readonly(),
|
|
12
|
+
}), z.object({
|
|
13
|
+
'absolutePath': z.string().readonly(),
|
|
14
|
+
'absent': z.literal(true).readonly(),
|
|
15
|
+
})]).readonly(),
|
|
16
|
+
})])
|
|
17
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_parameter_0$schema = z.intersection(z.string(), z.unknown())
|
|
18
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_parameter_1$schema = z.string()
|
|
19
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_result$schema = z.object({
|
|
20
|
+
'path': z.string().readonly(),
|
|
21
|
+
'entries': z.array(z.object({
|
|
22
|
+
'name': z.string().readonly(),
|
|
23
|
+
'type': z.union([z.literal("file"), z.literal("directory"), z.literal("other")]).readonly(),
|
|
24
|
+
'size': z.number().readonly().optional(),
|
|
25
|
+
})).readonly(),
|
|
26
|
+
'truncated': z.boolean().readonly(),
|
|
27
|
+
})
|
|
28
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_0$schema = z.intersection(z.string(), z.unknown())
|
|
29
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_1$schema = z.string()
|
|
30
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_2$schema = z.object({
|
|
31
|
+
'offset': z.number().readonly().optional(),
|
|
32
|
+
'limit': z.number().readonly().optional(),
|
|
33
|
+
})
|
|
34
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_result$schema = z.object({
|
|
35
|
+
'offset': z.number().readonly(),
|
|
36
|
+
'text': z.string().readonly(),
|
|
37
|
+
'lines': z.number().readonly(),
|
|
38
|
+
'eof': z.boolean().readonly(),
|
|
39
|
+
'absolutePath': z.string().readonly(),
|
|
40
|
+
'version': z.string().readonly(),
|
|
41
|
+
'bytes': z.number().readonly().optional(),
|
|
42
|
+
})
|
|
43
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_0$schema = z.intersection(z.string(), z.unknown())
|
|
44
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_1$schema = z.string()
|
|
45
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_2$schema = z.object({
|
|
46
|
+
'offset': z.number().readonly().optional(),
|
|
47
|
+
'length': z.number().readonly().optional(),
|
|
48
|
+
})
|
|
49
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_result$schema = z.object({
|
|
50
|
+
'offset': z.number().readonly(),
|
|
51
|
+
'data': z.string().readonly(),
|
|
52
|
+
'eof': z.boolean().readonly(),
|
|
53
|
+
'absolutePath': z.string().readonly(),
|
|
54
|
+
'version': z.string().readonly(),
|
|
55
|
+
'bytes': z.number().readonly().optional(),
|
|
56
|
+
})
|
|
57
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_parameter_0$schema = z.intersection(z.string(), z.unknown())
|
|
58
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_parameter_1$schema = z.string()
|
|
59
|
+
const _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_result$schema = z.object({
|
|
60
|
+
'absolutePath': z.string().readonly(),
|
|
61
|
+
'version': z.string().readonly(),
|
|
62
|
+
'bytes': z.number().readonly().optional(),
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
export const TYPERT_REMOTE = {
|
|
66
|
+
package: '@deepseek-ai/dsh-api-workspace-files',
|
|
67
|
+
descriptors: [
|
|
68
|
+
{
|
|
69
|
+
id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/changes',
|
|
70
|
+
service: 'workspaceFiles',
|
|
71
|
+
namespace: 'workspaceFiles',
|
|
72
|
+
method: 'changes',
|
|
73
|
+
mode: 'stream',
|
|
74
|
+
invocation: { kind: 'direct' },
|
|
75
|
+
scope: {
|
|
76
|
+
context: 'agent',
|
|
77
|
+
wire: 'agentId',
|
|
78
|
+
},
|
|
79
|
+
parameters: [
|
|
80
|
+
{
|
|
81
|
+
name: 'agent',
|
|
82
|
+
wire: 'agentId',
|
|
83
|
+
source: 'lookup',
|
|
84
|
+
lookup: 'agent',
|
|
85
|
+
codec: {
|
|
86
|
+
mode: 'strict',
|
|
87
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
88
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_parameter_0$schema,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
cancellation: { parameter: 'signal' },
|
|
93
|
+
result: {
|
|
94
|
+
mode: 'strict',
|
|
95
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileWatchFrame',
|
|
96
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_changes_result$schema,
|
|
97
|
+
},
|
|
98
|
+
sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":274,"column":3},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/list',
|
|
102
|
+
service: 'workspaceFiles',
|
|
103
|
+
namespace: 'workspaceFiles',
|
|
104
|
+
method: 'list',
|
|
105
|
+
invocation: { kind: 'direct' },
|
|
106
|
+
scope: {
|
|
107
|
+
context: 'agent',
|
|
108
|
+
wire: 'agentId',
|
|
109
|
+
},
|
|
110
|
+
parameters: [
|
|
111
|
+
{
|
|
112
|
+
name: 'agent',
|
|
113
|
+
wire: 'agentId',
|
|
114
|
+
source: 'lookup',
|
|
115
|
+
lookup: 'agent',
|
|
116
|
+
codec: {
|
|
117
|
+
mode: 'strict',
|
|
118
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
119
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_parameter_0$schema,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'path',
|
|
124
|
+
wire: 'path',
|
|
125
|
+
source: 'json',
|
|
126
|
+
codec: {
|
|
127
|
+
mode: 'strict',
|
|
128
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/list:path',
|
|
129
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_parameter_1$schema,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
cancellation: { parameter: 'signal' },
|
|
134
|
+
result: {
|
|
135
|
+
mode: 'strict',
|
|
136
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceDirectoryListing',
|
|
137
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_list_result$schema,
|
|
138
|
+
},
|
|
139
|
+
sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":246,"column":9},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/read',
|
|
143
|
+
service: 'workspaceFiles',
|
|
144
|
+
namespace: 'workspaceFiles',
|
|
145
|
+
method: 'read',
|
|
146
|
+
invocation: { kind: 'direct' },
|
|
147
|
+
scope: {
|
|
148
|
+
context: 'agent',
|
|
149
|
+
wire: 'agentId',
|
|
150
|
+
},
|
|
151
|
+
parameters: [
|
|
152
|
+
{
|
|
153
|
+
name: 'agent',
|
|
154
|
+
wire: 'agentId',
|
|
155
|
+
source: 'lookup',
|
|
156
|
+
lookup: 'agent',
|
|
157
|
+
codec: {
|
|
158
|
+
mode: 'strict',
|
|
159
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
160
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_0$schema,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'path',
|
|
165
|
+
wire: 'path',
|
|
166
|
+
source: 'json',
|
|
167
|
+
codec: {
|
|
168
|
+
mode: 'strict',
|
|
169
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/read:path',
|
|
170
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_1$schema,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'range',
|
|
175
|
+
wire: 'range',
|
|
176
|
+
source: 'json',
|
|
177
|
+
codec: {
|
|
178
|
+
mode: 'strict',
|
|
179
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileRange',
|
|
180
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_parameter_2$schema,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
cancellation: { parameter: 'signal' },
|
|
185
|
+
result: {
|
|
186
|
+
mode: 'strict',
|
|
187
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileText',
|
|
188
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_read_result$schema,
|
|
189
|
+
},
|
|
190
|
+
sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":197,"column":9},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/readBytes',
|
|
194
|
+
service: 'workspaceFiles',
|
|
195
|
+
namespace: 'workspaceFiles',
|
|
196
|
+
method: 'readBytes',
|
|
197
|
+
invocation: { kind: 'direct' },
|
|
198
|
+
scope: {
|
|
199
|
+
context: 'agent',
|
|
200
|
+
wire: 'agentId',
|
|
201
|
+
},
|
|
202
|
+
parameters: [
|
|
203
|
+
{
|
|
204
|
+
name: 'agent',
|
|
205
|
+
wire: 'agentId',
|
|
206
|
+
source: 'lookup',
|
|
207
|
+
lookup: 'agent',
|
|
208
|
+
codec: {
|
|
209
|
+
mode: 'strict',
|
|
210
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
211
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_0$schema,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'path',
|
|
216
|
+
wire: 'path',
|
|
217
|
+
source: 'json',
|
|
218
|
+
codec: {
|
|
219
|
+
mode: 'strict',
|
|
220
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/readBytes:path',
|
|
221
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_1$schema,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'range',
|
|
226
|
+
wire: 'range',
|
|
227
|
+
source: 'json',
|
|
228
|
+
codec: {
|
|
229
|
+
mode: 'strict',
|
|
230
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceByteRange',
|
|
231
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_parameter_2$schema,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
cancellation: { parameter: 'signal' },
|
|
236
|
+
result: {
|
|
237
|
+
mode: 'strict',
|
|
238
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileBytes',
|
|
239
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_readBytes_result$schema,
|
|
240
|
+
},
|
|
241
|
+
sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":217,"column":9},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/stat',
|
|
245
|
+
service: 'workspaceFiles',
|
|
246
|
+
namespace: 'workspaceFiles',
|
|
247
|
+
method: 'stat',
|
|
248
|
+
invocation: { kind: 'direct' },
|
|
249
|
+
scope: {
|
|
250
|
+
context: 'agent',
|
|
251
|
+
wire: 'agentId',
|
|
252
|
+
},
|
|
253
|
+
parameters: [
|
|
254
|
+
{
|
|
255
|
+
name: 'agent',
|
|
256
|
+
wire: 'agentId',
|
|
257
|
+
source: 'lookup',
|
|
258
|
+
lookup: 'agent',
|
|
259
|
+
codec: {
|
|
260
|
+
mode: 'strict',
|
|
261
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
262
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_parameter_0$schema,
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'path',
|
|
267
|
+
wire: 'path',
|
|
268
|
+
source: 'json',
|
|
269
|
+
codec: {
|
|
270
|
+
mode: 'strict',
|
|
271
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files#workspaceFiles/stat:path',
|
|
272
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_parameter_1$schema,
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
cancellation: { parameter: 'signal' },
|
|
277
|
+
result: {
|
|
278
|
+
mode: 'strict',
|
|
279
|
+
typeSymbol: '@deepseek-ai/dsh-api-workspace-files/types#WorkspaceFileStat',
|
|
280
|
+
schema: _deepseek_ai_dsh_api_workspace_files_workspaceFiles_stat_result$schema,
|
|
281
|
+
},
|
|
282
|
+
sourceLocation: {"file":"packages/api/workspace-files/src/index.ts","line":233,"column":9},
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export default TYPERT_REMOTE
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer of the `changes` stream: every `fs/observed` emission whose target
|
|
3
|
+
* lies inside a generation's workspace root becomes one frame of that
|
|
4
|
+
* generation. Observations are emitted by tools after their own filesystem
|
|
5
|
+
* operation, so the feed covers Agent writes only; the OS is not watched.
|
|
6
|
+
* Each generation acknowledges its observation queue and resolved workspace
|
|
7
|
+
* root with `ready` before emitting any queued or live changes.
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import type { WorkspaceFileWatchFrame } from './types.ts';
|
|
11
|
+
/** Owns `fs/observed` observation and every open `changes` generation. */
|
|
12
|
+
export declare class WorkspaceChangeFeed {
|
|
13
|
+
private readonly ctx;
|
|
14
|
+
private readonly followers;
|
|
15
|
+
/** @param ctx - Host context carrying the filesystem the observations come from. */
|
|
16
|
+
constructor(ctx: Context);
|
|
17
|
+
/**
|
|
18
|
+
* Open one generation reporting observations inside `workspaceRoot`.
|
|
19
|
+
* @param workspaceRoot - the session's workspace root path.
|
|
20
|
+
* @param signal - generation cancellation.
|
|
21
|
+
* @returns `ready` after observation is active and the root resolves, then
|
|
22
|
+
* observations made after the generation was first pulled, in emission order.
|
|
23
|
+
*/
|
|
24
|
+
follow(workspaceRoot: string, signal: AbortSignal): AsyncIterable<WorkspaceFileWatchFrame>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=changes.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer of the `changes` stream: every `fs/observed` emission whose target
|
|
3
|
+
* lies inside a generation's workspace root becomes one frame of that
|
|
4
|
+
* generation. Observations are emitted by tools after their own filesystem
|
|
5
|
+
* operation, so the feed covers Agent writes only; the OS is not watched.
|
|
6
|
+
* Each generation acknowledges its observation queue and resolved workspace
|
|
7
|
+
* root with `ready` before emitting any queued or live changes.
|
|
8
|
+
*/
|
|
9
|
+
import { Deque } from '@deepseek-ai/dsh-deque';
|
|
10
|
+
/** Owns `fs/observed` observation and every open `changes` generation. */
|
|
11
|
+
export class WorkspaceChangeFeed {
|
|
12
|
+
ctx;
|
|
13
|
+
followers = new Set();
|
|
14
|
+
/** @param ctx - Host context carrying the filesystem the observations come from. */
|
|
15
|
+
constructor(ctx) {
|
|
16
|
+
this.ctx = ctx;
|
|
17
|
+
ctx.on('fs/observed', (target, observation) => {
|
|
18
|
+
for (const follower of this.followers)
|
|
19
|
+
follower.push([target, observation]);
|
|
20
|
+
});
|
|
21
|
+
ctx.effect(() => () => {
|
|
22
|
+
for (const follower of this.followers)
|
|
23
|
+
follower.close();
|
|
24
|
+
this.followers.clear();
|
|
25
|
+
}, 'workspace-files.changes');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Open one generation reporting observations inside `workspaceRoot`.
|
|
29
|
+
* @param workspaceRoot - the session's workspace root path.
|
|
30
|
+
* @param signal - generation cancellation.
|
|
31
|
+
* @returns `ready` after observation is active and the root resolves, then
|
|
32
|
+
* observations made after the generation was first pulled, in emission order.
|
|
33
|
+
*/
|
|
34
|
+
async *follow(workspaceRoot, signal) {
|
|
35
|
+
signal.throwIfAborted();
|
|
36
|
+
// Registered before the root resolves, so nothing observed while it does is
|
|
37
|
+
// missed; the root only filters at drain time.
|
|
38
|
+
const follower = new ChangeFollower();
|
|
39
|
+
this.followers.add(follower);
|
|
40
|
+
try {
|
|
41
|
+
// Under the generation's signal, so a consumer leaving mid-resolve on a slow
|
|
42
|
+
// backend releases the follower now rather than when the resolve settles;
|
|
43
|
+
// a rejection the abort caused is the quiet end every other abort takes here.
|
|
44
|
+
const root = await this.ctx.fs.resolve(workspaceRoot, { signal }).catch((error) => {
|
|
45
|
+
if (signal.aborted)
|
|
46
|
+
return undefined;
|
|
47
|
+
throw error;
|
|
48
|
+
});
|
|
49
|
+
if (root === undefined || signal.aborted || follower.isClosed)
|
|
50
|
+
return;
|
|
51
|
+
yield { kind: 'ready' };
|
|
52
|
+
for await (const [target, observation] of follower.read(signal)) {
|
|
53
|
+
if (!this.ctx.fs.contains(root, target))
|
|
54
|
+
continue;
|
|
55
|
+
const absolutePath = this.ctx.fs.processPath(target);
|
|
56
|
+
yield {
|
|
57
|
+
kind: 'change',
|
|
58
|
+
change: observation.kind === 'present'
|
|
59
|
+
? { absolutePath, version: observation.version }
|
|
60
|
+
: { absolutePath, absent: true },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
this.followers.delete(follower);
|
|
66
|
+
follower.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** One generation's queue: observations wait here until its consumer pulls them. */
|
|
71
|
+
class ChangeFollower {
|
|
72
|
+
queue = new Deque();
|
|
73
|
+
wake;
|
|
74
|
+
closed = false;
|
|
75
|
+
/** Whether the generation was closed while its workspace root resolved. */
|
|
76
|
+
get isClosed() {
|
|
77
|
+
return this.closed;
|
|
78
|
+
}
|
|
79
|
+
push(observed) {
|
|
80
|
+
this.queue.pushBack(observed);
|
|
81
|
+
this.wake?.();
|
|
82
|
+
}
|
|
83
|
+
close() {
|
|
84
|
+
this.closed = true;
|
|
85
|
+
this.wake?.();
|
|
86
|
+
}
|
|
87
|
+
/** Drain until closed or aborted; anything still queued then is dropped with the generation. */
|
|
88
|
+
async *read(signal) {
|
|
89
|
+
const abort = () => { this.close(); };
|
|
90
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
91
|
+
if (signal.aborted)
|
|
92
|
+
abort();
|
|
93
|
+
try {
|
|
94
|
+
while (!this.closed) {
|
|
95
|
+
const observed = this.queue.popFront();
|
|
96
|
+
if (observed !== undefined) {
|
|
97
|
+
yield observed;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
await new Promise((resolve) => { this.wake = resolve; });
|
|
101
|
+
this.wake = undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
signal.removeEventListener('abort', abort);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=changes.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One Host `changes` subscription per session, fanned out to the open files of
|
|
3
|
+
* that session.
|
|
4
|
+
*
|
|
5
|
+
* The Host reports every agent write in a session on one stream; each open file
|
|
6
|
+
* wants only its own. The feed opens the session stream when the first follower
|
|
7
|
+
* arrives, hands each frame to the followers of its path, and disposes the
|
|
8
|
+
* stream when the last follower leaves. A follower buffers session changes
|
|
9
|
+
* until `stat` supplies its Host absolute path, then filters queued and live
|
|
10
|
+
* frames by that path, with `\\` normalized to `/`. Resource addresses identify
|
|
11
|
+
* reload requests; they never determine a notification path.
|
|
12
|
+
*/
|
|
13
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
14
|
+
import type { WorkspaceFilesRemote } from './remote.ts';
|
|
15
|
+
import type { WorkspaceFileNotice } from './types.ts';
|
|
16
|
+
/** Notices of one follower, delivered in order and pulled by its consumer. */
|
|
17
|
+
declare class Follower implements AsyncIterable<WorkspaceFileNotice> {
|
|
18
|
+
readonly address: string;
|
|
19
|
+
private readonly leave;
|
|
20
|
+
private readonly pending;
|
|
21
|
+
private readonly started;
|
|
22
|
+
private wake;
|
|
23
|
+
private ended;
|
|
24
|
+
private hostKey;
|
|
25
|
+
/**
|
|
26
|
+
* Resolves true after the Host acknowledges its subscription, or false if
|
|
27
|
+
* this follower ends before acknowledgement.
|
|
28
|
+
*/
|
|
29
|
+
readonly ready: Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* @param address - resource address used for reload lookup.
|
|
32
|
+
* @param leave - unregisters this follower and its abort listener.
|
|
33
|
+
*/
|
|
34
|
+
constructor(address: string, leave: () => void);
|
|
35
|
+
/** The normalized Host path, absent until a successful stat. */
|
|
36
|
+
get key(): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Select the Host path for queued and future changes.
|
|
39
|
+
* @param absolutePath - the successful stat's absolute path.
|
|
40
|
+
*/
|
|
41
|
+
bind(absolutePath: string): void;
|
|
42
|
+
/** The Host acknowledged an active subscription and resolved workspace root. */
|
|
43
|
+
start(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Queue one notice.
|
|
46
|
+
* @param notice - what the consumer receives next.
|
|
47
|
+
* @param key - normalized Host path for a change; absent for a reload.
|
|
48
|
+
*/
|
|
49
|
+
push(notice: WorkspaceFileNotice, key?: string): void;
|
|
50
|
+
/** Deliver what is queued, then finish. */
|
|
51
|
+
end(): void;
|
|
52
|
+
/** Unregister even when the consumer has not started pulling notices. */
|
|
53
|
+
dispose(): void;
|
|
54
|
+
/** @inheritdoc */
|
|
55
|
+
[Symbol.asyncIterator](): AsyncIterator<WorkspaceFileNotice>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Per-session fan-out of the Host's workspace file change stream.
|
|
59
|
+
*
|
|
60
|
+
* Owned by the provider; one instance serves every session of the Client.
|
|
61
|
+
*/
|
|
62
|
+
export declare class ChangeFeed {
|
|
63
|
+
private readonly remote;
|
|
64
|
+
/** Live feeds only: a feed removes itself when its stream closes. */
|
|
65
|
+
private readonly sessions;
|
|
66
|
+
/** Streams still closing, by session: the session's next feed opens after its predecessor has settled. */
|
|
67
|
+
private readonly closing;
|
|
68
|
+
/**
|
|
69
|
+
* @param remote - the Remote face carrying `$stream` and `workspaceFiles.changes`.
|
|
70
|
+
*/
|
|
71
|
+
constructor(remote: WorkspaceFilesRemote);
|
|
72
|
+
/**
|
|
73
|
+
* Follow one resource address in one session before its Host path is known.
|
|
74
|
+
*
|
|
75
|
+
* The follower is registered on call, not on first pull. Changes delivered
|
|
76
|
+
* to this Client are queued while stat is pending. The first follower starts
|
|
77
|
+
* the session's local `changes` call. The iterable ends
|
|
78
|
+
* when `signal` aborts or when the session stream is gone; ending it early
|
|
79
|
+
* (`break`, `return`) unregisters the follower as well, and the last follower
|
|
80
|
+
* of a session disposes its stream. Await a true `ready` result before stat
|
|
81
|
+
* so the Host subscription is active, then bind each stat's absolute path. Until binding,
|
|
82
|
+
* any session write can trigger a retry; after binding, only matching queued
|
|
83
|
+
* and live changes pass.
|
|
84
|
+
* @param sessionId - the session whose workspace holds the file.
|
|
85
|
+
* @param address - the resource address, used only for reload lookup.
|
|
86
|
+
* @param signal - ends the follow.
|
|
87
|
+
* @returns a single-consumer subscription with Host-path binding and explicit disposal.
|
|
88
|
+
*/
|
|
89
|
+
follow(sessionId: SessionId, address: string, signal: AbortSignal): Follower;
|
|
90
|
+
/**
|
|
91
|
+
* Ask an address and its same-session Host-path peers to `stat` again.
|
|
92
|
+
* @param sessionId - the session whose workspace holds the file.
|
|
93
|
+
* @param address - the resource address requesting a reload.
|
|
94
|
+
*/
|
|
95
|
+
requestRestat(sessionId: SessionId, address: string): void;
|
|
96
|
+
/**
|
|
97
|
+
* Wait for every stream that is still closing, so an owner tearing down
|
|
98
|
+
* leaves no Host stream behind.
|
|
99
|
+
* @returns resolves once no stream of this feed is closing.
|
|
100
|
+
*/
|
|
101
|
+
settle(): Promise<void>;
|
|
102
|
+
private feedOf;
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=change-feed.d.ts.map
|