@klarkxy/dsh-delegation 0.1.1 → 0.1.2

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
@@ -16,8 +16,7 @@ Enable the plugin in your profile, then reload the page or restart the profile a
16
16
 
17
17
  ## Use
18
18
 
19
- - On the new-session page, use the **Delegate** chip on the same row as the workspace and preset selectors before sending the first message: the chip shows the theme color when delegation is on. The choice locks once the session starts, including after reopening it. The chip applies to the session's main agent, and its subagents automatically receive matching execution guidance.
20
- - In **Plugins → Delegation Mode**, **Enable Delegation Mode for new sessions** sets the initial state for sessions created later.
19
+ - On the new-session page, use the **Delegate** chip on the same row as the workspace and preset selectors before sending the first message: the chip shows the theme color when delegation is on. The choice locks once the session starts, including after reopening it. A session forked from an existing one keeps its parent's state. The chip applies to the session's main agent, and its subagents automatically receive matching execution guidance.
21
20
  - Simple tasks can be completed directly. For larger tasks, the main agent assigns scoped work to subagents, coordinates shared interfaces, and checks their results before reporting completion.
22
21
 
23
22
  ## Limits
@@ -25,7 +24,7 @@ Enable the plugin in your profile, then reload the page or restart the profile a
25
24
  - Presets that expose subagent tools — Standard and PTC — support delegation; presets without subagent tools (such as Minimal and other complete-persona presets) keep the chip disabled.
26
25
  - The chip updates prompt guidance only; tool access and permissions remain unchanged, and delegation is guided rather than strictly enforced.
27
26
  - Delegation Mode stays fixed once a session starts, keeping the session's prompt cache stable.
28
- - Changing the default applies to sessions created afterwards; existing sessions keep their current state.
27
+ - Existing sessions keep their current state; a previously saved global default still applies to newly created sessions.
29
28
  - The added prompt section may reduce provider prompt-cache hits.
30
29
 
31
30
  ## License
@@ -16,8 +16,7 @@ dsh plugin --profile web add @klarkxy/dsh-delegation
16
16
 
17
17
  ## 使用
18
18
 
19
- - 在创建会话页,发送第一条消息前,使用工作区、预设选择器同一行的「委派」按钮:未开启时为普通样式,开启后显示主题色。选择在会话开始后锁定,重新打开也保持不变。按钮作用于该会话的主代理,它的子代理会自动获得对应的执行指引。
20
- - 在「插件 → 委派模式」中,「新会话默认启用委派」决定之后新建会话的初始状态。
19
+ - 在创建会话页,发送第一条消息前,使用工作区、预设选择器同一行的「委派」按钮:未开启时为普通样式,开启后显示主题色。选择在会话开始后锁定,重新打开也保持不变。从已有会话分叉出的会话继承父会话的状态。按钮作用于该会话的主代理,它的子代理会自动获得对应的执行指引。
21
20
  - 简单任务可以直接完成;较大任务由主代理先分派具体工作,再协调共同接口、检查子代理结果,最后汇报完成情况。
22
21
 
23
22
  ## 限制
@@ -25,7 +24,7 @@ dsh plugin --profile web add @klarkxy/dsh-delegation
25
24
  - 带子代理工具的预设(Standard 与 PTC)可使用委派;无子代理工具的预设(如 Minimal 及其他完整人设预设)按钮显示为禁用状态。
26
25
  - 按钮仅调整提示词引导,保持原有的工具与权限设置,通过提示引导模型委派。
27
26
  - 委派模式在会话开始后保持固定,以维持提示词缓存稳定。
28
- - 修改默认值仅影响之后新建的会话,已有会话保持原状态。
27
+ - 已有会话保持原状态;之前保存过的全局默认值仍作用于之后新建的会话。
29
28
  - 新增的提示词小节可能降低模型供应商的提示词缓存命中率。
30
29
 
31
30
  ## 许可证
@@ -590,172 +590,6 @@ const clientCss = `${officialUiCss("dlg-root")}
590
590
  .dlg-root .dlg-chip:disabled { opacity: 0.5; cursor: default; }
591
591
  .dlg-root .dlg-note { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }
592
592
  `;
593
- /** Host UI language, following live switches with the host's English fallback. */
594
- function useHostLocale(client) {
595
- const subscribe = (0, react.useCallback)((listener) => client.locale.subscribe?.(listener) ?? (() => {}), [client]);
596
- const snapshot = (0, react.useCallback)(() => client.locale.getSnapshot?.().active ?? "en", [client]);
597
- return (0, react.useSyncExternalStore)(subscribe, snapshot, snapshot);
598
- }
599
- const settingsZh = {
600
- default: "新会话默认启用委派",
601
- defaultHint: "只影响之后新建的会话;发送第一条消息前可单独选择,会话开始后保持锁定。需要预设包含子代理工具。",
602
- loading: "正在读取设置…",
603
- saved: "已保存。",
604
- stale: "设置已更新,请刷新后重试。",
605
- failed: "无法读取委派设置。",
606
- retry: "重试",
607
- refresh: "刷新设置"
608
- };
609
- const settingsEn = {
610
- default: "Enable Delegation Mode for new sessions",
611
- defaultHint: "Only affects sessions created later. Choose before sending the first message; the choice stays locked once the session starts. Requires a preset with subagent tools.",
612
- loading: "Loading settings…",
613
- saved: "Saved.",
614
- stale: "Settings changed; refresh and retry.",
615
- failed: "Could not load delegation settings.",
616
- retry: "Retry",
617
- refresh: "Refresh settings"
618
- };
619
- function settingsCopy(locale) {
620
- return String(locale).startsWith("zh") ? settingsZh : settingsEn;
621
- }
622
- /** Plugin-page card: the default flag applied to sessions created from now on. */
623
- function DelegationSettingsPanel(props) {
624
- const hostLocale = useHostLocale(props.client);
625
- const text = settingsCopy(props.locale ?? hostLocale);
626
- const [settings, setSettings] = (0, react.useState)();
627
- const [error, setError] = (0, react.useState)("");
628
- const [note, setNote] = (0, react.useState)(false);
629
- const [busy, setBusy] = (0, react.useState)(false);
630
- const operation = (0, react.useRef)({
631
- epoch: 0,
632
- active: false,
633
- writing: false
634
- });
635
- const call = (0, react.useCallback)((endpoint, payload = {}) => props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload), [props.client]);
636
- const refresh = (0, react.useCallback)(() => {
637
- const state = operation.current;
638
- if (!state.active || state.writing) return;
639
- const epoch = state.epoch;
640
- setBusy(true);
641
- rpc(call, "settings").then((next) => {
642
- if (!state.active || state.epoch !== epoch) return;
643
- setSettings(next);
644
- setError("");
645
- }).catch(() => {
646
- if (!state.active || state.epoch !== epoch) return;
647
- setError("failed");
648
- }).finally(() => {
649
- if (state.active && state.epoch === epoch) setBusy(false);
650
- });
651
- }, [call]);
652
- const refreshRef = (0, react.useRef)(refresh);
653
- refreshRef.current = refresh;
654
- (0, react.useEffect)(() => {
655
- const state = operation.current;
656
- state.epoch++;
657
- state.active = true;
658
- state.writing = false;
659
- setBusy(false);
660
- setSettings(void 0);
661
- setError("");
662
- setNote(false);
663
- refreshRef.current();
664
- return () => {
665
- state.active = false;
666
- state.epoch++;
667
- };
668
- }, [call]);
669
- const save = (0, react.useCallback)((defaultEnabled) => {
670
- const state = operation.current;
671
- if (!settings || !state.active || state.writing) return;
672
- state.writing = true;
673
- const epoch = state.epoch;
674
- setBusy(true);
675
- setNote(false);
676
- setError("");
677
- rpc(call, "settings.update", {
678
- defaultEnabled,
679
- expectedRevision: settings.revision
680
- }).then((next) => {
681
- if (!state.active || state.epoch !== epoch) return;
682
- setSettings(next);
683
- setNote(true);
684
- }).catch((reason) => {
685
- if (!state.active || state.epoch !== epoch) return;
686
- setError(reason instanceof RpcError && reason.code === "stale" ? "stale" : "failed");
687
- }).finally(() => {
688
- if (state.active && state.epoch === epoch) {
689
- state.writing = false;
690
- setBusy(false);
691
- }
692
- });
693
- }, [call, settings]);
694
- if (!settings) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
695
- className: "dlg-root dlg-settings dsh-ui-page",
696
- children: [error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
697
- role: "alert",
698
- className: "dsh-ui-error",
699
- children: text[error]
700
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
701
- role: "status",
702
- className: "dsh-ui-hint",
703
- children: text.loading
704
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
705
- variant: "ghost",
706
- size: "sm",
707
- disabled: busy,
708
- onClick: () => refreshRef.current(),
709
- children: text.retry
710
- })]
711
- });
712
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
713
- className: "dlg-root dlg-settings dsh-ui-page",
714
- "data-testid": "delegation-settings",
715
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
716
- className: "dlg-settings-status",
717
- children: [
718
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
719
- variant: "ghost",
720
- size: "sm",
721
- disabled: busy,
722
- onClick: () => refreshRef.current(),
723
- children: text.refresh
724
- }),
725
- error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
726
- role: "alert",
727
- className: "dsh-ui-error",
728
- children: text[error]
729
- }),
730
- note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
731
- role: "status",
732
- className: "dsh-ui-notice",
733
- children: text.saved
734
- })
735
- ]
736
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("article", {
737
- className: "dlg-root dsh-ui-card",
738
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
739
- className: "dsh-ui-toggle-row",
740
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
741
- className: "dsh-ui-toggle-text",
742
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
743
- className: "dsh-ui-toggle-label",
744
- children: text.default
745
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
746
- className: "dsh-ui-hint",
747
- children: text.defaultHint
748
- })]
749
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
750
- checked: settings.defaultEnabled,
751
- label: text.default,
752
- disabled: busy,
753
- onChange: (next) => save(next)
754
- })]
755
- })
756
- })]
757
- });
758
- }
759
593
  function apply(ctx) {
760
594
  const client = ctx;
761
595
  ctx.provide(DELEGATION_CLIENT_SERVICE, { active: true });
@@ -771,10 +605,6 @@ function apply(ctx) {
771
605
  document.head.appendChild(style);
772
606
  return () => style.remove();
773
607
  }, "delegation.styles");
