@khorsheed/dsh-context-guard 0.2.4 → 0.2.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.2.6(2026-10-24)
4
+
5
+ - `dsh.references` 去掉已退役的 `@khorsheed/dsh-bundle-conversation-toolbox`(其成员全部并入 basic)。
6
+
7
+ ## 0.2.5(2026-10-22)
8
+
9
+ - **设置卡回归插件页**:家族/模式 bundle 折叠后阈值设置卡整体失声——`plugins.row.config` 的键钉死了旧载体 bundle(成员行现由模式包承载,键永不命中),0.1.5 座位 `settings.plugin.item` 已被宿主改名删除(现名 `plugins.item`),鸭式老臂静默失效。现在改为注册一个 `plugins.item` 列表条目并以 `configForms.whileServed` 门在服役中的 `context-guard` 命名空间上:独立安装、家族 bundle、模式包三种形态同一张卡,组合摘掉该行时卡也干净消失。代价:宿主 <0.1.7-alpha.1 不再渲染设置卡(输入框压缩按钮等其余面不变,已记入 README 兼容节与 `dsh.compat.notes`)。见 [Agent Note](../../.agents/notes/implemented/bug-fix/2026-10-18-bundle-member-config-card-via-plugins-item.md)
10
+ - 适配宿主 0.2.1 线:verifiedHost 前移至 0.2.1-rc.1,`@deepseek-ai/dsh-*` peer 区间加宽覆盖 0.2.1 并声明 `engines.dsh`(`>=0.1.2-rc.1 <0.3.0-0`);退役 load 期 invariant 伴生探针(空仪式,无行为变化)
11
+
3
12
  ## 0.2.4(2026-09-30)
4
13
 
5
14
  - **设置面直接调用 schemastery 的类型化 `.volatile()`**:0.2.0 开发线解析到 schemastery 3.18.4,其 `Schema` 已声明 `volatile()`——手写的 `VolatileCapable` 强转探测不再类型重叠(TS2352)。运行期双线行为不变:探测在 0.1.5 的 schemastery 3.18.2(无 `volatile` 方法)上仍回落到普通字段
package/README.en.md CHANGED
@@ -47,9 +47,9 @@ plugins:
47
47
 
48
48
  ## Compatibility
49
49
 
50
- - npm release line (`@deepseek-ai/dsh@0.1.2-rc.1`): ✅ full — baseline moved to the 0.1.2-rc.1 API surface (single-arm 0.1.2 API consumption; the 0.1.1-rc.2 runtime arm is retired), full build+test green; minHost moves up to 0.1.2-rc.1 — older hosts stay on the previous release line.
51
- - 0.1.6-alpha.2 pre-release line (`@deepseek-ai/dsh@0.1.6-alpha.2`): ✅ full — the `settings.plugin.item` slot is removed in the ui-settings-plugins refactor; the settings card moves to `plugins.bundle.config` (keyed by package name, the Plugins page drawing the title chrome); the dual-inject probe keeps the 0.1.5 card working, minHost unchanged.
52
- - source line (deepseek-harness master): ✅ (verifiedHost: 0.1.2-rc.1)
50
+ - npm release line (`@deepseek-ai/dsh@0.1.2-rc.1`): ⚠️ button full, settings card absent — baseline moved to the 0.1.2-rc.1 API surface (single-arm 0.1.2 API consumption; the 0.1.1-rc.2 runtime arm is retired), full build+test green; the settings card now rides only the Plugins page's `plugins.item` seat on 0.1.7-alpha.1+ (mounted through `configForms.whileServed` while the Host serves the `context-guard` namespace — one card for a standalone install, the toolbox family bundle, or a mode pack), so this line renders the composer button only; minHost moves up to 0.1.2-rc.1 — older hosts stay on the previous release line.
51
+ - 0.1.6-alpha.2 pre-release line (`@deepseek-ai/dsh@0.1.6-alpha.2`): ⚠️ button full, settings card absent — the `plugins.item` slot exists, but the `whileServed` gate landed in 0.1.7-alpha.1, so no card mounts here; 0.1.5's legacy `settings.plugin.item` seat is retired with the host's deletion, minHost unchanged.
52
+ - source line (deepseek-harness master): ✅ (verifiedHost: 0.2.1-rc.1) — host-021 wave: full build+test green against the 0.2.1-rc.1 tree, no other surface change.
53
53
 
54
54
  **Version line mapping**: 0.2.0 and up support host `0.1.2-rc.1` and later; hosts on `0.1.0-rc.6` ~ `0.1.1-rc.2` stay on the 0.1.x release line (last release `0.1.0`).
55
55
 
@@ -81,7 +81,7 @@ At the default ratio (0.8) the button appears exactly when the official engine w
81
81
 
82
82
  Nothing changes for the model: clicking the button runs the same `/compact` the user could type, with the same command lifecycle in the session log. The plugin itself has no token or KV-cache effect.
83
83
 
84
- `/client` exports the plugin body (`apply`/`inject`) and the `CompactGuardButtonProps` / `ContextGuardSettingsCardProps` types.
84
+ `/client` exports the plugin body (`apply`/`inject`) and the `CompactGuardButtonProps` / `ContextGuardBundleConfigProps` types.
85
85
 
86
86
  </details>
87
87
 
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # last confirmed-consistent state. Both languages carry equal authority; after
3
3
  # editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/context-guard/README.en.md
