@benz-ai-x/dsh-md-preview 0.2.7 → 0.4.0
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/README.md +4 -2
- package/lib/client.js +117 -23
- package/lib/index.js +91 -12
- package/lib/typert/remote-client.js +119 -70
- package/lib/types/client/PreviewOverlay.d.ts +11 -8
- package/lib/types/client/WorkspaceBrowser.d.ts +23 -0
- package/lib/types/client/locale.d.ts +7 -0
- package/lib/types/client/preview-session.d.ts +96 -0
- package/lib/types/client/preview-state.d.ts +2 -0
- package/lib/types/client/use-preview-session.d.ts +36 -0
- package/lib/types/config.d.ts +4 -1
- package/lib/types/constants.d.ts +2 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/protocol.d.ts +16 -0
- package/lib/types/remote.d.ts +23 -1
- package/lib/types/typert/remote-client.d.ts +3 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -6,6 +6,12 @@ import z from "@deepseek-ai/schemastery";
|
|
|
6
6
|
const DEFAULT_MAX_BYTES = 1048576;
|
|
7
7
|
/** Markdown documents are the previewable vocabulary; deployments may widen it. */
|
|
8
8
|
const DEFAULT_ALLOWED_EXTENSIONS = [".md", ".markdown"];
|
|
9
|
+
/** The preview union: readable (and rendered) even though only markdown edits. */
|
|
10
|
+
const DEFAULT_PREVIEW_EXTENSIONS = [
|
|
11
|
+
".md",
|
|
12
|
+
".markdown",
|
|
13
|
+
".txt"
|
|
14
|
+
];
|
|
9
15
|
//#endregion
|
|
10
16
|
//#region src/remote.ts
|
|
11
17
|
var __runInitializers = function(thisArg, initializers, value) {
|
|
@@ -64,6 +70,12 @@ function fsErrorCode(error) {
|
|
|
64
70
|
if (typeof code === "string") return code;
|
|
65
71
|
}
|
|
66
72
|
}
|
|
73
|
+
/** Workspace-relative form of an entry target, falling back to its name. */
|
|
74
|
+
function workspaceRelative(rootPath, targetPath, name) {
|
|
75
|
+
if (targetPath === rootPath) return name;
|
|
76
|
+
const prefix = rootPath.endsWith("/") ? rootPath : `${rootPath}/`;
|
|
77
|
+
return targetPath.startsWith(prefix) ? targetPath.slice(prefix.length) : name;
|
|
78
|
+
}
|
|
67
79
|
/** Lowercased dot-prefixed extension of a path, or the empty string. */
|
|
68
80
|
function extensionOf(path) {
|
|
69
81
|
const name = path.slice(Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1);
|
|
@@ -83,11 +95,13 @@ let MdPreviewService = (() => {
|
|
|
83
95
|
let _instanceExtraInitializers = [];
|
|
84
96
|
let _read_decorators;
|
|
85
97
|
let _write_decorators;
|
|
98
|
+
let _list_decorators;
|
|
86
99
|
return class MdPreviewService extends _classSuper {
|
|
87
100
|
static {
|
|
88
101
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
89
102
|
_read_decorators = [Remote];
|
|
90
103
|
_write_decorators = [Remote];
|
|
104
|
+
_list_decorators = [Remote];
|
|
91
105
|
__esDecorate(this, null, _read_decorators, {
|
|
92
106
|
kind: "method",
|
|
93
107
|
name: "read",
|
|
@@ -110,6 +124,17 @@ let MdPreviewService = (() => {
|
|
|
110
124
|
},
|
|
111
125
|
metadata: _metadata
|
|
112
126
|
}, null, _instanceExtraInitializers);
|
|
127
|
+
__esDecorate(this, null, _list_decorators, {
|
|
128
|
+
kind: "method",
|
|
129
|
+
name: "list",
|
|
130
|
+
static: false,
|
|
131
|
+
private: false,
|
|
132
|
+
access: {
|
|
133
|
+
has: (obj) => "list" in obj,
|
|
134
|
+
get: (obj) => obj.list
|
|
135
|
+
},
|
|
136
|
+
metadata: _metadata
|
|
137
|
+
}, null, _instanceExtraInitializers);
|
|
113
138
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
114
139
|
enumerable: true,
|
|
115
140
|
configurable: true,
|
|
@@ -146,7 +171,7 @@ let MdPreviewService = (() => {
|
|
|
146
171
|
* @throws RemoteError with a stable MdPreview failure code.
|
|
147
172
|
*/
|
|
148
173
|
async read(sessionId, path, signal) {
|
|
149
|
-
const { target, info } = await this.resolveWorkspaceTarget(sessionId, path, signal, "read");
|
|
174
|
+
const { target, info } = await this.resolveWorkspaceTarget(sessionId, path, signal, "read", [...this.config.allowedExtensions, ...this.config.previewExtensions]);
|
|
150
175
|
if (info.size !== void 0 && info.size > this.config.maxBytes) throw failure("md-preview/too-large", `mdPreview/read refuses "${path}" above the configured byte cap`);
|
|
151
176
|
let content;
|
|
152
177
|
try {
|
|
@@ -175,7 +200,7 @@ let MdPreviewService = (() => {
|
|
|
175
200
|
* @throws RemoteError with a stable MdPreview failure code.
|
|
176
201
|
*/
|
|
177
202
|
async write(sessionId, path, content, fingerprint, force, signal) {
|
|
178
|
-
const { target, cwd } = await this.resolveWorkspaceTarget(sessionId, path, signal, "write");
|
|
203
|
+
const { target, cwd } = await this.resolveWorkspaceTarget(sessionId, path, signal, "write", this.config.allowedExtensions);
|
|
179
204
|
if (content.length > this.config.maxBytes) throw failure("md-preview/too-large", `mdPreview/write refuses "${path}" above the configured byte cap`);
|
|
180
205
|
if (fingerprint === void 0 && !force) throw failure("md-preview/bad-request", "mdPreview/write requires a fingerprint or force");
|
|
181
206
|
const expected = fingerprint === void 0 ? void 0 : {
|
|
@@ -204,6 +229,39 @@ let MdPreviewService = (() => {
|
|
|
204
229
|
};
|
|
205
230
|
}
|
|
206
231
|
/**
|
|
232
|
+
* List one workspace directory for the browser face; folders sort first,
|
|
233
|
+
* then entries alphabetize by name. A blank path lists the workspace root.
|
|
234
|
+
* @param sessionId - owning session; its header cwd roots the listing.
|
|
235
|
+
* @param path - directory path as the tree spelled it; blank = root.
|
|
236
|
+
* @param signal - caller cancellation carried through every fs call.
|
|
237
|
+
* @returns the requested path with its workspace-relative entries.
|
|
238
|
+
* @throws RemoteError with a stable MdPreview failure code.
|
|
239
|
+
*/
|
|
240
|
+
async list(sessionId, path, signal) {
|
|
241
|
+
const { root, target } = await this.resolveContainedTarget(sessionId, path, signal, "list");
|
|
242
|
+
const info = await this.ctx.fs.stat(target, signal);
|
|
243
|
+
if (info === void 0) throw failure("md-preview/not-found", `mdPreview/list cannot find "${path}"`);
|
|
244
|
+
if (info.type !== "directory") throw failure("md-preview/bad-request", `mdPreview/list requires a directory path, not "${path}"`);
|
|
245
|
+
let raw;
|
|
246
|
+
try {
|
|
247
|
+
raw = await this.ctx.fs.listDir(target, signal);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (signal.aborted) throw error;
|
|
250
|
+
throw failure("md-preview/unavailable", `mdPreview/list failed to list "${path}": ${error instanceof Error ? error.message : String(error)}`);
|
|
251
|
+
}
|
|
252
|
+
const rootPath = root.displayPath;
|
|
253
|
+
const entries = raw.map((entry) => ({
|
|
254
|
+
name: entry.name,
|
|
255
|
+
type: entry.type,
|
|
256
|
+
path: workspaceRelative(rootPath, entry.target.displayPath, entry.name)
|
|
257
|
+
}));
|
|
258
|
+
entries.sort((a, b) => a.type === b.type || a.type !== "directory" && b.type !== "directory" ? a.name.localeCompare(b.name) : a.type === "directory" ? -1 : 1);
|
|
259
|
+
return {
|
|
260
|
+
path: path.trim().length === 0 ? "" : path,
|
|
261
|
+
entries
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
207
265
|
* The shared authority preamble of the remote methods: resolve a path to a
|
|
208
266
|
* live, contained, regular workspace file, or reject it with the stable
|
|
209
267
|
* failure code. One home for the check order and the aborted-rethrow
|
|
@@ -215,16 +273,38 @@ let MdPreviewService = (() => {
|
|
|
215
273
|
* @returns the resolved target, its stat info, and the workspace cwd.
|
|
216
274
|
* @throws RemoteError with a stable MdPreview failure code.
|
|
217
275
|
*/
|
|
218
|
-
async resolveWorkspaceTarget(sessionId, path, signal, op) {
|
|
276
|
+
async resolveWorkspaceTarget(sessionId, path, signal, op, extensions) {
|
|
219
277
|
if (path.trim().length === 0) throw failure("md-preview/bad-request", `mdPreview/${op} requires a non-empty path`);
|
|
220
|
-
if (!isAllowedExtension(path,
|
|
278
|
+
if (!isAllowedExtension(path, extensions)) throw failure("md-preview/unsupported-extension", `mdPreview/${op} refuses non-previewable path "${path}"`);
|
|
279
|
+
const contained = await this.resolveContainedTarget(sessionId, path, signal, op);
|
|
280
|
+
const info = await this.ctx.fs.stat(contained.target, signal);
|
|
281
|
+
if (info === void 0) throw failure("md-preview/not-found", `mdPreview/${op} cannot find "${path}"`);
|
|
282
|
+
if (info.type !== "file") throw failure("md-preview/unsupported-extension", `mdPreview/${op} target "${path}" is not a regular file`);
|
|
283
|
+
return {
|
|
284
|
+
...contained,
|
|
285
|
+
info
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The authority middle shared by every method: session → workspace cwd →
|
|
290
|
+
* root resolve → target resolve (a blank path means the root itself) →
|
|
291
|
+
* containment. Extension and type checks belong to the callers.
|
|
292
|
+
* @param sessionId - owning session; its header cwd roots the resolution.
|
|
293
|
+
* @param path - requested path; blank spells the workspace root.
|
|
294
|
+
* @param signal - caller cancellation carried through every fs call.
|
|
295
|
+
* @param op - calling method name for diagnostic messages.
|
|
296
|
+
* @returns the resolved root, target, and the workspace cwd.
|
|
297
|
+
* @throws RemoteError with a stable MdPreview failure code.
|
|
298
|
+
*/
|
|
299
|
+
async resolveContainedTarget(sessionId, path, signal, op) {
|
|
221
300
|
const session = this.ctx.sessions.get(sessionId);
|
|
222
301
|
if (session === void 0) throw failure("md-preview/unknown-session", `mdPreview/${op} cannot resolve session "${sessionId}"`);
|
|
223
302
|
const cwd = session.header.cwd;
|
|
224
303
|
if (cwd === void 0) throw failure("md-preview/no-workspace", `mdPreview/${op} session "${sessionId}" has no working directory`);
|
|
225
304
|
const root = await this.ctx.fs.resolve(cwd, { signal });
|
|
226
305
|
let target;
|
|
227
|
-
|
|
306
|
+
if (path.trim().length === 0) target = root;
|
|
307
|
+
else try {
|
|
228
308
|
target = await this.ctx.fs.resolve(path, {
|
|
229
309
|
cwd,
|
|
230
310
|
signal
|
|
@@ -234,12 +314,9 @@ let MdPreviewService = (() => {
|
|
|
234
314
|
throw failure("md-preview/not-found", `mdPreview/${op} cannot resolve path "${path}"`);
|
|
235
315
|
}
|
|
236
316
|
if (!this.ctx.fs.contains(root, target)) throw failure("md-preview/forbidden", `mdPreview/${op} refuses paths outside the session workspace`);
|
|
237
|
-
const info = await this.ctx.fs.stat(target, signal);
|
|
238
|
-
if (info === void 0) throw failure("md-preview/not-found", `mdPreview/${op} cannot find "${path}"`);
|
|
239
|
-
if (info.type !== "file") throw failure("md-preview/unsupported-extension", `mdPreview/${op} target "${path}" is not a regular file`);
|
|
240
317
|
return {
|
|
318
|
+
root,
|
|
241
319
|
target,
|
|
242
|
-
info,
|
|
243
320
|
cwd
|
|
244
321
|
};
|
|
245
322
|
}
|
|
@@ -251,7 +328,8 @@ let MdPreviewService = (() => {
|
|
|
251
328
|
/** Standard Schema twin of {@link Config}; defaults live here, not in code. */
|
|
252
329
|
const Config = z.object({
|
|
253
330
|
maxBytes: z.number().min(1).default(DEFAULT_MAX_BYTES),
|
|
254
|
-
allowedExtensions: z.array(z.string()).default([...DEFAULT_ALLOWED_EXTENSIONS])
|
|
331
|
+
allowedExtensions: z.array(z.string()).default([...DEFAULT_ALLOWED_EXTENSIONS]),
|
|
332
|
+
previewExtensions: z.array(z.string()).default([...DEFAULT_PREVIEW_EXTENSIONS])
|
|
255
333
|
});
|
|
256
334
|
//#endregion
|
|
257
335
|
//#region src/protocol.ts
|
|
@@ -284,11 +362,12 @@ const inject = [
|
|
|
284
362
|
*/
|
|
285
363
|
function apply(ctx, config = {
|
|
286
364
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
287
|
-
allowedExtensions: [...DEFAULT_ALLOWED_EXTENSIONS]
|
|
365
|
+
allowedExtensions: [...DEFAULT_ALLOWED_EXTENSIONS],
|
|
366
|
+
previewExtensions: [...DEFAULT_PREVIEW_EXTENSIONS]
|
|
288
367
|
}) {
|
|
289
368
|
ctx.plugin(MdPreviewService, config);
|
|
290
369
|
}
|
|
291
370
|
//#endregion
|
|
292
|
-
export { Config, DEFAULT_ALLOWED_EXTENSIONS, DEFAULT_MAX_BYTES, MD_PREVIEW_FAILURE_CODES, MdPreviewService, apply, inject, isAllowedExtension, name };
|
|
371
|
+
export { Config, DEFAULT_ALLOWED_EXTENSIONS, DEFAULT_MAX_BYTES, DEFAULT_PREVIEW_EXTENSIONS, MD_PREVIEW_FAILURE_CODES, MdPreviewService, apply, inject, isAllowedExtension, name };
|
|
293
372
|
|
|
294
373
|
//# sourceMappingURL=index.js.map
|
|
@@ -24,48 +24,31 @@ const writeResult$schema = z.object({
|
|
|
24
24
|
path: z.string(),
|
|
25
25
|
fingerprint: z.string()
|
|
26
26
|
});
|
|
27
|
+
const listPath$schema = z.string();
|
|
28
|
+
const listEntry$schema = z.object({
|
|
29
|
+
name: z.string(),
|
|
30
|
+
type: z.enum([
|
|
31
|
+
"file",
|
|
32
|
+
"directory",
|
|
33
|
+
"other"
|
|
34
|
+
]),
|
|
35
|
+
path: z.string()
|
|
36
|
+
});
|
|
37
|
+
const listResult$schema = z.object({
|
|
38
|
+
path: z.string(),
|
|
39
|
+
entries: z.array(listEntry$schema)
|
|
40
|
+
});
|
|
27
41
|
/** The MdPreview contribution mounted by this package's browser entry. */
|
|
28
42
|
const TYPERT_REMOTE = {
|
|
29
43
|
package: "@benz-ai-x/dsh-md-preview",
|
|
30
|
-
descriptors: [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
wire: "sessionId",
|
|
39
|
-
source: "json",
|
|
40
|
-
codec: {
|
|
41
|
-
mode: "strict",
|
|
42
|
-
typeSymbol: "@deepseek-ai/dsh-session/types#SessionId",
|
|
43
|
-
schema: readSessionId$schema
|
|
44
|
-
}
|
|
45
|
-
}, {
|
|
46
|
-
name: "path",
|
|
47
|
-
wire: "path",
|
|
48
|
-
source: "json",
|
|
49
|
-
codec: {
|
|
50
|
-
mode: "strict",
|
|
51
|
-
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/read:path",
|
|
52
|
-
schema: readPath$schema
|
|
53
|
-
}
|
|
54
|
-
}],
|
|
55
|
-
cancellation: { parameter: "signal" },
|
|
56
|
-
result: {
|
|
57
|
-
mode: "strict",
|
|
58
|
-
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/read:result",
|
|
59
|
-
schema: readResult$schema
|
|
60
|
-
}
|
|
61
|
-
}, {
|
|
62
|
-
id: "@benz-ai-x/dsh-md-preview#mdPreview/write",
|
|
63
|
-
service: "mdPreview",
|
|
64
|
-
namespace: "mdPreview",
|
|
65
|
-
method: "write",
|
|
66
|
-
invocation: { kind: "direct" },
|
|
67
|
-
parameters: [
|
|
68
|
-
{
|
|
44
|
+
descriptors: [
|
|
45
|
+
{
|
|
46
|
+
id: "@benz-ai-x/dsh-md-preview#mdPreview/read",
|
|
47
|
+
service: "mdPreview",
|
|
48
|
+
namespace: "mdPreview",
|
|
49
|
+
method: "read",
|
|
50
|
+
invocation: { kind: "direct" },
|
|
51
|
+
parameters: [{
|
|
69
52
|
name: "sessionId",
|
|
70
53
|
wire: "sessionId",
|
|
71
54
|
source: "json",
|
|
@@ -74,55 +57,121 @@ const TYPERT_REMOTE = {
|
|
|
74
57
|
typeSymbol: "@deepseek-ai/dsh-session/types#SessionId",
|
|
75
58
|
schema: readSessionId$schema
|
|
76
59
|
}
|
|
77
|
-
},
|
|
78
|
-
{
|
|
60
|
+
}, {
|
|
79
61
|
name: "path",
|
|
80
62
|
wire: "path",
|
|
81
63
|
source: "json",
|
|
82
64
|
codec: {
|
|
83
65
|
mode: "strict",
|
|
84
|
-
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/
|
|
66
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/read:path",
|
|
85
67
|
schema: readPath$schema
|
|
86
68
|
}
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
69
|
+
}],
|
|
70
|
+
cancellation: { parameter: "signal" },
|
|
71
|
+
result: {
|
|
72
|
+
mode: "strict",
|
|
73
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/read:result",
|
|
74
|
+
schema: readResult$schema
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "@benz-ai-x/dsh-md-preview#mdPreview/write",
|
|
79
|
+
service: "mdPreview",
|
|
80
|
+
namespace: "mdPreview",
|
|
81
|
+
method: "write",
|
|
82
|
+
invocation: { kind: "direct" },
|
|
83
|
+
parameters: [
|
|
84
|
+
{
|
|
85
|
+
name: "sessionId",
|
|
86
|
+
wire: "sessionId",
|
|
87
|
+
source: "json",
|
|
88
|
+
codec: {
|
|
89
|
+
mode: "strict",
|
|
90
|
+
typeSymbol: "@deepseek-ai/dsh-session/types#SessionId",
|
|
91
|
+
schema: readSessionId$schema
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "path",
|
|
96
|
+
wire: "path",
|
|
97
|
+
source: "json",
|
|
98
|
+
codec: {
|
|
99
|
+
mode: "strict",
|
|
100
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:path",
|
|
101
|
+
schema: readPath$schema
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "content",
|
|
106
|
+
wire: "content",
|
|
107
|
+
source: "json",
|
|
108
|
+
codec: {
|
|
109
|
+
mode: "strict",
|
|
110
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:content",
|
|
111
|
+
schema: writeContent$schema
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "fingerprint",
|
|
116
|
+
wire: "fingerprint",
|
|
117
|
+
source: "json",
|
|
118
|
+
codec: {
|
|
119
|
+
mode: "strict",
|
|
120
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:fingerprint",
|
|
121
|
+
schema: writeFingerprint$schema
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "force",
|
|
126
|
+
wire: "force",
|
|
127
|
+
source: "json",
|
|
128
|
+
codec: {
|
|
129
|
+
mode: "strict",
|
|
130
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:force",
|
|
131
|
+
schema: writeForce$schema
|
|
132
|
+
}
|
|
96
133
|
}
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
|
|
134
|
+
],
|
|
135
|
+
cancellation: { parameter: "signal" },
|
|
136
|
+
result: {
|
|
137
|
+
mode: "strict",
|
|
138
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:result",
|
|
139
|
+
schema: writeResult$schema
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "@benz-ai-x/dsh-md-preview#mdPreview/list",
|
|
144
|
+
service: "mdPreview",
|
|
145
|
+
namespace: "mdPreview",
|
|
146
|
+
method: "list",
|
|
147
|
+
invocation: { kind: "direct" },
|
|
148
|
+
parameters: [{
|
|
149
|
+
name: "sessionId",
|
|
150
|
+
wire: "sessionId",
|
|
101
151
|
source: "json",
|
|
102
152
|
codec: {
|
|
103
153
|
mode: "strict",
|
|
104
|
-
typeSymbol: "@
|
|
105
|
-
schema:
|
|
154
|
+
typeSymbol: "@deepseek-ai/dsh-session/types#SessionId",
|
|
155
|
+
schema: readSessionId$schema
|
|
106
156
|
}
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
wire: "force",
|
|
157
|
+
}, {
|
|
158
|
+
name: "path",
|
|
159
|
+
wire: "path",
|
|
111
160
|
source: "json",
|
|
112
161
|
codec: {
|
|
113
162
|
mode: "strict",
|
|
114
|
-
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/
|
|
115
|
-
schema:
|
|
163
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/list:path",
|
|
164
|
+
schema: listPath$schema
|
|
116
165
|
}
|
|
166
|
+
}],
|
|
167
|
+
cancellation: { parameter: "signal" },
|
|
168
|
+
result: {
|
|
169
|
+
mode: "strict",
|
|
170
|
+
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/list:result",
|
|
171
|
+
schema: listResult$schema
|
|
117
172
|
}
|
|
118
|
-
],
|
|
119
|
-
cancellation: { parameter: "signal" },
|
|
120
|
-
result: {
|
|
121
|
-
mode: "strict",
|
|
122
|
-
typeSymbol: "@benz-ai-x/dsh-md-preview#mdPreview/write:result",
|
|
123
|
-
schema: writeResult$schema
|
|
124
173
|
}
|
|
125
|
-
|
|
174
|
+
]
|
|
126
175
|
};
|
|
127
176
|
//#endregion
|
|
128
177
|
export { TYPERT_REMOTE, TYPERT_REMOTE as default };
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
2
2
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
-
import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
|
|
4
3
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
5
|
-
import type { MdPreviewFile, MdPreviewWriteResult } from '../protocol.ts';
|
|
6
|
-
import type { MdPreviewState } from './preview-state.ts';
|
|
7
|
-
/** Read/write RPCs and panel dismissal, created in the plugin's apply world. */
|
|
4
|
+
import type { MdPreviewFile, MdPreviewListResult, MdPreviewWriteResult } from '../protocol.ts';
|
|
5
|
+
import type { MdPreviewState, MdPreviewTarget } from './preview-state.ts';
|
|
6
|
+
/** Read/write/list RPCs and panel dismissal, created in the plugin's apply world. */
|
|
8
7
|
export interface PreviewOverlayInjected {
|
|
9
8
|
hooks: {
|
|
10
9
|
/** Current preview target; null while the panel is closed. */
|
|
@@ -12,17 +11,21 @@ export interface PreviewOverlayInjected {
|
|
|
12
11
|
};
|
|
13
12
|
/** Dismiss the panel and drop the target. */
|
|
14
13
|
close(): void;
|
|
14
|
+
/** Set the preview target (the browser face's file-open handoff). */
|
|
15
|
+
setTarget(target: MdPreviewTarget | null): void;
|
|
15
16
|
/** One bounded read; the transport carries the AbortSignal. */
|
|
16
|
-
read(sessionId: SessionId, path: string, signal: AbortSignal): Promise<RemoteResult<MdPreviewFile>>;
|
|
17
|
+
read(sessionId: SessionId, path: string, signal: AbortSignal): Promise<import('@deepseek-ai/dsh-typert-protocol').RemoteResult<MdPreviewFile>>;
|
|
17
18
|
/** One guarded write; `fingerprint` comes from the backing read. */
|
|
18
|
-
write(sessionId: SessionId, path: string, content: string, fingerprint: string | undefined, force: boolean, signal: AbortSignal): Promise<RemoteResult<MdPreviewWriteResult>>;
|
|
19
|
+
write(sessionId: SessionId, path: string, content: string, fingerprint: string | undefined, force: boolean, signal: AbortSignal): Promise<import('@deepseek-ai/dsh-typert-protocol').RemoteResult<MdPreviewWriteResult>>;
|
|
20
|
+
/** One workspace directory listing; blank path lists the root. */
|
|
21
|
+
list(sessionId: SessionId, path: string, signal: AbortSignal): Promise<import('@deepseek-ai/dsh-typert-protocol').RemoteResult<MdPreviewListResult>>;
|
|
19
22
|
}
|
|
20
23
|
/** Full composed panel props. */
|
|
21
24
|
export type PreviewOverlayProps = PropsRuntime<'shell.overlay'> & InjectFace<PreviewOverlayInjected> & PropsLocale<'md-preview'>;
|
|
22
25
|
/**
|
|
23
26
|
* Render the preview panel for the current target.
|
|
24
|
-
* @param props - target hook, read
|
|
27
|
+
* @param props - target hook, read/write RPCs, dismissal, and the locale seat.
|
|
25
28
|
* @returns the docked panel, or null while closed.
|
|
26
29
|
*/
|
|
27
|
-
export declare function PreviewOverlay({ usePreviewTarget, close, read, write, t }: PreviewOverlayProps): import("react").JSX.Element | null;
|
|
30
|
+
export declare function PreviewOverlay({ usePreviewTarget, close, setTarget, read, write, list, t }: PreviewOverlayProps): import("react").JSX.Element | null;
|
|
28
31
|
//# sourceMappingURL=PreviewOverlay.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
|
|
2
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
3
|
+
import type { MdPreviewListResult } from '../protocol.ts';
|
|
4
|
+
/** Listing RPC and the file-open handoff, created in the plugin's apply world. */
|
|
5
|
+
export interface WorkspaceBrowserProps {
|
|
6
|
+
/** Owning session whose workspace the tree roots at. */
|
|
7
|
+
sessionId: SessionId;
|
|
8
|
+
/** One directory listing; the transport carries the AbortSignal. */
|
|
9
|
+
list(sessionId: SessionId, path: string, signal: AbortSignal): Promise<RemoteResult<MdPreviewListResult>>;
|
|
10
|
+
/** Open one file as the panel's preview target. */
|
|
11
|
+
onOpenFile(path: string): void;
|
|
12
|
+
/** Workspace-relative path of the current preview target, if any. */
|
|
13
|
+
currentPath: string | null;
|
|
14
|
+
/** Locale seat. */
|
|
15
|
+
t(key: string): string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Render the workspace tree for one session.
|
|
19
|
+
* @param props - session identity, listing RPC, file-open handoff, locale seat.
|
|
20
|
+
* @returns the tree element.
|
|
21
|
+
*/
|
|
22
|
+
export declare function WorkspaceBrowser({ sessionId, list, onOpenFile, currentPath, t }: WorkspaceBrowserProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=WorkspaceBrowser.d.ts.map
|
|
@@ -8,6 +8,7 @@ export declare const zh: {
|
|
|
8
8
|
'panel.loading': string;
|
|
9
9
|
'panel.empty': string;
|
|
10
10
|
'panel.error': string;
|
|
11
|
+
'panel.unsupported': string;
|
|
11
12
|
'panel.retry': string;
|
|
12
13
|
'panel.edit': string;
|
|
13
14
|
'panel.save': string;
|
|
@@ -21,6 +22,12 @@ export declare const zh: {
|
|
|
21
22
|
'panel.unsaved.title': string;
|
|
22
23
|
'panel.unsaved.discard': string;
|
|
23
24
|
'panel.unsaved.keep': string;
|
|
25
|
+
'browse.open': string;
|
|
26
|
+
'browse.back': string;
|
|
27
|
+
'browse.loading': string;
|
|
28
|
+
'browse.empty': string;
|
|
29
|
+
'browse.error': string;
|
|
30
|
+
'browse.retry': string;
|
|
24
31
|
'chip.preview': string;
|
|
25
32
|
'chip.open': string;
|
|
26
33
|
'action.label': string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PreviewSession machine: the pure state algebra of one preview target's
|
|
3
|
+
* lifecycle — content read, edit session, guarded save, prompts. The React
|
|
4
|
+
* adapter lives beside the panel (use-preview-session.ts); effects and RPC
|
|
5
|
+
* never enter here. `READ_STARTED` is the single reset point: a new read
|
|
6
|
+
* begins only when the previous document's whole session is over.
|
|
7
|
+
*/
|
|
8
|
+
import type { MdPreviewFile, MdPreviewWriteResult } from '../protocol.ts';
|
|
9
|
+
/** Content lifecycle of one preview target. */
|
|
10
|
+
export type PreviewSessionContent = {
|
|
11
|
+
readonly state: 'loading';
|
|
12
|
+
} | {
|
|
13
|
+
readonly state: 'ready';
|
|
14
|
+
readonly file: MdPreviewFile;
|
|
15
|
+
} | {
|
|
16
|
+
readonly state: 'failed';
|
|
17
|
+
readonly code: string;
|
|
18
|
+
readonly message: string;
|
|
19
|
+
};
|
|
20
|
+
/** Whole machine state for the panel's current preview target. */
|
|
21
|
+
export interface PreviewSessionState {
|
|
22
|
+
/** Read lifecycle of the current target. */
|
|
23
|
+
readonly content: PreviewSessionContent;
|
|
24
|
+
/** Panel face: rendering the document or editing a draft of it. */
|
|
25
|
+
readonly face: 'view' | 'edit';
|
|
26
|
+
/** The edit session's draft; meaningful only while `face` is edit. */
|
|
27
|
+
readonly draft: string;
|
|
28
|
+
/** A save is in flight. */
|
|
29
|
+
readonly saving: boolean;
|
|
30
|
+
/** The last save met a changed file; the conflict bar is up. */
|
|
31
|
+
readonly conflicted: boolean;
|
|
32
|
+
/** The last save failed for a non-conflict reason; the error bar is up. */
|
|
33
|
+
readonly saveError: {
|
|
34
|
+
readonly code: string;
|
|
35
|
+
readonly message: string;
|
|
36
|
+
} | null;
|
|
37
|
+
/** The unsaved guard is asking before a close. */
|
|
38
|
+
readonly unsavedPrompt: boolean;
|
|
39
|
+
/** The saved toast is showing. */
|
|
40
|
+
readonly toast: boolean;
|
|
41
|
+
/** The session asked the shell to close the panel; the adapter acts once. */
|
|
42
|
+
readonly closeRequested: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** One machine transition. */
|
|
45
|
+
export type PreviewSessionAction = {
|
|
46
|
+
readonly type: 'READ_STARTED';
|
|
47
|
+
} | {
|
|
48
|
+
readonly type: 'RETRY_READ';
|
|
49
|
+
} | {
|
|
50
|
+
readonly type: 'READ_RESOLVED';
|
|
51
|
+
readonly file: MdPreviewFile;
|
|
52
|
+
} | {
|
|
53
|
+
readonly type: 'READ_FAILED';
|
|
54
|
+
readonly code: string;
|
|
55
|
+
readonly message: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly type: 'ENTER_EDIT';
|
|
58
|
+
} | {
|
|
59
|
+
readonly type: 'EDIT';
|
|
60
|
+
readonly draft: string;
|
|
61
|
+
} | {
|
|
62
|
+
readonly type: 'SAVE_STARTED';
|
|
63
|
+
} | {
|
|
64
|
+
readonly type: 'SAVE_RESOLVED';
|
|
65
|
+
readonly result: MdPreviewWriteResult;
|
|
66
|
+
} | {
|
|
67
|
+
readonly type: 'SAVE_CONFLICT';
|
|
68
|
+
} | {
|
|
69
|
+
readonly type: 'SAVE_FAILED';
|
|
70
|
+
readonly code: string;
|
|
71
|
+
readonly message: string;
|
|
72
|
+
} | {
|
|
73
|
+
readonly type: 'CANCEL_EDIT';
|
|
74
|
+
} | {
|
|
75
|
+
readonly type: 'REQUEST_CLOSE';
|
|
76
|
+
} | {
|
|
77
|
+
readonly type: 'DISCARD';
|
|
78
|
+
} | {
|
|
79
|
+
readonly type: 'KEEP_EDITING';
|
|
80
|
+
} | {
|
|
81
|
+
readonly type: 'TOAST_EXPIRED';
|
|
82
|
+
};
|
|
83
|
+
/** The pristine state every session starts (and resets) from. */
|
|
84
|
+
export declare function initialPreviewSession(): PreviewSessionState;
|
|
85
|
+
/** Whether the draft differs from the loaded document. */
|
|
86
|
+
export declare function isDirty(state: PreviewSessionState): boolean;
|
|
87
|
+
/** The save-enable policy: something to save (dirty or conflicted), no save in flight. */
|
|
88
|
+
export declare function canSave(state: PreviewSessionState): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Apply one transition.
|
|
91
|
+
* @param state - current machine state.
|
|
92
|
+
* @param action - the transition.
|
|
93
|
+
* @returns the next state (transitions are total; guards decline no-ops).
|
|
94
|
+
*/
|
|
95
|
+
export declare function transition(state: PreviewSessionState, action: PreviewSessionAction): PreviewSessionState;
|
|
96
|
+
//# sourceMappingURL=preview-session.d.ts.map
|
|
@@ -13,6 +13,8 @@ export declare function createPreviewStore(): import("@deepseek-ai/dsh-client-st
|
|
|
13
13
|
export declare function basename(path: string): string;
|
|
14
14
|
/** Whether the client treats a produced path as a previewable markdown document. */
|
|
15
15
|
export declare function isPreviewable(path: string): boolean;
|
|
16
|
+
/** Whether a path may enter an edit session (the markdown-only editable set). */
|
|
17
|
+
export declare function isEditable(path: string): boolean;
|
|
16
18
|
/** Produced paths of one turn split into previewable and externally-opened groups, first-seen order preserved. */
|
|
17
19
|
export declare function splitPreviewable(paths: readonly string[]): {
|
|
18
20
|
previewable: string[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
|
|
2
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
3
|
+
import type { MdPreviewFile, MdPreviewWriteResult } from '../protocol.ts';
|
|
4
|
+
import type { MdPreviewTarget } from './preview-state.ts';
|
|
5
|
+
import { initialPreviewSession } from './preview-session.ts';
|
|
6
|
+
/** The adapter's inputs: the RPCs and dismissal from the plugin's apply world. */
|
|
7
|
+
export interface PanelDocumentSessionDeps {
|
|
8
|
+
readonly read: (sessionId: SessionId, path: string, signal: AbortSignal) => Promise<RemoteResult<MdPreviewFile>>;
|
|
9
|
+
readonly write: (sessionId: SessionId, path: string, content: string, fingerprint: string | undefined, force: boolean, signal: AbortSignal) => Promise<RemoteResult<MdPreviewWriteResult>>;
|
|
10
|
+
readonly close: () => void;
|
|
11
|
+
}
|
|
12
|
+
/** The panel-facing surface: machine state plus intent actions. */
|
|
13
|
+
export interface PanelDocumentSession {
|
|
14
|
+
readonly state: ReturnType<typeof initialPreviewSession>;
|
|
15
|
+
readonly canSave: boolean;
|
|
16
|
+
readonly dirty: boolean;
|
|
17
|
+
readonly actions: {
|
|
18
|
+
enterEdit(): void;
|
|
19
|
+
edit(draft: string): void;
|
|
20
|
+
save(force: boolean): void;
|
|
21
|
+
cancelEdit(): void;
|
|
22
|
+
reload(): void;
|
|
23
|
+
retryRead(): void;
|
|
24
|
+
requestClose(): void;
|
|
25
|
+
discard(): void;
|
|
26
|
+
keepEditing(): void;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run one PreviewSession for the current preview target.
|
|
31
|
+
* @param deps - read/write RPCs and the panel dismissal.
|
|
32
|
+
* @param target - the current preview target; null while the panel is closed.
|
|
33
|
+
* @returns machine state with derived flags and intent actions.
|
|
34
|
+
*/
|
|
35
|
+
export declare function usePanelDocumentSession(deps: PanelDocumentSessionDeps, target: MdPreviewTarget | null): PanelDocumentSession;
|
|
36
|
+
//# sourceMappingURL=use-preview-session.d.ts.map
|
package/lib/types/config.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ import z from '@deepseek-ai/schemastery';
|
|
|
4
4
|
export interface Config {
|
|
5
5
|
/** Largest file size the service will read and return, in bytes. */
|
|
6
6
|
maxBytes: number;
|
|
7
|
-
/** Extensions (lowercased, dot-prefixed) eligible for
|
|
7
|
+
/** Extensions (lowercased, dot-prefixed) eligible for editing. */
|
|
8
8
|
allowedExtensions: string[];
|
|
9
|
+
/** Extensions (lowercased, dot-prefixed) eligible for preview (a superset
|
|
10
|
+
* of the editable set — plain-text members render but never edit). */
|
|
11
|
+
previewExtensions: string[];
|
|
9
12
|
}
|
|
10
13
|
/** Standard Schema twin of {@link Config}; defaults live here, not in code. */
|
|
11
14
|
export declare const Config: z<Config>;
|
package/lib/types/constants.d.ts
CHANGED
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
export declare const DEFAULT_MAX_BYTES = 1048576;
|
|
4
4
|
/** Markdown documents are the previewable vocabulary; deployments may widen it. */
|
|
5
5
|
export declare const DEFAULT_ALLOWED_EXTENSIONS: readonly [".md", ".markdown"];
|
|
6
|
+
/** The preview union: readable (and rendered) even though only markdown edits. */
|
|
7
|
+
export declare const DEFAULT_PREVIEW_EXTENSIONS: readonly [".md", ".markdown", ".txt"];
|
|
6
8
|
//# sourceMappingURL=constants.d.ts.map
|