@dsh-plugin/dsh-loader 1.1.0-dev.32278873528 → 1.2.0-dev.32741629392

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.
Files changed (65) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +1 -1
  3. package/README.zh_CN.md +1 -1
  4. package/dist/adapters/dsh-1-x.js +4 -0
  5. package/dist/adapters/dsh-1-x.js.map +1 -1
  6. package/dist/api.d.ts +2 -0
  7. package/dist/api.js +18 -2
  8. package/dist/api.js.map +1 -1
  9. package/dist/client.d.ts +0 -1
  10. package/dist/client.js +13 -3
  11. package/dist/client.js.map +1 -1
  12. package/dist/index.js +7 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/patch.d.ts +112 -0
  15. package/dist/patch.js +179 -0
  16. package/dist/patch.js.map +1 -0
  17. package/dist/services/dsh-symbols.d.ts +70 -0
  18. package/dist/services/dsh-symbols.js +82 -0
  19. package/dist/services/dsh-symbols.js.map +1 -0
  20. package/dist/services/llm.d.ts +30 -0
  21. package/dist/services/llm.js +35 -0
  22. package/dist/services/llm.js.map +1 -0
  23. package/dist/services/registry.d.ts +144 -0
  24. package/dist/services/registry.js +209 -0
  25. package/dist/services/registry.js.map +1 -0
  26. package/dist/services/settings.d.ts +6 -0
  27. package/dist/services/settings.js +29 -1
  28. package/dist/services/settings.js.map +1 -1
  29. package/dist/services/web.js +20 -4
  30. package/dist/services/web.js.map +1 -1
  31. package/dist/setup.js +17 -1
  32. package/dist/setup.js.map +1 -1
  33. package/dist/types.d.ts +55 -0
  34. package/dist/version.d.ts +1 -1
  35. package/dist/version.js +1 -1
  36. package/lib/client.js +2775 -4
  37. package/lib/client.js.map +1 -1
  38. package/lib/types/adapters/dsh-1-x.d.ts +23 -0
  39. package/lib/types/adapters/index.d.ts +22 -0
  40. package/lib/types/client-ui.d.ts +40 -0
  41. package/lib/types/client.d.ts +156 -0
  42. package/lib/types/patch.d.ts +112 -0
  43. package/lib/types/registry.d.ts +35 -0
  44. package/lib/types/services/dsh-symbols.d.ts +70 -0
  45. package/lib/types/services/llm.d.ts +30 -0
  46. package/lib/types/services/registry.d.ts +144 -0
  47. package/lib/types/services/settings.d.ts +47 -0
  48. package/lib/types/types.d.ts +166 -0
  49. package/lib/types/ui/anchors.d.ts +56 -0
  50. package/lib/types/ui/components.d.ts +159 -0
  51. package/lib/types/ui/icons.d.ts +142 -0
  52. package/lib/types/ui/index.d.ts +30 -0
  53. package/lib/types/ui/menu.d.ts +104 -0
  54. package/lib/types/ui/slots.d.ts +152 -0
  55. package/lib/types/ui/style.d.ts +97 -0
  56. package/lib/types/version.d.ts +2 -0
  57. package/package.json +45 -11
  58. package/src/stable/compaction-basic.d.ts +1 -0
  59. package/src/stable/compaction-basic.js +5 -0
  60. package/src/stable/credentials.d.ts +1 -0
  61. package/src/stable/credentials.js +5 -0
  62. package/src/stable/subagent.d.ts +1 -0
  63. package/src/stable/subagent.js +5 -0
  64. package/src/stable/timeout.d.ts +1 -0
  65. package/src/stable/timeout.js +5 -0