5
- packages/context-guard/README.en.md: 7467dc5a37b821125c3f4f026ac65be1a8584591
6
- packages/context-guard/README.md: 89f1467584d849cf6da1a4717758305a77e25d7a
5
+ packages/context-guard/README.en.md: afd1d0c450b5e2916377d10a59b537b6fbff9d6f
6
+ packages/context-guard/README.md: ffbb010a2301151f96626f35c72c3208bd523bad
package/README.md CHANGED
@@ -47,9 +47,9 @@ plugins:
47
47
 
48
48
  ## Compatibility
49
49
 
50
- - npm 发布线(`@deepseek-ai/dsh@0.1.2-rc.1`):✅ 完整——基线迁移至 0.1.2-rc.1 API 面(单臂消费 0.1.2 API,0.1.1-rc.2 运行臂已退役),全量构建测试通过;minHost 前移至 0.1.2-rc.1,旧宿主请停留在旧发布线。
51
- - 0.1.6-alpha.2 预发布线(`@deepseek-ai/dsh@0.1.6-alpha.2`):✅ 完整——`settings.plugin.item` 槽随 ui-settings-plugins 重构删除,设置卡改投 `plugins.bundle.config`(按包名 keyed,Plugins 页绘制标题后渲染本表单);双注入探测保持 0.1.5 线旧卡可用,minHost 不动。
52
- - 源码线(deepseek-harness master):✅(verifiedHost: 0.1.2-rc.1)
50
+ - npm 发布线(`@deepseek-ai/dsh@0.1.2-rc.1`):⚠️ 按钮完整、设置卡缺位——基线迁移至 0.1.2-rc.1 API 面(单臂消费 0.1.2 API,0.1.1-rc.2 运行臂已退役),全量构建测试通过;设置卡自本版起只挂 0.1.7-alpha.1 起的 Plugins 页 `plugins.item` 席位(随 `configForms.whileServed` 在宿主服务 `context-guard` 命名空间时挂载,独立安装、toolbox 家族 bundle、模式包同一张卡),此线不再呈现卡片,composer 按钮不受影响;minHost 前移至 0.1.2-rc.1,旧宿主请停留在旧发布线。
51
+ - 0.1.6-alpha.2 预发布线(`@deepseek-ai/dsh@0.1.6-alpha.2`):⚠️ 按钮完整、设置卡缺位——`plugins.item` 槽已在,但 `whileServed` 门控随 0.1.7-alpha.1 落地,此线不挂卡;0.1.5 的旧 `settings.plugin.item` 席位已随宿主删除一并退役,minHost 不动。
52
+ - 源码线(deepseek-harness master):✅(verifiedHost: 0.2.1-rc.1)——host-021 波对 0.2.1-rc.1 树全量 build+test 绿,无其它表面变化。
53
53
 
54
54
  **版本线对照**:0.2.0 起支持宿主 `0.1.2-rc.1` 及以后;宿主 `0.1.0-rc.6` ~ `0.1.1-rc.2` 的用户请停留在 0.1.x 发布线(末版 `0.1.0`)。
55
55
 
@@ -81,7 +81,7 @@ plugins:
81
81
 
82
82
  对模型没有任何变化:点击执行的是与用户手动输入相同的 `/compact`,会话日志里也是同样的命令生命周期。插件本身无 token 与 KV 缓存影响。
83
83
 
84
- `/client` 导出即插件本体(`apply`/`inject`)与 `CompactGuardButtonProps` / `ContextGuardSettingsCardProps` 类型。
84
+ `/client` 导出即插件本体(`apply`/`inject`)与 `CompactGuardButtonProps` / `ContextGuardBundleConfigProps` 类型。
85
85
 
86
86
  </details>
87
87
 