774
- ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
775
- name: "plugins.bundle.config",
776
- key: PLUGIN_NAME
777
- }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DelegationSettingsPanel, { client }))), "delegation.settings");
778
608
  ctx.effect(() => client.slots.inject("conversation.hero.options", () => client.slots.register({
779
609
  name: "conversation.hero.options",
780
610
  id: "delegation",
@@ -788,7 +618,6 @@ function apply(ctx) {
788
618
  }
789
619
  //#endregion
790
620
  exports.DelegationAction = DelegationAction;
791
- exports.DelegationSettingsPanel = DelegationSettingsPanel;
792
621
  exports.apply = apply;
793
622
  exports.clientCss = clientCss;
794
623
  exports.inject = inject;
@@ -1 +1 @@
1
- {"version":3,"file":"client.inner.cjs","names":["useState","useRef","useCallback","Tooltip","Pill","IconUsersOutlineRegular","useSyncExternalStore","Button","Switch"],"sources":["../../dsh-plugin-kit/src/official-ui.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["/**\n * Shared contract that keeps every plugin's browser-side UI on the official\n * DeepSeek Harness Web design language.\n *\n * Two rules produce that language, and both are load-bearing here:\n *\n * 1. Colour, radius, elevation and focus come from the host theme's real\n * `--dsw-*` tokens, written under their own names. Plugins never invent a\n * token, never alias the official ones behind a private palette (a private\n * alias is just a second, diverging theme), and never carries a literal\n * fallback — the host publishes light and dark, and a literal would pin one\n * of them. The only non-colour custom properties used are the host's own\n * content-font axis and frame clearance.\n *\n * 2. Anything the host already ships is used, not reimplemented. Controls come\n * from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n * `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n * `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n * form suite). This module only styles what primitives do not cover: page\n * scaffolding, field layout, banners, empty states and scroll regions.\n *\n * The metrics below are transcribed from the primitives' own CSS modules so a\n * feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n * 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n * that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n */\n\n/**\n * Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n *\n * Plugins may only colour through this list. It is exported so the guard test\n * can fail a build when a stylesheet reaches for anything else — the failure\n * mode this prevents is silent: an unknown token resolves to nothing, so a\n * border disappears or a label inherits the wrong colour with no error anywhere.\n */\nexport const OFFICIAL_THEME_TOKENS = {\n /** Surfaces, from the page up to the topmost nested card. */\n surface: [\n '--dsw-alias-bg-base',\n '--dsw-alias-bg-layer-1',\n '--dsw-alias-bg-layer-2',\n '--dsw-alias-bg-layer-3',\n '--dsw-alias-bg-layer-4',\n '--dsw-alias-bg-module-platform',\n '--dsw-alias-bg-overlay',\n ],\n /** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n border: ['--dsw-alias-border-l1', '--dsw-alias-border-l2', '--dsw-alias-border-l3', '--dsw-alias-border-l4'],\n /** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n label: [\n '--dsw-alias-label-primary',\n '--dsw-alias-label-secondary',\n '--dsw-alias-label-tertiary',\n '--dsw-alias-label-caption',\n '--dsw-alias-label-dimmed',\n '--dsw-alias-label-error',\n '--dsw-alias-label-primary-foreground',\n ],\n /** Interactive fills. The `-danger` hover belongs to destructive rows. */\n interactive: [\n '--dsw-alias-interactive-bg-hover',\n '--dsw-alias-interactive-bg-active',\n '--dsw-alias-interactive-bg-hover-danger',\n ],\n /** Accent and status. `business` is the focus ring's default colour. */\n accent: [\n '--dsw-alias-brand-primary',\n '--dsw-alias-button-primary-fill',\n '--dsw-alias-button-primary-hover',\n '--dsw-alias-button-tool-bar-fill',\n '--dsw-alias-button-tool-bar-hover',\n '--dsw-alias-button-ghost-active-fill',\n '--dsw-alias-button-ghost-active-border',\n ],\n state: [\n '--dsw-alias-state-business-primary',\n '--dsw-alias-state-success-primary',\n '--dsw-alias-state-warn-primary',\n '--dsw-alias-state-error-primary',\n '--dsw-alias-state-idle-primary',\n ],\n /** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n radius: ['--dsw-radius-sm', '--dsw-radius-md', '--dsw-radius-lg', '--dsw-radius-panel'],\n /** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n elevation: [\n '--dsw-elevation-soft',\n '--dsw-elevation-stroke',\n '--dsw-elevation-stroke-color',\n '--dsw-elevation-panel',\n '--dsw-elevation-prominent',\n ],\n /** Floats, masks and scrollbars. */\n overlay: [\n '--dsw-menu-surface-fill',\n '--dsw-menu-backdrop-filter',\n '--dsw-mask-blur',\n '--dsw-alias-bg-mask-1',\n '--dsw-alias-menu-icon',\n '--dsw-alias-scrollbar-bg-l2',\n '--dsw-alias-scrollbar-hover-l2',\n '--dsw-shadow-lv3',\n ],\n /** Motion, focus and type axis, published by the host rather than by a component. */\n system: [\n '--dsw-focus-ring-width',\n '--dsw-focus-ring-color',\n '--dsw-font-markdown-code-font-family',\n '--ds-transition-duration',\n '--ds-ease-in-out',\n '--ds-font-family-code',\n '--dsh-scrollbar-thumb',\n '--dsh-scrollbar-thumb-hover',\n '--dsh-content-font-size-secondary',\n '--dsh-content-font-delta',\n '--dsh-frame-top-clearance',\n ],\n} as const\n\n/** Every official token name, flat. Used by the token guard test. */\nexport const OFFICIAL_THEME_TOKEN_NAMES: readonly string[] = Object.values(OFFICIAL_THEME_TOKENS).flat()\n\n/** The elevation steps a surface can be raised by, softest first. */\nexport type OfficialElevation = 'soft' | 'stroke' | 'panel' | 'prominent'\n\n/**\n * The host's focus ring shorthand, verbatim. Writing this per control is how\n * rings drift apart; a stylesheet that draws its own focus style should use\n * {@link officialFocus} instead. The colour fallback is the host's own default.\n */\nexport const OFFICIAL_FOCUS_RING =\n 'var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))'\n\n/**\n * A complete `outline` declaration at the official geometry. `offset` defaults\n * to the 2px the native controls use; the host's inline field rules sit at 1px\n * and a segmented tab pulls the ring inside itself at -2px.\n */\nexport function officialFocus(offset = '2px'): string {\n return `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`\n}\n\n/**\n * An elevated surface. The host draws a raised surface's edge inside its\n * shadow rather than as a border, so a card sets `border: 0` and takes the edge\n * from the elevation — which is also why its border stays off the alias-border\n * set that a flat, non-elevated rule would use.\n */\nexport function officialElevation(level: OfficialElevation): string {\n return `border: 0; box-shadow: var(--dsw-elevation-${level})`\n}\n\n/**\n * An elevated surface whose edge should read as a specific hairline. Rebinding\n * the stroke colour is how a menu card picks l1 while a panel picks l3, without\n * the two growing apart by hand.\n */\nexport function officialStrokedElevation(level: OfficialElevation, color: string): string {\n return `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`\n}\n\n/**\n * The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n *\n * Scoping is what keeps this safe to always-bundle into every client: the rules\n * can only match inside the plugin's own subtree, so two plugins can both mount\n * `dsh-ui-card` without either styling the other's markup.\n *\n * Each recipe matches the root element *and* its descendants, because the\n * commonest arrangement is one element that is both — a surface that carries\n * the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n * the `dsh-ui-surface`. A descendant-only scope would silently leave those\n * unstyled, with no error anywhere.\n *\n * A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n * content leaves the plugin's subtree entirely. A portaled surface therefore\n * needs its own root class on an element inside the portal.\n *\n * Only patterns that primitives do not provide live here. If a control appears\n * below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n * bug in this file: use the primitive and delete the recipe.\n */\nexport function officialUiCss(roots: string | readonly string[]): string {\n // One plugin often mounts several unrelated surfaces (a settings seat, a chat\n // card, a header menu), so the caller names every root. The rules below are\n // nested under a single selector list and use `&`, which the browser expands\n // per root — so one stylesheet covers all of them without duplicating itself.\n const scope = (typeof roots === 'string' ? [roots] : roots).map(root => `.${root}`).join(', ')\n const sheet = `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n/* Plugin detail pages share one reading column. These are layout recipes;\n * controls keep their own primitive styles. Form spacing follows the host's\n * settings-form/fields.module.css and SettingsForm.module.css. */\n& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }\n& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }\n&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }\n& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }\n& .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }\n@media (max-width: 560px) {\n & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }\n}\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n ${officialElevation('stroke')}\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n/* Grid fields share a row, so the stacked-field divider must not win later in\n * the cascade. Reset it here, after the field recipe. */\n& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px 14px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-left: 3px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n padding: 20px 16px;\n border: 0.5px dashed var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n min-width: 0;\n padding: 10px 12px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n padding: 10px 12px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n position: relative;\n display: flex;\n flex-direction: column;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-menu-surface-fill);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n box-shadow: var(--dsw-elevation-prominent);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n line-height: 20px;\n min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* --- Native textarea. The primitives ship no textarea either, so a settings\n * prompt keeps the platform element and the same field shell as the select:\n * 0.5px l4, radius-md, layer-3, 13/1.5 type. It grows vertically instead of\n * locking to the select's 34px row. --- */\n& .dsh-ui-textarea {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n resize: vertical;\n padding: 8px 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n& .dsh-ui-textarea:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-textarea:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-textarea::placeholder { color: var(--dsw-alias-label-dimmed); }\n& .dsh-ui-textarea[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`\n // Widen every recipe from \"a descendant of the root\" to \"the root, or one of\n // its descendants\". Written as a transform rather than by hand so no recipe\n // can be added later with only the descendant form. The pattern is narrow on\n // purpose: a leading `&` followed by one recipe class and no combinator, so\n // sibling and child rules such as `.dsh-ui-field + .dsh-ui-field` keep their\n // own meaning and are left alone.\n return sheet.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?=\\s*\\{)/gm, (_match, className: string) =>\n `&${className}, & ${className}`)\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nimport type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-delegation'\nexport const RPC_CHANNEL = '/dsh-delegation'\nexport const DELEGATION_CLIENT_SERVICE = 'dshDelegationClient'\n\n/** Native delegation tools; Delegation Mode only helps presets that mount one. */\nexport const DELEGATION_TOOLS = ['subagent', 'subagent_fork'] as const\n\nexport interface DelegationSettings {\n readonly revision: number\n /** Initial delegation flag for sessions created from now on. */\n readonly defaultEnabled: boolean\n}\n\nexport const defaultSettings = (): DelegationSettings => ({ revision: 0, defaultEnabled: false })\n\nexport type DelegationRole = 'coordinator' | 'executor'\n\nexport interface DelegationSessionStatus {\n readonly sessionId: string\n /** 'executor' for subagent threads: they never carry their own switch. */\n readonly role: DelegationRole\n /** The session record's flag; false when the session has no record yet. */\n readonly enabled: boolean\n /** The session record's revision; 0 when the session has no record yet. */\n readonly revision: number\n /** No edit is allowed once the first turn starts, or while the session is cold. */\n readonly locked: boolean\n /**\n * Whether a live agent on this session sees a delegation tool; null when no\n * agent is live, so a stale answer is never shown as unavailable.\n */\n readonly capable: boolean | null\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport { Button, IconUsersOutlineRegular, Pill, Switch, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport {\n DELEGATION_CLIENT_SERVICE, PLUGIN_NAME, RPC_CHANNEL,\n type DelegationSessionStatus, type DelegationSettings, type RpcResult,\n} from './contracts.ts'\n\nexport const name = 'dsh-delegation-client'\nexport const inject = ['slots', 'connection', 'locale'] as const\n\nconst NS = 'dsh-delegation.action'\n\nconst zh = {\n action: '委派',\n mode: '委派模式',\n titleOn: '本会话将使用委派模式:主代理负责拆解、委派和验收;会话开始后保持锁定',\n titleOff: '开启委派模式:主代理把具体工作交给子代理;会话开始后保持锁定',\n locked: '请在会话开始前选择委派模式',\n incapable: '当前预设缺少子代理工具,需切换到带子代理工具的预设',\n stale: '状态已在别处更改,已刷新',\n failed: '切换失败',\n}\n\nconst en: Record<keyof typeof zh, string> = {\n action: 'Delegate',\n mode: 'Delegation Mode',\n titleOn: 'This session will use Delegation Mode: the main agent plans, delegates, and reviews. Locked once the session starts.',\n titleOff: 'Turn on Delegation Mode: the main agent hands the work to subagents. Locked once the session starts.',\n locked: 'Choose Delegation Mode before the session starts',\n incapable: 'Delegation Mode unavailable: this preset has no subagent tools',\n stale: 'State changed elsewhere; refreshed',\n failed: 'Could not toggle Delegation Mode',\n}\n\ntype Key = keyof typeof zh\ntype Translate = (key: Key) => string\n\n/** A failed RPC keeps its code so the view can name a rejection it understands. */\nclass RpcError extends Error {\n readonly code: string\n constructor(code: string, message: string) {\n super(message)\n this.name = 'RpcError'\n this.code = code\n }\n}\n\nasync function rpc<T>(call: (endpoint: string, payload: unknown) => Promise<unknown>, endpoint: string, payload: unknown = {}): Promise<T> {\n const result = await call(endpoint, payload) as RpcResult<T> | undefined\n if (!result || result.ok !== true) {\n const failed = result && 'error' in result ? result.error : undefined\n throw new RpcError(failed?.code ?? 'unknown', failed?.message ?? '')\n }\n return result.value\n}\n\nexport interface DelegationSessionSnapshotLike {\n openState?: string\n running?: boolean\n blank?: boolean\n awaitingFirstTurn?: boolean\n pendingSubmissions?: readonly unknown[]\n}\n\nexport interface DelegationActionProps {\n sessionId: string\n call: (endpoint: string, payload: unknown) => Promise<unknown>\n /** Host connection-generation subscription; refetches on reconnect. */\n subscribeGeneration?: (listener: () => void) => (() => void) | undefined\n /** Host per-session selector hook; a cold→open transition triggers a refetch. */\n useSession?: <T>(selector: (snapshot: DelegationSessionSnapshotLike) => T) => T\n /** Changing a blank session's preset must refresh tool availability. */\n useProjection?: (key: 'agentPreset') => string | null | undefined\n t: Translate\n}\n\n/** Brief notice shown after a toggle problem, in the tooltip and an aria-live span. */\ntype Notice = '' | 'stale' | 'failed' | 'locked'\n\nexport function DelegationAction({ sessionId, call, subscribeGeneration, useSession, useProjection, t }: DelegationActionProps) {\n const [status, setStatus] = useState<DelegationSessionStatus>()\n const [saving, setSaving] = useState(false)\n const [notice, setNotice] = useState<Notice>('')\n const generationRef = useRef(0)\n const readSeqRef = useRef(0)\n const openState = useSession?.(snapshot => snapshot.openState)\n const sessionRunning = useSession?.(snapshot => snapshot.running === true)\n const sessionBlank = useSession?.(snapshot => snapshot.blank)\n const submitting = useSession?.(snapshot => snapshot.awaitingFirstTurn === true || (snapshot.pendingSubmissions?.length ?? 0) > 0)\n const preset = useProjection?.('agentPreset')\n\n const load = useCallback(async () => {\n const generation = generationRef.current\n const seq = ++readSeqRef.current\n try {\n const next = await rpc<DelegationSessionStatus>(call, 'session.status', { sessionId })\n if (generationRef.current !== generation || seq !== readSeqRef.current) return\n // Revisions never decrease and records are never deleted, so a stale read\n // that lands after a fresher write must not roll the button back.\n setStatus(prev => prev && prev.sessionId === next.sessionId && next.revision < prev.revision ? prev : next)\n } catch {\n // A failed refetch keeps the last known state; the button stays put.\n }\n }, [call, sessionId])\n\n useEffect(() => {\n generationRef.current += 1\n readSeqRef.current += 1\n setStatus(undefined)\n setSaving(false)\n setNotice('')\n }, [sessionId])\n\n useEffect(() => { void load() }, [load, openState, sessionRunning, sessionBlank, preset])\n\n useEffect(() => {\n const off = subscribeGeneration?.(() => { void load() })\n const win = typeof window === 'undefined' ? undefined : window\n const onFocus = () => { void load() }\n win?.addEventListener('focus', onFocus)\n return () => { off?.(); win?.removeEventListener('focus', onFocus) }\n }, [load, subscribeGeneration])\n\n useEffect(() => {\n if (!notice) return\n const timer = setTimeout(() => setNotice(''), 4000)\n return () => clearTimeout(timer)\n }, [notice])\n\n const toggle = useCallback(async () => {\n if (!status || saving || status.locked || sessionBlank === false || sessionRunning || submitting || status.capable !== true) return\n const generation = generationRef.current\n readSeqRef.current += 1\n setSaving(true)\n setNotice('')\n try {\n const next = await rpc<DelegationSessionStatus>(call, 'session.update', {\n sessionId, enabled: !status.enabled, expectedRevision: status.revision,\n })\n if (generationRef.current !== generation) return\n setStatus(next)\n } catch (reason) {\n if (generationRef.current !== generation) return\n if (reason instanceof RpcError && (reason.code === 'stale' || reason.code === 'session-locked')) {\n setNotice(reason.code === 'stale' ? 'stale' : 'locked')\n void load()\n } else {\n setNotice('failed')\n }\n } finally {\n if (generationRef.current === generation) setSaving(false)\n }\n }, [call, load, saving, sessionId, status, sessionBlank, sessionRunning, submitting])\n\n if (!status || status.role === 'executor' || sessionBlank === false) return null\n const capable = status.capable === true\n const enabled = status.enabled\n const locked = status.locked || sessionRunning || submitting\n const tooltip = status.capable === false ? t('incapable') : locked ? t('locked') : notice ? t(notice) : enabled ? t('titleOn') : t('titleOff')\n return (\n <span className=\"dlg-root dlg-action\">\n <Tooltip label={tooltip} side=\"bottom\" gap={4}>\n <Pill\n className=\"dlg-chip\"\n active={enabled}\n aria-pressed={enabled}\n aria-label={t('mode')}\n disabled={!capable || locked || saving}\n onClick={() => void toggle()}\n >\n <IconUsersOutlineRegular />\n <span className=\"dlg-chip-label\">{t('action')}</span>\n </Pill>\n </Tooltip>\n {notice ? <span role=\"status\" className=\"dlg-note\">{t(notice)}</span> : null}\n </span>\n )\n}\n\nexport const clientCss = `${officialUiCss('dlg-root')}\n.dlg-root.dlg-action { display: inline-flex; align-items: center; gap: 6px; }\n.dlg-root .dlg-chip { display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 10px; border-radius: 999px; font-size: 13px; line-height: 20px; border: 1px solid var(--dsw-alias-border-l3); background: transparent; color: var(--dsw-alias-label-secondary); cursor: pointer; }\n.dlg-root .dlg-chip svg { width: 16px; height: 16px; }\n.dlg-root .dlg-chip:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n.dlg-root .dlg-chip[aria-pressed=\"true\"] { background: var(--dsw-alias-button-primary-fill); border-color: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); }\n.dlg-root .dlg-chip[aria-pressed=\"true\"]:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); border-color: var(--dsw-alias-button-primary-hover); }\n.dlg-root .dlg-chip:disabled { opacity: 0.5; cursor: default; }\n.dlg-root .dlg-note { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshDelegationClient: { active: boolean } }\n}\n\ntype Client = Context & {\n connection: {\n generation?: { subscribe(listener: () => void): () => void }\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; order: number; locale: string; inject: () => unknown } | { name: string; key: string }, render: unknown): () => void\n }\n locale: {\n register(ns: string, locales: { zh: Record<string, string>; en: Record<string, string> }): () => void\n getSnapshot?(): { active: string }\n subscribe?(listener: () => void): () => void\n }\n}\n\n/** Host UI language, following live switches with the host's English fallback. */\nfunction useHostLocale(client: Client): string {\n const subscribe = useCallback(\n (listener: () => void) => client.locale.subscribe?.(listener) ?? (() => {}),\n [client],\n )\n const snapshot = useCallback(() => client.locale.getSnapshot?.().active ?? 'en', [client])\n return useSyncExternalStore(subscribe, snapshot, snapshot)\n}\n\nconst settingsZh = {\n default: '新会话默认启用委派',\n defaultHint: '只影响之后新建的会话;发送第一条消息前可单独选择,会话开始后保持锁定。需要预设包含子代理工具。',\n loading: '正在读取设置…',\n saved: '已保存。',\n stale: '设置已更新,请刷新后重试。',\n failed: '无法读取委派设置。',\n retry: '重试',\n refresh: '刷新设置',\n}\n\nconst settingsEn: Record<keyof typeof settingsZh, string> = {\n default: 'Enable Delegation Mode for new sessions',\n defaultHint: 'Only affects sessions created later. Choose before sending the first message; the choice stays locked once the session starts. Requires a preset with subagent tools.',\n loading: 'Loading settings…',\n saved: 'Saved.',\n stale: 'Settings changed; refresh and retry.',\n failed: 'Could not load delegation settings.',\n retry: 'Retry',\n refresh: 'Refresh settings',\n}\n\nfunction settingsCopy(locale: string): Record<keyof typeof settingsZh, string> {\n return String(locale).startsWith('zh') ? settingsZh : settingsEn\n}\n\n/** Plugin-page card: the default flag applied to sessions created from now on. */\nexport function DelegationSettingsPanel(props: { client: Client; locale?: string }) {\n const hostLocale = useHostLocale(props.client)\n const text = settingsCopy(props.locale ?? hostLocale)\n const [settings, setSettings] = useState<DelegationSettings>()\n const [error, setError] = useState<'' | 'failed' | 'stale'>('')\n const [note, setNote] = useState(false)\n const [busy, setBusy] = useState(false)\n const operation = useRef({ epoch: 0, active: false, writing: false })\n\n const call = useCallback(\n (endpoint: string, payload: unknown = {}) => props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload),\n [props.client],\n )\n\n const refresh = useCallback(() => {\n const state = operation.current\n if (!state.active || state.writing) return\n const epoch = state.epoch\n setBusy(true)\n void rpc<DelegationSettings>(call, 'settings').then(next => {\n if (!state.active || state.epoch !== epoch) return\n setSettings(next)\n setError('')\n }).catch(() => {\n if (!state.active || state.epoch !== epoch) return\n setError('failed')\n }).finally(() => {\n if (state.active && state.epoch === epoch) setBusy(false)\n })\n }, [call])\n const refreshRef = useRef(refresh)\n refreshRef.current = refresh\n useEffect(() => {\n const state = operation.current\n state.epoch++\n state.active = true\n state.writing = false\n setBusy(false)\n setSettings(undefined)\n setError('')\n setNote(false)\n refreshRef.current()\n return () => { state.active = false; state.epoch++ }\n }, [call])\n\n const save = useCallback((defaultEnabled: boolean) => {\n const state = operation.current\n if (!settings || !state.active || state.writing) return\n state.writing = true\n const epoch = state.epoch\n setBusy(true)\n setNote(false)\n setError('')\n void rpc<DelegationSettings>(call, 'settings.update', {\n defaultEnabled,\n expectedRevision: settings.revision,\n }).then(next => {\n if (!state.active || state.epoch !== epoch) return\n setSettings(next)\n setNote(true)\n }).catch(reason => {\n if (!state.active || state.epoch !== epoch) return\n setError(reason instanceof RpcError && reason.code === 'stale' ? 'stale' : 'failed')\n }).finally(() => {\n if (state.active && state.epoch === epoch) { state.writing = false; setBusy(false) }\n })\n }, [call, settings])\n\n if (!settings) {\n return (\n <section className=\"dlg-root dlg-settings dsh-ui-page\">\n {error\n ? <p role=\"alert\" className=\"dsh-ui-error\">{text[error]}</p>\n : <p role=\"status\" className=\"dsh-ui-hint\">{text.loading}</p>}\n <Button variant=\"ghost\" size=\"sm\" disabled={busy} onClick={() => refreshRef.current()}>{text.retry}</Button>\n </section>\n )\n }\n\n return (\n <section className=\"dlg-root dlg-settings dsh-ui-page\" data-testid=\"delegation-settings\">\n <div className=\"dlg-settings-status\">\n <Button variant=\"ghost\" size=\"sm\" disabled={busy} onClick={() => refreshRef.current()}>{text.refresh}</Button>\n {error && <p role=\"alert\" className=\"dsh-ui-error\">{text[error]}</p>}\n {note && <p role=\"status\" className=\"dsh-ui-notice\">{text.saved}</p>}\n </div>\n <article className=\"dlg-root dsh-ui-card\">\n <header className=\"dsh-ui-toggle-row\">\n <div className=\"dsh-ui-toggle-text\">\n <h3 className=\"dsh-ui-toggle-label\">{text.default}</h3>\n <p className=\"dsh-ui-hint\">{text.defaultHint}</p>\n </div>\n <Switch\n checked={settings.defaultEnabled}\n label={text.default}\n disabled={busy}\n onChange={next => save(next)}\n />\n </header>\n </article>\n </section>\n )\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.provide(DELEGATION_CLIENT_SERVICE, { active: true })\n ctx.effect(() => client.locale.register(NS, { zh: { ...zh }, en: { ...en } }), 'delegation.locale')\n // Style both the new-session option and the independent settings page.\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', PLUGIN_NAME)\n style.textContent = clientCss\n document.head.appendChild(style)\n return () => style.remove()\n }, 'delegation.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register(\n { name: 'plugins.bundle.config', key: PLUGIN_NAME },\n () => <DelegationSettingsPanel client={client} />,\n )), 'delegation.settings')\n ctx.effect(() => client.slots.inject('conversation.hero.options', () => client.slots.register(\n {\n name: 'conversation.hero.options',\n id: 'delegation',\n order: 20,\n locale: NS,\n inject: () => ({\n call: (endpoint: string, payload: unknown) => client.connection.rpc.call(RPC_CHANNEL, endpoint, payload),\n subscribeGeneration: (listener: () => void) => client.connection.generation?.subscribe(listener),\n }),\n },\n DelegationAction,\n )), 'delegation.slot')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.inner.cjs","names":["useState","useRef","useCallback","Tooltip","Pill","IconUsersOutlineRegular"],"sources":["../../dsh-plugin-kit/src/official-ui.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["/**\n * Shared contract that keeps every plugin's browser-side UI on the official\n * DeepSeek Harness Web design language.\n *\n * Two rules produce that language, and both are load-bearing here:\n *\n * 1. Colour, radius, elevation and focus come from the host theme's real\n * `--dsw-*` tokens, written under their own names. Plugins never invent a\n * token, never alias the official ones behind a private palette (a private\n * alias is just a second, diverging theme), and never carries a literal\n * fallback — the host publishes light and dark, and a literal would pin one\n * of them. The only non-colour custom properties used are the host's own\n * content-font axis and frame clearance.\n *\n * 2. Anything the host already ships is used, not reimplemented. Controls come\n * from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n * `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n * `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n * form suite). This module only styles what primitives do not cover: page\n * scaffolding, field layout, banners, empty states and scroll regions.\n *\n * The metrics below are transcribed from the primitives' own CSS modules so a\n * feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n * 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n * that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n */\n\n/**\n * Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n *\n * Plugins may only colour through this list. It is exported so the guard test\n * can fail a build when a stylesheet reaches for anything else — the failure\n * mode this prevents is silent: an unknown token resolves to nothing, so a\n * border disappears or a label inherits the wrong colour with no error anywhere.\n */\nexport const OFFICIAL_THEME_TOKENS = {\n /** Surfaces, from the page up to the topmost nested card. */\n surface: [\n '--dsw-alias-bg-base',\n '--dsw-alias-bg-layer-1',\n '--dsw-alias-bg-layer-2',\n '--dsw-alias-bg-layer-3',\n '--dsw-alias-bg-layer-4',\n '--dsw-alias-bg-module-platform',\n '--dsw-alias-bg-overlay',\n ],\n /** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n border: ['--dsw-alias-border-l1', '--dsw-alias-border-l2', '--dsw-alias-border-l3', '--dsw-alias-border-l4'],\n /** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n label: [\n '--dsw-alias-label-primary',\n '--dsw-alias-label-secondary',\n '--dsw-alias-label-tertiary',\n '--dsw-alias-label-caption',\n '--dsw-alias-label-dimmed',\n '--dsw-alias-label-error',\n '--dsw-alias-label-primary-foreground',\n ],\n /** Interactive fills. The `-danger` hover belongs to destructive rows. */\n interactive: [\n '--dsw-alias-interactive-bg-hover',\n '--dsw-alias-interactive-bg-active',\n '--dsw-alias-interactive-bg-hover-danger',\n ],\n /** Accent and status. `business` is the focus ring's default colour. */\n accent: [\n '--dsw-alias-brand-primary',\n '--dsw-alias-button-primary-fill',\n '--dsw-alias-button-primary-hover',\n '--dsw-alias-button-tool-bar-fill',\n '--dsw-alias-button-tool-bar-hover',\n '--dsw-alias-button-ghost-active-fill',\n '--dsw-alias-button-ghost-active-border',\n ],\n state: [\n '--dsw-alias-state-business-primary',\n '--dsw-alias-state-success-primary',\n '--dsw-alias-state-warn-primary',\n '--dsw-alias-state-error-primary',\n '--dsw-alias-state-idle-primary',\n ],\n /** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n radius: ['--dsw-radius-sm', '--dsw-radius-md', '--dsw-radius-lg', '--dsw-radius-panel'],\n /** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n elevation: [\n '--dsw-elevation-soft',\n '--dsw-elevation-stroke',\n '--dsw-elevation-stroke-color',\n '--dsw-elevation-panel',\n '--dsw-elevation-prominent',\n ],\n /** Floats, masks and scrollbars. */\n overlay: [\n '--dsw-menu-surface-fill',\n '--dsw-menu-backdrop-filter',\n '--dsw-mask-blur',\n '--dsw-alias-bg-mask-1',\n '--dsw-alias-menu-icon',\n '--dsw-alias-scrollbar-bg-l2',\n '--dsw-alias-scrollbar-hover-l2',\n '--dsw-shadow-lv3',\n ],\n /** Motion, focus and type axis, published by the host rather than by a component. */\n system: [\n '--dsw-focus-ring-width',\n '--dsw-focus-ring-color',\n '--dsw-font-markdown-code-font-family',\n '--ds-transition-duration',\n '--ds-ease-in-out',\n '--ds-font-family-code',\n '--dsh-scrollbar-thumb',\n '--dsh-scrollbar-thumb-hover',\n '--dsh-content-font-size-secondary',\n '--dsh-content-font-delta',\n '--dsh-frame-top-clearance',\n ],\n} as const\n\n/** Every official token name, flat. Used by the token guard test. */\nexport const OFFICIAL_THEME_TOKEN_NAMES: readonly string[] = Object.values(OFFICIAL_THEME_TOKENS).flat()\n\n/** The elevation steps a surface can be raised by, softest first. */\nexport type OfficialElevation = 'soft' | 'stroke' | 'panel' | 'prominent'\n\n/**\n * The host's focus ring shorthand, verbatim. Writing this per control is how\n * rings drift apart; a stylesheet that draws its own focus style should use\n * {@link officialFocus} instead. The colour fallback is the host's own default.\n */\nexport const OFFICIAL_FOCUS_RING =\n 'var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))'\n\n/**\n * A complete `outline` declaration at the official geometry. `offset` defaults\n * to the 2px the native controls use; the host's inline field rules sit at 1px\n * and a segmented tab pulls the ring inside itself at -2px.\n */\nexport function officialFocus(offset = '2px'): string {\n return `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`\n}\n\n/**\n * An elevated surface. The host draws a raised surface's edge inside its\n * shadow rather than as a border, so a card sets `border: 0` and takes the edge\n * from the elevation — which is also why its border stays off the alias-border\n * set that a flat, non-elevated rule would use.\n */\nexport function officialElevation(level: OfficialElevation): string {\n return `border: 0; box-shadow: var(--dsw-elevation-${level})`\n}\n\n/**\n * An elevated surface whose edge should read as a specific hairline. Rebinding\n * the stroke colour is how a menu card picks l1 while a panel picks l3, without\n * the two growing apart by hand.\n */\nexport function officialStrokedElevation(level: OfficialElevation, color: string): string {\n return `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`\n}\n\n/**\n * The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n *\n * Scoping is what keeps this safe to always-bundle into every client: the rules\n * can only match inside the plugin's own subtree, so two plugins can both mount\n * `dsh-ui-card` without either styling the other's markup.\n *\n * Each recipe matches the root element *and* its descendants, because the\n * commonest arrangement is one element that is both — a surface that carries\n * the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n * the `dsh-ui-surface`. A descendant-only scope would silently leave those\n * unstyled, with no error anywhere.\n *\n * A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n * content leaves the plugin's subtree entirely. A portaled surface therefore\n * needs its own root class on an element inside the portal.\n *\n * Only patterns that primitives do not provide live here. If a control appears\n * below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n * bug in this file: use the primitive and delete the recipe.\n */\nexport function officialUiCss(roots: string | readonly string[]): string {\n // One plugin often mounts several unrelated surfaces (a settings seat, a chat\n // card, a header menu), so the caller names every root. The rules below are\n // nested under a single selector list and use `&`, which the browser expands\n // per root — so one stylesheet covers all of them without duplicating itself.\n const scope = (typeof roots === 'string' ? [roots] : roots).map(root => `.${root}`).join(', ')\n const sheet = `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n/* Plugin detail pages share one reading column. These are layout recipes;\n * controls keep their own primitive styles. Form spacing follows the host's\n * settings-form/fields.module.css and SettingsForm.module.css. */\n& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }\n& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }\n&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }\n& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }\n& .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }\n@media (max-width: 560px) {\n & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }\n}\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n ${officialElevation('stroke')}\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n/* Grid fields share a row, so the stacked-field divider must not win later in\n * the cascade. Reset it here, after the field recipe. */\n& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px 14px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-left: 3px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n padding: 20px 16px;\n border: 0.5px dashed var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n min-width: 0;\n padding: 10px 12px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n padding: 10px 12px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n position: relative;\n display: flex;\n flex-direction: column;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-menu-surface-fill);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n box-shadow: var(--dsw-elevation-prominent);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n line-height: 20px;\n min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* --- Native textarea. The primitives ship no textarea either, so a settings\n * prompt keeps the platform element and the same field shell as the select:\n * 0.5px l4, radius-md, layer-3, 13/1.5 type. It grows vertically instead of\n * locking to the select's 34px row. --- */\n& .dsh-ui-textarea {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n resize: vertical;\n padding: 8px 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n& .dsh-ui-textarea:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-textarea:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-textarea::placeholder { color: var(--dsw-alias-label-dimmed); }\n& .dsh-ui-textarea[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`\n // Widen every recipe from \"a descendant of the root\" to \"the root, or one of\n // its descendants\". Written as a transform rather than by hand so no recipe\n // can be added later with only the descendant form. The pattern is narrow on\n // purpose: a leading `&` followed by one recipe class and no combinator, so\n // sibling and child rules such as `.dsh-ui-field + .dsh-ui-field` keep their\n // own meaning and are left alone.\n return sheet.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?=\\s*\\{)/gm, (_match, className: string) =>\n `&${className}, & ${className}`)\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nimport type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-delegation'\nexport const RPC_CHANNEL = '/dsh-delegation'\nexport const DELEGATION_CLIENT_SERVICE = 'dshDelegationClient'\n\n/** Native delegation tools; Delegation Mode only helps presets that mount one. */\nexport const DELEGATION_TOOLS = ['subagent', 'subagent_fork'] as const\n\nexport interface DelegationSettings {\n readonly revision: number\n /**\n * Initial flag seeded into new sessions before the settings switch existed.\n * No user-facing control writes it anymore; the stored value is still read\n * as the seed fallback so existing profiles keep their saved preference.\n */\n readonly defaultEnabled: boolean\n}\n\nexport const defaultSettings = (): DelegationSettings => ({ revision: 0, defaultEnabled: false })\n\nexport type DelegationRole = 'coordinator' | 'executor'\n\nexport interface DelegationSessionStatus {\n readonly sessionId: string\n /** 'executor' for subagent threads: they never carry their own switch. */\n readonly role: DelegationRole\n /** The session record's flag; false when the session has no record yet. */\n readonly enabled: boolean\n /** The session record's revision; 0 when the session has no record yet. */\n readonly revision: number\n /** No edit is allowed once the first turn starts, or while the session is cold. */\n readonly locked: boolean\n /**\n * Whether a live agent on this session sees a delegation tool; null when no\n * agent is live, so a stale answer is never shown as unavailable.\n */\n readonly capable: boolean | null\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { IconUsersOutlineRegular, Pill, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport {\n DELEGATION_CLIENT_SERVICE, PLUGIN_NAME, RPC_CHANNEL,\n type DelegationSessionStatus, type RpcResult,\n} from './contracts.ts'\n\nexport const name = 'dsh-delegation-client'\nexport const inject = ['slots', 'connection', 'locale'] as const\n\nconst NS = 'dsh-delegation.action'\n\nconst zh = {\n action: '委派',\n mode: '委派模式',\n titleOn: '本会话将使用委派模式:主代理负责拆解、委派和验收;会话开始后保持锁定',\n titleOff: '开启委派模式:主代理把具体工作交给子代理;会话开始后保持锁定',\n locked: '请在会话开始前选择委派模式',\n incapable: '当前预设缺少子代理工具,需切换到带子代理工具的预设',\n stale: '状态已在别处更改,已刷新',\n failed: '切换失败',\n}\n\nconst en: Record<keyof typeof zh, string> = {\n action: 'Delegate',\n mode: 'Delegation Mode',\n titleOn: 'This session will use Delegation Mode: the main agent plans, delegates, and reviews. Locked once the session starts.',\n titleOff: 'Turn on Delegation Mode: the main agent hands the work to subagents. Locked once the session starts.',\n locked: 'Choose Delegation Mode before the session starts',\n incapable: 'Delegation Mode unavailable: this preset has no subagent tools',\n stale: 'State changed elsewhere; refreshed',\n failed: 'Could not toggle Delegation Mode',\n}\n\ntype Key = keyof typeof zh\ntype Translate = (key: Key) => string\n\n/** A failed RPC keeps its code so the view can name a rejection it understands. */\nclass RpcError extends Error {\n readonly code: string\n constructor(code: string, message: string) {\n super(message)\n this.name = 'RpcError'\n this.code = code\n }\n}\n\nasync function rpc<T>(call: (endpoint: string, payload: unknown) => Promise<unknown>, endpoint: string, payload: unknown = {}): Promise<T> {\n const result = await call(endpoint, payload) as RpcResult<T> | undefined\n if (!result || result.ok !== true) {\n const failed = result && 'error' in result ? result.error : undefined\n throw new RpcError(failed?.code ?? 'unknown', failed?.message ?? '')\n }\n return result.value\n}\n\nexport interface DelegationSessionSnapshotLike {\n openState?: string\n running?: boolean\n blank?: boolean\n awaitingFirstTurn?: boolean\n pendingSubmissions?: readonly unknown[]\n}\n\nexport interface DelegationActionProps {\n sessionId: string\n call: (endpoint: string, payload: unknown) => Promise<unknown>\n /** Host connection-generation subscription; refetches on reconnect. */\n subscribeGeneration?: (listener: () => void) => (() => void) | undefined\n /** Host per-session selector hook; a cold→open transition triggers a refetch. */\n useSession?: <T>(selector: (snapshot: DelegationSessionSnapshotLike) => T) => T\n /** Changing a blank session's preset must refresh tool availability. */\n useProjection?: (key: 'agentPreset') => string | null | undefined\n t: Translate\n}\n\n/** Brief notice shown after a toggle problem, in the tooltip and an aria-live span. */\ntype Notice = '' | 'stale' | 'failed' | 'locked'\n\nexport function DelegationAction({ sessionId, call, subscribeGeneration, useSession, useProjection, t }: DelegationActionProps) {\n const [status, setStatus] = useState<DelegationSessionStatus>()\n const [saving, setSaving] = useState(false)\n const [notice, setNotice] = useState<Notice>('')\n const generationRef = useRef(0)\n const readSeqRef = useRef(0)\n const openState = useSession?.(snapshot => snapshot.openState)\n const sessionRunning = useSession?.(snapshot => snapshot.running === true)\n const sessionBlank = useSession?.(snapshot => snapshot.blank)\n const submitting = useSession?.(snapshot => snapshot.awaitingFirstTurn === true || (snapshot.pendingSubmissions?.length ?? 0) > 0)\n const preset = useProjection?.('agentPreset')\n\n const load = useCallback(async () => {\n const generation = generationRef.current\n const seq = ++readSeqRef.current\n try {\n const next = await rpc<DelegationSessionStatus>(call, 'session.status', { sessionId })\n if (generationRef.current !== generation || seq !== readSeqRef.current) return\n // Revisions never decrease and records are never deleted, so a stale read\n // that lands after a fresher write must not roll the button back.\n setStatus(prev => prev && prev.sessionId === next.sessionId && next.revision < prev.revision ? prev : next)\n } catch {\n // A failed refetch keeps the last known state; the button stays put.\n }\n }, [call, sessionId])\n\n useEffect(() => {\n generationRef.current += 1\n readSeqRef.current += 1\n setStatus(undefined)\n setSaving(false)\n setNotice('')\n }, [sessionId])\n\n useEffect(() => { void load() }, [load, openState, sessionRunning, sessionBlank, preset])\n\n useEffect(() => {\n const off = subscribeGeneration?.(() => { void load() })\n const win = typeof window === 'undefined' ? undefined : window\n const onFocus = () => { void load() }\n win?.addEventListener('focus', onFocus)\n return () => { off?.(); win?.removeEventListener('focus', onFocus) }\n }, [load, subscribeGeneration])\n\n useEffect(() => {\n if (!notice) return\n const timer = setTimeout(() => setNotice(''), 4000)\n return () => clearTimeout(timer)\n }, [notice])\n\n const toggle = useCallback(async () => {\n if (!status || saving || status.locked || sessionBlank === false || sessionRunning || submitting || status.capable !== true) return\n const generation = generationRef.current\n readSeqRef.current += 1\n setSaving(true)\n setNotice('')\n try {\n const next = await rpc<DelegationSessionStatus>(call, 'session.update', {\n sessionId, enabled: !status.enabled, expectedRevision: status.revision,\n })\n if (generationRef.current !== generation) return\n setStatus(next)\n } catch (reason) {\n if (generationRef.current !== generation) return\n if (reason instanceof RpcError && (reason.code === 'stale' || reason.code === 'session-locked')) {\n setNotice(reason.code === 'stale' ? 'stale' : 'locked')\n void load()\n } else {\n setNotice('failed')\n }\n } finally {\n if (generationRef.current === generation) setSaving(false)\n }\n }, [call, load, saving, sessionId, status, sessionBlank, sessionRunning, submitting])\n\n if (!status || status.role === 'executor' || sessionBlank === false) return null\n const capable = status.capable === true\n const enabled = status.enabled\n const locked = status.locked || sessionRunning || submitting\n const tooltip = status.capable === false ? t('incapable') : locked ? t('locked') : notice ? t(notice) : enabled ? t('titleOn') : t('titleOff')\n return (\n <span className=\"dlg-root dlg-action\">\n <Tooltip label={tooltip} side=\"bottom\" gap={4}>\n <Pill\n className=\"dlg-chip\"\n active={enabled}\n aria-pressed={enabled}\n aria-label={t('mode')}\n disabled={!capable || locked || saving}\n onClick={() => void toggle()}\n >\n <IconUsersOutlineRegular />\n <span className=\"dlg-chip-label\">{t('action')}</span>\n </Pill>\n </Tooltip>\n {notice ? <span role=\"status\" className=\"dlg-note\">{t(notice)}</span> : null}\n </span>\n )\n}\n\nexport const clientCss = `${officialUiCss('dlg-root')}\n.dlg-root.dlg-action { display: inline-flex; align-items: center; gap: 6px; }\n.dlg-root .dlg-chip { display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 10px; border-radius: 999px; font-size: 13px; line-height: 20px; border: 1px solid var(--dsw-alias-border-l3); background: transparent; color: var(--dsw-alias-label-secondary); cursor: pointer; }\n.dlg-root .dlg-chip svg { width: 16px; height: 16px; }\n.dlg-root .dlg-chip:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n.dlg-root .dlg-chip[aria-pressed=\"true\"] { background: var(--dsw-alias-button-primary-fill); border-color: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); }\n.dlg-root .dlg-chip[aria-pressed=\"true\"]:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); border-color: var(--dsw-alias-button-primary-hover); }\n.dlg-root .dlg-chip:disabled { opacity: 0.5; cursor: default; }\n.dlg-root .dlg-note { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshDelegationClient: { active: boolean } }\n}\n\ntype Client = Context & {\n connection: {\n generation?: { subscribe(listener: () => void): () => void }\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; order: number; label?: () => string; locale?: string; inject?: () => unknown }, render: unknown): () => void\n }\n locale: {\n register(ns: string, locales: { zh: Record<string, string>; en: Record<string, string> }): () => void\n }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.provide(DELEGATION_CLIENT_SERVICE, { active: true })\n ctx.effect(() => client.locale.register(NS, { zh: { ...zh }, en: { ...en } }), 'delegation.locale')\n // Style the new-session Delegate chip.\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', PLUGIN_NAME)\n style.textContent = clientCss\n document.head.appendChild(style)\n return () => style.remove()\n }, 'delegation.styles')\n // No settings row: delegation is chosen per session on the new-session\n // page, so a global default switch was redundant. The settings RPC stays\n // alive so stored rows that already carry defaultEnabled keep working.\n ctx.effect(() => client.slots.inject('conversation.hero.options', () => client.slots.register(\n {\n name: 'conversation.hero.options',\n id: 'delegation',\n order: 20,\n locale: NS,\n inject: () => ({\n call: (endpoint: string, payload: unknown) => client.connection.rpc.call(RPC_CHANNEL, endpoint, payload),\n subscribeGeneration: (listener: () => void) => client.connection.generation?.subscribe(listener),\n }),\n },\n DelegationAction,\n )), 'delegation.slot')\n}\n"],"mappings":"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"}
package/lib/client.js CHANGED
@@ -596,172 +596,6 @@ const clientCss = `${officialUiCss("dlg-root")}
596
596
  .dlg-root .dlg-chip:disabled { opacity: 0.5; cursor: default; }
597
597
  .dlg-root .dlg-note { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }
598
598
  `;
599
- /** Host UI language, following live switches with the host's English fallback. */
600
- function useHostLocale(client) {
601
- const subscribe = (0, react.useCallback)((listener) => client.locale.subscribe?.(listener) ?? (() => {}), [client]);
602
- const snapshot = (0, react.useCallback)(() => client.locale.getSnapshot?.().active ?? "en", [client]);
603
- return (0, react.useSyncExternalStore)(subscribe, snapshot, snapshot);
604
- }
605
- const settingsZh = {
606
- default: "新会话默认启用委派",
607
- defaultHint: "只影响之后新建的会话;发送第一条消息前可单独选择,会话开始后保持锁定。需要预设包含子代理工具。",
608
- loading: "正在读取设置…",
609
- saved: "已保存。",
610
- stale: "设置已更新,请刷新后重试。",
611
- failed: "无法读取委派设置。",
612
- retry: "重试",
613
- refresh: "刷新设置"
614
- };
615
- const settingsEn = {
616
- default: "Enable Delegation Mode for new sessions",
617
- defaultHint: "Only affects sessions created later. Choose before sending the first message; the choice stays locked once the session starts. Requires a preset with subagent tools.",
618
- loading: "Loading settings…",
619
- saved: "Saved.",
620
- stale: "Settings changed; refresh and retry.",
621
- failed: "Could not load delegation settings.",
622
- retry: "Retry",
623
- refresh: "Refresh settings"
624
- };
625
- function settingsCopy(locale) {
626
- return String(locale).startsWith("zh") ? settingsZh : settingsEn;
627
- }
628
- /** Plugin-page card: the default flag applied to sessions created from now on. */
629
- function DelegationSettingsPanel(props) {
630
- const hostLocale = useHostLocale(props.client);
631
- const text = settingsCopy(props.locale ?? hostLocale);
632
- const [settings, setSettings] = (0, react.useState)();
633
- const [error, setError] = (0, react.useState)("");
634
- const [note, setNote] = (0, react.useState)(false);
635
- const [busy, setBusy] = (0, react.useState)(false);
636
- const operation = (0, react.useRef)({
637
- epoch: 0,
638
- active: false,
639
- writing: false
640
- });
641
- const call = (0, react.useCallback)((endpoint, payload = {}) => props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload), [props.client]);
642
- const refresh = (0, react.useCallback)(() => {
643
- const state = operation.current;
644
- if (!state.active || state.writing) return;
645
- const epoch = state.epoch;
646
- setBusy(true);
647
- rpc(call, "settings").then((next) => {
648
- if (!state.active || state.epoch !== epoch) return;
649
- setSettings(next);
650
- setError("");
651
- }).catch(() => {
652
- if (!state.active || state.epoch !== epoch) return;
653
- setError("failed");
654
- }).finally(() => {
655
- if (state.active && state.epoch === epoch) setBusy(false);
656
- });
657
- }, [call]);
658
- const refreshRef = (0, react.useRef)(refresh);
659
- refreshRef.current = refresh;
660
- (0, react.useEffect)(() => {
661
- const state = operation.current;
662
- state.epoch++;
663
- state.active = true;
664
- state.writing = false;
665
- setBusy(false);
666
- setSettings(void 0);
667
- setError("");
668
- setNote(false);
669
- refreshRef.current();
670
- return () => {
671
- state.active = false;
672
- state.epoch++;
673
- };
674
- }, [call]);
675
- const save = (0, react.useCallback)((defaultEnabled) => {
676
- const state = operation.current;
677
- if (!settings || !state.active || state.writing) return;
678
- state.writing = true;
679
- const epoch = state.epoch;
680
- setBusy(true);
681
- setNote(false);
682
- setError("");
683
- rpc(call, "settings.update", {
684
- defaultEnabled,
685
- expectedRevision: settings.revision
686
- }).then((next) => {
687
- if (!state.active || state.epoch !== epoch) return;
688
- setSettings(next);
689
- setNote(true);
690
- }).catch((reason) => {
691
- if (!state.active || state.epoch !== epoch) return;
692
- setError(reason instanceof RpcError && reason.code === "stale" ? "stale" : "failed");
693
- }).finally(() => {
694
- if (state.active && state.epoch === epoch) {
695
- state.writing = false;
696
- setBusy(false);
697
- }
698
- });
699
- }, [call, settings]);
700
- if (!settings) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
701
- className: "dlg-root dlg-settings dsh-ui-page",
702
- children: [error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
703
- role: "alert",
704
- className: "dsh-ui-error",
705
- children: text[error]
706
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
707
- role: "status",
708
- className: "dsh-ui-hint",
709
- children: text.loading
710
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
711
- variant: "ghost",
712
- size: "sm",
713
- disabled: busy,
714
- onClick: () => refreshRef.current(),
715
- children: text.retry
716
- })]
717
- });
718
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
719
- className: "dlg-root dlg-settings dsh-ui-page",
720
- "data-testid": "delegation-settings",
721
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
722
- className: "dlg-settings-status",
723
- children: [
724
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
725
- variant: "ghost",
726
- size: "sm",
727
- disabled: busy,
728
- onClick: () => refreshRef.current(),
729
- children: text.refresh
730
- }),
731
- error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
732
- role: "alert",
733
- className: "dsh-ui-error",
734
- children: text[error]
735
- }),
736
- note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
737
- role: "status",
738
- className: "dsh-ui-notice",
739
- children: text.saved
740
- })
741
- ]
742
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("article", {
743
- className: "dlg-root dsh-ui-card",
744
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
745
- className: "dsh-ui-toggle-row",
746
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
747
- className: "dsh-ui-toggle-text",
748
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
749
- className: "dsh-ui-toggle-label",
750
- children: text.default
751
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
752
- className: "dsh-ui-hint",
753
- children: text.defaultHint
754
- })]
755
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
756
- checked: settings.defaultEnabled,
757
- label: text.default,
758
- disabled: busy,
759
- onChange: (next) => save(next)
760
- })]
761
- })
762
- })]
763
- });
764
- }
765
599
  function apply(ctx) {
766
600
  const client = ctx;
767
601
  ctx.provide(DELEGATION_CLIENT_SERVICE, { active: true });
@@ -777,10 +611,6 @@ function apply(ctx) {
777
611
  document.head.appendChild(style);
778
612
  return () => style.remove();
779
613
  }, "delegation.styles");
