@aiwayds/dsh-llm-proxy 0.5.0 → 0.7.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 CHANGED
@@ -21,7 +21,7 @@ LLM 列表命中 > SYSTEM proxy(env 语义)> 直连
21
21
 
22
22
  ```bash
23
23
  # 方式一:作为 npm 插件加入 profile
24
- dsh plugin add @aiwayds/dsh-llm-proxy # 或在 settings.yaml 的 plugins 里声明
24
+ dsh plugin add @aiwayds/dsh-llm-proxy
25
25
 
26
26
  # 方式二:手动 patch 挂载(本包自带 cordis.patch.yml)
27
27
  # 在 profile 的 bundles 中插入:
@@ -29,7 +29,7 @@ dsh plugin add @aiwayds/dsh-llm-proxy # 或在 settings.yaml 的 plugins 里
29
29
  # name: '@aiwayds/dsh-llm-proxy'
30
30
  ```
31
31
 
32
- > **要求 dsh >= 0.1.5-rc.2** — 本插件只跟随 dsh RC/stable 线(CI 与发版在运行时解析 latest/next 中更新的 dist-tag)。**不再支持 alpha 线。**
32
+ > **要求 dsh >= 0.1.7-rc.1** — 本插件只跟随 dsh RC/stable 线(CI 与发版在运行时解析 latest/next 中更新的 dist-tag)。**不再支持 alpha 线。**
33
33
 
34
34
  > ⚠️ 最低宿主要求:0.2.0 起本插件声明 `inject: ['skills']`,要求宿主 dsh 提供 skills