package/lib/client.js CHANGED
@@ -10,8 +10,9 @@ window.__ModuleLoader__.load({
10
10
  /**
11
11
  * The settings namespace owned by the context-guard plugin. Plain string so
12
12
  * both the host half (settings registration) and the browser half
13
- * (settingsScope binding and the 0.1.5 settings.plugin.item card key) import
14
- * it without dragging host-only dependencies into the client bundle.
13
+ * (settingsScope binding, the whileServed gate, and the plugins.item entry
14
+ * id) import it without dragging host-only dependencies into the client
15
+ * bundle.
15
16
  */
16
17
  /** Settings namespace owned by the context-guard plugin. */
17
18
  const CONTEXT_GUARD_NS = "context-guard";
@@ -147,20 +148,6 @@ window.__ModuleLoader__.load({
147
148
  }
148
149
  //#endregion
149
150
  //#region src/client/icons.tsx
150
- const IconChevronDownOutlineMedium = ({ size = 14, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
151
- width: size,
152
- height: size,
153
- className,
154
- viewBox: "0 0 16 16",
155
- fill: "none",
156
- xmlns: "http://www.w3.org/2000/svg",
157
- "aria-hidden": "true",
158
- strokeWidth: 1.3,
159
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
160
- d: "M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6",
161
- stroke: "currentColor"
162
- })
163
- });
164
151
  const IconWarningOutlineMedium = ({ size = 16, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
165
152
  width: size,
166
153
  height: size,
@@ -220,9 +207,9 @@ window.__ModuleLoader__.load({
220
207
  document.head.appendChild(tag);
221
208
  }
222
209
  var CompactGuardButton_module_css_default = {
223
- "icon": "BFFw2a_icon",
224
- "button": "BFFw2a_button",
225
210
  "wrap": "BFFw2a_wrap",
211
+ "button": "BFFw2a_button",
212
+ "icon": "BFFw2a_icon",
226
213
  "warning": "BFFw2a_warning",
227
214
  "error": "BFFw2a_error"
228
215
  };
@@ -302,30 +289,30 @@ window.__ModuleLoader__.load({
302
289
  document.head.appendChild(tag);
303
290
  }
304
291
  var SettingsCard_module_css_default = {
305
- "fieldHead": "DKjZXq_fieldHead",
306
- "headText": "DKjZXq_headText",
307
- "chevron": "DKjZXq_chevron",
308
- "inputRow": "DKjZXq_inputRow",
309
- "hint": "DKjZXq_hint",
310
- "saved": "DKjZXq_saved",
311
- "header": "DKjZXq_header",
312
292
  "description": "DKjZXq_description",
293
+ "header": "DKjZXq_header",
294
+ "chevron": "DKjZXq_chevron",
313
295
  "name": "DKjZXq_name",
314
- "body": "DKjZXq_body",
315
- "errorText": "DKjZXq_errorText",
316
- "field": "DKjZXq_field",
317
296
  "reset": "DKjZXq_reset",
297
+ "cardOpen": "DKjZXq_cardOpen",
298
+ "chevronOpen": "DKjZXq_chevronOpen",
299
+ "saved": "DKjZXq_saved",
318
300
  "fieldName": "DKjZXq_fieldName",
301
+ "card": "DKjZXq_card",
302
+ "field": "DKjZXq_field",
303
+ "body": "DKjZXq_body",
304
+ "hint": "DKjZXq_hint",
305
+ "fieldHead": "DKjZXq_fieldHead",
319
306
  "status": "DKjZXq_status",
320
- "cardOpen": "DKjZXq_cardOpen",
307
+ "footer": "DKjZXq_footer",
308
+ "errorText": "DKjZXq_errorText",
321
309
  "inputInvalid": "DKjZXq_inputInvalid",
322
- "save": "DKjZXq_save",
323
- "card": "DKjZXq_card",
310
+ "inputRow": "DKjZXq_inputRow",
324
311
  "badge": "DKjZXq_badge",
325
- "input": "DKjZXq_input",
326
- "footer": "DKjZXq_footer",
327
312
  "secondary": "DKjZXq_secondary",
328
- "chevronOpen": "DKjZXq_chevronOpen"
313
+ "headText": "DKjZXq_headText",
314
+ "save": "DKjZXq_save",
315
+ "input": "DKjZXq_input"
329
316
  };
330
317
  //#endregion
331
318
  //#region src/client/SettingsCard.tsx
@@ -493,51 +480,11 @@ window.__ModuleLoader__.load({
493
480
  });
494
481
  }
495
482
  /**
496
- * The context-guard settings card in the 0.1.5 plugin configuration tab: the
497
- * same collapsible chrome the official plugin cards use (a header naming the
498
- * plugin and what its settings govern, disclosing the controls in place),
499
- * re-implemented here because the client bundle-purity gate forbids
500
- * value-importing the official card chrome.
501
- */
502
- function ContextGuardSettingsCard({ useConfig, scope, t }) {
503
- const snapshot = useConfig((value) => value);
504
- const value = snapshot.status === "ready" ? snapshot.value : void 0;
505
- const [open, setOpen] = (0, react.useState)(false);
506
- const draft = useThresholdDraft(scope, snapshot, value);
507
- if (snapshot.status === "unavailable") return null;
508
- const title = t("settings.title");
509
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
510
- className: open ? `${SettingsCard_module_css_default.card} ${SettingsCard_module_css_default.cardOpen}` : SettingsCard_module_css_default.card,
511
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
512
- type: "button",
513
- className: SettingsCard_module_css_default.header,
514
- "aria-expanded": open,
515
- "aria-label": `${t(open ? "settings.collapse" : "settings.expand")}: ${title}`,
516
- onClick: () => {
517
- setOpen(!open);
518
- },
519
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
520
- className: SettingsCard_module_css_default.headText,
521
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
522
- className: SettingsCard_module_css_default.name,
523
- children: title
524
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
525
- className: SettingsCard_module_css_default.description,
526
- children: t("settings.description")
527
- })]
528
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutlineMedium, { className: open ? `${SettingsCard_module_css_default.chevron} ${SettingsCard_module_css_default.chevronOpen}` : SettingsCard_module_css_default.chevron })]
529
- }), open && value !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsBody, {
530
- snapshot,
531
- draft,
532
- t
533
- })]
534
- });
535
- }
536
- /**
537
- * The bundle's configuration on the alpha.2 Plugins page
538
- * (`plugins.bundle.config`, keyed by package name): the page draws the title,
539
- * the icon, and the crumb itself, so the entry renders the one-liner for the
540
- * `summary` view and the bare form — with its own save control — for `page`.
483
+ * The context-guard settings card on the Plugins page (the `plugins.item`
484
+ * entry client/index.ts registers while the Host serves the namespace): the
485
+ * page draws the title, the icon, and the crumb itself, so the entry renders
486
+ * the one-liner for the `summary` view and the bare form — with its own save
487
+ * control — for `page`.
541
488
  */