780
- ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
781
- name: "plugins.bundle.config",
782
- key: PLUGIN_NAME
783
- }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DelegationSettingsPanel, { client }))), "delegation.settings");
784
614
  ctx.effect(() => client.slots.inject("conversation.hero.options", () => client.slots.register({
785
615
  name: "conversation.hero.options",
786
616
  id: "delegation",
@@ -794,7 +624,6 @@ function apply(ctx) {
794
624
  }
795
625
  //#endregion
796
626
  exports.DelegationAction = DelegationAction;
797
- exports.DelegationSettingsPanel = DelegationSettingsPanel;
798
627
  exports.apply = apply;
799
628
  exports.clientCss = clientCss;
800
629
  exports.inject = inject;
@@ -8,7 +8,11 @@ declare const DELEGATION_CLIENT_SERVICE = "dshDelegationClient";
8
8
  declare const DELEGATION_TOOLS: readonly ["subagent", "subagent_fork"];
9
9
  interface DelegationSettings {
10
10
  readonly revision: number;
11
- /** Initial delegation flag for sessions created from now on. */
11
+ /**
12
+ * Initial flag seeded into new sessions before the settings switch existed.
13
+ * No user-facing control writes it anymore; the stored value is still read
14
+ * as the seed fallback so existing profiles keep their saved preference.
15
+ */
12
16
  readonly defaultEnabled: boolean;
13
17
  }
14
18
  declare const defaultSettings: () => DelegationSettings;
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nimport type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-delegation'\nexport const RPC_CHANNEL = '/dsh-delegation'\nexport const DELEGATION_CLIENT_SERVICE = 'dshDelegationClient'\n\n/** Native delegation tools; Delegation Mode only helps presets that mount one. */\nexport const DELEGATION_TOOLS = ['subagent', 'subagent_fork'] as const\n\nexport interface DelegationSettings {\n readonly revision: number\n /** Initial delegation flag for sessions created from now on. */\n readonly defaultEnabled: boolean\n}\n\nexport const defaultSettings = (): DelegationSettings => ({ revision: 0, defaultEnabled: false })\n\nexport type DelegationRole = 'coordinator' | 'executor'\n\nexport interface DelegationSessionStatus {\n readonly sessionId: string\n /** 'executor' for subagent threads: they never carry their own switch. */\n readonly role: DelegationRole\n /** The session record's flag; false when the session has no record yet. */\n readonly enabled: boolean\n /** The session record's revision; 0 when the session has no record yet. */\n readonly revision: number\n /** No edit is allowed once the first turn starts, or while the session is cold. */\n readonly locked: boolean\n /**\n * Whether a live agent on this session sees a delegation tool; null when no\n * agent is live, so a stale answer is never shown as unavailable.\n */\n readonly capable: boolean | null\n}\n"],"mappings":";AAIA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,4BAA4B;;AAGzC,MAAa,mBAAmB,CAAC,YAAY,eAAe;AAQ5D,MAAa,yBAA6C;CAAE,UAAU;CAAG,gBAAgB;AAAM"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nimport type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-delegation'\nexport const RPC_CHANNEL = '/dsh-delegation'\nexport const DELEGATION_CLIENT_SERVICE = 'dshDelegationClient'\n\n/** Native delegation tools; Delegation Mode only helps presets that mount one. */\nexport const DELEGATION_TOOLS = ['subagent', 'subagent_fork'] as const\n\nexport interface DelegationSettings {\n readonly revision: number\n /**\n * Initial flag seeded into new sessions before the settings switch existed.\n * No user-facing control writes it anymore; the stored value is still read\n * as the seed fallback so existing profiles keep their saved preference.\n */\n readonly defaultEnabled: boolean\n}\n\nexport const defaultSettings = (): DelegationSettings => ({ revision: 0, defaultEnabled: false })\n\nexport type DelegationRole = 'coordinator' | 'executor'\n\nexport interface DelegationSessionStatus {\n readonly sessionId: string\n /** 'executor' for subagent threads: they never carry their own switch. */\n readonly role: DelegationRole\n /** The session record's flag; false when the session has no record yet. */\n readonly enabled: boolean\n /** The session record's revision; 0 when the session has no record yet. */\n readonly revision: number\n /** No edit is allowed once the first turn starts, or while the session is cold. */\n readonly locked: boolean\n /**\n * Whether a live agent on this session sees a delegation tool; null when no\n * agent is live, so a stale answer is never shown as unavailable.\n */\n readonly capable: boolean | null\n}\n"],"mappings":";AAIA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,4BAA4B;;AAGzC,MAAa,mBAAmB,CAAC,YAAY,eAAe;AAY5D,MAAa,yBAA6C;CAAE,UAAU;CAAG,gBAAgB;AAAM"}
package/lib/index.d.ts CHANGED
@@ -104,7 +104,7 @@ declare class DelegationService {
104
104
  /**
105
105
  * `agent/created` seeding. Only a fresh ('startup') non-subagent session gets
106
106
  * an initial row: a human fork inherits its parent's flag, every other new
107
- * top-level session takes the current `defaultEnabled`. Resumed, cleared and
107
+ * top-level session takes the stored `defaultEnabled`. Resumed, cleared and
108
108
  * compacted sessions keep whatever they already have — and stay off when
109
109
  * they predate the plugin.
110
110
  */
package/lib/index.js CHANGED
@@ -173,7 +173,7 @@ var DelegationService = class {
173
173
  /**
174
174
  * `agent/created` seeding. Only a fresh ('startup') non-subagent session gets
175
175
  * an initial row: a human fork inherits its parent's flag, every other new
176
- * top-level session takes the current `defaultEnabled`. Resumed, cleared and
176
+ * top-level session takes the stored `defaultEnabled`. Resumed, cleared and
177
177
  * compacted sessions keep whatever they already have — and stay off when
178
178
  * they predate the plugin.
179
179
  */
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/storage.ts","../src/service.ts","../src/prompts.ts","../src/policy.ts","../src/index.ts"],"sourcesContent":["import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\nimport { z } from 'zod'\nimport { defaultSettings, type DelegationSettings } from './contracts.ts'\n\nexport const SETTINGS_KEY = 'global'\n\nexport const settingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n defaultEnabled: z.boolean(),\n}).strict()\n\nexport const sessionSchema = z.object({\n enabled: z.boolean(),\n revision: z.number().int().min(1),\n}).strict()\n\nexport interface SessionDelegation {\n readonly enabled: boolean\n readonly revision: number\n}\n\nexport const settingsUpdateSchema = z.object({\n defaultEnabled: z.boolean(),\n expectedRevision: z.number().int().nonnegative(),\n}).strict()\n\nexport const sessionStatusSchema = z.object({\n sessionId: z.string().min(1),\n}).strict()\n\nexport const sessionUpdateSchema = z.object({\n sessionId: z.string().min(1),\n enabled: z.boolean(),\n expectedRevision: z.number().int().nonnegative(),\n}).strict()\n\nexport const delegationDomain = defineDomain({\n name: 'dsh_delegation',\n version: 1,\n tables: {\n settings: domainTable<string, DelegationSettings>(settingsSchema),\n sessions: domainTable<string, SessionDelegation>(sessionSchema),\n },\n})\n\n/** A missing or unreadable settings row reads as the shipped defaults. */\nexport function parseSettings(value: unknown): DelegationSettings {\n const parsed = settingsSchema.safeParse(value)\n if (!parsed.success) return defaultSettings()\n return { revision: parsed.data.revision, defaultEnabled: parsed.data.defaultEnabled }\n}\n\n/** A missing or unreadable session row reads as \"no record\": off, revision 0. */\nexport function parseSession(value: unknown): SessionDelegation | undefined {\n const parsed = sessionSchema.safeParse(value)\n if (!parsed.success) return undefined\n return { enabled: parsed.data.enabled, revision: parsed.data.revision }\n}\n","import { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport {\n DELEGATION_TOOLS, type DelegationSessionStatus, type DelegationSettings,\n} from './contracts.ts'\nimport { parseSession, parseSettings, SETTINGS_KEY, type SessionDelegation } from './storage.ts'\nimport type { DelegationSessionLike } from './policy.ts'\n\nexport class DelegationError extends Error {\n readonly code: string\n constructor(code: string, message: string) {\n super(message)\n this.name = 'DelegationError'\n this.code = code\n }\n}\n\nexport interface DelegationTableLike<V> {\n get(key: string): V | undefined\n put(key: string, value: V): Promise<void>\n}\n\nexport interface DelegationAgentLike {\n readonly id: string\n readonly session?: DelegationSessionLike\n /** Claims the host's idle phase; waking input waits until this task settles. */\n runMaintenance?<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T>\n}\n\n/** Cold-session read handle from the host's session query engine. */\nexport interface DelegationObservationLike {\n readonly header?: unknown\n [Symbol.dispose](): void\n}\n\nexport interface DelegationServiceDeps {\n /** Parsed global settings row (one key: 'global'). */\n readonly settings: DelegationTableLike<DelegationSettings>\n /** Parsed per-session rows (key: session id). */\n readonly records: DelegationTableLike<SessionDelegation>\n readonly sessionStore?: { get(id: string): DelegationSessionLike | undefined }\n readonly agents?: { get(id: string): DelegationAgentLike | undefined }\n readonly tools?: { get(name: string, scope?: unknown): unknown }\n /** Durable turn-boundary projection, including inherited and resumed turns. */\n readonly hasStarted?: (session: DelegationSessionLike) => boolean\n /** Reads persisted headers for sessions that are not live (cold sessions). */\n readonly sessionQuery?: {\n observeSession(id: string, options: { signal?: AbortSignal; projectionMode?: string }): Promise<DelegationObservationLike>\n }\n}\n\n/**\n * In-process CAS over the two domain tables. Table `get` is synchronous, so a\n * per-key promise chain serializes check-and-write: two concurrent updates can\n * never both pass the revision check, and a caller only hears success after\n * `put` resolves.\n */\nexport class DelegationService {\n private readonly deps: DelegationServiceDeps\n private readonly chains = new Map<string, Promise<void>>()\n\n constructor(deps: DelegationServiceDeps) {\n this.deps = deps\n }\n\n private enqueue<T>(key: string, work: () => Promise<T>): Promise<T> {\n const pending = this.chains.get(key) ?? Promise.resolve()\n const result = pending.then(work, work)\n this.chains.set(key, result.then(() => {}, () => {}))\n return result\n }\n\n getSettings(): DelegationSettings {\n return parseSettings(this.deps.settings.get(SETTINGS_KEY))\n }\n\n updateSettings(defaultEnabled: boolean, expectedRevision: number): Promise<DelegationSettings> {\n return this.enqueue('settings', async () => {\n const current = this.getSettings()\n if (current.revision !== expectedRevision) {\n throw new DelegationError('stale', 'dsh-delegation: settings changed; refresh and retry')\n }\n const next: DelegationSettings = { revision: current.revision + 1, defaultEnabled }\n await this.deps.settings.put(SETTINGS_KEY, next)\n return next\n })\n }\n\n /** The parsed session row; undefined means no record (off, revision 0). */\n record(sessionId: string): SessionDelegation | undefined {\n return parseSession(this.deps.records.get(sessionId))\n }\n\n private locked(session: DelegationSessionLike | undefined, agent: DelegationAgentLike | undefined): boolean {\n // A cold or incompletely composed session cannot safely race prompt admission.\n return !session || !agent?.runMaintenance || this.deps.hasStarted?.(session) !== false\n }\n\n /**\n * The session header: live sessions read the store snapshot; a cold session\n * is resolved through the query engine and the observation is always\n * disposed before returning. Unknown sessions throw `no-session`.\n */\n private async requireHeader(sessionId: string, signal?: AbortSignal): Promise<unknown> {\n const live = this.deps.sessionStore?.get(sessionId)\n if (live) return live.header\n const query = this.deps.sessionQuery\n if (!query) throw new DelegationError('no-session', `dsh-delegation: no live session ${sessionId}`)\n let observation: DelegationObservationLike\n try {\n observation = await query.observeSession(sessionId, { signal, projectionMode: 'none' })\n } catch {\n throw new DelegationError('no-session', `dsh-delegation: no session ${sessionId}`)\n }\n try {\n return observation.header\n } finally {\n observation[Symbol.dispose]()\n }\n }\n\n async sessionStatus(sessionId: string, signal?: AbortSignal): Promise<DelegationSessionStatus> {\n const session = this.deps.sessionStore?.get(sessionId)\n const header = session ? session.header : await this.requireHeader(sessionId, signal)\n const agent = session ? this.deps.agents?.get(sessionId) : undefined\n const capable = agent === undefined\n ? null\n : DELEGATION_TOOLS.some(name => this.deps.tools?.get(name, agent) !== undefined)\n const record = this.record(sessionId)\n return {\n sessionId,\n role: isSubagentSession({ header }) ? 'executor' : 'coordinator',\n enabled: record?.enabled ?? false,\n revision: record?.revision ?? 0,\n locked: this.locked(session, agent),\n capable,\n }\n }\n\n async updateSession(sessionId: string, enabled: boolean, expectedRevision: number, signal?: AbortSignal): Promise<DelegationSessionStatus> {\n const session = this.deps.sessionStore?.get(sessionId)\n const header = session ? session.header : await this.requireHeader(sessionId, signal)\n if (isSubagentSession({ header })) {\n throw new DelegationError('not-top-level', 'dsh-delegation: only a top-level session carries the switch')\n }\n await this.enqueue(`session:${sessionId}`, async () => {\n const live = this.deps.sessionStore?.get(sessionId)\n const agent = this.deps.agents?.get(sessionId)\n const requireEditable = () => {\n if (this.locked(live, agent)) {\n throw new DelegationError('session-locked', 'dsh-delegation: choose delegation before the session starts')\n }\n }\n requireEditable()\n let entered = false\n try {\n // The host holds first-turn input while storage commits. Without this\n // guard, a slow save could change the policy after the first assembly.\n await agent!.runMaintenance!(async maintenanceSignal => {\n entered = true\n requireEditable()\n maintenanceSignal.throwIfAborted()\n signal?.throwIfAborted()\n const current = this.record(sessionId)\n const revision = current?.revision ?? 0\n if (revision !== expectedRevision) {\n throw new DelegationError('stale', 'dsh-delegation: session state changed; refresh and retry')\n }\n await this.deps.records.put(sessionId, { enabled, revision: revision + 1 })\n })\n } catch (error) {\n if (!entered) throw new DelegationError('session-busy', 'dsh-delegation: session is busy; refresh and retry')\n throw error\n }\n })\n return this.sessionStatus(sessionId, signal)\n }\n\n /**\n * `agent/created` seeding. Only a fresh ('startup') non-subagent session gets\n * an initial row: a human fork inherits its parent's flag, every other new\n * top-level session takes the current `defaultEnabled`. Resumed, cleared and\n * compacted sessions keep whatever they already have — and stay off when\n * they predate the plugin.\n */\n async seedSession(agent: DelegationAgentLike, source: string): Promise<void> {\n if (source !== 'startup') return\n const session = agent.session\n if (!session || isSubagentSession(session)) return\n const id = session.id\n await this.enqueue(`session:${id}`, async () => {\n if (this.record(id)) return\n const parentId = typeof session.header?.parentSession === 'string' ? session.header.parentSession : undefined\n const inherited = parentId ? this.record(parentId) : undefined\n const enabled = inherited?.enabled ?? this.getSettings().defaultEnabled\n await this.deps.records.put(id, { enabled, revision: 1 })\n })\n }\n}\n","/**\n * System prompt text for delegation mode. Kept literal (the section registers\n * with `interpolate: false`), so no `{{variable}}` syntax may appear here.\n */\n\n/** Coordinator policy for a top-level session with delegation on. */\nexport function coordinatorPrompt(tools: readonly string[]): string {\n const names = tools.map(name => `\\`${name}\\``).join(' / ')\n return `## Delegation mode\n\nDelegation mode is on. You are the coordinator; ${names} are how you get substantive work done. You own the requirements, division of work, integration decisions, acceptance, and the final response.\n\nFor a task with multiple components or substantive implementation steps, dispatch a scoped subagent task BEFORE implementing it yourself. A todo list or a promise to delegate is not a delegation. Do not first design every function, read the entire project, or start writing the deliverable. If the split is unclear, delegate a focused discovery task and use its report to choose the next assignments.\n\n- Make a short plan that is sufficient to assign work, then call the delegation tool. Prefer a fresh subagent for a self-contained brief. A fork inherits completed turns, not the current in-flight user request: always include the current task and constraints explicitly.\n- Each brief must contain the goal, working directory, allowed files, shared interface/data contracts, acceptance criteria, and what to report. Give each file one active owner. Start independent assignments together; resolve shared contracts before dependent work starts.\n- Subagents read, implement, run commands, test, and fix their assigned work. You may do a brief targeted read or an acceptance check to make a coordination decision; do not use that exception to take over an implementation task.\n- Track the returned subagent ids. Use native completion notifications and send_message for questions, corrections, or follow-up work. Do not repeatedly poll or sleep. Do not claim completion while required work is still running.\n- Inspect the delivered files and verification evidence. Send concrete failures back to the responsible subagent; collect and check the correction. Finish with the usable result, the checks actually performed, and any remaining limitation.\n\nA simple question, short rewrite, or genuinely small self-contained task may be completed directly. This exception does not cover building an application or completing a multi-part feature. Keep user-facing updates in the user's language.`\n}\n\n/** Executor policy for a subagent whose top-level session has delegation on. */\nexport const EXECUTOR_PROMPT = `## Delegated task\n\nYou are a subagent carrying out a task delegated by a coordinating agent. Coordinator instructions that appear earlier in this conversation, for example ones inherited through a fork, do not apply to you.\n\n- Do the work yourself: read, search, edit, run commands, and verify as the task requires. Make concrete progress in the assigned files; do not stop at a design or a plan. Do not pass the task on to further subagents unless the brief asks for it or clearly independent parts justify running them in parallel.\n- Stay within the brief. If it is ambiguous, make a reasonable choice and state it; if you are blocked, stop and report what is missing.\n- Respect file ownership and agreed interfaces. Ask the coordinator before changing another worker's files or a shared contract.\n- Verify your result before reporting.\n- End with a concise report: the result, the files or locations changed, the evidence (commands run and their outcome), and unresolved issues. Do not paste full logs.`\n\n/** Stable operational reminder; the host persists it only when context changes. */\nexport function coordinatorReminder(tools: readonly string[]): string {\n return `Delegation mode: coordinator. For multi-part work, your next implementation action must be a scoped assignment through ${tools.map(name => `\\`${name}\\``).join(' / ')}, not doing that implementation yourself. Plan only far enough to dispatch; give workers file ownership and interface contracts, then collect and verify their results. Simple self-contained tasks may be answered directly. This mode remains fixed for this session.`\n}\n\nexport const EXECUTOR_REMINDER = 'Delegation mode: executor. Carry out the assigned work in your allowed files and verify it. Earlier coordinator reminders inherited from a parent do not assign you the coordinator role. Report concrete results and evidence to your parent.'\n","import { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { DELEGATION_TOOLS } from './contracts.ts'\nimport { coordinatorPrompt, coordinatorReminder, EXECUTOR_PROMPT, EXECUTOR_REMINDER } from './prompts.ts'\n\nexport interface DelegationSessionLike {\n readonly id: string\n readonly header?: { readonly parentSession?: unknown }\n}\n\n/** The per-assembly lookups the policy needs; callers inject the live stores. */\nexport interface DelegationLookups {\n /** Parsed per-session record; undefined means no record. */\n record(sessionId: string): { readonly enabled: boolean } | undefined\n session(sessionId: string): DelegationSessionLike | undefined\n /** Whether a tool name resolves in this assembly's scope. */\n toolVisible(name: string, scope: unknown): boolean\n}\n\nexport interface DelegationAssembleContext {\n readonly agent?: { readonly session: DelegationSessionLike }\n readonly scope?: unknown\n}\n\n/** Ancestor walk bound: subagent chains deeper than this bail out as off. */\nconst MAX_PARENT_HOPS = 16\n\n/** First non-subagent ancestor reachable through `header.parentSession`. */\nfunction topLevelSession(\n session: DelegationSessionLike,\n sessions: DelegationLookups['session'],\n): DelegationSessionLike | undefined {\n const seen = new Set<string>([session.id])\n let current = session\n for (let hop = 0; hop < MAX_PARENT_HOPS && isSubagentSession(current); hop++) {\n const parentId = typeof current.header?.parentSession === 'string' ? current.header.parentSession : undefined\n if (!parentId || seen.has(parentId)) return undefined\n seen.add(parentId)\n const parent = sessions(parentId)\n if (!parent) return undefined\n current = parent\n }\n return isSubagentSession(current) ? undefined : current\n}\n\ntype Policy = { role: 'executor' } | { role: 'coordinator'; tools: readonly string[] }\n\n/** Both prompt surfaces must use the same role and capability decision. */\nfunction delegationPolicy(context: DelegationAssembleContext, lookups: DelegationLookups): Policy | undefined {\n const session = context.agent?.session\n if (!session) return undefined\n if (isSubagentSession(session)) {\n const root = topLevelSession(session, lookups.session)\n return root && lookups.record(root.id)?.enabled ? { role: 'executor' } : undefined\n }\n if (!lookups.record(session.id)?.enabled) return undefined\n const visible = DELEGATION_TOOLS.filter(name => lookups.toolVisible(name, context.scope))\n return visible.length ? { role: 'coordinator', tools: visible } : undefined\n}\n\n/** Static system guidance. No per-step counters or progress belong in this text. */\nexport function delegationSectionText(context: DelegationAssembleContext, lookups: DelegationLookups): string {\n const policy = delegationPolicy(context, lookups)\n if (!policy) return ''\n return policy.role === 'executor' ? EXECUTOR_PROMPT : coordinatorPrompt(policy.tools)\n}\n\n/** Stable user-role context snapshot, refreshed by the host after compaction. */\nexport function delegationReminderText(context: DelegationAssembleContext, lookups: DelegationLookups): string {\n const policy = delegationPolicy(context, lookups)\n if (!policy) return ''\n return policy.role === 'executor' ? EXECUTOR_REMINDER : coordinatorReminder(policy.tools)\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-agent'\nimport type { Session } from '@deepseek-ai/dsh-session'\nimport type {} from '@deepseek-ai/dsh-session-query'\nimport type {} from '@deepseek-ai/dsh-storage-domain'\nimport type {} from '@deepseek-ai/dsh-system-prompt'\nimport type {} from '@deepseek-ai/dsh-tools'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-plugin-kit/host-rpc'\nimport {\n PLUGIN_NAME, RPC_CHANNEL,\n type DelegationSessionStatus, type DelegationSettings, type RpcResult,\n} from './contracts.ts'\nimport { delegationDomain,\n sessionStatusSchema, sessionUpdateSchema, settingsUpdateSchema } from './storage.ts'\nimport { DelegationError, DelegationService, type DelegationAgentLike, type DelegationServiceDeps } from './service.ts'\nimport { delegationSectionText, delegationReminderText, type DelegationLookups } from './policy.ts'\n\nexport const name = PLUGIN_NAME\nexport const inject = ['systemPrompt', 'storageDomain', 'sessions', 'agents', 'tools', 'sessionQuery', 'sessionProjections', 'connection', 'webServer'] as const\nexport { DelegationService, DelegationError } from './service.ts'\nexport { delegationSectionText } from './policy.ts'\nexport { coordinatorPrompt, EXECUTOR_PROMPT } from './prompts.ts'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { delegation: DelegationService }\n}\n\nfunction fail(error: unknown): RpcResult<never> {\n if (error instanceof DelegationError) {\n return { ok: false, error: { code: error.code, message: error.message } }\n }\n const message = error instanceof Error ? error.message : String(error)\n return { ok: false, error: { code: 'internal', message } }\n}\n\nexport async function handleRpc(\n service: DelegationService,\n endpoint: string,\n payload: unknown,\n signal: AbortSignal,\n): Promise<RpcResult> {\n try {\n switch (endpoint) {\n case 'settings': {\n const value: DelegationSettings = service.getSettings()\n return { ok: true, value }\n }\n case 'settings.update': {\n const parsed = settingsUpdateSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'settings update is invalid' } }\n const value: DelegationSettings = await service.updateSettings(parsed.data.defaultEnabled, parsed.data.expectedRevision)\n return { ok: true, value }\n }\n case 'session.status': {\n const parsed = sessionStatusSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'sessionId is required' } }\n const value: DelegationSessionStatus = await service.sessionStatus(parsed.data.sessionId, signal)\n return { ok: true, value }\n }\n case 'session.update': {\n const parsed = sessionUpdateSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'session update is invalid' } }\n const value: DelegationSessionStatus = await service.updateSession(\n parsed.data.sessionId, parsed.data.enabled, parsed.data.expectedRevision, signal)\n return { ok: true, value }\n }\n default:\n return { ok: false, error: { code: 'not-found', message: `unknown endpoint: ${endpoint}` } }\n }\n } catch (error) {\n return fail(error)\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Context & HostRpcContext\n const domain = await ctx.storageDomain.open(delegationDomain)\n const service = new DelegationService({\n settings: domain.table('settings'),\n records: domain.table('sessions'),\n sessionStore: ctx.sessions as unknown as DelegationServiceDeps['sessionStore'],\n agents: ctx.agents as unknown as DelegationServiceDeps['agents'],\n tools: ctx.tools as unknown as DelegationServiceDeps['tools'],\n sessionQuery: ctx.sessionQuery as unknown as DelegationServiceDeps['sessionQuery'],\n hasStarted: session => {\n const boundary = ctx.sessionProjections.stateOf(session as Session, 'turnBoundary')\n return boundary === undefined || boundary.openTurnStartSeq !== null || boundary.lastTurn > 0\n },\n })\n ctx.provide('delegation', service)\n ctx.effect(() => () => domain.close(), 'delegation.lifecycle')\n // Seeding listens on agent/created: serial and awaited before the agent's\n // queued work, so the row exists before the first prompt assembly. A throw\n // here would fail agent creation, so the listener never propagates one.\n ctx.effect(() => ctx.on('agent/created', async ({ agent, source }: { agent: DelegationAgentLike; source: string }) => {\n try {\n await service.seedSession(agent, source)\n } catch (error) {\n ctx.logger.warn('dsh-delegation: could not seed session state: %s', error instanceof Error ? error.message : String(error))\n }\n }), 'delegation.seed')\n // Read-only advisory text evaluated at every assembly; the choice is locked\n // before the first model step and stays stable across later turns. Covers\n // subagent sessions deliberately: the executor half IS their prompt.\n const sectionSessions = ctx.sessions as unknown as DelegationServiceDeps['sessionStore']\n const sectionTools = ctx.tools as unknown as DelegationServiceDeps['tools']\n const lookups: DelegationLookups = {\n record: sessionId => service.record(sessionId),\n session: id => sectionSessions?.get(id),\n toolVisible: (tool, scope) => sectionTools?.get(tool, scope) !== undefined,\n }\n ctx.effect(() => ctx.systemPrompt.section({\n name: 'delegation:policy',\n order: ctx.systemPrompt.getSectionOrder('TOOL_SUBAGENT') + 2,\n interpolate: false,\n text: context => delegationSectionText(context, lookups),\n }), 'delegation.section')\n // Native runtime context is durable and appended only when its snapshot\n // changes (or after compaction), not a new reminder injected at every step.\n // Include children deliberately: a fork must replace inherited coordinator\n // context with its own executor role. Neither contribution writes by itself.\n ctx.effect(() => ctx.systemPrompt.context({\n name: 'delegation:role',\n order: ctx.systemPrompt.getContextOrder('SUBAGENT_DELEGATION') + 2,\n required: true,\n interpolate: false,\n text: context => delegationReminderText(context, lookups),\n }), 'delegation.context')\n ctx.effect(() => registerHostRpc(host, RPC_CHANNEL,\n (endpoint, payload, signal) => handleRpc(service, endpoint, payload, signal)), 'delegation.rpc')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/storage.ts","../src/service.ts","../src/prompts.ts","../src/policy.ts","../src/index.ts"],"sourcesContent":["import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\nimport { z } from 'zod'\nimport { defaultSettings, type DelegationSettings } from './contracts.ts'\n\nexport const SETTINGS_KEY = 'global'\n\nexport const settingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n defaultEnabled: z.boolean(),\n}).strict()\n\nexport const sessionSchema = z.object({\n enabled: z.boolean(),\n revision: z.number().int().min(1),\n}).strict()\n\nexport interface SessionDelegation {\n readonly enabled: boolean\n readonly revision: number\n}\n\nexport const settingsUpdateSchema = z.object({\n defaultEnabled: z.boolean(),\n expectedRevision: z.number().int().nonnegative(),\n}).strict()\n\nexport const sessionStatusSchema = z.object({\n sessionId: z.string().min(1),\n}).strict()\n\nexport const sessionUpdateSchema = z.object({\n sessionId: z.string().min(1),\n enabled: z.boolean(),\n expectedRevision: z.number().int().nonnegative(),\n}).strict()\n\nexport const delegationDomain = defineDomain({\n name: 'dsh_delegation',\n version: 1,\n tables: {\n settings: domainTable<string, DelegationSettings>(settingsSchema),\n sessions: domainTable<string, SessionDelegation>(sessionSchema),\n },\n})\n\n/** A missing or unreadable settings row reads as the shipped defaults. */\nexport function parseSettings(value: unknown): DelegationSettings {\n const parsed = settingsSchema.safeParse(value)\n if (!parsed.success) return defaultSettings()\n return { revision: parsed.data.revision, defaultEnabled: parsed.data.defaultEnabled }\n}\n\n/** A missing or unreadable session row reads as \"no record\": off, revision 0. */\nexport function parseSession(value: unknown): SessionDelegation | undefined {\n const parsed = sessionSchema.safeParse(value)\n if (!parsed.success) return undefined\n return { enabled: parsed.data.enabled, revision: parsed.data.revision }\n}\n","import { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport {\n DELEGATION_TOOLS, type DelegationSessionStatus, type DelegationSettings,\n} from './contracts.ts'\nimport { parseSession, parseSettings, SETTINGS_KEY, type SessionDelegation } from './storage.ts'\nimport type { DelegationSessionLike } from './policy.ts'\n\nexport class DelegationError extends Error {\n readonly code: string\n constructor(code: string, message: string) {\n super(message)\n this.name = 'DelegationError'\n this.code = code\n }\n}\n\nexport interface DelegationTableLike<V> {\n get(key: string): V | undefined\n put(key: string, value: V): Promise<void>\n}\n\nexport interface DelegationAgentLike {\n readonly id: string\n readonly session?: DelegationSessionLike\n /** Claims the host's idle phase; waking input waits until this task settles. */\n runMaintenance?<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T>\n}\n\n/** Cold-session read handle from the host's session query engine. */\nexport interface DelegationObservationLike {\n readonly header?: unknown\n [Symbol.dispose](): void\n}\n\nexport interface DelegationServiceDeps {\n /** Parsed global settings row (one key: 'global'). */\n readonly settings: DelegationTableLike<DelegationSettings>\n /** Parsed per-session rows (key: session id). */\n readonly records: DelegationTableLike<SessionDelegation>\n readonly sessionStore?: { get(id: string): DelegationSessionLike | undefined }\n readonly agents?: { get(id: string): DelegationAgentLike | undefined }\n readonly tools?: { get(name: string, scope?: unknown): unknown }\n /** Durable turn-boundary projection, including inherited and resumed turns. */\n readonly hasStarted?: (session: DelegationSessionLike) => boolean\n /** Reads persisted headers for sessions that are not live (cold sessions). */\n readonly sessionQuery?: {\n observeSession(id: string, options: { signal?: AbortSignal; projectionMode?: string }): Promise<DelegationObservationLike>\n }\n}\n\n/**\n * In-process CAS over the two domain tables. Table `get` is synchronous, so a\n * per-key promise chain serializes check-and-write: two concurrent updates can\n * never both pass the revision check, and a caller only hears success after\n * `put` resolves.\n */\nexport class DelegationService {\n private readonly deps: DelegationServiceDeps\n private readonly chains = new Map<string, Promise<void>>()\n\n constructor(deps: DelegationServiceDeps) {\n this.deps = deps\n }\n\n private enqueue<T>(key: string, work: () => Promise<T>): Promise<T> {\n const pending = this.chains.get(key) ?? Promise.resolve()\n const result = pending.then(work, work)\n this.chains.set(key, result.then(() => {}, () => {}))\n return result\n }\n\n getSettings(): DelegationSettings {\n return parseSettings(this.deps.settings.get(SETTINGS_KEY))\n }\n\n updateSettings(defaultEnabled: boolean, expectedRevision: number): Promise<DelegationSettings> {\n return this.enqueue('settings', async () => {\n const current = this.getSettings()\n if (current.revision !== expectedRevision) {\n throw new DelegationError('stale', 'dsh-delegation: settings changed; refresh and retry')\n }\n const next: DelegationSettings = { revision: current.revision + 1, defaultEnabled }\n await this.deps.settings.put(SETTINGS_KEY, next)\n return next\n })\n }\n\n /** The parsed session row; undefined means no record (off, revision 0). */\n record(sessionId: string): SessionDelegation | undefined {\n return parseSession(this.deps.records.get(sessionId))\n }\n\n private locked(session: DelegationSessionLike | undefined, agent: DelegationAgentLike | undefined): boolean {\n // A cold or incompletely composed session cannot safely race prompt admission.\n return !session || !agent?.runMaintenance || this.deps.hasStarted?.(session) !== false\n }\n\n /**\n * The session header: live sessions read the store snapshot; a cold session\n * is resolved through the query engine and the observation is always\n * disposed before returning. Unknown sessions throw `no-session`.\n */\n private async requireHeader(sessionId: string, signal?: AbortSignal): Promise<unknown> {\n const live = this.deps.sessionStore?.get(sessionId)\n if (live) return live.header\n const query = this.deps.sessionQuery\n if (!query) throw new DelegationError('no-session', `dsh-delegation: no live session ${sessionId}`)\n let observation: DelegationObservationLike\n try {\n observation = await query.observeSession(sessionId, { signal, projectionMode: 'none' })\n } catch {\n throw new DelegationError('no-session', `dsh-delegation: no session ${sessionId}`)\n }\n try {\n return observation.header\n } finally {\n observation[Symbol.dispose]()\n }\n }\n\n async sessionStatus(sessionId: string, signal?: AbortSignal): Promise<DelegationSessionStatus> {\n const session = this.deps.sessionStore?.get(sessionId)\n const header = session ? session.header : await this.requireHeader(sessionId, signal)\n const agent = session ? this.deps.agents?.get(sessionId) : undefined\n const capable = agent === undefined\n ? null\n : DELEGATION_TOOLS.some(name => this.deps.tools?.get(name, agent) !== undefined)\n const record = this.record(sessionId)\n return {\n sessionId,\n role: isSubagentSession({ header }) ? 'executor' : 'coordinator',\n enabled: record?.enabled ?? false,\n revision: record?.revision ?? 0,\n locked: this.locked(session, agent),\n capable,\n }\n }\n\n async updateSession(sessionId: string, enabled: boolean, expectedRevision: number, signal?: AbortSignal): Promise<DelegationSessionStatus> {\n const session = this.deps.sessionStore?.get(sessionId)\n const header = session ? session.header : await this.requireHeader(sessionId, signal)\n if (isSubagentSession({ header })) {\n throw new DelegationError('not-top-level', 'dsh-delegation: only a top-level session carries the switch')\n }\n await this.enqueue(`session:${sessionId}`, async () => {\n const live = this.deps.sessionStore?.get(sessionId)\n const agent = this.deps.agents?.get(sessionId)\n const requireEditable = () => {\n if (this.locked(live, agent)) {\n throw new DelegationError('session-locked', 'dsh-delegation: choose delegation before the session starts')\n }\n }\n requireEditable()\n let entered = false\n try {\n // The host holds first-turn input while storage commits. Without this\n // guard, a slow save could change the policy after the first assembly.\n await agent!.runMaintenance!(async maintenanceSignal => {\n entered = true\n requireEditable()\n maintenanceSignal.throwIfAborted()\n signal?.throwIfAborted()\n const current = this.record(sessionId)\n const revision = current?.revision ?? 0\n if (revision !== expectedRevision) {\n throw new DelegationError('stale', 'dsh-delegation: session state changed; refresh and retry')\n }\n await this.deps.records.put(sessionId, { enabled, revision: revision + 1 })\n })\n } catch (error) {\n if (!entered) throw new DelegationError('session-busy', 'dsh-delegation: session is busy; refresh and retry')\n throw error\n }\n })\n return this.sessionStatus(sessionId, signal)\n }\n\n /**\n * `agent/created` seeding. Only a fresh ('startup') non-subagent session gets\n * an initial row: a human fork inherits its parent's flag, every other new\n * top-level session takes the stored `defaultEnabled`. Resumed, cleared and\n * compacted sessions keep whatever they already have — and stay off when\n * they predate the plugin.\n */\n async seedSession(agent: DelegationAgentLike, source: string): Promise<void> {\n if (source !== 'startup') return\n const session = agent.session\n if (!session || isSubagentSession(session)) return\n const id = session.id\n await this.enqueue(`session:${id}`, async () => {\n if (this.record(id)) return\n const parentId = typeof session.header?.parentSession === 'string' ? session.header.parentSession : undefined\n const inherited = parentId ? this.record(parentId) : undefined\n const enabled = inherited?.enabled ?? this.getSettings().defaultEnabled\n await this.deps.records.put(id, { enabled, revision: 1 })\n })\n }\n}\n","/**\n * System prompt text for delegation mode. Kept literal (the section registers\n * with `interpolate: false`), so no `{{variable}}` syntax may appear here.\n */\n\n/** Coordinator policy for a top-level session with delegation on. */\nexport function coordinatorPrompt(tools: readonly string[]): string {\n const names = tools.map(name => `\\`${name}\\``).join(' / ')\n return `## Delegation mode\n\nDelegation mode is on. You are the coordinator; ${names} are how you get substantive work done. You own the requirements, division of work, integration decisions, acceptance, and the final response.\n\nFor a task with multiple components or substantive implementation steps, dispatch a scoped subagent task BEFORE implementing it yourself. A todo list or a promise to delegate is not a delegation. Do not first design every function, read the entire project, or start writing the deliverable. If the split is unclear, delegate a focused discovery task and use its report to choose the next assignments.\n\n- Make a short plan that is sufficient to assign work, then call the delegation tool. Prefer a fresh subagent for a self-contained brief. A fork inherits completed turns, not the current in-flight user request: always include the current task and constraints explicitly.\n- Each brief must contain the goal, working directory, allowed files, shared interface/data contracts, acceptance criteria, and what to report. Give each file one active owner. Start independent assignments together; resolve shared contracts before dependent work starts.\n- Subagents read, implement, run commands, test, and fix their assigned work. You may do a brief targeted read or an acceptance check to make a coordination decision; do not use that exception to take over an implementation task.\n- Track the returned subagent ids. Use native completion notifications and send_message for questions, corrections, or follow-up work. Do not repeatedly poll or sleep. Do not claim completion while required work is still running.\n- Inspect the delivered files and verification evidence. Send concrete failures back to the responsible subagent; collect and check the correction. Finish with the usable result, the checks actually performed, and any remaining limitation.\n\nA simple question, short rewrite, or genuinely small self-contained task may be completed directly. This exception does not cover building an application or completing a multi-part feature. Keep user-facing updates in the user's language.`\n}\n\n/** Executor policy for a subagent whose top-level session has delegation on. */\nexport const EXECUTOR_PROMPT = `## Delegated task\n\nYou are a subagent carrying out a task delegated by a coordinating agent. Coordinator instructions that appear earlier in this conversation, for example ones inherited through a fork, do not apply to you.\n\n- Do the work yourself: read, search, edit, run commands, and verify as the task requires. Make concrete progress in the assigned files; do not stop at a design or a plan. Do not pass the task on to further subagents unless the brief asks for it or clearly independent parts justify running them in parallel.\n- Stay within the brief. If it is ambiguous, make a reasonable choice and state it; if you are blocked, stop and report what is missing.\n- Respect file ownership and agreed interfaces. Ask the coordinator before changing another worker's files or a shared contract.\n- Verify your result before reporting.\n- End with a concise report: the result, the files or locations changed, the evidence (commands run and their outcome), and unresolved issues. Do not paste full logs.`\n\n/** Stable operational reminder; the host persists it only when context changes. */\nexport function coordinatorReminder(tools: readonly string[]): string {\n return `Delegation mode: coordinator. For multi-part work, your next implementation action must be a scoped assignment through ${tools.map(name => `\\`${name}\\``).join(' / ')}, not doing that implementation yourself. Plan only far enough to dispatch; give workers file ownership and interface contracts, then collect and verify their results. Simple self-contained tasks may be answered directly. This mode remains fixed for this session.`\n}\n\nexport const EXECUTOR_REMINDER = 'Delegation mode: executor. Carry out the assigned work in your allowed files and verify it. Earlier coordinator reminders inherited from a parent do not assign you the coordinator role. Report concrete results and evidence to your parent.'\n","import { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { DELEGATION_TOOLS } from './contracts.ts'\nimport { coordinatorPrompt, coordinatorReminder, EXECUTOR_PROMPT, EXECUTOR_REMINDER } from './prompts.ts'\n\nexport interface DelegationSessionLike {\n readonly id: string\n readonly header?: { readonly parentSession?: unknown }\n}\n\n/** The per-assembly lookups the policy needs; callers inject the live stores. */\nexport interface DelegationLookups {\n /** Parsed per-session record; undefined means no record. */\n record(sessionId: string): { readonly enabled: boolean } | undefined\n session(sessionId: string): DelegationSessionLike | undefined\n /** Whether a tool name resolves in this assembly's scope. */\n toolVisible(name: string, scope: unknown): boolean\n}\n\nexport interface DelegationAssembleContext {\n readonly agent?: { readonly session: DelegationSessionLike }\n readonly scope?: unknown\n}\n\n/** Ancestor walk bound: subagent chains deeper than this bail out as off. */\nconst MAX_PARENT_HOPS = 16\n\n/** First non-subagent ancestor reachable through `header.parentSession`. */\nfunction topLevelSession(\n session: DelegationSessionLike,\n sessions: DelegationLookups['session'],\n): DelegationSessionLike | undefined {\n const seen = new Set<string>([session.id])\n let current = session\n for (let hop = 0; hop < MAX_PARENT_HOPS && isSubagentSession(current); hop++) {\n const parentId = typeof current.header?.parentSession === 'string' ? current.header.parentSession : undefined\n if (!parentId || seen.has(parentId)) return undefined\n seen.add(parentId)\n const parent = sessions(parentId)\n if (!parent) return undefined\n current = parent\n }\n return isSubagentSession(current) ? undefined : current\n}\n\ntype Policy = { role: 'executor' } | { role: 'coordinator'; tools: readonly string[] }\n\n/** Both prompt surfaces must use the same role and capability decision. */\nfunction delegationPolicy(context: DelegationAssembleContext, lookups: DelegationLookups): Policy | undefined {\n const session = context.agent?.session\n if (!session) return undefined\n if (isSubagentSession(session)) {\n const root = topLevelSession(session, lookups.session)\n return root && lookups.record(root.id)?.enabled ? { role: 'executor' } : undefined\n }\n if (!lookups.record(session.id)?.enabled) return undefined\n const visible = DELEGATION_TOOLS.filter(name => lookups.toolVisible(name, context.scope))\n return visible.length ? { role: 'coordinator', tools: visible } : undefined\n}\n\n/** Static system guidance. No per-step counters or progress belong in this text. */\nexport function delegationSectionText(context: DelegationAssembleContext, lookups: DelegationLookups): string {\n const policy = delegationPolicy(context, lookups)\n if (!policy) return ''\n return policy.role === 'executor' ? EXECUTOR_PROMPT : coordinatorPrompt(policy.tools)\n}\n\n/** Stable user-role context snapshot, refreshed by the host after compaction. */\nexport function delegationReminderText(context: DelegationAssembleContext, lookups: DelegationLookups): string {\n const policy = delegationPolicy(context, lookups)\n if (!policy) return ''\n return policy.role === 'executor' ? EXECUTOR_REMINDER : coordinatorReminder(policy.tools)\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-agent'\nimport type { Session } from '@deepseek-ai/dsh-session'\nimport type {} from '@deepseek-ai/dsh-session-query'\nimport type {} from '@deepseek-ai/dsh-storage-domain'\nimport type {} from '@deepseek-ai/dsh-system-prompt'\nimport type {} from '@deepseek-ai/dsh-tools'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-plugin-kit/host-rpc'\nimport {\n PLUGIN_NAME, RPC_CHANNEL,\n type DelegationSessionStatus, type DelegationSettings, type RpcResult,\n} from './contracts.ts'\nimport { delegationDomain,\n sessionStatusSchema, sessionUpdateSchema, settingsUpdateSchema } from './storage.ts'\nimport { DelegationError, DelegationService, type DelegationAgentLike, type DelegationServiceDeps } from './service.ts'\nimport { delegationSectionText, delegationReminderText, type DelegationLookups } from './policy.ts'\n\nexport const name = PLUGIN_NAME\nexport const inject = ['systemPrompt', 'storageDomain', 'sessions', 'agents', 'tools', 'sessionQuery', 'sessionProjections', 'connection', 'webServer'] as const\nexport { DelegationService, DelegationError } from './service.ts'\nexport { delegationSectionText } from './policy.ts'\nexport { coordinatorPrompt, EXECUTOR_PROMPT } from './prompts.ts'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { delegation: DelegationService }\n}\n\nfunction fail(error: unknown): RpcResult<never> {\n if (error instanceof DelegationError) {\n return { ok: false, error: { code: error.code, message: error.message } }\n }\n const message = error instanceof Error ? error.message : String(error)\n return { ok: false, error: { code: 'internal', message } }\n}\n\nexport async function handleRpc(\n service: DelegationService,\n endpoint: string,\n payload: unknown,\n signal: AbortSignal,\n): Promise<RpcResult> {\n try {\n switch (endpoint) {\n case 'settings': {\n const value: DelegationSettings = service.getSettings()\n return { ok: true, value }\n }\n case 'settings.update': {\n const parsed = settingsUpdateSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'settings update is invalid' } }\n const value: DelegationSettings = await service.updateSettings(parsed.data.defaultEnabled, parsed.data.expectedRevision)\n return { ok: true, value }\n }\n case 'session.status': {\n const parsed = sessionStatusSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'sessionId is required' } }\n const value: DelegationSessionStatus = await service.sessionStatus(parsed.data.sessionId, signal)\n return { ok: true, value }\n }\n case 'session.update': {\n const parsed = sessionUpdateSchema.safeParse(payload)\n if (!parsed.success) return { ok: false, error: { code: 'bad-request', message: 'session update is invalid' } }\n const value: DelegationSessionStatus = await service.updateSession(\n parsed.data.sessionId, parsed.data.enabled, parsed.data.expectedRevision, signal)\n return { ok: true, value }\n }\n default:\n return { ok: false, error: { code: 'not-found', message: `unknown endpoint: ${endpoint}` } }\n }\n } catch (error) {\n return fail(error)\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Context & HostRpcContext\n const domain = await ctx.storageDomain.open(delegationDomain)\n const service = new DelegationService({\n settings: domain.table('settings'),\n records: domain.table('sessions'),\n sessionStore: ctx.sessions as unknown as DelegationServiceDeps['sessionStore'],\n agents: ctx.agents as unknown as DelegationServiceDeps['agents'],\n tools: ctx.tools as unknown as DelegationServiceDeps['tools'],\n sessionQuery: ctx.sessionQuery as unknown as DelegationServiceDeps['sessionQuery'],\n hasStarted: session => {\n const boundary = ctx.sessionProjections.stateOf(session as Session, 'turnBoundary')\n return boundary === undefined || boundary.openTurnStartSeq !== null || boundary.lastTurn > 0\n },\n })\n ctx.provide('delegation', service)\n ctx.effect(() => () => domain.close(), 'delegation.lifecycle')\n // Seeding listens on agent/created: serial and awaited before the agent's\n // queued work, so the row exists before the first prompt assembly. A throw\n // here would fail agent creation, so the listener never propagates one.\n ctx.effect(() => ctx.on('agent/created', async ({ agent, source }: { agent: DelegationAgentLike; source: string }) => {\n try {\n await service.seedSession(agent, source)\n } catch (error) {\n ctx.logger.warn('dsh-delegation: could not seed session state: %s', error instanceof Error ? error.message : String(error))\n }\n }), 'delegation.seed')\n // Read-only advisory text evaluated at every assembly; the choice is locked\n // before the first model step and stays stable across later turns. Covers\n // subagent sessions deliberately: the executor half IS their prompt.\n const sectionSessions = ctx.sessions as unknown as DelegationServiceDeps['sessionStore']\n const sectionTools = ctx.tools as unknown as DelegationServiceDeps['tools']\n const lookups: DelegationLookups = {\n record: sessionId => service.record(sessionId),\n session: id => sectionSessions?.get(id),\n toolVisible: (tool, scope) => sectionTools?.get(tool, scope) !== undefined,\n }\n ctx.effect(() => ctx.systemPrompt.section({\n name: 'delegation:policy',\n order: ctx.systemPrompt.getSectionOrder('TOOL_SUBAGENT') + 2,\n interpolate: false,\n text: context => delegationSectionText(context, lookups),\n }), 'delegation.section')\n // Native runtime context is durable and appended only when its snapshot\n // changes (or after compaction), not a new reminder injected at every step.\n // Include children deliberately: a fork must replace inherited coordinator\n // context with its own executor role. Neither contribution writes by itself.\n ctx.effect(() => ctx.systemPrompt.context({\n name: 'delegation:role',\n order: ctx.systemPrompt.getContextOrder('SUBAGENT_DELEGATION') + 2,\n required: true,\n interpolate: false,\n text: context => delegationReminderText(context, lookups),\n }), 'delegation.context')\n ctx.effect(() => registerHostRpc(host, RPC_CHANNEL,\n (endpoint, payload, signal) => handleRpc(service, endpoint, payload, signal)), 'delegation.rpc')\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klarkxy/dsh-delegation",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Delegation Mode: a per-session switch where the main agent plans, delegates, and reviews while subagents carry out the work.",
5
5
  "icon": "./icon.svg",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -74,7 +74,7 @@
74
74
  "test": "vitest run --root ../.. --config vitest.editor-plugins.config.ts --maxWorkers=2 plugins/dsh-delegation/src"
75
75
  },
76
76
  "dependencies": {
77
- "@klarkxy/dsh-plugin-kit": "0.5.0",
77
+ "@klarkxy/dsh-plugin-kit": "0.6.0",
78
78
  "zod": "^4.1.5"
79
79
  },
80
80
  "peerDependencies": {
@@ -148,6 +148,6 @@
148
148
  "registry": "https://registry.npmjs.org/"
149
149
  },
150
150
  "dshRelease": {
151
- "contentHash": "73deda9fe174094b3c3b5266f6d1a8d8033756e1da1acf6f20480b6061f64e03"
151
+ "contentHash": "440dec0d34e5fd37c234b3f3aab916a9a37838772566c4272fafbdc42949f198"
152
152
  }
153
153
  }