35
35
  > 服务(`@deepseek-ai/dsh-skill` 0.1.1-rc 系列+)。无该服务的旧宿主上,本插件(含代理
@@ -81,36 +81,42 @@ rm -r ~/.agents/skills/dsh-llm-proxy-config # npx skills add 装出的条目
81
81
  (devDependencies 保留供本地构建)。请勿把它们挪进 dependencies——那会装出第二份
82
82
  cordis 闭包,导致双实例崩溃(详见 dsh 生态 link-dsh-closure 机制)。
83
83
 
84
- ## 配置入口(settings.yaml 命名空间段)
84
+ ## 配置入口(插件 entry config / 设置页)
85
85
 
86
- dsh 插件的用户配置唯一入口是 **settings.yaml 里按插件 id 命名的命名空间段**。本插件通过
87
- `@deepseek-ai/dsh-settings`(要求 `>=0.1.5-rc.2`)settings provider 的
88
- `installSection` 注册了 `dsh-llm-proxy` 命名空间
89
- (与 harness 内置插件 `llm-deepseek` 的 `llm-deepseek:` 段同机制),所以请在
90
- `~/.dsh/settings.yaml` 写:
86
+ dsh 0.1.7 起,插件配置 = **插件声明的 static Config schema**(声明即注册):本插件为
87
+ entry `dsh-llm-proxy` 声明了 `enabled` / `systemMode` / `llmProxy` 三个字段且全部
88
+ `.volatile()`,宿主据此在设置页生成表单,用户值落在 profile patch 里该 entry 的
89
+ `config:` 段;设置页改动**免重启热生效**(volatile-only 写入不重挂插件,本插件原地
90
+ 重建 router,值未变的写入自动跳过重建)。
91
91
 
92
92
  ```yaml
93
- dsh-llm-proxy:
94
- enabled: true # 总开关,默认 true;false 时完全不动全局
95
- systemMode: env # 'env'(默认,读环境变量)| 'off'(全部直连,仅 llmProxy 生效)
96
- llmProxy: # 匹配列表,按顺序首条命中生效
97
- - match: "api.deepseek.org" # 域名精确匹配(含任意端口)
98
- proxy: "http://127.0.0.1:7890"
99
- - match: "*.volces.com" # 通配:volces.com 本身 + 任意子域
100
- proxy: "http://127.0.0.1:7891"
101
- - match: "https://api.openai.com" # 完整 origin 精确匹配(大小写不敏感)
102
- proxy: "http://127.0.0.1:7892"
93
+ # profile 的 cordis.patch.yml(设置页写入也落在这里):
94
+ - id: dsh-llm-proxy
95
+ config:
96
+ enabled: true # 总开关,默认 true;false 时完全不动全局
97
+ systemMode: env # 'env'(默认,读环境变量)| 'off'(全部直连,仅 llmProxy 生效)
98
+ llmProxy: # 匹配列表,按顺序首条命中生效
99
+ - match: "api.deepseek.org" # 域名精确匹配(含任意端口)
100
+ proxy: "http://127.0.0.1:7890"
101
+ - match: "*.volces.com" # 通配:volces.com 本身 + 任意子域
102
+ proxy: "http://127.0.0.1:7891"
103
+ - match: "https://api.openai.com" # 完整 origin 精确匹配(大小写不敏感)
104
+ proxy: "http://127.0.0.1:7892"
103
105
  ```
104
106
 
105
107
  要点:
106
108
 
107
- - **顶层键必须是 `dsh-llm-proxy:`**(与插件 id 一致)。写其他键(如 `llm-proxy:`)不会
108
- 被读到,静默失效。
109
- - 编辑 settings.yaml **热生效**:settings provider 发布变更后,插件会拆掉旧 router、按新
110
- 配置重建,无需重启。
109
+ - **旧 `settings.yaml` 的 `dsh-llm-proxy:` 段自动迁移**:0.1.7 宿主启动时把旧
110
+ settings.yaml 各段按「段名 = entry id」一次性导入 profile patch。本插件旧段名与
111
+ entry id 同为 `dsh-llm-proxy`、三个键都在 volatile Config 里,存量用户值零手工迁移
112
+ (导入后旧文件被宿主改名为 `settings.yaml.imported`)。
113
+ - **entry id 必须是 `dsh-llm-proxy`**(bundle patch insert 的 id)。旧 settings.yaml 段名
114
+ 写成其他键(如 `llm-proxy:`)不会被导入,静默失效。
115
+ - 编辑 **热生效**:volatile-only 改动不重挂插件,插件拆掉旧 router、按新配置原地重建,
116
+ 无需重启。
111
117
  - bundle entry config(`cordis.patch.yml` insert 行的 `config:`)作为 base 层仍然有效;
112
- settings.yaml 段覆盖其上的同名键。
113
- - 未挂载 settings 服务的宿主自动回退到 entry config,插件照常工作。
118
+ profile patch/设置页值覆盖其上的同名键。
119
+ - 未挂载 settings 服务的宿主上,事件订阅自动休眠,entry config 照常生效。
114
120
 
115
121
  ### match 规则
116
122
 
@@ -159,7 +165,7 @@ undici `ProxyAgent` 只支持 **http:// 与 https://** 上游代理。
159
165
  ```bash
160
166
  # 1. 配一个本地回显代理(如 clash/mihomo 的 mixed-port 7890)
161
167
  export HTTPS_PROXY=http://127.0.0.1:7890
162
- # 2. settings.yaml 配 dsh-llm-proxy 段,把某个 API 域名指到另一端口
168
+ # 2. 给 dsh-llm-proxy entry 配 llmProxy(设置页/profile patch),把某个 API 域名指到另一端口
163
169
  # 3. 启动 dsh 后发起对话,观察代理访问日志:
164
170
  # - llmProxy 命中域名的请求出现在该条代理日志里
165
171
  # - 其他外网请求出现在 7890 日志里
package/icon.svg ADDED
@@ -0,0 +1,5 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M12 3.5 20.5 12 12 20.5 3.5 12Z"/>
3
+ <path d="M1.5 12h2M20.5 12h2"/>
4
+ <circle cx="12" cy="12" r="1.2"/>
5
+ </svg>
package/lib/index.d.ts CHANGED
@@ -14,13 +14,16 @@
14
14
  * apply() also registers a bundled skill (skills/dsh-llm-proxy-config/SKILL.md) that
15
15
  * carries the plugin's configuration and troubleshooting guide.
16
16
  *
17
- * User configuration arrives exclusively through the `dsh-llm-proxy`
18
- * settings.yaml namespace (registered via the settings provider's
19
- * installSection, the same seam harness core plugins use); the bundle entry
20
- * config is the base layer.
21
- * Edits to the settings section hot-publish: the router is rebuilt in place,
22
- * unless the resolved values are unchanged, in which case the rebuild is
23
- * skipped (the settings attach itself fires one redundant onChange).
17
+ * User configuration is declared as the plugin's static Config schema
18
+ * (`apply.Config`, the dsh >= 0.1.7-rc.1 settings system): every field is
19
+ * `.volatile()`, so the settings page can edit all of them and volatile-only
20
+ * writes swap the live references in place without remounting the plugin. The
21
+ * host's `settings/document-updated` event for this entry triggers a rejudge
22
+ * that rebuilds the router in place — unless the resolved values are
23
+ * unchanged, in which case the rebuild is skipped. Legacy `settings.yaml`
24
+ * sections are imported once by the host at startup (the old namespace equals
25
+ * the bundle entry id `dsh-llm-proxy`, so existing user values carry over);
26
+ * the bundle entry config remains the base layer under profile patches.
24
27
  *
25
28
  * Environment variables are only read, never written: mutating
26
29
  * process.env.HTTP_PROXY in an already-started process has no effect on
@@ -28,7 +31,7 @@
28
31
  *
29
32
  * @module @aiwayds/dsh-llm-proxy
30
33
  */
31
- import type { Context } from '@deepseek-ai/cordis';
34
+ import type { Context, Volatile } from '@deepseek-ai/cordis';
32
35
  import z from '@deepseek-ai/schemastery';
33
36
  import * as undici from 'undici';
34
37
  import { type LlmProxyEntry } from './router.ts';
@@ -37,8 +40,29 @@ export { createProxyRouterDispatcher, resolveRoute, type LlmProxyEntry, type Rou
37
40
  export declare const name = "dsh-llm-proxy";
38
41
  /** Service required by the bundled skill provider. */
39
42
  export declare const inject: string[];
40
- /** Plugin configuration. */
43
+ /**
44
+ * Runtime plugin configuration as injected into {@link apply}: every field is
45
+ * a live volatile reference declared in the static {@link Config} schema. The
46
+ * host swaps the references in place on settings-page edits (no plugin
47
+ * remount); `.get()` returns a deep-frozen snapshot of the current values.
48
+ */
41
49
  export interface Config {
50
+ /** Master switch; `false` leaves globals untouched (default `true`). */
51
+ enabled: Volatile<boolean>;
52
+ /**
53
+ * Fallback mode for requests no llmProxy entry matches (default `env`):
54
+ * `env` applies HTTPS_PROXY / HTTP_PROXY / ALL_PROXY / NO_PROXY from the
55
+ * startup environment; `off` connects directly.
56
+ */
57
+ systemMode: Volatile<'env' | 'off'>;
58
+ /** Ordered LLM proxy list; the first entry whose match hits wins. */
59
+ llmProxy: Volatile<Array<{
60
+ match: string;
61
+ proxy: string;
62
+ }>>;
63
+ }
64
+ /** Plain (unwrapped) plugin configuration values, e.g. from an entry patch. */
65
+ export interface ConfigInput {
42
66
  /** Master switch; `false` leaves globals untouched (default `true`). */
43
67
  enabled?: boolean;
44
68
  /**
@@ -48,13 +72,42 @@ export interface Config {
48
72
  */
49
73
  systemMode?: 'env' | 'off';
50
74
  /** Ordered LLM proxy list; the first entry whose match hits wins. */
51
- llmProxy?: Array<{
75
+ llmProxy?: ReadonlyArray<{
52
76
  match: string;
53
77
  proxy: string;
54
78
  }>;
55
79
  }
56
- /** Runtime schema for {@link Config}. */
57
- export declare const Config: z<Config>;
80
+ /**
81
+ * Static config schema for the plugin: declaration is registration in the
82
+ * 0.1.7 settings system — the host projects this schema into the entry's
83
+ * settings form (keyed by the entry id {@link ENTRY_ID}) and resolves entry
84
+ * configs through it. All three fields are user-adjustable proxy policy and
85
+ * are marked `.volatile()` so the settings page offers them with hot reload:
86
+ * volatile-only edits never remount the plugin, and {@link apply} rebuilds
87
+ * the router in place when the values actually change. Every field carries a
88
+ * `.default()` so an unconfigured entry still resolves fully populated.
89
+ */
90
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
91
+ enabled: z<boolean, boolean, "volatile-defined">;
92
+ systemMode: z<"env" | "off", "env" | "off", "volatile-defined">;
93
+ llmProxy: z<NoInfer<({
94
+ match?: string | null | undefined;
95
+ proxy?: string | null | undefined;
96
+ } & import("@deepseek-ai/cosmokit").Dict)[]>, NoInfer<Schemastery.ObjectT<NoInfer<{
97
+ match: z<string, string, "plain">;
98
+ proxy: z<string, string, "plain">;
99
+ }>>[]>, "volatile-defined">;
100
+ }>>, Schemastery.ObjectT<NoInfer<{
101
+ enabled: z<boolean, boolean, "volatile-defined">;
102
+ systemMode: z<"env" | "off", "env" | "off", "volatile-defined">;
103
+ llmProxy: z<NoInfer<({
104
+ match?: string | null | undefined;
105
+ proxy?: string | null | undefined;
106
+ } & import("@deepseek-ai/cosmokit").Dict)[]>, NoInfer<Schemastery.ObjectT<NoInfer<{
107
+ match: z<string, string, "plain">;
108
+ proxy: z<string, string, "plain">;
109
+ }>>[]>, "volatile-defined">;
110
+ }>>, "plain">;
58
111
  /**
59
112
  * Mask the userinfo part of a proxy URL ("user:pass@host") so log lines and
60
113
  * error messages never carry credentials.
@@ -68,9 +121,9 @@ export interface ResolvedConfig {
68
121
  }
69
122
  /**
70
123
  * Validate, default, and freeze the plugin configuration.
71
- * @param config - optional plugin configuration; omission selects defaults.
124
+ * @param config - optional plain configuration values; omission selects defaults.
72
125
  */
73
- export declare function resolveConfig(config: Config | undefined): ResolvedConfig;
126
+ export declare function resolveConfig(config: ConfigInput | undefined): ResolvedConfig;
74
127
  /** Injectable seams for tests; production defaults build real undici agents. */
75
128
  export interface ApplyInternals {
76
129
  /**
@@ -93,11 +146,35 @@ export interface ApplyInternals {
93
146
  */
94
147
  export declare function stripFrontmatter(raw: string): string;
95
148
  /**
96
- * Install the global routing dispatcher, wire the `dsh-llm-proxy` settings
97
- * namespace, register the bundled skill provider, and register teardown.
149
+ * Install the global routing dispatcher, subscribe to this entry's settings
150
+ * updates, register the bundled skill provider, and register teardown.
98
151
  * @param ctx - plugin context owning the dispose effect.
99
- * @param config - composition entry config; the base layer under the
100
- * settings.yaml `dsh-llm-proxy` section.
152
+ * @param config - live volatile references resolved from the entry config
153
+ * through the static {@link Config} schema (the base layer under the
154
+ * user's profile patch / imported settings section); omission selects the
155
+ * schema defaults.
101
156
  * @param internals - injectable dispatcher factories for tests.
102
157
  */
103
- export declare function apply(ctx: Context, config?: Config, internals?: ApplyInternals): void;
158
+ export declare const apply: ((ctx: Context, config?: Config, internals?: ApplyInternals) => void) & {
159
+ Config: z<Schemastery.ObjectS<NoInfer<{
160
+ enabled: z<boolean, boolean, "volatile-defined">;
161
+ systemMode: z<"env" | "off", "env" | "off", "volatile-defined">;
162
+ llmProxy: z<NoInfer<({
163
+ match?: string | null | undefined;
164
+ proxy?: string | null | undefined;
165
+ } & import("@deepseek-ai/cosmokit").Dict)[]>, NoInfer<Schemastery.ObjectT<NoInfer<{
166
+ match: z<string, string, "plain">;
167
+ proxy: z<string, string, "plain">;
168
+ }>>[]>, "volatile-defined">;
169
+ }>>, Schemastery.ObjectT<NoInfer<{
170
+ enabled: z<boolean, boolean, "volatile-defined">;
171
+ systemMode: z<"env" | "off", "env" | "off", "volatile-defined">;
172
+ llmProxy: z<NoInfer<({
173
+ match?: string | null | undefined;
174
+ proxy?: string | null | undefined;
175
+ } & import("@deepseek-ai/cosmokit").Dict)[]>, NoInfer<Schemastery.ObjectT<NoInfer<{
176
+ match: z<string, string, "plain">;
177
+ proxy: z<string, string, "plain">;
178
+ }>>[]>, "volatile-defined">;
179
+ }>>, "plain">;
180
+ };
package/lib/index.js CHANGED
@@ -14,13 +14,16 @@
14
14
  * apply() also registers a bundled skill (skills/dsh-llm-proxy-config/SKILL.md) that
15
15
  * carries the plugin's configuration and troubleshooting guide.
16
16
  *
17
- * User configuration arrives exclusively through the `dsh-llm-proxy`
18
- * settings.yaml namespace (registered via the settings provider's
19
- * installSection, the same seam harness core plugins use); the bundle entry
20
- * config is the base layer.
21
- * Edits to the settings section hot-publish: the router is rebuilt in place,
22
- * unless the resolved values are unchanged, in which case the rebuild is
23
- * skipped (the settings attach itself fires one redundant onChange).
17
+ * User configuration is declared as the plugin's static Config schema
18
+ * (`apply.Config`, the dsh >= 0.1.7-rc.1 settings system): every field is
19
+ * `.volatile()`, so the settings page can edit all of them and volatile-only
20
+ * writes swap the live references in place without remounting the plugin. The
21
+ * host's `settings/document-updated` event for this entry triggers a rejudge
22
+ * that rebuilds the router in place — unless the resolved values are
23
+ * unchanged, in which case the rebuild is skipped. Legacy `settings.yaml`
24
+ * sections are imported once by the host at startup (the old namespace equals
25
+ * the bundle entry id `dsh-llm-proxy`, so existing user values carry over);
26
+ * the bundle entry config remains the base layer under profile patches.
24
27
  *
25
28
  * Environment variables are only read, never written: mutating
26
29
  * process.env.HTTP_PROXY in an already-started process has no effect on
@@ -41,25 +44,30 @@ export const name = 'dsh-llm-proxy';
41
44
  /** Service required by the bundled skill provider. */
42
45
  export const inject = ['skills'];
43
46
  /**
44
- * The settings.yaml namespace this plugin owns. dsh feeds user configuration
45
- * to plugins only through registered settings namespaces; the document
46
- * section key that reaches this plugin is exactly this string.
47
- *
48
- * A plain literal is the supported spelling since dsh-settings
49
- * 0.1.2-alpha.3: `register`/`installSection` brand-check the namespace at the
50
- * type level (`SettingsNamespaceInput`) and validate the same pattern at
51
- * runtime (`parseSettingsNamespace`), replacing the removed
52
- * `settingsNamespace()` helper.
47
+ * The bundle entry id this plugin mounts under (the `cordis.patch.yml`
48
+ * insert). In the 0.1.7 settings system the entry id doubles as the settings
49
+ * document namespace: `settings/document-updated` events for this id concern
50
+ * this plugin's form. It equals the pre-0.1.7 settings.yaml namespace, so
51
+ * legacy user sections are imported by the host into this entry unchanged.
52
+ */
53
+ const ENTRY_ID = 'dsh-llm-proxy';
54
+ /**
55
+ * Static config schema for the plugin: declaration is registration in the
56
+ * 0.1.7 settings system — the host projects this schema into the entry's
57
+ * settings form (keyed by the entry id {@link ENTRY_ID}) and resolves entry
58
+ * configs through it. All three fields are user-adjustable proxy policy and
59
+ * are marked `.volatile()` so the settings page offers them with hot reload:
60
+ * volatile-only edits never remount the plugin, and {@link apply} rebuilds
61
+ * the router in place when the values actually change. Every field carries a
62
+ * `.default()` so an unconfigured entry still resolves fully populated.
53
63
  */
54
- const SETTINGS_NAMESPACE = 'dsh-llm-proxy';
55
- /** Runtime schema for {@link Config}. */
56
64
  export const Config = z.object({
57
- enabled: z.boolean().default(true),
58
- systemMode: z.union([z.const('env'), z.const('off')]).default('env'),
65
+ enabled: z.boolean().default(true).volatile(),
66
+ systemMode: z.union([z.const('env'), z.const('off')]).default('env').volatile(),
59
67
  llmProxy: z.array(z.object({
60
68
  match: z.string(),
61
69
  proxy: z.string(),
62
- })),
70
+ })).default([]).volatile(),
63
71
  });
64
72
  const CONFIG_KEYS = new Set(['enabled', 'systemMode', 'llmProxy']);
65
73
  /**
@@ -96,7 +104,7 @@ function validateProxyUrl(proxy, index) {
96
104
  }
97
105
  /**
98
106
  * Validate, default, and freeze the plugin configuration.
99
- * @param config - optional plugin configuration; omission selects defaults.
107
+ * @param config - optional plain configuration values; omission selects defaults.
100
108
  */
101
109
  export function resolveConfig(config) {
102
110
  if (config !== undefined) {
@@ -183,7 +191,7 @@ const SKILL_RESOURCE_BASE = {
183
191
  };
184
192
  const SKILL_INVOCATION = { modelInvocable: true, userInvocable: true };
185
193
  /** Routing description; must stay identical to the SKILL.md frontmatter (asserted in tests). */
186
- const SKILL_DESCRIPTION = 'dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:settings.yaml 顶层 `dsh-llm-proxy:` 段(enabled/systemMode/llmProxy)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。';
194
+ const SKILL_DESCRIPTION = 'dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:`dsh-llm-proxy` 插件配置(enabled/systemMode/llmProxy,设置页可改、免重启热更;旧 settings.yaml `dsh-llm-proxy:` 段启动时自动导入)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。';
187
195
  const SKILL_CANDIDATE = {
188
196
  name: SKILL_PROVIDER_NAME,
189
197
  description: SKILL_DESCRIPTION,
@@ -237,23 +245,23 @@ export function stripFrontmatter(raw) {
237
245
  return raw;
238
246
  }
239
247
  /**
240
- * Install the global routing dispatcher, wire the `dsh-llm-proxy` settings
241
- * namespace, register the bundled skill provider, and register teardown.
248
+ * Install the global routing dispatcher, subscribe to this entry's settings
249
+ * updates, register the bundled skill provider, and register teardown.
242
250
  * @param ctx - plugin context owning the dispose effect.
243
- * @param config - composition entry config; the base layer under the
244
- * settings.yaml `dsh-llm-proxy` section.
251
+ * @param config - live volatile references resolved from the entry config
252
+ * through the static {@link Config} schema (the base layer under the
253
+ * user's profile patch / imported settings section); omission selects the
254
+ * schema defaults.
245
255
  * @param internals - injectable dispatcher factories for tests.
246
256
  */
247
- export function apply(ctx, config = {}, internals = {}) {
257
+ export const apply = Object.assign(function apply(ctx, config = Config({}), internals = {}) {
248
258
  // `inject = ['skills']` guarantees the service exists on every real host;
249
259
  // register unconditionally so a missing service fails loud instead of
250
260
  // silently dropping the bundled skill.
251
261
  ctx.skills.registerProvider(() => skillProvider);
252
- // Current authoritative config source: the entry until a settings scope
253
- // layers the user's settings.yaml section on top (and back to the entry if
254
- // the settings provider detaches). The seam hands over a thunk so every
255
- // rejudge reads the live layered value instead of a stale snapshot.
256
- let getSource = () => config;
262
+ // The volatile references above ARE the authoritative config source: the
263
+ // host swaps them in place on volatile-only settings edits, so every
264
+ // rejudge reads the current layered value directly through `.get()`.
257
265
  let active;
258
266
  let activePolicy;
259
267
  let effectRegistered = false;
@@ -289,7 +297,11 @@ export function apply(ctx, config = {}, internals = {}) {
289
297
  const rejudge = (failFast) => {
290
298
  let policy;
291
299
  try {
292
- policy = resolveConfig(getSource());
300
+ policy = resolveConfig({
301
+ enabled: config.enabled.get(),
302
+ systemMode: config.systemMode.get(),
303
+ llmProxy: config.llmProxy.get(),
304
+ });
293
305
  }
294
306
  catch (error) {
295
307
  if (failFast)
@@ -297,10 +309,9 @@ export function apply(ctx, config = {}, internals = {}) {
297
309
  ctx.logger?.error('dsh-llm-proxy: ignoring invalid settings update, keeping current routing: %s', error instanceof Error ? error.message : String(error));
298
310
  return;
299
311
  }
300
- // Attaching the settings scope fires onChange unconditionally, even when
301
- // the layered section resolves to the same values as the entry base
302
- // layer; rebuilding then would tear down and reinstall an identical
303
- // router for nothing. Skip when no resolved value changed.
312
+ // Settings events can announce writes whose resolved policy is identical
313
+ // to the live one; rebuilding then would tear down and reinstall an
314
+ // identical router for nothing. Skip when no resolved value changed.
304
315
  if (activePolicy !== undefined && deepEqualJson(policy, activePolicy))
305
316
  return;
306
317
  if (!policy.enabled) {
@@ -328,24 +339,24 @@ export function apply(ctx, config = {}, internals = {}) {
328
339
  if (previous)
329
340
  teardownLayer(previous);
330
341
  };
331
- // Start immediately with the entry config so the plugin works even on hosts
332
- // that never mount a settings service; when the service appears, the
333
- // layered section takes over and subsequent edits hot-publish here.
342
+ // Start immediately with the resolved entry config so the plugin works even
343
+ // on hosts that never mount a settings service; when the service is
344
+ // present, settings edits arrive as in-place reference swaps announced by
345
+ // the document-updated event, and subsequent edits hot-publish here.
334
346
  rejudge(true);
335
- // Optional-settings consumer wiring. The rc.2 module-level
336
- // installSettingsSection() helper was removed in dsh-settings
337
- // 0.1.2-alpha.3; the attach / detach-fallback / watch body moved behind the
338
- // provider as SettingsProvider.installSection (identical semantics — the
339
- // entry config stays the fallback source when the provider detaches).
340
- // ctx.inject keeps the whole wiring dormant on hosts that never mount a
341
- // settings service.
347
+ // Optional-settings consumer wiring. dsh-settings 0.1.7 deleted
348
+ // SettingsProvider/installSection: the plugin's static Config schema
349
+ // (attached to this function below) is the declaration, volatile-only
350
+ // edits land in the references without a remount, and the settings service
351
+ // announces them per entry id. The ctx.inject keeps the listener dormant on
352
+ // hosts that never mount a settings service; mixed (volatile+ordinary)
353
+ // edits remount the plugin instead, rerunning apply() from the top.
342
354
  ctx.inject(['settings'], (sctx) => {
343
- sctx.settings.installSection(ctx, SETTINGS_NAMESPACE, Config, config, {
344
- setSource: (current) => {
345
- getSource = current;
346
- },
347
- onChange: () => rejudge(false),
355
+ sctx.on('settings/document-updated', (ns) => {
356
+ if (ns !== ENTRY_ID)
357
+ return;
358
+ rejudge(false);
348
359
  });
349
360
  });
350
- }
361
+ }, { Config });
351
362
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "dsh-llm-proxy",
4
+ "description": "System proxy (env) plus LLM traffic-splitting proxy via a process-global undici routing dispatcher."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "dsh-llm-proxy",
4
+ "description": "系统代理(env)与基于进程级 undici 路由 dispatcher 的 LLM 流量分流代理。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@aiwayds/dsh-llm-proxy",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "dsh plugin: SYSTEM proxy (env) + LLM traffic-splitting proxy via a process-global undici routing dispatcher",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
+ "icon": "./icon.svg",
8
9
  "license": "MIT",
9
10
  "keywords": [
10
11
  "dsh",
@@ -27,7 +28,9 @@
27
28
  "lib",
28
29
  "cordis.patch.yml",
29
30
  "src",
30
- "skills"
31
+ "skills",
32
+ "icon.svg",
33
+ "locale/*.json"
31
34
  ],
32
35
  "scripts": {
33
36
  "build": "tsc -p tsconfig.json",
@@ -35,16 +38,17 @@
35
38
  "pretest": "npm run build",
36
39
  "prepare": "npm run build",
37
40
  "test": "node --test test/match.test.mjs test/router.test.mjs test/config.test.mjs test/skill.test.mjs test/dispose.test.mjs test/e2e.test.mjs",
38
- "smoke": "node scripts/smoke-boot.mjs"
41
+ "smoke": "node scripts/smoke-boot.mjs",
42
+ "postinstall": "node scripts/link-dsh-closure.mjs"
39
43
  },
40
44
  "dependencies": {
41
45
  "undici": "8.9.0"
42
46
  },
43
47
  "peerDependencies": {
44
- "@deepseek-ai/cordis": "4.0.2",
45
- "@deepseek-ai/schemastery": "3.18.2",
46
- "@deepseek-ai/dsh-settings": ">=0.1.5-rc.2",
47
- "@deepseek-ai/dsh-skill": ">=0.1.5-rc.2"
48
+ "@deepseek-ai/cordis": "4.0.4",
49
+ "@deepseek-ai/schemastery": "3.18.4",
50
+ "@deepseek-ai/dsh-settings": ">=0.2.0-rc.2",
51
+ "@deepseek-ai/dsh-skill": ">=0.2.0-rc.2"
48
52
  },
49
53
  "peerDependenciesMeta": {
50
54
  "@deepseek-ai/cordis": {
@@ -58,10 +62,10 @@
58
62
  }
59
63
  },
60
64
  "devDependencies": {
61
- "@deepseek-ai/cordis": "4.0.2",
62
- "@deepseek-ai/schemastery": "3.18.2",
63
- "@deepseek-ai/dsh-settings": "0.1.5-rc.2",
64
- "@deepseek-ai/dsh-skill": "0.1.5-rc.2",
65
+ "@deepseek-ai/cordis": "4.0.4",
66
+ "@deepseek-ai/schemastery": "3.18.4",
67
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
68
+ "@deepseek-ai/dsh-skill": "0.2.0-rc.2",
65
69
  "@types/node": "^24.0.0",
66
70
  "typescript": "^5.9.0"
67
71
  },
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dsh-llm-proxy-config
3
- description: "dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:settings.yaml 顶层 `dsh-llm-proxy:` 段(enabled/systemMode/llmProxy)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。"
3
+ description: "dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:`dsh-llm-proxy` 插件配置(enabled/systemMode/llmProxy,设置页可改、免重启热更;旧 settings.yaml `dsh-llm-proxy:` 段启动时自动导入)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。"
4
4
  ---
5
5
 
6
6
  # dsh-llm-proxy 使用指南(LLM 分流代理)
@@ -8,29 +8,33 @@ description: "dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使
8
8
  > dsh 插件:**SYSTEM proxy + LLM 分流代理**。进程级 undici 路由 Dispatcher 把 LLM 流量
9
9
  > 按配置列表分流到指定代理,其余流量走系统代理(启动环境变量),都没配则直连。
10
10
 
11
- ## 配置入口(settings.yaml 顶层命名空间段)
11
+ ## 配置入口(entry config / 设置页)
12
12
 
13
- 在 `~/.dsh/settings.yaml` 写**顶层 `dsh-llm-proxy:` 段**(与插件 id 一致,同 harness 内置
14
- 插件 `llm-deepseek:` 段机制):
13
+ 0.1.7 起配置=插件 entry `dsh-llm-proxy` 的 config(static Config schema 声明,三字段全部
14
+ volatile):设置页表单可改、免重启热生效;用户值落在 profile patch 里该 entry 的 `config:` 段:
15
15
 
16
16
  ```yaml
17
- dsh-llm-proxy:
18
- enabled: true # 总开关,默认 true;false 时完全不动全局
19
- systemMode: env # 'env'(默认,读环境变量)| 'off'(全部直连,仅 llmProxy 生效)
20
- llmProxy: # 匹配列表,按顺序首条命中生效
21
- - match: "api.deepseek.org" # host 精确匹配(含任意端口)
22
- proxy: "http://127.0.0.1:7890"
23
- - match: "*.volces.com" # 通配:volces.com 本身 + 任意子域
24
- proxy: "http://127.0.0.1:7891"
25
- - match: "https://api.openai.com" # 完整 origin 精确匹配(大小写不敏感)
26
- proxy: "http://127.0.0.1:7892"
17
+ - id: dsh-llm-proxy
18
+ config:
19
+ enabled: true # 总开关,默认 true;false 时完全不动全局
20
+ systemMode: env # 'env'(默认,读环境变量)| 'off'(全部直连,仅 llmProxy 生效)
21
+ llmProxy: # 匹配列表,按顺序首条命中生效
22
+ - match: "api.deepseek.org" # host 精确匹配(含任意端口)
23
+ proxy: "http://127.0.0.1:7890"
24
+ - match: "*.volces.com" # 通配:volces.com 本身 + 任意子域
25
+ proxy: "http://127.0.0.1:7891"
26
+ - match: "https://api.openai.com" # 完整 origin 精确匹配(大小写不敏感)
27
+ proxy: "http://127.0.0.1:7892"
27
28
  ```
28
29
 
29
30
  要点:
30
31
 
31
- - 编辑 **热生效**:无需重启,插件拆旧 router 按新配置重建。
32
- - bundle entry config(cordis.patch.yml 的 `config:`)是 base 层;settings.yaml 段覆盖其上
33
- 同名键。未挂载 settings 服务的宿主自动回退 entry config,插件照常工作。
32
+ - **旧 `settings.yaml` 的 `dsh-llm-proxy:` 段自动迁移**:0.1.7 宿主启动时按
33
+ 「段名 = entry id」一次性导入(段内三键均为 volatile,可干净导入),旧文件改名为
34
+ `settings.yaml.imported`。
35
+ - 编辑 **热生效**:无需重启,插件拆旧 router 按新配置原地重建(volatile-only 不重挂插件)。
36
+ - bundle entry config(cordis.patch.yml 的 `config:`)是 base 层;profile patch/设置页值
37
+ 覆盖其上同名键。未挂载 settings 服务的宿主上 entry config 照常生效。
34
38
 
35
39
  ## 优先级语义
36
40
 
@@ -62,8 +66,8 @@ LLM 列表命中 > SYSTEM proxy(env 语义)> 直连
62
66
 
63
67
  ## 排障清单
64
68
 
65
- 1. **完全不生效** → 先查顶层键名:必须是 `dsh-llm-proxy:`;写成 `llm-proxy:` 等其他键
66
- 不会被读到,**静默失效**。
69
+ 1. **完全不生效** → 先查 entry id/旧段名:必须是 `dsh-llm-proxy`;写成 `llm-proxy:` 等
70
+ 其他键不会被读到,**静默失效**。
67
71
  2. **启动即报错** → proxy 用了 `socks5://` 等不支持的 schema;换 http(s) 代理。
68
72
  3. **走了代理但目标返回 407** → 代理自身认证问题,检查代理凭证;本插件日志/error
69
73
  message 中 proxy URL 的 userinfo 一律脱敏为 `***@host`。
package/src/index.ts CHANGED
@@ -14,13 +14,16 @@
14
14
  * apply() also registers a bundled skill (skills/dsh-llm-proxy-config/SKILL.md) that
15
15
  * carries the plugin's configuration and troubleshooting guide.
16
16
  *
17
- * User configuration arrives exclusively through the `dsh-llm-proxy`
18
- * settings.yaml namespace (registered via the settings provider's
19
- * installSection, the same seam harness core plugins use); the bundle entry
20
- * config is the base layer.
21
- * Edits to the settings section hot-publish: the router is rebuilt in place,
22
- * unless the resolved values are unchanged, in which case the rebuild is
23
- * skipped (the settings attach itself fires one redundant onChange).
17
+ * User configuration is declared as the plugin's static Config schema
18
+ * (`apply.Config`, the dsh >= 0.1.7-rc.1 settings system): every field is
19
+ * `.volatile()`, so the settings page can edit all of them and volatile-only
20
+ * writes swap the live references in place without remounting the plugin. The
21
+ * host's `settings/document-updated` event for this entry triggers a rejudge
22
+ * that rebuilds the router in place — unless the resolved values are
23
+ * unchanged, in which case the rebuild is skipped. Legacy `settings.yaml`
24
+ * sections are imported once by the host at startup (the old namespace equals
25
+ * the bundle entry id `dsh-llm-proxy`, so existing user values carry over);
26
+ * the bundle entry config remains the base layer under profile patches.
24
27
  *
25
28
  * Environment variables are only read, never written: mutating
26
29
  * process.env.HTTP_PROXY in an already-started process has no effect on
@@ -31,14 +34,13 @@
31
34
 
32
35
  import { readFile } from 'node:fs/promises'
33
36
  import { fileURLToPath } from 'node:url'
34
- import type { Context } from '@deepseek-ai/cordis'
37
+ import type { Context, Volatile } from '@deepseek-ai/cordis'
35
38
  // Type-only side-effect import: loads dsh-settings' `declare module
36
- // '@deepseek-ai/cordis'` augmentation, which is what puts `ctx.settings` on
37
- // the Context type. There is no runtime import — the host provides the
38
- // settings service; alpha.3 removed the module-level settingsNamespace(),
39
- // installSettingsSection(), and deepEqualJson() helpers this plugin used to
40
- // import (see SETTINGS_NAMESPACE below, the installSection call in apply(),
41
- // and ./deep-equal.ts for their replacements).
39
+ // '@deepseek-ai/cordis'` augmentations, which put `ctx.settings` on the
40
+ // Context type and type the `settings/document-updated` event. There is no
41
+ // runtime import — the host provides the settings service; 0.1.7 replaced the
42
+ // old SettingsProvider/installSection seam with the plugin's static Config
43
+ // schema plus volatile fields (see apply.Config below).
42
44
  import type {} from '@deepseek-ai/dsh-settings'
43
45
  import {
44
46
  BUNDLED_SKILL_RANK,
@@ -60,20 +62,35 @@ export const name = 'dsh-llm-proxy'
60
62
  export const inject = ['skills']
61
63
 
62
64
  /**
63
- * The settings.yaml namespace this plugin owns. dsh feeds user configuration
64
- * to plugins only through registered settings namespaces; the document
65
- * section key that reaches this plugin is exactly this string.
66
- *
67
- * A plain literal is the supported spelling since dsh-settings
68
- * 0.1.2-alpha.3: `register`/`installSection` brand-check the namespace at the
69
- * type level (`SettingsNamespaceInput`) and validate the same pattern at
70
- * runtime (`parseSettingsNamespace`), replacing the removed
71
- * `settingsNamespace()` helper.
65
+ * The bundle entry id this plugin mounts under (the `cordis.patch.yml`
66
+ * insert). In the 0.1.7 settings system the entry id doubles as the settings
67
+ * document namespace: `settings/document-updated` events for this id concern
68
+ * this plugin's form. It equals the pre-0.1.7 settings.yaml namespace, so
69
+ * legacy user sections are imported by the host into this entry unchanged.
72
70
  */
73
- const SETTINGS_NAMESPACE = 'dsh-llm-proxy'
71
+ const ENTRY_ID = 'dsh-llm-proxy'
74
72
 
75
- /** Plugin configuration. */
73
+ /**
74
+ * Runtime plugin configuration as injected into {@link apply}: every field is
75
+ * a live volatile reference declared in the static {@link Config} schema. The
76
+ * host swaps the references in place on settings-page edits (no plugin
77
+ * remount); `.get()` returns a deep-frozen snapshot of the current values.
78
+ */
76
79
  export interface Config {
80
+ /** Master switch; `false` leaves globals untouched (default `true`). */
81
+ enabled: Volatile<boolean>
82
+ /**
83
+ * Fallback mode for requests no llmProxy entry matches (default `env`):
84
+ * `env` applies HTTPS_PROXY / HTTP_PROXY / ALL_PROXY / NO_PROXY from the
85
+ * startup environment; `off` connects directly.
86
+ */
87
+ systemMode: Volatile<'env' | 'off'>
88
+ /** Ordered LLM proxy list; the first entry whose match hits wins. */
89
+ llmProxy: Volatile<Array<{ match: string; proxy: string }>>
90
+ }
91
+
92
+ /** Plain (unwrapped) plugin configuration values, e.g. from an entry patch. */
93
+ export interface ConfigInput {
77
94
  /** Master switch; `false` leaves globals untouched (default `true`). */
78
95
  enabled?: boolean
79
96
  /**
@@ -83,18 +100,27 @@ export interface Config {
83
100
  */
84
101
  systemMode?: 'env' | 'off'
85
102
  /** Ordered LLM proxy list; the first entry whose match hits wins. */
86
- llmProxy?: Array<{ match: string; proxy: string }>
103
+ llmProxy?: ReadonlyArray<{ match: string; proxy: string }>
87
104
  }
88
105
 
89
- /** Runtime schema for {@link Config}. */
106
+ /**
107
+ * Static config schema for the plugin: declaration is registration in the
108
+ * 0.1.7 settings system — the host projects this schema into the entry's
109
+ * settings form (keyed by the entry id {@link ENTRY_ID}) and resolves entry
110
+ * configs through it. All three fields are user-adjustable proxy policy and
111
+ * are marked `.volatile()` so the settings page offers them with hot reload:
112
+ * volatile-only edits never remount the plugin, and {@link apply} rebuilds
113
+ * the router in place when the values actually change. Every field carries a
114
+ * `.default()` so an unconfigured entry still resolves fully populated.
115
+ */
90
116
  export const Config = z.object({
91
- enabled: z.boolean().default(true),
92
- systemMode: z.union([z.const('env'), z.const('off')]).default('env'),
117
+ enabled: z.boolean().default(true).volatile(),
118
+ systemMode: z.union([z.const('env'), z.const('off')]).default('env').volatile(),
93
119
  llmProxy: z.array(z.object({
94
120
  match: z.string(),
95
121
  proxy: z.string(),
96
- })),
97
- }) as unknown as z<Config>
122
+ })).default([]).volatile(),
123
+ })
98
124
 