package/dist/patch.js ADDED
@@ -0,0 +1,179 @@
1
+ /**
2
+ * The dshloader PATCH protocol (`ctx.dshLoader.patch` / `__dshLoader__.patch`).
3
+ *
4
+ * Monkey-patching a host method or global is the only way to intervene in
5
+ * behaviour dsh exposes no extension point for. Three plugins in this family
6
+ * each hand-rolled the protocol and they did NOT agree:
7
+ *
8
+ * - dsh-loader's own `Module._resolveFilename` hook → identity-checked restore
9
+ * - dsh-network-settings' `globalThis.fetch` wrapper → identity-checked restore
10
+ * - dsh-better-sidebar's `workspaces.openPath` wrap → UNCONDITIONAL restore
11
+ *
12
+ * The last one silently destroys a later plugin's wrapper when it disposes
13
+ * first, even though its own comment promised the opposite. This module is the
14
+ * single correct implementation; every patch site delegates here.
15
+ *
16
+ * The five guarantees:
17
+ *
18
+ * 1. RAW original — each patch captures EXACTLY the value present when it
19
+ * installed (another plugin's wrapper when one is already there) and
20
+ * restores that value verbatim, never a bound copy. This is what lets a
21
+ * chain of wrappers survive disposal in any order.
22
+ * 2. Identity-checked restore — disposal only reverts the slot when it still
23
+ * holds OUR wrapper. If somebody patched on top afterwards, we leave the
24
+ * chain alone (reverting would delete their wrapper).
25
+ * 3. Re-apply safety — re-applying the same `id` recovers the true original
26
+ * first, so HMR / repeated `apply()` can never nest a wrapper in itself.
27
+ * This holds while our patch is the OUTERMOST one; if a foreign patch was
28
+ * layered on top in between, re-applying chains instead (un-nesting a
29
+ * middle wrapper is not possible without rebuilding the whole chain).
30
+ * 4. Cross-instance durability — slot bookkeeping lives in a WeakMap parked on
31
+ * `globalThis` under a `Symbol.for` key, so a reloaded module instance still
32
+ * sees the original captured by its predecessor. Targets are never mutated.
33
+ * 5. Loud misuse — patching a non-function method, or a missing target, throws
34
+ * instead of silently no-op'ing.
35
+ *
36
+ * Pure and environment-agnostic: no DOM, no Node builtins, so the same module
37
+ * serves the host half and the browser half.
38
+ *
39
+ * @module @dsh-plugin/dsh-loader/patch
40
+ */
41
+ /**
42
+ * Registry key on `globalThis`. `Symbol.for` (not a fresh Symbol) so a
43
+ * re-instantiated module — HMR, a second bundle copy — finds the same registry
44
+ * and therefore the same captured originals.
45
+ */
46
+ const REGISTRY_KEY = Symbol.for('dshloader.patch.registry.v1');
47
+ /** The process-wide patch registry (targets are keys; nothing is written onto them). */
48
+ function registry() {
49
+ const scope = globalThis;
50
+ let found = scope[REGISTRY_KEY];
51
+ if (found === undefined) {
52
+ found = new WeakMap();
53
+ scope[REGISTRY_KEY] = found;
54
+ }
55
+ return found;
56
+ }
57
+ /** The slot table for one target, created on first use. */
58
+ function slotsOf(target) {
59
+ const reg = registry();
60
+ let table = reg.get(target);
61
+ if (table === undefined) {
62
+ table = new Map();
63
+ reg.set(target, table);
64
+ }
65
+ return table;
66
+ }
67
+ /** Read the current value of `target[key]` without tripping getters twice. */
68
+ function read(target, key) {
69
+ return target[key];
70
+ }
71
+ /** Write `target[key]`, surfacing a frozen / read-only slot as a loud error. */
72
+ function write(target, key, value, what) {
73
+ try {
74
+ target[key] = value;
75
+ }
76
+ catch (cause) {
77
+ throw new Error(`dshloader.patch: cannot write ${what} — the slot is read-only or frozen`, { cause });
78
+ }
79
+ if (read(target, key) !== value) {
80
+ // A non-writable data property assigns silently in sloppy mode.
81
+ throw new Error(`dshloader.patch: writing ${what} had no effect — the slot is not writable`);
82
+ }
83
+ }
84
+ /**
85
+ * Build the handle for one installed slot. Kept separate so a re-apply of the
86
+ * same id can hand back a handle over the existing bookkeeping.
87
+ */
88
+ function makeHandle(target, key, slot) {
89
+ return {
90
+ get active() {
91
+ return read(target, key) === slot.wrapper;
92
+ },
93
+ get original() {
94
+ return slot.original;
95
+ },
96
+ dispose() {
97
+ // Guarantee 2: only revert while the slot still carries OUR wrapper.
98
+ if (read(target, key) !== slot.wrapper)
99
+ return;
100
+ write(target, key, slot.original, `${String(key)} (restore)`);
101
+ const table = registry().get(target);
102
+ if (table?.get(key) === slot)
103
+ table.delete(key);
104
+ },
105
+ };
106
+ }
107
+ /**
108
+ * Patch one slot of `target`. The low-level primitive behind
109
+ * {@link PatchAPI.method} and {@link PatchAPI.global}.
110
+ *
111
+ * @param target - object owning the slot (a service instance, `globalThis`, …).
112
+ * @param key - property key to wrap.
113
+ * @param wrap - receives the value currently in the slot (the previous wrapper
114
+ * when another patch is already installed — chaining is intended) and returns
115
+ * the replacement.
116
+ * @param options - see {@link PatchOptions}.
117
+ * @returns the handle whose `dispose()` reverts this patch.
118
+ */
119
+ export function patchSlot(target, key, wrap, options = {}) {
120
+ if (target === null || (typeof target !== 'object' && typeof target !== 'function')) {
121
+ throw new TypeError(`dshloader.patch: target must be an object, received ${typeof target}`);
122
+ }
123
+ if (typeof wrap !== 'function') {
124
+ throw new TypeError('dshloader.patch: wrap must be a function');
125
+ }
126
+ const id = options.id ?? 'anonymous';
127
+ const table = slotsOf(target);
128
+ const existing = table.get(key);
129
+ // Guarantee 3: a re-apply of the same id must not wrap our own wrapper.
130
+ // Restore the captured original first, then patch the pristine slot.
131
+ if (existing !== undefined && existing.id === id && read(target, key) === existing.wrapper) {
132
+ write(target, key, existing.original, `${String(key)} (re-apply reset)`);
133
+ table.delete(key);
134
+ }
135
+ const current = read(target, key);
136
+ if (typeof current !== 'function') {
137
+ throw new TypeError(`dshloader.patch: ${String(key)} is ${current === undefined ? 'missing' : typeof current}, not a function`);
138
+ }
139
+ // Guarantee 1: capture EXACTLY the value present at install time. When another
140
+ // plugin already wrapped this slot, that wrapper is our original and restoring
141
+ // it is what keeps their patch alive (see the ordered-disposal tests).
142
+ const original = current;
143
+ const wrapper = wrap(current);
144
+ if (typeof wrapper !== 'function') {
145
+ throw new TypeError('dshloader.patch: wrap must return a function');
146
+ }
147
+ write(target, key, wrapper, String(key));
148
+ const slot = { original, wrapper, id };
149
+ table.set(key, slot);
150
+ return makeHandle(target, key, slot);
151
+ }
152
+ /** Whether a dshloader patch is currently installed on `target[key]`. */
153
+ export function isPatched(target, key) {
154
+ const slot = registry().get(target)?.get(key);
155
+ return slot !== undefined && read(target, key) === slot.wrapper;
156
+ }
157
+ /** The patch id currently installed on `target[key]`, or `undefined`. */
158
+ export function patchIdOf(target, key) {
159
+ const slot = registry().get(target)?.get(key);
160
+ return slot !== undefined && read(target, key) === slot.wrapper ? slot.id : undefined;
161
+ }
162
+ /** Build the `patch` facade. Stateless — all bookkeeping is in the global registry. */
163
+ export function createPatchAPI() {
164
+ return {
165
+ method(target, key, wrap, options) {
166
+ return patchSlot(target, key, wrap, options);
167
+ },
168
+ global(key, wrap, options = {}) {
169
+ const scope = options.scope ?? globalThis;
170
+ return patchSlot(scope, key, wrap, options);
171
+ },
172
+ slot(target, key, wrap, options) {
173
+ return patchSlot(target, key, wrap, options);
174
+ },
175
+ isPatched,
176
+ patchIdOf,
177
+ };
178
+ }
179
+ //# sourceMappingURL=patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.js","sourceRoot":"","sources":["../src/patch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /** Node's `setTimeout` ceiling (2^31 - 1), used when dsh-timeout is unavailable. */
2
+ export declare const NODE_MAX_TIMER_DELAY_MS = 2147483647;
3
+ /** The raw modules this facade forwards to, as resolved at boot. */
4
+ export interface DshSymbolModules {
5
+ tools?: {
6
+ defineTool?: unknown;
7
+ ToolArgsError?: unknown;
8
+ };
9
+ timeout?: {
10
+ deadline?: unknown;
11
+ MAX_TIMER_DELAY_MS?: number;
12
+ };
13
+ credentials?: {
14
+ credentialRef?: unknown;
15
+ };
16
+ subagent?: {
17
+ delegationDepthOf?: unknown;
18
+ };
19
+ compaction?: {
20
+ BasicCompactionEngine?: unknown;
21
+ };
22
+ llm?: {
23
+ BlockAssembler?: unknown;
24
+ };
25
+ }
26
+ /**
27
+ * Module-level dsh symbols, grouped by owning package.
28
+ *
29
+ * Types are deliberately loose (`any`-shaped call signatures): pinning dsh's
30
+ * internal shapes here would defeat the shim's purpose, exactly as
31
+ * `src/types.ts` explains for the service surfaces.
32
+ */
33
+ export interface DshSymbolsAPI {
34
+ tools: {
35
+ /** `defineTool(definition)` — build a tool definition dsh's registry accepts. */
36
+ defineTool<T>(definition: T): T;
37
+ /** `ToolArgsError` — the error class dsh expects for invalid tool arguments. */
38
+ readonly ToolArgsError: new (messages: string[]) => Error;
39
+ };
40
+ timeout: {
41
+ /** `deadline(...)` — dsh's cancellation-aware deadline helper. */
42
+ deadline<T>(...args: any[]): T;
43
+ /** dsh's timer ceiling; falls back to Node's own 2^31-1 when unavailable. */
44
+ readonly MAX_TIMER_DELAY_MS: number;
45
+ };
46
+ credentials: {
47
+ /** `credentialRef(ref)` — brand a raw reference for `credentials.resolve`. */
48
+ credentialRef(ref: unknown): unknown;
49
+ };
50
+ subagent: {
51
+ /** `delegationDepthOf(agent)` — how deep a delegated agent sits. */
52
+ delegationDepthOf(agent: unknown): number;
53
+ };
54
+ compaction: {
55
+ /**
56
+ * `BasicCompactionEngine` — the base class a plugin subclasses to override
57
+ * `summarize`. Throws when unavailable, because a subclass declaration has
58
+ * no meaningful fallback.
59
+ */
60
+ readonly BasicCompactionEngine: new (...args: any[]) => any;
61
+ };
62
+ llm: {
63
+ /** `BlockAssembler` — dsh's streaming content-block assembler. */
64
+ readonly BlockAssembler: new (...args: any[]) => any;
65
+ };
66
+ }
67
+ /** Build the `ctx.dshLoader.dsh` facade over boot-resolved modules. */
68
+ export declare function createDshSymbolsAPI(opts: {
69
+ modules?: DshSymbolModules;
70
+ }): DshSymbolsAPI;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Module-level dsh symbols (`ctx.dshLoader.dsh`).
3
+ *
4
+ * Some things a plugin needs are MODULE-level exports of `@deepseek-ai/*`
5
+ * packages rather than methods on a cordis service, so `services.get(...)`
6
+ * cannot reach them: `defineTool`, `ToolArgsError`, `deadline`,
7
+ * `credentialRef`, `delegationDepthOf`, and the `BasicCompactionEngine` base
8
+ * class a plugin subclasses.
9
+ *
10
+ * WHY A FACADE AND NOT THE STABLE SUBPATHS: the `@dsh-plugin/dsh-loader/tools`
11
+ * style subpaths are `export * from '@deepseek-ai/...'`, which requires that
12
+ * package to be resolvable FROM dshloader's own location — true for a client
13
+ * bundle (the browser module table resolves it) but not reliably true on the
14
+ * host, where dshloader sits in the profile and dsh is installed globally. A
15
+ * failed ESM static import is a hard boot failure; a facade degrades per symbol
16
+ * and says why. See docs/facades.md §0.
17
+ *
18
+ * Resolution happens once at boot (see `preloadRegistryModules`), so every
19
+ * accessor here is synchronous.
20
+ *
21
+ * @module @dsh-plugin/dsh-loader/services/dsh-symbols
22
+ */
23
+ import { LOG_PREFIX } from '../version.js';
24
+ /** Node's `setTimeout` ceiling (2^31 - 1), used when dsh-timeout is unavailable. */
25
+ export const NODE_MAX_TIMER_DELAY_MS = 2147483647;
26
+ /** Build a loud accessor for one required symbol. */
27
+ function required(value, pkg, symbol) {
28
+ if (value === undefined || value === null) {
29
+ throw new Error(`${LOG_PREFIX}:dsh.${symbol} — ${pkg} is unavailable in this runtime; ` +
30
+ 'the calling plugin cannot proceed without it');
31
+ }
32
+ return value;
33
+ }
34
+ /** Build the `ctx.dshLoader.dsh` facade over boot-resolved modules. */
35
+ export function createDshSymbolsAPI(opts) {
36
+ const m = opts.modules ?? {};
37
+ return {
38
+ tools: {
39
+ defineTool(definition) {
40
+ const fn = required(m.tools?.defineTool, '@deepseek-ai/dsh-tools', 'tools.defineTool');
41
+ return fn(definition);
42
+ },
43
+ get ToolArgsError() {
44
+ return required(m.tools?.ToolArgsError, '@deepseek-ai/dsh-tools', 'tools.ToolArgsError');
45
+ },
46
+ },
47
+ timeout: {
48
+ deadline(...args) {
49
+ const fn = required(m.timeout?.deadline, '@deepseek-ai/dsh-timeout', 'timeout.deadline');
50
+ return fn(...args);
51
+ },
52
+ // A platform constant (Node's setTimeout ceiling), not a dsh-versioned
53
+ // value, so falling back to the literal is safe rather than a guess.
54
+ get MAX_TIMER_DELAY_MS() {
55
+ return m.timeout?.MAX_TIMER_DELAY_MS ?? NODE_MAX_TIMER_DELAY_MS;
56
+ },
57
+ },
58
+ credentials: {
59
+ credentialRef(ref) {
60
+ const fn = required(m.credentials?.credentialRef, '@deepseek-ai/dsh-credentials', 'credentials.credentialRef');
61
+ return fn(ref);
62
+ },
63
+ },
64
+ subagent: {
65
+ delegationDepthOf(agent) {
66
+ const fn = required(m.subagent?.delegationDepthOf, '@deepseek-ai/dsh-subagent', 'subagent.delegationDepthOf');
67
+ return fn(agent);
68
+ },
69
+ },
70
+ compaction: {
71
+ get BasicCompactionEngine() {
72
+ return required(m.compaction?.BasicCompactionEngine, '@deepseek-ai/dsh-compaction-basic', 'compaction.BasicCompactionEngine');
73
+ },
74
+ },
75
+ llm: {
76
+ get BlockAssembler() {
77
+ return required(m.llm?.BlockAssembler, '@deepseek-ai/dsh-llm', 'llm.BlockAssembler');
78
+ },
79
+ },
80
+ };
81
+ }
82
+ //# sourceMappingURL=dsh-symbols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-symbols.js","sourceRoot":"","sources":["../../src/services/dsh-symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,oFAAoF;AACpF,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;AAsDlD,qDAAqD;AACrD,SAAS,QAAQ,CAAI,KAAc,EAAE,GAAW,EAAE,MAAc;IAC9D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,QAAQ,MAAM,MAAM,GAAG,mCAAmC;YACrE,8CAA8C,CACjD,CAAC;IACJ,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,mBAAmB,CAAC,IAAoC;IACtE,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IAC7B,OAAO;QACL,KAAK,EAAE;YACL,UAAU,CAAC,UAAU;gBACnB,MAAM,EAAE,GAAG,QAAQ,CACjB,CAAC,CAAC,KAAK,EAAE,UAAU,EACnB,wBAAwB,EACxB,kBAAkB,CACnB,CAAC;gBACF,OAAO,EAAE,CAAC,UAAU,CAAsB,CAAC;YAC7C,CAAC;YACD,IAAI,aAAa;gBACf,OAAO,QAAQ,CACb,CAAC,CAAC,KAAK,EAAE,aAAa,EACtB,wBAAwB,EACxB,qBAAqB,CACtB,CAAC;YACJ,CAAC;SACF;QACD,OAAO,EAAE;YACP,QAAQ,CAAC,GAAG,IAAW;gBACrB,MAAM,EAAE,GAAG,QAAQ,CACjB,CAAC,CAAC,OAAO,EAAE,QAAQ,EACnB,0BAA0B,EAC1B,kBAAkB,CACnB,CAAC;gBACF,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YACrB,CAAC;YACD,uEAAuE;YACvE,qEAAqE;YACrE,IAAI,kBAAkB;gBACpB,OAAO,CAAC,CAAC,OAAO,EAAE,kBAAkB,IAAI,uBAAuB,CAAC;YAClE,CAAC;SACF;QACD,WAAW,EAAE;YACX,aAAa,CAAC,GAAG;gBACf,MAAM,EAAE,GAAG,QAAQ,CACjB,CAAC,CAAC,WAAW,EAAE,aAAa,EAC5B,8BAA8B,EAC9B,2BAA2B,CAC5B,CAAC;gBACF,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;SACF;QACD,QAAQ,EAAE;YACR,iBAAiB,CAAC,KAAK;gBACrB,MAAM,EAAE,GAAG,QAAQ,CACjB,CAAC,CAAC,QAAQ,EAAE,iBAAiB,EAC7B,2BAA2B,EAC3B,4BAA4B,CAC7B,CAAC;gBACF,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;SACF;QACD,UAAU,EAAE;YACV,IAAI,qBAAqB;gBACvB,OAAO,QAAQ,CACb,CAAC,CAAC,UAAU,EAAE,qBAAqB,EACnC,mCAAmC,EACnC,kCAAkC,CACnC,CAAC;YACJ,CAAC;SACF;QACD,GAAG,EAAE;YACH,IAAI,cAAc;gBAChB,OAAO,QAAQ,CACb,CAAC,CAAC,GAAG,EAAE,cAAc,EACrB,sBAAsB,EACtB,oBAAoB,CACrB,CAAC;YACJ,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /** The `@deepseek-ai/dsh-llm` surface the facades forward to. */
2
+ export interface LlmModule {
3
+ createUserMessage?: (input: unknown) => unknown;
4
+ deepFreeze?: <T>(value: T) => T;
5
+ /** Streaming content-block assembler; surfaced through `dshLoader.dsh.llm`. */
6
+ BlockAssembler?: unknown;
7
+ }
8
+ /** The `llm` facade exposed on the host API. */
9
+ export interface LlmAPI {
10
+ /**
11
+ * Build one identified, frozen user-role message.
12
+ *
13
+ * @param input - complete content and source for a new user message.
14
+ * @returns the immutable message.
15
+ * @throws when `@deepseek-ai/dsh-llm` is unavailable — callers building a
16
+ * message have no meaningful fallback, so this fails loudly rather than
17
+ * handing back something the agent loop would reject.
18
+ */
19
+ createUserMessage(input: unknown): unknown;
20
+ /**
21
+ * Deep-freeze a value with dsh's own helper (so frozen-ness matches what the
22
+ * runtime expects). Falls back to `Object.freeze` on the top level when the
23
+ * module is unavailable.
24
+ */
25
+ deepFreeze<T>(value: T): T;
26
+ }
27
+ /** Build the `ctx.dshLoader.llm` facade. */
28
+ export declare function createLlmAPI(opts: {
29
+ module?: LlmModule;
30
+ }): LlmAPI;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * LLM stable API (`ctx.dshLoader.llm`).
3
+ *
4
+ * Message CONSTRUCTION helpers are module-level exports of
5
+ * `@deepseek-ai/dsh-llm`, not methods on a cordis service, so
6
+ * `services.get('llm')` cannot reach them — a plugin that needs
7
+ * `createUserMessage` would otherwise have to import `@deepseek-ai/*`
8
+ * directly and lose its decoupling.
9
+ *
10
+ * Inference itself stays on the service: `services.get('llm').stream(...)`.
11
+ * This facade deliberately covers only the module-level helpers.
12
+ *
13
+ * @module @dsh-plugin/dsh-loader/services/llm
14
+ */
15
+ import { LOG_PREFIX } from '../version.js';
16
+ /** Build the `ctx.dshLoader.llm` facade. */
17
+ export function createLlmAPI(opts) {
18
+ const { module } = opts;
19
+ return {
20
+ createUserMessage(input) {
21
+ const make = module?.createUserMessage;
22
+ if (typeof make !== 'function') {
23
+ throw new Error(`${LOG_PREFIX}:llm.createUserMessage — @deepseek-ai/dsh-llm is unavailable; cannot construct a message`);
24
+ }
25
+ return make(input);
26
+ },
27
+ deepFreeze(value) {
28
+ const freeze = module?.deepFreeze;
29
+ if (typeof freeze === 'function')
30
+ return freeze(value);
31
+ return Object.freeze(value);
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AA8B3C,4CAA4C;AAC5C,MAAM,UAAU,YAAY,CAAC,IAA4B;IACvD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,OAAO;QACL,iBAAiB,CAAC,KAAK;YACrB,MAAM,IAAI,GAAG,MAAM,EAAE,iBAAiB,CAAC;YACvC,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,0FAA0F,CACxG,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,UAAU,CAAC,KAAK;YACd,MAAM,MAAM,GAAG,MAAM,EAAE,UAAU,CAAC;YAClC,IAAI,OAAO,MAAM,KAAK,UAAU;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YACvD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,144 @@
1
+ import type { CordisContext } from '../types.js';
2
+ /** A live tool definition as the tools registry holds it (shape kept loose on purpose). */
3
+ export interface ToolDefinitionLike {
4
+ name?: string;
5
+ description?: string;
6
+ parameters?: Record<string, unknown>;
7
+ execute?: (args: Record<string, unknown>, exec: unknown) => Promise<unknown>;
8
+ [key: string]: unknown;
9
+ }
10
+ /** One permission preset row as the `permissionPresets` table stores it. */
11
+ export interface PermissionPresetLike {
12
+ sandbox: string;
13
+ approval: string;
14
+ name?: string;
15
+ description?: string;
16
+ [key: string]: unknown;
17
+ }
18
+ /** The optional dsh modules the facades need, resolved once at boot. */
19
+ export interface RegistryModules {
20
+ /** `@deepseek-ai/dsh-sandbox` — for `ESCALATION_TARGETS`. */
21
+ sandbox?: {
22
+ ESCALATION_TARGETS?: readonly string[];
23
+ };
24
+ /** `@deepseek-ai/dsh-permission-presets` — for `effectivePermissionPreset`. */
25
+ permissionPresets?: {
26
+ effectivePermissionPreset?: (events: readonly unknown[]) => string | undefined;
27
+ };
28
+ /**
29
+ * `@deepseek-ai/dsh-settings` — the settings facade DELEGATES to these rather
30
+ * than reimplementing them. `installSettingsSection` in particular carries
31
+ * real upstream behaviour (register `base` from the composition entry, point
32
+ * the source thunk at the resolved scope, fall back to the entry when the
33
+ * service goes away, all riding the scoped fiber); copying that into a shim
34
+ * would be a bug farm.
35
+ */
36
+ settings?: {
37
+ installSettingsSection?: (ctx: unknown, ns: unknown, schema: unknown, entry: unknown, hooks: unknown) => void;
38
+ settingsNamespace?: (id: string) => unknown;
39
+ SettingsConflictError?: new (...args: never[]) => Error;
40
+ };
41
+ /**
42
+ * `@deepseek-ai/dsh-llm` — message-construction helpers are MODULE-level
43
+ * exports, not service methods, so `services.get('llm')` cannot reach them.
44
+ */
45
+ llm?: import('./llm.js').LlmModule;
46
+ /** `@deepseek-ai/dsh-tools` — `defineTool` / `ToolArgsError` are module-level. */
47
+ tools?: {
48
+ defineTool?: unknown;
49
+ ToolArgsError?: unknown;
50
+ };
51
+ /** `@deepseek-ai/dsh-timeout` — `deadline` / `MAX_TIMER_DELAY_MS`. */
52
+ timeout?: {
53
+ deadline?: unknown;
54
+ MAX_TIMER_DELAY_MS?: number;
55
+ };
56
+ /** `@deepseek-ai/dsh-credentials` — `credentialRef`. */
57
+ credentials?: {
58
+ credentialRef?: unknown;
59
+ };
60
+ /** `@deepseek-ai/dsh-subagent` — `delegationDepthOf`. */
61
+ subagent?: {
62
+ delegationDepthOf?: unknown;
63
+ };
64
+ /** `@deepseek-ai/dsh-compaction-basic` — the `BasicCompactionEngine` base class. */
65
+ compaction?: {
66
+ BasicCompactionEngine?: unknown;
67
+ };
68
+ }
69
+ /**
70
+ * Load the optional dsh modules the facades proxy.
71
+ *
72
+ * The specifiers are held in variables so TypeScript does not try to resolve
73
+ * them at build time: dshloader declares no `@deepseek-ai/*` dependency, and
74
+ * these packages only exist in the dsh runtime that loads the profile.
75
+ *
76
+ * @returns whatever resolved; a missing module simply stays `undefined`.
77
+ */
78
+ export declare function preloadRegistryModules(): Promise<RegistryModules>;
79
+ /** Tool-registry accessors. */
80
+ export interface ToolsRegistryAPI {
81
+ /** Every registered tool definition; `[]` when the registry shape is unreachable. */
82
+ list(): ToolDefinitionLike[];
83
+ /** One definition by tool name. */
84
+ get(name: string): ToolDefinitionLike | undefined;
85
+ /**
86
+ * Run `patcher` over every registered definition now and after every
87
+ * `tools/change`, so load order between this plugin and the tool plugins does
88
+ * not matter.
89
+ *
90
+ * A definition is handed to a given `id` at most once (a non-enumerable
91
+ * `Symbol.for` marker on the definition), which is what stops a `tools/change`
92
+ * storm from wrapping `execute` again and again.
93
+ *
94
+ * @param patcher - mutates one live definition; throwing is contained and logged.
95
+ * @param options.id - stable patch id, used for the once-per-definition marker.
96
+ * @returns a disposer that stops the replay (already-applied patches stay).
97
+ */
98
+ patchAll(patcher: (def: ToolDefinitionLike) => void, options: {
99
+ id: string;
100
+ }): () => void;
101
+ }
102
+ /** Sandbox-registry accessors. */
103
+ export interface SandboxRegistryAPI {
104
+ /** The escalation modes escalation tools advertise; `[]` when unreachable. */
105
+ escalationTargets(): readonly string[];
106
+ /**
107
+ * Advertise one extra escalation mode (idempotent).
108
+ * @returns a disposer removing the mode again; a no-op when unreachable.
109
+ */
110
+ addEscalationTarget(mode: string): () => void;
111
+ }
112
+ /** Permission-preset registry accessors. */
113
+ export interface PermissionPresetsRegistryAPI {
114
+ /** The live preset table, or `undefined` when the service is absent. */
115
+ table(): Record<string, PermissionPresetLike> | undefined;
116
+ /**
117
+ * Define a preset unless the key already exists (declaration in a
118
+ * `cordis.patch.yml` layer wins).
119
+ * @returns a disposer removing only a preset this call actually added.
120
+ */
121
+ define(key: string, preset: PermissionPresetLike): () => void;
122
+ /**
123
+ * Fold a session's effective permission-preset key from its event log.
124
+ * @returns the preset key, or `undefined` when the helper is unavailable.
125
+ */
126
+ effective(events: readonly unknown[]): string | undefined;
127
+ }
128
+ /** The `registry` facade exposed on the host API. */
129
+ export interface RegistryAPI {
130
+ tools: ToolsRegistryAPI;
131
+ sandbox: SandboxRegistryAPI;
132
+ permissionPresets: PermissionPresetsRegistryAPI;
133
+ }
134
+ /**
135
+ * Build the `ctx.dshLoader.registry` facade.
136
+ *
137
+ * @param opts.ctx - the cordis context (services are read lazily, never cached,
138
+ * so a service arriving later is still picked up).
139
+ * @param opts.modules - optional dsh modules from {@link preloadRegistryModules}.
140
+ */
141
+ export declare function createRegistryAPI(opts: {
142
+ ctx: CordisContext;
143
+ modules?: RegistryModules;
144
+ }): RegistryAPI;