542
489
  function ContextGuardBundleConfig({ view, useConfig, scope, t }) {
543
490
  const snapshot = useConfig((value) => value);
@@ -557,12 +504,6 @@ window.__ModuleLoader__.load({
557
504
  //#endregion
558
505
  //#region src/client/index.ts
559
506
  /**
560
- * This bundle's package name — the key the Plugins page dispatches
561
- * `plugins.bundle.config` entries on (identity triangle: cordis.patch.yml,
562
- * tsdown.config.ts, invariant.ts).
563
- */
564
- const PACKAGE_NAME = "@khorsheed/dsh-context-guard";
565
- /**
566
507
  * Required services: the slot ledger, the command Remote, and the copy. The
567
508
  * settings scope is deliberately NOT injected — rc.1 and 0.1.5 name different
568
509
  * services (`configForms` vs `settingsScope`), and a composition without
@@ -604,34 +545,22 @@ window.__ModuleLoader__.load({
604
545
  hooks: { config: scope }
605
546
  })
606
547
  }, CompactGuardButton));
607
- ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
608
- name: "plugins.bundle.config",
609
- key: PACKAGE_NAME,
610
- locale: NS,
611
- inject: () => ({
612
- scope,
613
- hooks: { config: scope }
614
- })
615
- }, ContextGuardBundleConfig));
616
- ctx.slots.inject("plugins.row.config", () => ctx.slots.register({
617
- name: "plugins.row.config",
618
- key: "@khorsheed/dsh-bundle-conversation-toolbox#context-guard",
619
- locale: NS,
620
- inject: () => ({
621
- scope,
622
- hooks: { config: scope }
623
- })
624
- }, ContextGuardBundleConfig));
625
- const legacy = ctx.slots;
626
- legacy.inject("settings.plugin.item", () => legacy.register({
627
- name: "settings.plugin.item",
628
- key: CONTEXT_GUARD_NS,
629
- locale: NS,
630
- inject: () => ({
631
- scope,
632
- hooks: { config: scope }
633
- })
634
- }, ContextGuardSettingsCard));
548
+ const t = ctx.locale.bind(NS);
549
+ ctx.inject(["configForms"], (formsCtx) => {
550
+ const forms = formsCtx.configForms;
551
+ if (typeof forms.whileServed !== "function") return;
552
+ return forms.whileServed([CONTEXT_GUARD_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
553
+ name: "plugins.item",
554
+ id: CONTEXT_GUARD_NS,
555
+ order: 100,
556
+ label: () => t("settings.title"),
557
+ locale: NS,
558
+ inject: () => ({
559
+ scope,
560
+ hooks: { config: scope }
561
+ })
562
+ }, ContextGuardBundleConfig)));
563
+ });
635
564
  }
636
565
  //#endregion
637
566
  exports.NS = NS;
package/lib/index.js CHANGED
@@ -3,8 +3,9 @@ import z from "@deepseek-ai/schemastery";
3
3
  /**
4
4
  * The settings namespace owned by the context-guard plugin. Plain string so
5
5
  * both the host half (settings registration) and the browser half
6
- * (settingsScope binding and the 0.1.5 settings.plugin.item card key) import
7
- * it without dragging host-only dependencies into the client bundle.
6
+ * (settingsScope binding, the whileServed gate, and the plugins.item entry
7
+ * id) import it without dragging host-only dependencies into the client
8
+ * bundle.
8
9
  */
9
10
  /** Settings namespace owned by the context-guard plugin. */
10
11
  const CONTEXT_GUARD_NS = "context-guard";
@@ -1,17 +1,10 @@
1
- import type { ContextGuardBundleConfigProps, ContextGuardSettingsCardProps } from './slots.ts';
1
+ import type { ContextGuardBundleConfigProps } from './slots.ts';
2
2
  /**
3
- * The context-guard settings card in the 0.1.5 plugin configuration tab: the
4
- * same collapsible chrome the official plugin cards use (a header naming the
5
- * plugin and what its settings govern, disclosing the controls in place),
6
- * re-implemented here because the client bundle-purity gate forbids
7
- * value-importing the official card chrome.
8
- */
9
- export declare function ContextGuardSettingsCard({ useConfig, scope, t }: ContextGuardSettingsCardProps): import("react").JSX.Element | null;
10
- /**
11
- * The bundle's configuration on the alpha.2 Plugins page
12
- * (`plugins.bundle.config`, keyed by package name): the page draws the title,
13
- * the icon, and the crumb itself, so the entry renders the one-liner for the
14
- * `summary` view and the bare form — with its own save control — for `page`.
3
+ * The context-guard settings card on the Plugins page (the `plugins.item`
4
+ * entry client/index.ts registers while the Host serves the namespace): the
5
+ * page draws the title, the icon, and the crumb itself, so the entry renders
6
+ * the one-liner for the `summary` view and the bare form — with its own save
7
+ * control — for `page`.
15
8
  */
16
9
  export declare function ContextGuardBundleConfig({ view, useConfig, scope, t }: ContextGuardBundleConfigProps): import("react").JSX.Element | null;
17
10
  //# sourceMappingURL=SettingsCard.d.ts.map
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
- import { IconChevronDownOutlineMedium } from './icons.js';
4
3
  import css from './SettingsCard.module.css';
5
4
  /** Parse a draft into a number, or NaN when it is not one. */
6
5
  function parseNumber(text) {
@@ -91,27 +90,11 @@ function SettingsBody({ snapshot, draft, t }) {
91
90
  return (_jsxs("div", { className: css.body, children: [_jsxs("label", { className: css.field, children: [_jsxs("span", { className: css.fieldHead, children: [_jsx("span", { className: css.fieldName, children: t('settings.field.threshold') }), overridden(snapshot, 'thresholdRatio') && _jsx("span", { className: css.badge, children: t('settings.overridden') })] }), _jsxs("span", { className: css.inputRow, children: [_jsx("input", { className: draft.threshold.invalid ? `${css.input} ${css.inputInvalid}` : css.input, type: "number", step: "0.01", min: "0.01", max: "1", value: draft.threshold.text, "aria-label": t('settings.field.threshold'), onChange: (event) => { draft.write({ text: event.target.value, invalid: false }, 0.01, 1); } }), _jsx("button", { type: "button", className: css.reset, onClick: draft.reset, children: t('settings.reset') })] }), _jsx("span", { className: css.hint, children: t('settings.field.threshold.hint') })] }), _jsxs("span", { className: css.footer, children: [_jsxs("span", { className: css.status, children: [draft.saved ? _jsx("span", { className: css.saved, children: t('settings.saved') }) : null, draft.error ? _jsx("span", { className: css.errorText, children: t('settings.error') }) : null] }), _jsx("button", { type: "button", className: css.secondary, disabled: !draft.dirty, onClick: draft.discard, children: t('settings.discard') }), _jsx("button", { type: "button", className: css.save, disabled: !draft.dirty || draft.threshold.invalid || snapshot.writable !== true, onClick: draft.save, children: t('settings.save') })] })] }));
92
91
  }
93
92
  /**
94
- * The context-guard settings card in the 0.1.5 plugin configuration tab: the
95
- * same collapsible chrome the official plugin cards use (a header naming the
96
- * plugin and what its settings govern, disclosing the controls in place),
97
- * re-implemented here because the client bundle-purity gate forbids
98
- * value-importing the official card chrome.
99
- */
100
- export function ContextGuardSettingsCard({ useConfig, scope, t }) {
101
- const snapshot = useConfig(value => value);
102
- const value = snapshot.status === 'ready' ? snapshot.value : undefined;
103
- const [open, setOpen] = useState(false);
104
- const draft = useThresholdDraft(scope, snapshot, value);
105
- if (snapshot.status === 'unavailable')
106
- return null;
107
- const title = t('settings.title');
108
- return (_jsxs("li", { className: open ? `${css.card} ${css.cardOpen}` : css.card, children: [_jsxs("button", { type: "button", className: css.header, "aria-expanded": open, "aria-label": `${t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`, onClick: () => { setOpen(!open); }, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, children: title }), _jsx("span", { className: css.description, children: t('settings.description') })] }), _jsx(IconChevronDownOutlineMedium, { className: open ? `${css.chevron} ${css.chevronOpen}` : css.chevron })] }), open && value !== undefined && _jsx(SettingsBody, { snapshot: snapshot, draft: draft, t: t })] }));
109
- }
110
- /**
111
- * The bundle's configuration on the alpha.2 Plugins page
112
- * (`plugins.bundle.config`, keyed by package name): the page draws the title,
113
- * the icon, and the crumb itself, so the entry renders the one-liner for the
114
- * `summary` view and the bare form — with its own save control — for `page`.
93
+ * The context-guard settings card on the Plugins page (the `plugins.item`
94
+ * entry client/index.ts registers while the Host serves the namespace): the
95
+ * page draws the title, the icon, and the crumb itself, so the entry renders
96
+ * the one-liner for the `summary` view and the bare form — with its own save
97
+ * control — for `page`.
115
98
  */