99
125
  const CONFIG_KEYS: ReadonlySet<string> = new Set(['enabled', 'systemMode', 'llmProxy'])
100
126
 
@@ -140,9 +166,9 @@ export interface ResolvedConfig {
140
166
 
141
167
  /**
142
168
  * Validate, default, and freeze the plugin configuration.
143
- * @param config - optional plugin configuration; omission selects defaults.
169
+ * @param config - optional plain configuration values; omission selects defaults.
144
170
  */
145
- export function resolveConfig(config: Config | undefined): ResolvedConfig {
171
+ export function resolveConfig(config: ConfigInput | undefined): ResolvedConfig {
146
172
  if (config !== undefined) {
147
173
  for (const key of Object.keys(config)) {
148
174
  if (!CONFIG_KEYS.has(key)) throw new Error(`dsh-llm-proxy: config: unknown key "${key}"`)
@@ -279,7 +305,7 @@ const SKILL_RESOURCE_BASE = {
279
305
  const SKILL_INVOCATION = { modelInvocable: true, userInvocable: true } as const
280
306
 
281
307
  /** Routing description; must stay identical to the SKILL.md frontmatter (asserted in tests). */
282
- const SKILL_DESCRIPTION = 'dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:settings.yaml 顶层 `dsh-llm-proxy:` 段(enabled/systemMode/llmProxy)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。'
308
+ const SKILL_DESCRIPTION = 'dsh 出站代理 / LLM 分流插件(@aiwayds/dsh-llm-proxy)使用指南。凡给 dsh 插件配置 HTTP 代理、LLM 出站分流,或排查代理网络问题时先读本指南:`dsh-llm-proxy` 插件配置(enabled/systemMode/llmProxy,设置页可改、免重启热更;旧 settings.yaml `dsh-llm-proxy:` 段启动时自动导入)、llmProxy match 规则、代理 407、CONNECT 挂起、socks5 报错(SOCKS 不支持)、NODE_USE_ENV_PROXY 等价替代。触发词:dsh 代理、HTTP 代理、LLM 分流、llmProxy、llm-proxy、407、CONNECT 挂起、SOCKS、HTTPS_PROXY、NO_PROXY、出站代理、NODE_USE_ENV_PROXY。'
283
309
 
284
310
  const SKILL_CANDIDATE: SkillCandidate = {
285
311
  name: SKILL_PROVIDER_NAME,
@@ -335,26 +361,27 @@ export function stripFrontmatter(raw: string): string {
335
361
  }
336
362
 
337
363
  /**
338
- * Install the global routing dispatcher, wire the `dsh-llm-proxy` settings
339
- * namespace, register the bundled skill provider, and register teardown.
364
+ * Install the global routing dispatcher, subscribe to this entry's settings
365
+ * updates, register the bundled skill provider, and register teardown.
340
366
  * @param ctx - plugin context owning the dispose effect.
341
- * @param config - composition entry config; the base layer under the
342
- * settings.yaml `dsh-llm-proxy` section.
367
+ * @param config - live volatile references resolved from the entry config
368
+ * through the static {@link Config} schema (the base layer under the
369
+ * user's profile patch / imported settings section); omission selects the
370
+ * schema defaults.
343
371
  * @param internals - injectable dispatcher factories for tests.
344
372
  */
345
- export function apply(ctx: Context, config: Config = {}, internals: ApplyInternals = {}): void {
346
- // `inject = ['skills']` guarantees the service exists on every real host;
347
- // register unconditionally so a missing service fails loud instead of
348
- // silently dropping the bundled skill.
349
- ctx.skills.registerProvider(() => skillProvider)
350
- // Current authoritative config source: the entry until a settings scope
351
- // layers the user's settings.yaml section on top (and back to the entry if
352
- // the settings provider detaches). The seam hands over a thunk so every
353
- // rejudge reads the live layered value instead of a stale snapshot.
354
- let getSource: () => Config = () => config
355
- let active: ActiveLayer | undefined
356
- let activePolicy: ResolvedConfig | undefined
357
- let effectRegistered = false
373
+ export const apply = Object.assign(
374
+ function apply(ctx: Context, config: Config = Config({}), internals: ApplyInternals = {}): void {
375
+ // `inject = ['skills']` guarantees the service exists on every real host;
376
+ // register unconditionally so a missing service fails loud instead of
377
+ // silently dropping the bundled skill.
378
+ ctx.skills.registerProvider(() => skillProvider)
379
+ // The volatile references above ARE the authoritative config source: the
380
+ // host swaps them in place on volatile-only settings edits, so every
381
+ // rejudge reads the current layered value directly through `.get()`.
382
+ let active: ActiveLayer | undefined
383
+ let activePolicy: ResolvedConfig | undefined
384
+ let effectRegistered = false
358
385
 
359
386
  function installLayer(policy: ResolvedConfig): ActiveLayer {
360
387
  const systemDispatcher =
@@ -392,7 +419,11 @@ export function apply(ctx: Context, config: Config = {}, internals: ApplyInterna
392
419
  const rejudge = (failFast: boolean): void => {
393
420
  let policy: ResolvedConfig
394
421
  try {
395
- policy = resolveConfig(getSource())
422
+ policy = resolveConfig({
423
+ enabled: config.enabled.get(),
424
+ systemMode: config.systemMode.get(),
425
+ llmProxy: config.llmProxy.get(),
426
+ })
396
427
  } catch (error) {
397
428
  if (failFast) throw error
398
429
  ctx.logger?.error(
@@ -401,10 +432,9 @@ export function apply(ctx: Context, config: Config = {}, internals: ApplyInterna
401
432
  )
402
433
  return
403
434
  }
404
- // Attaching the settings scope fires onChange unconditionally, even when
405
- // the layered section resolves to the same values as the entry base
406
- // layer; rebuilding then would tear down and reinstall an identical
407
- // router for nothing. Skip when no resolved value changed.
435
+ // Settings events can announce writes whose resolved policy is identical
436
+ // to the live one; rebuilding then would tear down and reinstall an
437
+ // identical router for nothing. Skip when no resolved value changed.
408
438
  if (activePolicy !== undefined && deepEqualJson(policy, activePolicy)) return
409
439
  if (!policy.enabled) {
410
440
  const current = active
@@ -431,23 +461,22 @@ export function apply(ctx: Context, config: Config = {}, internals: ApplyInterna
431
461
  if (previous) teardownLayer(previous)
432
462
  }
433
463
 
434
- // Start immediately with the entry config so the plugin works even on hosts
435
- // that never mount a settings service; when the service appears, the
436
- // layered section takes over and subsequent edits hot-publish here.
464
+ // Start immediately with the resolved entry config so the plugin works even
465
+ // on hosts that never mount a settings service; when the service is
466
+ // present, settings edits arrive as in-place reference swaps announced by
467
+ // the document-updated event, and subsequent edits hot-publish here.
437
468
  rejudge(true)
438
- // Optional-settings consumer wiring. The rc.2 module-level
439
- // installSettingsSection() helper was removed in dsh-settings
440
- // 0.1.2-alpha.3; the attach / detach-fallback / watch body moved behind the
441
- // provider as SettingsProvider.installSection (identical semantics — the
442
- // entry config stays the fallback source when the provider detaches).
443
- // ctx.inject keeps the whole wiring dormant on hosts that never mount a
444
- // settings service.
469
+ // Optional-settings consumer wiring. dsh-settings 0.1.7 deleted
470
+ // SettingsProvider/installSection: the plugin's static Config schema
471
+ // (attached to this function below) is the declaration, volatile-only
472
+ // edits land in the references without a remount, and the settings service
473
+ // announces them per entry id. The ctx.inject keeps the listener dormant on
474
+ // hosts that never mount a settings service; mixed (volatile+ordinary)
475
+ // edits remount the plugin instead, rerunning apply() from the top.
445
476
  ctx.inject(['settings'], (sctx) => {
446
- sctx.settings.installSection(ctx, SETTINGS_NAMESPACE, Config, config, {
447
- setSource: (current) => {
448
- getSource = current
449
- },
450
- onChange: () => rejudge(false),
477
+ sctx.on('settings/document-updated', (ns) => {
478
+ if (ns !== ENTRY_ID) return
479
+ rejudge(false)
451
480
  })
452
481
  })
453
- }
482
+ }, { Config })