@xiaoso/dsh-tool-plus 0.1.9 → 0.1.10-beta.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/README.en.md +12 -5
- package/README.md +11 -4
- package/THIRD_PARTY_NOTICES.md +36 -0
- package/lib/client.js +272 -181
- package/lib/index.mjs +875 -1081
- package/lib/{scrapers-mhvFrvjH.mjs → scrapers-DODCPcZW.mjs} +1 -1
- package/lib/types/client/BashPlusCard.d.ts +6 -6
- package/lib/types/client/ToolPlusSection.d.ts +3 -3
- package/lib/types/client/forms.d.ts +6 -6
- package/lib/types/client/index.d.ts +25 -12
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/preset-panel.d.ts +54 -42
- package/lib/types/config/settings.d.ts +202 -21
- package/lib/types/host/browser-probe-rpc.d.ts +2 -1
- package/lib/types/host/preset-host.d.ts +103 -0
- package/lib/types/host/preset-rpc.d.ts +37 -72
- package/lib/types/presets/compare.d.ts +14 -37
- package/lib/types/presets/conflicts.d.ts +59 -0
- package/lib/types/presets/delta.d.ts +23 -18
- package/lib/types/presets/plan.d.ts +55 -0
- package/lib/types/presets/rows.d.ts +84 -0
- package/lib/types/presets/status.d.ts +56 -47
- package/lib/types/tools/bash/background.d.ts +20 -5
- package/lib/types/tools/bash/streaming-output.d.ts +4 -2
- package/lib/types/tools/shared/browser-rpc-channel.d.ts +84 -42
- package/lib/types/web/client/labels.d.ts +1 -1
- package/lib/types/web/client/row-utils.d.ts +26 -1
- package/lib/{utils-eiUz9n8I.mjs → utils-D80w8vry.mjs} +1 -1
- package/package.json +61 -46
- package/presets/tool-plus-ptc.patch.yml +164 -0
- package/presets/tool-plus-standard.patch.yml +158 -0
- package/lib/types/presets/install.d.ts +0 -44
- package/lib/types/presets/paths.d.ts +0 -41
- package/lib/types/presets/rewrite.d.ts +0 -86
- package/presets/install-presets.mjs +0 -143
- package/presets/package.json +0 -42
- package/presets/tool-plus-ptc/agent.cordis.yml +0 -284
- package/presets/tool-plus-ptc/preset.yml +0 -3
- package/presets/tool-plus-standard/agent.cordis.yml +0 -269
- package/presets/tool-plus-standard/preset.yml +0 -3
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Plugin-owned settings surface for the ported bash tool: the `
|
|
3
|
-
* namespace, a FLAT settings schema (OMP `bash*`-style scalar keys — the
|
|
4
|
-
* client
|
|
5
|
-
* nested {@link RuntimeConfig} the runtime consumes, and the
|
|
6
|
-
* consumer wiring. Keeping the whole config-export surface
|
|
7
|
-
* ported OMP runtime stay pristine — the entry only calls
|
|
2
|
+
* Plugin-owned settings surface for the ported bash tool: the `tool-plus`
|
|
3
|
+
* namespace, a FLAT settings schema (OMP `bash*`-style scalar keys — the shared
|
|
4
|
+
* client configuration form writes scalar fields only), its defaults, the
|
|
5
|
+
* mapping onto the nested {@link RuntimeConfig} the runtime consumes, and the
|
|
6
|
+
* optional-settings consumer wiring. Keeping the whole config-export surface
|
|
7
|
+
* here lets the ported OMP runtime stay pristine — the entry only calls
|
|
8
8
|
* {@link installBashPlusSettings} and re-exports this module's `Config`.
|
|
9
9
|
* @module @xiaoso/dsh-tool-plus/settings
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
12
|
import z from '@deepseek-ai/schemastery';
|
|
13
13
|
import type { MinimizerConfig } from '../tools/bash/types.ts';
|
|
14
|
+
/**
|
|
15
|
+
* The Loader commits a settings write into this plugin's live config
|
|
16
|
+
* references and announces the changed paths on the owning fiber
|
|
17
|
+
* (`@deepseek-ai/cordis-plugin-loader` declares this event). The declaration
|
|
18
|
+
* lives in the Loader package, which a business plugin does not depend on, so
|
|
19
|
+
* the one event this module consumes is spelled here — copied verbatim from the
|
|
20
|
+
* Loader's own declaration, so a future signature change fails loudly here
|
|
21
|
+
* instead of silently missing the notification.
|
|
22
|
+
*/
|
|
23
|
+
declare module '@deepseek-ai/cordis' {
|
|
24
|
+
interface Events {
|
|
25
|
+
/**
|
|
26
|
+
* Volatile config values were committed into the running fiber without a remount; dispatched to the owning fiber only.
|
|
27
|
+
* @param paths - changed config paths as key arrays; every value is committed before dispatch.
|
|
28
|
+
* @mode emit
|
|
29
|
+
*/
|
|
30
|
+
'loader/volatile-update'(paths: readonly (readonly string[])[]): void;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
14
33
|
/** Truncation strategy for background→foreground completion messages (OMP config parity). */
|
|
15
34
|
export type OutputTruncateStrategy = 'bytes' | 'lines';
|
|
16
35
|
/** Retention mode for a truncated completion message: head, tail, or middle (head+tail). */
|
|
@@ -125,8 +144,9 @@ export declare const DEFAULT_AUTO_BACKGROUND_MS = 60000;
|
|
|
125
144
|
export declare const DEFAULT_MAX_BACKGROUND_JOBS = 15;
|
|
126
145
|
/**
|
|
127
146
|
* Plugin settings, one scalar key per option — every field is writable through
|
|
128
|
-
* the client `
|
|
129
|
-
*
|
|
147
|
+
* the shared client configuration form (`ctx.configForms.get('tool-plus')`
|
|
148
|
+
* `.set`/`.unset`). Defaults live in the {@link Config} schema and in
|
|
149
|
+
* {@link resolveConfig}.
|
|
130
150
|
*/
|
|
131
151
|
export interface Config {
|
|
132
152
|
enableRunInBackground?: boolean;
|
|
@@ -193,28 +213,189 @@ export interface Config {
|
|
|
193
213
|
imagesResizeJpegQuality?: number;
|
|
194
214
|
}
|
|
195
215
|
/**
|
|
196
|
-
* Runtime configuration schema for the plugin
|
|
197
|
-
*
|
|
216
|
+
* Runtime configuration schema for the plugin, in the dsh 0.1.7 settings shape:
|
|
217
|
+
* EVERY field is declared `.volatile()`, because a settings namespace is the
|
|
218
|
+
* plugin's own entry and `SettingsForms.describe()` serves exactly the fields
|
|
219
|
+
* whose schema declares them live. {@link resolveConfig} maps the flat surface
|
|
220
|
+
* onto {@link RuntimeConfig}.
|
|
221
|
+
*
|
|
222
|
+
* The annotation is deliberately inferred rather than written as `z<Config>`:
|
|
223
|
+
* the schema's parsed output is {@link LiveConfig} (one stable reference per
|
|
224
|
+
* field), while {@link Config} stays the plain settings DOCUMENT the browser
|
|
225
|
+
* edits and the specs pass in.
|
|
226
|
+
*/
|
|
227
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
228
|
+
enableRunInBackground: z<boolean, boolean, "volatile-defined">;
|
|
229
|
+
autoBackgroundMs: z<number, number, "volatile-defined">;
|
|
230
|
+
defaultTimeoutMs: z<number, number, "volatile-defined">;
|
|
231
|
+
maxTimeoutMs: z<number, number, "volatile-defined">;
|
|
232
|
+
outputMaxBytes: z<number, number, "volatile-defined">;
|
|
233
|
+
outputSinkTailBytes: z<number, number, "volatile-defined">;
|
|
234
|
+
outputSinkHeadBytes: z<number, number, "volatile-defined">;
|
|
235
|
+
minimizerEnabled: z<boolean, boolean, "volatile-defined">;
|
|
236
|
+
interceptorEnabled: z<boolean, boolean, "volatile-defined">;
|
|
237
|
+
nonInteractiveEnv: z<boolean, boolean, "volatile-defined">;
|
|
238
|
+
snapshotEnabled: z<boolean, boolean, "volatile-defined">;
|
|
239
|
+
rmSafe: z<boolean, boolean, "volatile-defined">;
|
|
240
|
+
useShellCommandWrapper: z<boolean, boolean, "volatile-defined">;
|
|
241
|
+
webCards: z<boolean, boolean, "volatile-defined">;
|
|
242
|
+
maxBackgroundJobs: z<number, number, "volatile-defined">;
|
|
243
|
+
outputTruncateStrategy: z<"lines" | "bytes", "lines" | "bytes", "volatile-defined">;
|
|
244
|
+
outputTruncateTriggerBytes: z<number, number, "volatile-defined">;
|
|
245
|
+
outputTruncateTriggerLines: z<number, number, "volatile-defined">;
|
|
246
|
+
outputTruncateByteMode: z<"middle" | "head" | "tail", "middle" | "head" | "tail", "volatile-defined">;
|
|
247
|
+
outputTruncateByteHeadBytes: z<number, number, "volatile-defined">;
|
|
248
|
+
outputTruncateByteTailBytes: z<number, number, "volatile-defined">;
|
|
249
|
+
outputTruncateLineMode: z<"middle" | "head" | "tail", "middle" | "head" | "tail", "volatile-defined">;
|
|
250
|
+
outputTruncateLineHeadLines: z<number, number, "volatile-defined">;
|
|
251
|
+
outputTruncateLineTailLines: z<number, number, "volatile-defined">;
|
|
252
|
+
editBlockAutoGenerated: z<boolean, boolean, "volatile-defined">;
|
|
253
|
+
readSummarizeEnabled: z<boolean, boolean, "volatile-defined">;
|
|
254
|
+
readSummarizeProse: z<boolean, boolean, "volatile-defined">;
|
|
255
|
+
readSummarizeMinBodyLines: z<number, number, "volatile-defined">;
|
|
256
|
+
readSummarizeMinCommentLines: z<number, number, "volatile-defined">;
|
|
257
|
+
readSummarizeMinTotalLines: z<number, number, "volatile-defined">;
|
|
258
|
+
readSummarizeUnfoldUntil: z<number, number, "volatile-defined">;
|
|
259
|
+
readSummarizeUnfoldLimit: z<number, number, "volatile-defined">;
|
|
260
|
+
editMode: z<"replace" | "patch" | "hashline" | "apply_patch", "replace" | "patch" | "hashline" | "apply_patch", "volatile-defined">;
|
|
261
|
+
editFuzzyMatch: z<boolean, boolean, "volatile-defined">;
|
|
262
|
+
editFuzzyThreshold: z<number, number, "volatile-defined">;
|
|
263
|
+
editEnforceSeenLines: z<boolean, boolean, "volatile-defined">;
|
|
264
|
+
readDefaultLimit: z<number, number, "volatile-defined">;
|
|
265
|
+
readLineNumbers: z<boolean, boolean, "volatile-defined">;
|
|
266
|
+
readRenderMarkdown: z<boolean, boolean, "volatile-defined">;
|
|
267
|
+
readConcurrentSafe: z<boolean, boolean, "volatile-defined">;
|
|
268
|
+
grepContextBefore: z<number, number, "volatile-defined">;
|
|
269
|
+
grepContextAfter: z<number, number, "volatile-defined">;
|
|
270
|
+
grepCaseDefault: z<boolean, boolean, "volatile-defined">;
|
|
271
|
+
grepGitignoreDefault: z<boolean, boolean, "volatile-defined">;
|
|
272
|
+
globGitignoreDefault: z<boolean, boolean, "volatile-defined">;
|
|
273
|
+
globHiddenDefault: z<boolean, boolean, "volatile-defined">;
|
|
274
|
+
astGrepEnabled: z<boolean, boolean, "volatile-defined">;
|
|
275
|
+
astEditEnabled: z<boolean, boolean, "volatile-defined">;
|
|
276
|
+
fetchEnabled: z<boolean, boolean, "volatile-defined">;
|
|
277
|
+
fetchMaxTimeoutSeconds: z<number, number, "volatile-defined">;
|
|
278
|
+
fetchReader: z<"trafilatura" | "lynx" | "auto" | "native" | "parallel" | "jina" | "browser", "trafilatura" | "lynx" | "auto" | "native" | "parallel" | "jina" | "browser", "volatile-defined">;
|
|
279
|
+
browserReaderEnabled: z<boolean, boolean, "volatile-defined">;
|
|
280
|
+
imagesAutoResize: z<boolean, boolean, "volatile-defined">;
|
|
281
|
+
imagesBlockImages: z<boolean, boolean, "volatile-defined">;
|
|
282
|
+
imagesExcludeWebp: z<boolean, boolean, "volatile-defined">;
|
|
283
|
+
imagesInputMaxBytes: z<number, number, "volatile-defined">;
|
|
284
|
+
imagesResizeMaxSide: z<number, number, "volatile-defined">;
|
|
285
|
+
imagesResizeMaxBytes: z<number, number, "volatile-defined">;
|
|
286
|
+
imagesResizeMinSide: z<number, number, "volatile-defined">;
|
|
287
|
+
imagesResizeJpegQuality: z<number, number, "volatile-defined">;
|
|
288
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
289
|
+
enableRunInBackground: z<boolean, boolean, "volatile-defined">;
|
|
290
|
+
autoBackgroundMs: z<number, number, "volatile-defined">;
|
|
291
|
+
defaultTimeoutMs: z<number, number, "volatile-defined">;
|
|
292
|
+
maxTimeoutMs: z<number, number, "volatile-defined">;
|
|
293
|
+
outputMaxBytes: z<number, number, "volatile-defined">;
|
|
294
|
+
outputSinkTailBytes: z<number, number, "volatile-defined">;
|
|
295
|
+
outputSinkHeadBytes: z<number, number, "volatile-defined">;
|
|
296
|
+
minimizerEnabled: z<boolean, boolean, "volatile-defined">;
|
|
297
|
+
interceptorEnabled: z<boolean, boolean, "volatile-defined">;
|
|
298
|
+
nonInteractiveEnv: z<boolean, boolean, "volatile-defined">;
|
|
299
|
+
snapshotEnabled: z<boolean, boolean, "volatile-defined">;
|
|
300
|
+
rmSafe: z<boolean, boolean, "volatile-defined">;
|
|
301
|
+
useShellCommandWrapper: z<boolean, boolean, "volatile-defined">;
|
|
302
|
+
webCards: z<boolean, boolean, "volatile-defined">;
|
|
303
|
+
maxBackgroundJobs: z<number, number, "volatile-defined">;
|
|
304
|
+
outputTruncateStrategy: z<"lines" | "bytes", "lines" | "bytes", "volatile-defined">;
|
|
305
|
+
outputTruncateTriggerBytes: z<number, number, "volatile-defined">;
|
|
306
|
+
outputTruncateTriggerLines: z<number, number, "volatile-defined">;
|
|
307
|
+
outputTruncateByteMode: z<"middle" | "head" | "tail", "middle" | "head" | "tail", "volatile-defined">;
|
|
308
|
+
outputTruncateByteHeadBytes: z<number, number, "volatile-defined">;
|
|
309
|
+
outputTruncateByteTailBytes: z<number, number, "volatile-defined">;
|
|
310
|
+
outputTruncateLineMode: z<"middle" | "head" | "tail", "middle" | "head" | "tail", "volatile-defined">;
|
|
311
|
+
outputTruncateLineHeadLines: z<number, number, "volatile-defined">;
|
|
312
|
+
outputTruncateLineTailLines: z<number, number, "volatile-defined">;
|
|
313
|
+
editBlockAutoGenerated: z<boolean, boolean, "volatile-defined">;
|
|
314
|
+
readSummarizeEnabled: z<boolean, boolean, "volatile-defined">;
|
|
315
|
+
readSummarizeProse: z<boolean, boolean, "volatile-defined">;
|
|
316
|
+
readSummarizeMinBodyLines: z<number, number, "volatile-defined">;
|
|
317
|
+
readSummarizeMinCommentLines: z<number, number, "volatile-defined">;
|
|
318
|
+
readSummarizeMinTotalLines: z<number, number, "volatile-defined">;
|
|
319
|
+
readSummarizeUnfoldUntil: z<number, number, "volatile-defined">;
|
|
320
|
+
readSummarizeUnfoldLimit: z<number, number, "volatile-defined">;
|
|
321
|
+
editMode: z<"replace" | "patch" | "hashline" | "apply_patch", "replace" | "patch" | "hashline" | "apply_patch", "volatile-defined">;
|
|
322
|
+
editFuzzyMatch: z<boolean, boolean, "volatile-defined">;
|
|
323
|
+
editFuzzyThreshold: z<number, number, "volatile-defined">;
|
|
324
|
+
editEnforceSeenLines: z<boolean, boolean, "volatile-defined">;
|
|
325
|
+
readDefaultLimit: z<number, number, "volatile-defined">;
|
|
326
|
+
readLineNumbers: z<boolean, boolean, "volatile-defined">;
|
|
327
|
+
readRenderMarkdown: z<boolean, boolean, "volatile-defined">;
|
|
328
|
+
readConcurrentSafe: z<boolean, boolean, "volatile-defined">;
|
|
329
|
+
grepContextBefore: z<number, number, "volatile-defined">;
|
|
330
|
+
grepContextAfter: z<number, number, "volatile-defined">;
|
|
331
|
+
grepCaseDefault: z<boolean, boolean, "volatile-defined">;
|
|
332
|
+
grepGitignoreDefault: z<boolean, boolean, "volatile-defined">;
|
|
333
|
+
globGitignoreDefault: z<boolean, boolean, "volatile-defined">;
|
|
334
|
+
globHiddenDefault: z<boolean, boolean, "volatile-defined">;
|
|
335
|
+
astGrepEnabled: z<boolean, boolean, "volatile-defined">;
|
|
336
|
+
astEditEnabled: z<boolean, boolean, "volatile-defined">;
|
|
337
|
+
fetchEnabled: z<boolean, boolean, "volatile-defined">;
|
|
338
|
+
fetchMaxTimeoutSeconds: z<number, number, "volatile-defined">;
|
|
339
|
+
fetchReader: z<"trafilatura" | "lynx" | "auto" | "native" | "parallel" | "jina" | "browser", "trafilatura" | "lynx" | "auto" | "native" | "parallel" | "jina" | "browser", "volatile-defined">;
|
|
340
|
+
browserReaderEnabled: z<boolean, boolean, "volatile-defined">;
|
|
341
|
+
imagesAutoResize: z<boolean, boolean, "volatile-defined">;
|
|
342
|
+
imagesBlockImages: z<boolean, boolean, "volatile-defined">;
|
|
343
|
+
imagesExcludeWebp: z<boolean, boolean, "volatile-defined">;
|
|
344
|
+
imagesInputMaxBytes: z<number, number, "volatile-defined">;
|
|
345
|
+
imagesResizeMaxSide: z<number, number, "volatile-defined">;
|
|
346
|
+
imagesResizeMaxBytes: z<number, number, "volatile-defined">;
|
|
347
|
+
imagesResizeMinSide: z<number, number, "volatile-defined">;
|
|
348
|
+
imagesResizeJpegQuality: z<number, number, "volatile-defined">;
|
|
349
|
+
}>>, "plain">;
|
|
350
|
+
/**
|
|
351
|
+
* Live entry config: what the Loader hands `apply` for this entry, and what
|
|
352
|
+
* {@link installBashPlusSettings} re-reads after a settings write commits. One
|
|
353
|
+
* stable reference per schema field — read it through `.get()`, never as a
|
|
354
|
+
* plain value.
|
|
198
355
|
*/
|
|
199
|
-
export
|
|
356
|
+
export type LiveConfig = ReturnType<typeof Config>;
|
|
200
357
|
/**
|
|
201
358
|
* Resolve the flat settings (composition entry or the settings document) to
|
|
202
359
|
* the nested runtime config the ported OMP runtime consumes. A direct mount
|
|
203
360
|
* (`ctx.plugin`) skips the Loader's schema parse, so the `?? default` pass
|
|
204
361
|
* mirrors the schema; the settings namespace resolution rides the same path.
|
|
205
|
-
*
|
|
362
|
+
* Accepts both shapes a caller can hold: the Loader's live entry config (one
|
|
363
|
+
* reference per field) and a plain settings document.
|
|
364
|
+
* @param input - the entry's live config, or a plain (possibly partial) document.
|
|
206
365
|
* @returns the fully-defaulted nested runtime config.
|
|
207
366
|
*/
|
|
208
|
-
export declare function resolveConfig(
|
|
367
|
+
export declare function resolveConfig(input: Config | LiveConfig): RuntimeConfig;
|
|
209
368
|
/**
|
|
210
|
-
* Install the optional-settings consumer wiring for this plugin
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
369
|
+
* Install the optional-settings consumer wiring for this plugin, in the dsh
|
|
370
|
+
* 0.1.7 shape.
|
|
371
|
+
*
|
|
372
|
+
* 0.1.7 deleted the namespace-registration API (`SettingsForms` no longer has
|
|
373
|
+
* `installSection`): a settings namespace is not something a plugin installs
|
|
374
|
+
* any more — it IS the plugin's own profile entry, and the service serves
|
|
375
|
+
* exactly the Config fields whose schema declares them live
|
|
376
|
+
* ({@link Config} declares every field `.volatile()`). The plugin therefore
|
|
377
|
+
* keeps one authoritative source, its own entry config:
|
|
378
|
+
*
|
|
379
|
+
* - the Loader merges the composition layers and the profile override before
|
|
380
|
+
* `apply` runs, so the entry already carries the effective settings;
|
|
381
|
+
* - a settings write is committed INTO that entry's live references without a
|
|
382
|
+
* remount, and the Loader then announces the changed paths on this fiber
|
|
383
|
+
* (`loader/volatile-update`) — which is the signal for refreshing
|
|
384
|
+
* registration facts (the `editMode`-sensitive descriptions and the AST
|
|
385
|
+
* switches), exactly as the settings docs prescribe.
|
|
386
|
+
*
|
|
387
|
+
* The plugin ships its own settings pages in the browser half, so it owns its
|
|
388
|
+
* page policy: `configure({ auto: false })` tells the settings service not to
|
|
389
|
+
* auto-generate a schema page for this entry. That call rides an optional
|
|
390
|
+
* `ctx.inject(['settings'], ...)` child, so the plugin runs unchanged in a
|
|
391
|
+
* deployment that composes no settings service at all.
|
|
392
|
+
*
|
|
393
|
+
* Mirrors the official bash-local pattern (`packages/shell/bash-local`): the
|
|
394
|
+
* business plugin reads its own Config references and registers only its page
|
|
395
|
+
* policy; nothing re-registers the namespace.
|
|
216
396
|
* @param ctx - plugin context owning the wiring.
|
|
217
|
-
* @param entry -
|
|
397
|
+
* @param entry - the entry's config as the Loader resolved it (live references
|
|
398
|
+
* over the composition layers and the profile override), or a plain document.
|
|
218
399
|
* @param onSource - receives a thunk of the currently authoritative runtime config.
|
|
219
400
|
*/
|
|
220
|
-
export declare function installBashPlusSettings(ctx: Context, entry: Config, onSource: (current: () => RuntimeConfig) => void): void;
|
|
401
|
+
export declare function installBashPlusSettings(ctx: Context, entry: Config | LiveConfig, onSource: (current: () => RuntimeConfig) => void): void;
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* **Why this registers its own route instead of calling `connection.rpc.handle`.**
|
|
8
8
|
* The documented helper is unusable from a plugin in a real web deployment on
|
|
9
|
-
* dsh 0.1.5-rc.1
|
|
9
|
+
* dsh 0.1.5-rc.1 — and still on 0.1.7-rc.1, re-checked for this migration:
|
|
10
|
+
* `HostConnectionService.rpc` builds its handle against
|
|
10
11
|
* `owner = this.ctx` (`rpc-host.ts: "Generic channel registry scoped to the
|
|
11
12
|
* Context reading this service"`), and `register()` then evaluates
|
|
12
13
|
* `owner.webServer.register(route)`. The client-connection row declares
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half of the preset surface: read the deployment's declared presets and
|
|
3
|
+
* apply the panel's three actions through the harness's own config editor.
|
|
4
|
+
*
|
|
5
|
+
* WHY WE DO NOT WRITE FILES OURSELVES: dsh 0.1.7 removed the directory preset
|
|
6
|
+
* mechanism and the `agent_preset` tool with it. The only supported programmatic
|
|
7
|
+
* write path is `ctx.configEditor.edit()`, and it is a better one than we had —
|
|
8
|
+
* it takes the profile lock, serializes with HMR, validates the next config
|
|
9
|
+
* through the Loader's own waterfall, writes atomically, rolls back on a failed
|
|
10
|
+
* reconcile, and refuses when a home patch or `--patch` overlay would defeat the
|
|
11
|
+
* edit. It also gives us "revert to the bundled declaration" for free: handing
|
|
12
|
+
* back the inherited config makes it delete the override's `config` key.
|
|
13
|
+
*
|
|
14
|
+
* The service is resolved per call, so a deployment that mounts the editor
|
|
15
|
+
* after this plugin still works instead of caching an early `undefined`.
|
|
16
|
+
*
|
|
17
|
+
* Everything here is a thin adapter; the decisions live in `src/presets/**`
|
|
18
|
+
* (pure, fs-free, unit-testable) and this module only resolves services and
|
|
19
|
+
* shapes results.
|
|
20
|
+
* @module @xiaoso/dsh-tool-plus/host/preset-host
|
|
21
|
+
*/
|
|
22
|
+
import { type PresetActionResultValue, type PresetCompareValue, type PresetStatusListValue } from '../tools/shared/browser-rpc-channel.ts';
|
|
23
|
+
import { type PresetActionKind } from '../presets/plan.ts';
|
|
24
|
+
/** The context slice this module needs: Cordis service lookup only. */
|
|
25
|
+
export interface PresetHostCtx {
|
|
26
|
+
get(name: string): unknown;
|
|
27
|
+
}
|
|
28
|
+
/** Structural view of one addressable Loader entry. */
|
|
29
|
+
interface EntryLike {
|
|
30
|
+
options: {
|
|
31
|
+
id: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
config?: unknown;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** One `configEditor.configuration()` row. */
|
|
37
|
+
interface ConfigurationRowLike {
|
|
38
|
+
entry: EntryLike;
|
|
39
|
+
/** The bundled layer's config (our shipped declaration). */
|
|
40
|
+
inherited: Record<string, unknown>;
|
|
41
|
+
/** The profile layer's config; `{}` when the user never overrode the row. */
|
|
42
|
+
override: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The slice of `@deepseek-ai/dsh-config-editor` this plugin uses. Declared
|
|
46
|
+
* structurally so the plugin keeps zero build-time coupling to a package it
|
|
47
|
+
* never bundles.
|
|
48
|
+
*/
|
|
49
|
+
export interface ConfigEditorLike {
|
|
50
|
+
/** Absolute path of the profile patch this editor writes. */
|
|
51
|
+
readonly documentPath: string;
|
|
52
|
+
entries(): readonly EntryLike[];
|
|
53
|
+
configuration(): readonly ConfigurationRowLike[];
|
|
54
|
+
edit(entry: EntryLike, change: (current: Record<string, unknown>, inherited: Record<string, unknown>) => Record<string, unknown>): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/** One roster entry as the registry reports it. */
|
|
57
|
+
interface RosterRowLike {
|
|
58
|
+
readonly id?: unknown;
|
|
59
|
+
readonly name?: unknown;
|
|
60
|
+
readonly description?: unknown;
|
|
61
|
+
readonly broken?: unknown;
|
|
62
|
+
readonly isDefault?: unknown;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The slice of the preset registry this plugin uses.
|
|
66
|
+
*
|
|
67
|
+
* `remoteExportList()` is preferred: it is the roster the official client reads,
|
|
68
|
+
* and unlike `list()` it also carries `isDefault`. `list()` remains the fallback
|
|
69
|
+
* for a deployment whose registry predates the exported roster.
|
|
70
|
+
*/
|
|
71
|
+
export interface AgentPresetsLike {
|
|
72
|
+
list?(): Promise<readonly RosterRowLike[]>;
|
|
73
|
+
remoteExportList?(): Promise<{
|
|
74
|
+
readonly presets?: readonly RosterRowLike[];
|
|
75
|
+
} | undefined>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Answer `presets/status`.
|
|
79
|
+
* @param ctx - context used to resolve the config editor and the registry.
|
|
80
|
+
* @returns the panel's full status payload.
|
|
81
|
+
*/
|
|
82
|
+
export declare function listPresetStatuses(ctx: PresetHostCtx): Promise<PresetStatusListValue>;
|
|
83
|
+
/**
|
|
84
|
+
* Answer `presets/apply` by planning the action and, when it is worth writing,
|
|
85
|
+
* delegating the write to the harness's own config editor.
|
|
86
|
+
* @param ctx - context used to resolve the services.
|
|
87
|
+
* @param presetId - the preset to act on.
|
|
88
|
+
* @param action - `upgrade`, `align` or `revert`.
|
|
89
|
+
* @param templateId - the align target (required for `align`).
|
|
90
|
+
* @returns the action result, never throwing.
|
|
91
|
+
*/
|
|
92
|
+
export declare function applyPresetAction(ctx: PresetHostCtx, presetId: string, action: PresetActionKind, templateId?: string): Promise<PresetActionResultValue>;
|
|
93
|
+
/**
|
|
94
|
+
* Answer `presets/compare`: one preset's effective plugins against one of our
|
|
95
|
+
* declared templates. Never throws; an unresolvable side reports `unreadable`
|
|
96
|
+
* (that is a state the panel renders as a red dot, not a failed call).
|
|
97
|
+
* @param ctx - context used to resolve the services.
|
|
98
|
+
* @param presetId - the preset being inspected.
|
|
99
|
+
* @param templateId - the template to compare it against.
|
|
100
|
+
* @returns the comparison.
|
|
101
|
+
*/
|
|
102
|
+
export declare function comparePresetAgainstTemplate(ctx: PresetHostCtx, presetId: string, templateId: string): Promise<PresetCompareValue>;
|
|
103
|
+
export {};
|
|
@@ -1,102 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Host half of the preset endpoints: answers `presets/status` (roster +
|
|
3
|
-
* conflicts + template diff)
|
|
4
|
-
*
|
|
3
|
+
* conflicts + template diff), `presets/apply` (upgrade / align / revert) and
|
|
4
|
+
* `presets/compare` for the settings panel's 「全局」tab.
|
|
5
5
|
*
|
|
6
|
-
* These endpoints live on the **same** `/tool-plus`
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `connection.rpc.handle
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* These endpoints live on the **same** `/tool-plus` route as `browser/detect`
|
|
7
|
+
* and `rmSafe/status` (see `browser-probe-rpc.ts`). That route is a plain
|
|
8
|
+
* `webServer.register({ kind: 'prefix', path: '/tool-plus' })` registration, NOT
|
|
9
|
+
* `connection.rpc.handle`: in this deployment the Connection handler resolves
|
|
10
|
+
* its owner through `this.ctx` without the `webServer` injection, so a
|
|
11
|
+
* `rpc.handle` registration never takes effect. The Connection service is still
|
|
12
|
+
* used for its loopback trust fence (`connection.requestRejection`).
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* from a non-loopback host.
|
|
14
|
+
* This module is a wire adapter only: payload validation plus dispatch into an
|
|
15
|
+
* injected {@link PresetRpcDeps}. The service lookup, the configuration reads
|
|
16
|
+
* and the writes live in `../host/preset-host.ts`; the decision logic lives in
|
|
17
|
+
* `src/presets/**`. Trust policy is `loopback` — these endpoints read the user's
|
|
18
|
+
* profile configuration and the write path edits it, so they must never be
|
|
19
|
+
* reachable from a non-loopback host.
|
|
20
20
|
* @module @xiaoso/dsh-tool-plus/host/preset-rpc
|
|
21
21
|
*/
|
|
22
22
|
import type { ConnectionRpcHandler } from '@deepseek-ai/dsh-client-connection';
|
|
23
|
-
import { type PresetActionPayload, type PresetComparePayloadValue } from '../tools/shared/browser-rpc-channel.ts';
|
|
24
|
-
import type { PresetInstallResult } from '../presets/install.ts';
|
|
25
|
-
import type { PresetComparison, PresetTemplate } from '../presets/compare.ts';
|
|
26
|
-
import type { PresetRosterEntry, PresetStatus } from '../presets/status.ts';
|
|
27
|
-
/** Payload shape of a `presets/compare` call (shared contract). */
|
|
28
|
-
type PresetComparePayload = PresetComparePayloadValue;
|
|
23
|
+
import { type PresetActionPayload, type PresetActionResultValue, type PresetActionValue, type PresetComparePayloadValue, type PresetCompareValue, type PresetStatusListValue } from '../tools/shared/browser-rpc-channel.ts';
|
|
29
24
|
/** Result shape of one Connection RPC call (official pattern in the gateway). */
|
|
30
25
|
type ConnectionRpcResult = Awaited<ReturnType<ConnectionRpcHandler>>;
|
|
26
|
+
/** The context slice this handler needs: pass-through to the injected deps. */
|
|
27
|
+
export interface PresetEndpointCtx {
|
|
28
|
+
/** Cordis service lookup, forwarded to the host implementation. */
|
|
29
|
+
get(name: string): unknown;
|
|
30
|
+
}
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* is reached through the context, and every field is validated on the way in.
|
|
32
|
+
* Everything the endpoints need from the host plane. Injected so this module
|
|
33
|
+
* stays a thin wire adapter whose parsing helpers are testable without a
|
|
34
|
+
* Connection service, a Loader, or a profile.
|
|
36
35
|
*/
|
|
37
|
-
interface RosterPresetLike {
|
|
38
|
-
readonly id?: unknown;
|
|
39
|
-
readonly trust?: unknown;
|
|
40
|
-
readonly path?: unknown;
|
|
41
|
-
readonly name?: unknown;
|
|
42
|
-
readonly description?: unknown;
|
|
43
|
-
readonly broken?: unknown;
|
|
44
|
-
}
|
|
45
|
-
/** The only slice of the official agent-presets service this plugin uses. */
|
|
46
|
-
export interface AgentPresetsServiceLike {
|
|
47
|
-
list(): Promise<readonly RosterPresetLike[]>;
|
|
48
|
-
}
|
|
49
|
-
/** Install-time dependencies: the preset analysis owned by the host half. */
|
|
50
36
|
export interface PresetRpcDeps {
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
/** Apply one action to one preset
|
|
54
|
-
applyAction: (id: string, action:
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Read-only comparison between one roster preset and one of our templates.
|
|
59
|
-
* Returns `status: 'unreadable'` instead of throwing when a file cannot be
|
|
60
|
-
* read — that is a state the panel renders (red dot), not a failed call.
|
|
61
|
-
*/
|
|
62
|
-
comparePreset: (preset: PresetRosterEntry, templateId: string) => PresetComparison;
|
|
37
|
+
/** Read every declared preset with its conflicts and template diff. */
|
|
38
|
+
listPresets: (ctx: PresetEndpointCtx) => Promise<PresetStatusListValue>;
|
|
39
|
+
/** Apply one action to one preset. The only path that writes. */
|
|
40
|
+
applyAction: (ctx: PresetEndpointCtx, id: string, action: PresetActionValue, templateId?: string) => Promise<PresetActionResultValue>;
|
|
41
|
+
/** Read-only comparison between one preset and one of our declarations. */
|
|
42
|
+
comparePreset: (ctx: PresetEndpointCtx, presetId: string, templateId: string) => Promise<PresetCompareValue>;
|
|
63
43
|
}
|
|
64
44
|
/**
|
|
65
45
|
* Validate a `presets/compare` payload: two non-empty ids, nothing else.
|
|
66
46
|
* @param payload - the raw RPC payload.
|
|
67
47
|
* @returns the narrowed payload, or undefined when invalid.
|
|
68
48
|
*/
|
|
69
|
-
export declare function parsePresetComparePayload(payload: unknown):
|
|
49
|
+
export declare function parsePresetComparePayload(payload: unknown): PresetComparePayloadValue | undefined;
|
|
70
50
|
/**
|
|
71
51
|
* Validate a `presets/apply` payload. Anything that is not exactly
|
|
72
|
-
* `{ id: non-empty string, action: 'upgrade' | '
|
|
73
|
-
* write endpoint never receives a half-formed request.
|
|
52
|
+
* `{ id: non-empty string, action: 'upgrade' | 'align' | 'revert', templateId?: non-empty string }`
|
|
53
|
+
* is rejected, so the write endpoint never receives a half-formed request.
|
|
74
54
|
* @param payload - the raw RPC payload.
|
|
75
55
|
* @returns the narrowed payload, or undefined when invalid.
|
|
76
56
|
*/
|
|
77
57
|
export declare function parsePresetActionPayload(payload: unknown): PresetActionPayload | undefined;
|
|
78
58
|
/**
|
|
79
|
-
*
|
|
80
|
-
* treated as `user` (the conservative side: it is a writable preset only when
|
|
81
|
-
* the caller proves otherwise — the caller matches ids against our templates).
|
|
82
|
-
* @param preset - raw entry from `ctx.agentPresets.list()`.
|
|
83
|
-
* @returns the entry in our own shape.
|
|
84
|
-
*/
|
|
85
|
-
export declare function toRosterEntry(preset: RosterPresetLike): PresetRosterEntry;
|
|
86
|
-
/** The context slice this handler needs: service lookup only. */
|
|
87
|
-
export interface PresetEndpointCtx {
|
|
88
|
-
/** Cordis service lookup; `agentPresets` is mounted by the harness. */
|
|
89
|
-
get(name: string): unknown;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Answer one preset endpoint on the shared `/tool-plus` channel.
|
|
59
|
+
* Answer one preset endpoint on the shared `/tool-plus` route.
|
|
93
60
|
*
|
|
94
61
|
* Returns `undefined` for an endpoint this module does not own, so the caller
|
|
95
|
-
* (the single
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* @param ctx - context used to resolve the `agentPresets` service.
|
|
99
|
-
* @param deps - injected preset analysis.
|
|
62
|
+
* (the single route handler) can keep serving its own families.
|
|
63
|
+
* @param ctx - context forwarded to the injected host implementation.
|
|
64
|
+
* @param deps - injected host implementation.
|
|
100
65
|
* @param endpoint - the requested endpoint name.
|
|
101
66
|
* @param payload - the raw RPC payload.
|
|
102
67
|
* @returns the RPC result, or undefined when the endpoint is not ours.
|
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 预设比较:把"
|
|
2
|
+
* 预设比较:把"某份 preset 生效的 plugins"和"某个随包声明的 plugins"放在一起看。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* "
|
|
4
|
+
* 面板是两块信息、两个状态点:
|
|
5
|
+
* ①**工具行**:这份 preset 里那 4 个冲突行都禁用了吗(=`conflicts`);
|
|
6
|
+
* ②**完整比较**:内容上和选中的模板差多少(=`items`,弹窗里逐条展示)。
|
|
7
|
+
* 只读,绝不写盘。比较一律**不跳过**冲突行的 `disabled` —— 第二个点要的是
|
|
8
|
+
* "完整的比较",工具开关的不同也必须出现在差异清单里,否则会出现"说内容一致、
|
|
9
|
+
* 却说工具行没配好"这种自相矛盾的读数。
|
|
10
10
|
* @module @xiaoso/dsh-tool-plus/presets/compare
|
|
11
11
|
*/
|
|
12
|
-
import { type PresetDeps } from './paths.ts';
|
|
13
12
|
import { type PresetDeltaItem } from './delta.ts';
|
|
14
|
-
/** 面板"对比模板"下拉的一项:模板 id(可读性靠 name)。 */
|
|
15
|
-
export interface PresetTemplate {
|
|
16
|
-
id: string;
|
|
17
|
-
name?: string;
|
|
18
|
-
}
|
|
19
13
|
/** 一次比较的结果(面板两个状态点 + 弹窗的全部数据)。 */
|
|
20
14
|
export interface PresetComparison {
|
|
21
|
-
/**
|
|
15
|
+
/** 任一侧不是合法行列表 → `unreadable`,此时 `items` 为空。 */
|
|
22
16
|
status: 'ok' | 'unreadable';
|
|
23
|
-
/**
|
|
17
|
+
/** 这份 preset 里还没禁用的冲突行(空 = 本插件的工具已生效)。 */
|
|
24
18
|
conflicts: string[];
|
|
25
|
-
/**
|
|
19
|
+
/** 内容层面逐项一致(顺序不同不算差异,逐值比较)。 */
|
|
26
20
|
identical: boolean;
|
|
27
21
|
yoursCount: number;
|
|
28
22
|
behindCount: number;
|
|
@@ -30,26 +24,9 @@ export interface PresetComparison {
|
|
|
30
24
|
items: PresetDeltaItem[];
|
|
31
25
|
}
|
|
32
26
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @param
|
|
35
|
-
* @
|
|
36
|
-
*/
|
|
37
|
-
export declare function listTemplates(deps?: PresetDeps): PresetTemplate[];
|
|
38
|
-
/** 读一份模板的组合文件;不存在返回 undefined。 */
|
|
39
|
-
export declare function readTemplateComposition(templateId: string, deps?: PresetDeps): string | undefined;
|
|
40
|
-
/**
|
|
41
|
-
* 比较两份组合文件文本(纯函数,只读)。
|
|
42
|
-
* @param presetText - 所选预设的原文。
|
|
43
|
-
* @param templateText - 所选模板的原文。
|
|
27
|
+
* 比较两份 `config.plugins`(纯函数,只读)。
|
|
28
|
+
* @param presetPlugins - 所选 preset 生效的 plugins。
|
|
29
|
+
* @param templatePlugins - 所选模板的 plugins(随包声明)。
|
|
44
30
|
* @returns 两个状态点与弹窗需要的全部数据。
|
|
45
31
|
*/
|
|
46
|
-
export declare function
|
|
47
|
-
/**
|
|
48
|
-
* 读盘版比较:预设一侧用 roster 给的组合文件路径,模板一侧按 id 去包里找。
|
|
49
|
-
* 任一侧读不到都返回 `unreadable` —— 那是面板要渲染的红点,不是调用失败。
|
|
50
|
-
* @param presetPath - 所选预设的组合文件绝对路径(来自 roster)。
|
|
51
|
-
* @param templateId - 所选模板的 id。
|
|
52
|
-
* @param deps - 路径注入(测试用)。
|
|
53
|
-
* @returns 比较结果。
|
|
54
|
-
*/
|
|
55
|
-
export declare function comparePresetFile(presetPath: string, templateId: string, deps?: PresetDeps): PresetComparison;
|
|
32
|
+
export declare function comparePlugins(presetPlugins: unknown, templatePlugins: unknown): PresetComparison;
|