116
99
  export function ContextGuardBundleConfig({ view, useConfig, scope, t }) {
117
100
  const snapshot = useConfig(value => value);
@@ -4,14 +4,11 @@
4
4
  * tool row that appears automatically when the next request's budget
5
5
  * (`contextPressure.projectedTokens` + the output budget) crosses
6
6
  * `thresholdRatio` of the routed model's context window — plus one settings
7
- * surface editing the same number live: a standalone install renders the
8
- * bundle's own configuration on its Plugins-page detail view
9
- * (`plugins.bundle.config`, keyed by package name), a family-bundle install
10
- * renders the same card through the row-level configure entry on the
11
- * BUNDLE's detail view (`plugins.row.config`, keyed
12
- * `@khorsheed/dsh-bundle-conversation-toolbox#context-guard`), and 0.1.5
13
- * renders the `settings.plugin.item` card in the plugin configuration tab
14
- * (keyed by the settings namespace). The action
7
+ * card editing the same number live: a `plugins.item` entry on the Plugins
8
+ * page gated by `configForms.whileServed` on the `context-guard` namespace
9
+ * (the official companion convention), so every install shape — standalone,
10
+ * the basic bundle, a mode pack — surfaces the same card, and
11
+ * a composition without the row shows no trace of it. The action
15
12
  * rides the official `/compact` command
16
13
  * channel (`remote.commands.execute` → host `ctx.commands` →
17
14
  * `ctx.compaction.compactNow`); the config rides the official settings
@@ -41,7 +38,7 @@ export type { ContextGuardKey } from './locales.ts';
41
38
  export { guardReading } from './guard.ts';
42
39
  export type { GuardInput, GuardLevel, GuardReading } from './guard.ts';
43
40
  export type { GuardScope, GuardScopeSnapshot } from './scope.ts';
44
- export type { CompactGuardButtonProps, ContextGuardBundleConfigProps, ContextGuardInjected, ContextGuardSettingsCardInjected, ContextGuardSettingsCardProps, } from './slots.ts';
41
+ export type { CompactGuardButtonProps, ContextGuardBundleConfigProps, ContextGuardInjected, ContextGuardSettingsCardInjected, } from './slots.ts';
45
42
  /** Dictionary namespace owned by this plugin. */
46
43
  export { NS };
47
44
  /**
@@ -3,17 +3,11 @@ import { resolveConfig } from './config.js';
3
3
  import { en, NS, zh } from './locales.js';
4
4
  import { bindGuardScope, GuardScopeChannel } from './scope.js';
5
5
  import { CompactGuardButton } from './CompactGuardButton.js';
6
- import { ContextGuardBundleConfig, ContextGuardSettingsCard } from './SettingsCard.js';
6
+ import { ContextGuardBundleConfig } from './SettingsCard.js';
7
7
  export { resolveConfig } from './config.js';
8
8
  export { guardReading } from './guard.js';
9
9
  /** Dictionary namespace owned by this plugin. */
10
10
  export { NS };
11
- /**
12
- * This bundle's package name — the key the Plugins page dispatches
13
- * `plugins.bundle.config` entries on (identity triangle: cordis.patch.yml,
14
- * tsdown.config.ts, invariant.ts).
15
- */
16
- const PACKAGE_NAME = '@khorsheed/dsh-context-guard';
17
11
  /**
18
12
  * Required services: the slot ledger, the command Remote, and the copy. The
19
13
  * settings scope is deliberately NOT injected — rc.1 and 0.1.5 name different
@@ -60,44 +54,34 @@ export function apply(ctx, config) {
60
54
  hooks: { config: scope },
61
55
  }),
62
56
  }, CompactGuardButton));
63
- // The settings surface follows the host line AND the install shape — three
64
- // tracks, all riding slots.inject so each fires only where its declaration
65
- // exists. Standalone install: the package's own Plugins-page detail view
66
- // (`plugins.bundle.config`, keyed by package name). Installed as a
67
- // conversation-toolbox member: the member is no longer the profile's
68
- // direct dependency, so only the bundle gets a detail view — the card rides
69
- // the row-level slot (`plugins.row.config`, keyed `<bundle package>#<row
70
- // id>` with the row id the bundle's patch declares) and the bundle's page
71
- // gains a configure entry opening it. 0.1.5: the legacy
72
- // configurable-plugins tab card (`settings.plugin.item`, keyed by the
73
- // settings namespace) through a string-keyed duck narrow of the same
74
- // service (the slot name is gone from the alpha.2 SlotMap).
75
- ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({
76
- name: 'plugins.bundle.config',
77
- key: PACKAGE_NAME,
78
- locale: NS,
79
- inject: () => ({
80
- scope,
81
- hooks: { config: scope },
82
- }),
83
- }, ContextGuardBundleConfig));
84
- ctx.slots.inject('plugins.row.config', () => ctx.slots.register({
85
- name: 'plugins.row.config',
86
- key: '@khorsheed/dsh-bundle-conversation-toolbox#context-guard',
87
- locale: NS,
88
- inject: () => ({
89
- scope,
90
- hooks: { config: scope },
91
- }),
92
- }, ContextGuardBundleConfig));
93
- const legacy = ctx.slots;
94
- legacy.inject('settings.plugin.item', () => legacy.register({
95
- name: 'settings.plugin.item',
96
- key: CONTEXT_GUARD_NS,
97
- locale: NS,
98
- inject: () => ({
99
- scope,
100
- hooks: { config: scope },
101
- }),
102
- }, ContextGuardSettingsCard));
57
+ // One Plugins-page card gated on the SERVED NAMESPACE, never on the install
58
+ // shape: whichever composition carries the `context-guard` row — standalone,
59
+ // the basic bundle, or a mode pack — serves the row's
60
+ // volatile Config under the row id, and `whileServed` keeps the
61
+ // `plugins.item` entry alive for exactly that span (the official companion
62
+ // convention), so a composition without the row shows no trace of the card.
63
+ // This replaces the retired per-shape seats: `plugins.row.config` hardcoded
64
+ // one carrier bundle into its key, and the host deleted
65
+ // `settings.plugin.item`. The probe rides a deferred inject because
66
+ // configForms exists only on the alpha.2+ host line; a 0.1.5 host never
67
+ // fires it, and a configForms predating whileServed (0.1.6-alpha.2) skips
68
+ // the card.
69
+ const t = ctx.locale.bind(NS);
70
+ ctx.inject(['configForms'], (formsCtx) => {
71
+ const forms = formsCtx.configForms;
72
+ if (typeof forms.whileServed !== 'function')
73
+ return;
74
+ return forms.whileServed([CONTEXT_GUARD_NS], () => ctx.slots.inject('plugins.item', () => ctx.slots.register({
75
+ name: 'plugins.item',
76
+ id: CONTEXT_GUARD_NS,
77
+ // Community cards sort after the official settings pages (orders 10-40).
78
+ order: 100,
79
+ label: () => t('settings.title'),
80
+ locale: NS,
81
+ inject: () => ({
82
+ scope,
83
+ hooks: { config: scope },
84
+ }),
85
+ }, ContextGuardBundleConfig)));
86
+ });
103
87
  }
@@ -1,13 +1,10 @@
1
1
  /**
2
2
  * Slot-facing types of the context-guard client half: the injected faces of
3
- * the composer-tool-row compact button and the settings surfaces, both
4
- * carrying the shared `context-guard` settings scope as a hooks source so the
5
- * button and the card react to the same live section. The settings surface
6
- * has one face per host line: the alpha.2 Plugins page renders the bundle's
7
- * configuration (`plugins.bundle.config`, keyed by package name, owner prop
8
- * `view`); the 0.1.5 configurable-plugins tab renders the card
9
- * (`settings.plugin.item`, keyed by the settings namespace, owner props
10
- * intentionally empty — the structural type below is exact).
3
+ * the composer-tool-row compact button and the settings card, both carrying
4
+ * the shared `context-guard` settings scope as a hooks source so the button
5
+ * and the card react to the same live section. The settings surface is the
6
+ * Plugins page's `plugins.item` entry (owner prop `view`), registered by
7
+ * client/index.ts while the Host serves the `context-guard` namespace.
11
8
  */
12
9
  import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
13
10
  import type { GuardScope } from './scope.ts';
@@ -29,7 +26,7 @@ export interface ContextGuardInjected {
29
26
  }
30
27
  /** Full props of the composer-tool-row compact entry. */
31
28
  export type CompactGuardButtonProps = PropsRuntime<'conversation.input.right'> & InjectFace<ContextGuardInjected> & PropsLocale<'context-guard'>;
32
- /** Injected face of both settings surfaces: the same shared section, read and written here. */
29
+ /** Injected face of the settings card: the same shared section, read and written here. */
33
30
  export interface ContextGuardSettingsCardInjected {
34
31
  /** The live section handle; the card stages edits and writes through it on save. */
35
32
  scope: GuardScope;
@@ -38,13 +35,6 @@ export interface ContextGuardSettingsCardInjected {
38
35
  config: GuardScope;
39
36
  };
40
37
  }
41
- /**
42
- * Full props of the 0.1.5 settings.plugin.item card entry. The removed slot's
43
- * owner share was intentionally empty, so the props are the injected face and
44
- * the locale seat alone; the registration goes through a duck-typed narrow of
45
- * the slots service (see client/index.ts).
46
- */
47
- export type ContextGuardSettingsCardProps = InjectFace<ContextGuardSettingsCardInjected> & PropsLocale<'context-guard'>;
48
- /** Full props of the alpha.2 plugins.bundle.config entry (owner prop `view`). */
49
- export type ContextGuardBundleConfigProps = PropsRuntime<'plugins.bundle.config'> & InjectFace<ContextGuardSettingsCardInjected> & PropsLocale<'context-guard'>;
38
+ /** Full props of the plugins.item card entry (owner prop `view`). */
39
+ export type ContextGuardBundleConfigProps = PropsRuntime<'plugins.item'> & InjectFace<ContextGuardSettingsCardInjected> & PropsLocale<'context-guard'>;
50
40
  //# sourceMappingURL=slots.d.ts.map
@@ -38,8 +38,8 @@ export function apply(ctx, config = {}) {
38
38
  return;
39
39
  }
40
40
  // rc.1: the entry's own Config (above) is the served form. Keep the
41
- // auto-generated page out of the settings tree — the bundle's own cards
42
- // (plugins.bundle.config / the legacy tab seat) edit the same field.
41
+ // auto-generated page out of the settings tree — the bundle's own
42
+ // Plugins-page card (plugins.item) edits the same field.
43
43
  if (typeof settings.configure === 'function')
44
44
  settings.configure({ auto: false }, ctx.fiber);
45
45
  });
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * The settings namespace owned by the context-guard plugin. Plain string so
3
3
  * both the host half (settings registration) and the browser half
4
- * (settingsScope binding and the 0.1.5 settings.plugin.item card key) import
5
- * it without dragging host-only dependencies into the client bundle.
4
+ * (settingsScope binding, the whileServed gate, and the plugins.item entry
5
+ * id) import it without dragging host-only dependencies into the client
6
+ * bundle.
6
7
  */
7
8
  /** Settings namespace owned by the context-guard plugin. */
8
9
  export declare const CONTEXT_GUARD_NS = "context-guard";
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * The settings namespace owned by the context-guard plugin. Plain string so
3
3
  * both the host half (settings registration) and the browser half
4
- * (settingsScope binding and the 0.1.5 settings.plugin.item card key) import
5
- * it without dragging host-only dependencies into the client bundle.
4
+ * (settingsScope binding, the whileServed gate, and the plugins.item entry
5
+ * id) import it without dragging host-only dependencies into the client
6
+ * bundle.
6
7
  */
7
8
  /** Settings namespace owned by the context-guard plugin. */
8
9
  export const CONTEXT_GUARD_NS = 'context-guard';
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "context",
9
9
  "compaction"
10
10
  ],
11
- "version": "0.2.4",
11
+ "version": "0.2.6",
12
12
  "type": "module",
13
13
  "main": "lib/index.js",
14
14
  "types": "lib/types/index.d.ts",
@@ -17,10 +17,6 @@
17
17
  "types": "./lib/types/index.d.ts",
18
18
  "default": "./lib/index.js"
19
19
  },
20
- "./invariant": {
21
- "types": "./lib/types/invariant.d.ts",
22
- "default": "./lib/invariant.js"
23
- },
24
20
  "./client": {
25
21
  "types": "./lib/types/client/index.d.ts",
26
22
  "default": "./lib/client.js"
@@ -30,9 +26,6 @@
30
26
  "./locale/*.json": "./locale/*.json"
31
27
  },
32
28
  "dsh": {
33
- "references": [
34
- "@khorsheed/dsh-bundle-conversation-toolbox"
35
- ],
36
29
  "bundle": {
37
30
  "patch": "./cordis.patch.yml"
38
31
  },
@@ -48,20 +41,23 @@
48
41
  },
49
42
  "compat": {
50
43
  "minHost": "0.1.2-rc.1",
51
- "verifiedHost": "0.1.2-rc.1"
44
+ "verifiedHost": "0.2.1-rc.1",
45
+ "notes": "The settings card mounts only on host 0.1.7-alpha.1+ (the Plugins page plugins.item seat, gated by configForms.whileServed on the served context-guard namespace); older lines render the composer button only."
52
46
  }
53
47
  },
54
48
  "license": "MIT",
49
+ "engines": {
50
+ "dsh": ">=0.1.2-rc.1 <0.3.0-0"
51
+ },
55
52
  "peerDependencies": {
56
53
  "@deepseek-ai/cordis": "^4.0.1",
57
- "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6 || ^0.2.0-rc.1",
58
- "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6 || ^0.2.0-rc.1",
59
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6 || ^0.2.0-rc.1",
60
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || ^0.2.0-rc.1",
61
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6 || ^0.2.0-rc.1",
62
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6 || ^0.2.0-rc.1",
63
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6 || ^0.2.0-rc.1",
64
- "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.6 || ^0.2.0-rc.1",
54
+ "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
55
+ "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
56
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
57
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
58
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
59
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
60
+ "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
65
61
  "react": "^18.2.0"
66
62
  },
67
63
  "files": [
package/lib/invariant.js DELETED
@@ -1,26 +0,0 @@
1
- //#region lib/types/invariant.js
2
- /**
3
- * Package-owned invariant companion for `@khorsheed/dsh-context-guard`.
4
- * @module @khorsheed/dsh-context-guard/invariant
5
- */
6
- const PACKAGE_NAME = "@khorsheed/dsh-context-guard";
7
- /** Cordis companion plugin name. */
8
- const name = "context-guard-invariant";
9
- /** Service required before the companion can reserve package ownership. */
10
- const inject = ["invariants"];
11
- /**
12
- * No runtime invariant: every compact action is executed through the official
13
- * `/compact` command channel, whose command-log invariant companion audits the
14
- * command lifecycle, and the plugin's one composer-tool-row entry proves
15
- * disposal through the browser-plugin spec. No second authority exists to
16
- * check at runtime.
17
- */
18
- const install = () => {};
19
- /**
20
- * Register this package's invariant companion.
21
- * @param ctx - Cordis context carrying the invariant service.
22
- * @returns the installed registration's disposer after setup succeeds.
23
- */
24
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
25
- //#endregion
26
- export { apply, inject, name };
@@ -1,16 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@khorsheed/dsh-context-guard`.
3
- * @module @khorsheed/dsh-context-guard/invariant
4
- */
5
- import type { Context } from '@deepseek-ai/cordis';
6
- /** Cordis companion plugin name. */
7
- export declare const name = "context-guard-invariant";
8
- /** Service required before the companion can reserve package ownership. */
9
- export declare const inject: string[];
10
- /**
11
- * Register this package's invariant companion.
12
- * @param ctx - Cordis context carrying the invariant service.
13
- * @returns the installed registration's disposer after setup succeeds.
14
- */
15
- export declare const apply: (ctx: Context) => Promise<() => void>;
16
- //# sourceMappingURL=invariant.d.ts.map
@@ -1,24 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@khorsheed/dsh-context-guard`.
3
- * @module @khorsheed/dsh-context-guard/invariant
4
- */
5
- const PACKAGE_NAME = '@khorsheed/dsh-context-guard';
6
- /** Cordis companion plugin name. */
7
- export const name = 'context-guard-invariant';
8
- /** Service required before the companion can reserve package ownership. */
9
- export const inject = ['invariants'];
10
- /**
11
- * No runtime invariant: every compact action is executed through the official
12
- * `/compact` command channel, whose command-log invariant companion audits the
13
- * command lifecycle, and the plugin's one composer-tool-row entry proves
14
- * disposal through the browser-plugin spec. No second authority exists to
15
- * check at runtime.
16
- */
17
- const install = () => { };
18
- /**
19
- * Register this package's invariant companion.
20
- * @param ctx - Cordis context carrying the invariant service.
21
- * @returns the installed registration's disposer after setup succeeds.
22
- */
23
- export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
24
- /* jscpd:ignore-end */