dsh-model-switch 0.4.19 → 0.4.21

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/lib/client.js CHANGED
@@ -33,6 +33,16 @@ window.__ModuleLoader__.load({
33
33
  provider: "imageProvider",
34
34
  model: "imageModel"
35
35
  });
36
+ /** Auto-preset reviewer route; both unset means the reviewer follows the session model. */
37
+ const AUTO_REVIEW_SETTINGS_FIELDS = Object.freeze({
38
+ provider: "autoReviewProvider",
39
+ model: "autoReviewModel"
40
+ });
41
+ /** Compaction summarization route for `/compact` and automatic compaction; both unset means the official default (the conversation target). */
42
+ const COMPACTION_SETTINGS_FIELDS = Object.freeze({
43
+ provider: "compactProvider",
44
+ model: "compactModel"
45
+ });
36
46
  function deriveSubagentSettings(settings) {
37
47
  return {
38
48
  mode: settings.subagentMode,
@@ -53,6 +63,22 @@ window.__ModuleLoader__.load({
53
63
  ...settings.imageModel === void 0 ? {} : { model: settings.imageModel }
54
64
  };
55
65
  }
66
+ function deriveAutoReviewSettings(settings) {
67
+ return {
68
+ ...settings.autoReviewProvider === void 0 ? {} : { provider: settings.autoReviewProvider },
69
+ ...settings.autoReviewModel === void 0 ? {} : { model: settings.autoReviewModel }
70
+ };
71
+ }
72
+ function deriveCompactionSettings(settings) {
73
+ return {
74
+ ...settings.compactProvider === void 0 ? {} : { provider: settings.compactProvider },
75
+ ...settings.compactModel === void 0 ? {} : { model: settings.compactModel }
76
+ };
77
+ }
78
+ /** Whether both fields of a model route form a complete pair; an incomplete pair stays off. */
79
+ function routePairConfigured(route) {
80
+ return route !== void 0 && (route.provider ?? "").trim() !== "" && (route.model ?? "").trim() !== "";
81
+ }
56
82
  //#endregion
57
83
  //#region src/client/derived-config-form.ts
58
84
  function deriveConfigForm(source, project, fields) {
@@ -603,6 +629,19 @@ window.__ModuleLoader__.load({
603
629
  return values.filter((value) => value !== void 0 && value !== "").join(" · ");
604
630
  }
605
631
  function RouteIcon({ kind }) {
632
+ if (kind === "compaction") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
633
+ width: "18",
634
+ height: "18",
635
+ viewBox: "0 0 18 18",
636
+ fill: "none",
637
+ "aria-hidden": "true",
638
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
639
+ d: "M5 3.5 9 7.5l4-4M5 14.5 9 10.5l4 4",
640
+ stroke: "currentColor",
641
+ strokeLinecap: "round",
642
+ strokeLinejoin: "round"
643
+ })
644
+ });
606
645
  if (kind === "main") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
607
646
  width: "18",
608
647
  height: "18",
@@ -686,6 +725,23 @@ window.__ModuleLoader__.load({
686
725
  })
687
726
  ]
688
727
  });
728
+ if (kind === "autoReview") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
729
+ width: "18",
730
+ height: "18",
731
+ viewBox: "0 0 18 18",
732
+ fill: "none",
733
+ "aria-hidden": "true",
734
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
735
+ d: "M9 2.5 14.5 4.8v4.1c0 3.1-2.3 5.7-5.5 6.6-3.2-.9-5.5-3.5-5.5-6.6V4.8L9 2.5Z",
736
+ stroke: "currentColor",
737
+ strokeLinejoin: "round"
738
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
739
+ d: "m6.6 8.9 1.7 1.7 3.2-3.4",
740
+ stroke: "currentColor",
741
+ strokeLinecap: "round",
742
+ strokeLinejoin: "round"
743
+ })]
744
+ });
689
745
  return null;
690
746
  }
691
747
  function RouteCard({ title, summary, hint, icon, open, onToggle, disabled = false, badge, badgeWarn = false, trailing, expandable = true, children }) {
@@ -857,11 +913,15 @@ window.__ModuleLoader__.load({
857
913
  const { main, subagent, draft, groups } = controller;
858
914
  const search = props.useSearchSettings((value) => value);
859
915
  const image = props.useImageSettings((value) => value);
916
+ const autoReview = props.useAutoReviewSettings((value) => value);
917
+ const compaction = props.useCompactionSettings((value) => value);
860
918
  const switchSettings = props.useSwitchSettings((value) => value);
861
919
  const [open, setOpen] = (0, react.useState)();
862
920
  const [subagentDraft, setSubagentDraft, resetSubagent] = useDraft(subagent);
863
921
  const [searchDraft, setSearchDraft, resetSearch] = useDraft(search);
864
922
  const [imageDraft, setImageDraft, resetImage] = useDraft(image);
923
+ const [autoReviewDraft, setAutoReviewDraft, resetAutoReview] = useDraft(autoReview);
924
+ const [compactionDraft, setCompactionDraft, resetCompaction] = useDraft(compaction);
865
925
  const [busy, setBusy] = (0, react.useState)();
866
926
  const [message, setMessage] = (0, react.useState)();
867
927
  const [compactBusy, setCompactBusy] = (0, react.useState)(false);
@@ -956,11 +1016,17 @@ window.__ModuleLoader__.load({
956
1016
  const searchChoices = capabilityChoices(searchGroups, searchDraft, void 0, "search");
957
1017
  const searchAvailable = searchLive?.searchProviderAdapters.available ?? false;
958
1018
  const imageChoices = capabilityChoices(groups, imageDraft, props.capabilities.imageProviderAdapters.providers ?? [], "image");
1019
+ const autoReviewChoices = deriveRouteChoices(groups, autoReviewDraft);
1020
+ const autoReviewOn = routePairConfigured(autoReview.value);
1021
+ const compactionChoices = deriveRouteChoices(groups, compactionDraft);
1022
+ const compactionOn = routePairConfigured(compaction.value);
959
1023
  const synced = [
960
1024
  main,
961
1025
  subagent,
962
1026
  search,
963
- image
1027
+ image,
1028
+ autoReview,
1029
+ compaction
964
1030
  ].every((snapshot) => snapshot.status === "ready");
965
1031
  const run = async (route, operation) => {
966
1032
  if (busy !== void 0) return;
@@ -1019,12 +1085,103 @@ window.__ModuleLoader__.load({
1019
1085
  if (current.value?.model !== next.model) await props.setCapability(route, "model", next.model);
1020
1086
  });
1021
1087
  };
1088
+ const saveAutoReview = () => {
1089
+ if (autoReviewDraft === void 0) return;
1090
+ run("autoReview", async () => {
1091
+ if (autoReview.value?.provider !== autoReviewDraft.provider) await props.setCapability("autoReview", "provider", autoReviewDraft.provider);
1092
+ if (autoReview.value?.model !== autoReviewDraft.model) await props.setCapability("autoReview", "model", autoReviewDraft.model);
1093
+ });
1094
+ };
1095
+ const saveCompaction = () => {
1096
+ if (compactionDraft === void 0) return;
1097
+ run("compaction", async () => {
1098
+ if (compaction.value?.provider !== compactionDraft.provider) await props.setCapability("compaction", "provider", compactionDraft.provider);
1099
+ if (compaction.value?.model !== compactionDraft.model) await props.setCapability("compaction", "model", compactionDraft.model);
1100
+ });
1101
+ };
1102
+ /**
1103
+ * The reviewer switch: Off unsets both stored fields (follow the session
1104
+ * model); On seeds the route from Main so the pin takes effect immediately
1105
+ * and stays editable below. A failed write reports, never flips silently.
1106
+ */
1107
+ const persistAutoReviewEnabled = (enabled) => {
1108
+ if (busy === "autoReview" || !autoReview.writable || autoReview.value === void 0) return;
1109
+ if (!enabled) {
1110
+ setOpen((current) => current === "autoReview" ? void 0 : current);
1111
+ run("autoReview", async () => {
1112
+ if (autoReview.value?.provider !== void 0) await props.setCapability("autoReview", "provider", void 0);
1113
+ if (autoReview.value?.model !== void 0) await props.setCapability("autoReview", "model", void 0);
1114
+ });
1115
+ return;
1116
+ }
1117
+ const seed = draft;
1118
+ if (seed === void 0 || seed.provider.trim() === "" || seed.model.trim() === "") return;
1119
+ setBusy("autoReview");
1120
+ setMessage(void 0);
1121
+ (async () => {
1122
+ if (autoReview.value?.provider !== seed.provider) await props.setCapability("autoReview", "provider", seed.provider);
1123
+ if (autoReview.value?.model !== seed.model) await props.setCapability("autoReview", "model", seed.model);
1124
+ })().then(() => {
1125
+ setAutoReviewDraft({
1126
+ provider: seed.provider,
1127
+ model: seed.model
1128
+ });
1129
+ setBusy(void 0);
1130
+ setOpen("autoReview");
1131
+ }, (error) => {
1132
+ setBusy(void 0);
1133
+ setMessage({
1134
+ route: "autoReview",
1135
+ text: error instanceof Error ? error.message : props.t("requestFailed")
1136
+ });
1137
+ });
1138
+ };
1139
+ /**
1140
+ * The compaction switch: Off unsets both stored fields (official default =
1141
+ * the conversation target); On seeds the route from Main so the pin takes
1142
+ * effect immediately and stays editable below. A failed write reports,
1143
+ * never flips silently.
1144
+ */
1145
+ const persistCompactionEnabled = (enabled) => {
1146
+ if (busy === "compaction" || !compaction.writable || compaction.value === void 0) return;
1147
+ if (!enabled) {
1148
+ setOpen((current) => current === "compaction" ? void 0 : current);
1149
+ run("compaction", async () => {
1150
+ if (compaction.value?.provider !== void 0) await props.setCapability("compaction", "provider", void 0);
1151
+ if (compaction.value?.model !== void 0) await props.setCapability("compaction", "model", void 0);
1152
+ });
1153
+ return;
1154
+ }
1155
+ const seed = draft;
1156
+ if (seed === void 0 || seed.provider.trim() === "" || seed.model.trim() === "") return;
1157
+ setBusy("compaction");
1158
+ setMessage(void 0);
1159
+ (async () => {
1160
+ if (compaction.value?.provider !== seed.provider) await props.setCapability("compaction", "provider", seed.provider);
1161
+ if (compaction.value?.model !== seed.model) await props.setCapability("compaction", "model", seed.model);
1162
+ })().then(() => {
1163
+ setCompactionDraft({
1164
+ provider: seed.provider,
1165
+ model: seed.model
1166
+ });
1167
+ setBusy(void 0);
1168
+ setOpen("compaction");
1169
+ }, (error) => {
1170
+ setBusy(void 0);
1171
+ setMessage({
1172
+ route: "compaction",
1173
+ text: error instanceof Error ? error.message : props.t("requestFailed")
1174
+ });
1175
+ });
1176
+ };
1022
1177
  const mainSummary = draft === void 0 ? props.t("loading") : compact(routeName(groups, draft), mainEffectiveEffort);
1023
1178
  const subagentRole = subagentDraft?.mode === "fixed" && subagentDraft.provider !== void 0 && subagentDraft.provider !== "" ? props.providerRoleOf?.(subagentDraft.provider) : void 0;
1024
1179
  const subagentOn = subagentDraft?.mode === "fixed";
1025
1180
  const subagentSummary = subagentDraft === void 0 ? props.t("loading") : subagentOn ? compact(routeName(groups, subagentRoute), isAgentRole(subagentRole) ? props.t("agentBadge") : void 0, defaultEffort === void 0 ? props.t("providerDefaultShort") : compact(props.t("providerDefaultShort"), defaultEffort)) : props.t("subagentOff");
1026
1181
  const subagentDisabled = subagent.status !== "ready" || !subagent.writable || subagentDraft === void 0 || busy === "subagent" || !subagentOn || (subagentDraft.provider ?? "").trim() === "" || (subagentDraft.model ?? "").trim() === "";
1027
1182
  const capabilityDisabled = (route, snapshot, next) => snapshot.status !== "ready" || !snapshot.writable || next === void 0 || busy === route || (next.provider ?? "").trim() === "" || (next.model ?? "").trim() === "";
1183
+ const autoReviewDisabled = autoReview.status !== "ready" || !autoReview.writable || autoReviewDraft === void 0 || busy === "autoReview" || !autoReviewOn || (autoReviewDraft.provider ?? "").trim() === "" || (autoReviewDraft.model ?? "").trim() === "";
1184
+ const compactionDisabled = compaction.status !== "ready" || !compaction.writable || compactionDraft === void 0 || busy === "compaction" || !compactionOn || (compactionDraft.provider ?? "").trim() === "" || (compactionDraft.model ?? "").trim() === "";
1028
1185
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
1029
1186
  className: ModelSwitchSettings_module_css_default.section,
1030
1187
  children: [
@@ -1394,6 +1551,134 @@ window.__ModuleLoader__.load({
1394
1551
  disabled: true,
1395
1552
  badge: props.t("unavailable"),
1396
1553
  badgeWarn: true
1554
+ }),
1555
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteCard, {
1556
+ title: props.t("autoReview"),
1557
+ summary: autoReviewDraft === void 0 ? props.t("loading") : autoReviewOn ? routeName(groups, autoReviewDraft) : props.t("autoReviewFollow"),
1558
+ hint: props.t("autoReviewHelp"),
1559
+ icon: "autoReview",
1560
+ open: open === "autoReview" && autoReviewOn,
1561
+ onToggle: () => {
1562
+ if (autoReviewOn) toggle("autoReview");
1563
+ },
1564
+ expandable: autoReviewOn,
1565
+ trailing: autoReviewDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
1566
+ checked: autoReviewOn,
1567
+ disabled: busy === "autoReview" || !autoReview.writable,
1568
+ label: props.t("autoReview"),
1569
+ onChange: persistAutoReviewEnabled
1570
+ }),
1571
+ children: autoReviewDraft === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1572
+ className: ModelSwitchSettings_module_css_default.hint,
1573
+ children: props.t("loading")
1574
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1576
+ className: ModelSwitchSettings_module_css_default.hint,
1577
+ children: props.t("autoReviewRouteHelp")
1578
+ }),
1579
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1580
+ className: ModelSwitchSettings_module_css_default.formGrid,
1581
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
1582
+ label: props.t("provider"),
1583
+ value: autoReviewDraft.provider ?? "",
1584
+ disabled: busy === "autoReview" || !autoReview.writable,
1585
+ choices: autoReviewChoices.providers,
1586
+ onChange: (provider) => {
1587
+ const first = groups.find((group) => group.id === provider)?.models[0];
1588
+ setAutoReviewDraft({
1589
+ provider,
1590
+ ...first === void 0 ? {} : { model: first.id }
1591
+ });
1592
+ }
1593
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
1594
+ label: props.t("model"),
1595
+ value: autoReviewDraft.model ?? "",
1596
+ disabled: busy === "autoReview" || !autoReview.writable,
1597
+ choices: autoReviewChoices.models,
1598
+ onChange: (model) => {
1599
+ setAutoReviewDraft({
1600
+ ...autoReviewDraft,
1601
+ model
1602
+ });
1603
+ }
1604
+ })]
1605
+ }),
1606
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Actions, {
1607
+ t: props.t,
1608
+ busy: busy === "autoReview",
1609
+ disabled: autoReviewDisabled,
1610
+ ...message?.route === "autoReview" ? { message: message.text } : {},
1611
+ onCancel: () => {
1612
+ resetAutoReview();
1613
+ setMessage(void 0);
1614
+ },
1615
+ onSave: saveAutoReview
1616
+ })
1617
+ ] })
1618
+ }),
1619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteCard, {
1620
+ title: props.t("compaction"),
1621
+ summary: compactionDraft === void 0 ? props.t("loading") : compactionOn ? routeName(groups, compactionDraft) : props.t("compactionFollow"),
1622
+ hint: props.t("compactionHelp"),
1623
+ icon: "compaction",
1624
+ open: open === "compaction" && compactionOn,
1625
+ onToggle: () => {
1626
+ if (compactionOn) toggle("compaction");
1627
+ },
1628
+ expandable: compactionOn,
1629
+ trailing: compactionDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
1630
+ checked: compactionOn,
1631
+ disabled: busy === "compaction" || !compaction.writable,
1632
+ label: props.t("compaction"),
1633
+ onChange: persistCompactionEnabled
1634
+ }),
1635
+ children: compactionDraft === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1636
+ className: ModelSwitchSettings_module_css_default.hint,
1637
+ children: props.t("loading")
1638
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1639
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1640
+ className: ModelSwitchSettings_module_css_default.hint,
1641
+ children: props.t("compactionRouteHelp")
1642
+ }),
1643
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1644
+ className: ModelSwitchSettings_module_css_default.formGrid,
1645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
1646
+ label: props.t("provider"),
1647
+ value: compactionDraft.provider ?? "",
1648
+ disabled: busy === "compaction" || !compaction.writable,
1649
+ choices: compactionChoices.providers,
1650
+ onChange: (provider) => {
1651
+ const first = groups.find((group) => group.id === provider)?.models[0];
1652
+ setCompactionDraft({
1653
+ provider,
1654
+ ...first === void 0 ? {} : { model: first.id }
1655
+ });
1656
+ }
1657
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
1658
+ label: props.t("model"),
1659
+ value: compactionDraft.model ?? "",
1660
+ disabled: busy === "compaction" || !compaction.writable,
1661
+ choices: compactionChoices.models,
1662
+ onChange: (model) => {
1663
+ setCompactionDraft({
1664
+ ...compactionDraft,
1665
+ model
1666
+ });
1667
+ }
1668
+ })]
1669
+ }),
1670
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Actions, {
1671
+ t: props.t,
1672
+ busy: busy === "compaction",
1673
+ disabled: compactionDisabled,
1674
+ ...message?.route === "compaction" ? { message: message.text } : {},
1675
+ onCancel: () => {
1676
+ resetCompaction();
1677
+ setMessage(void 0);
1678
+ },
1679
+ onSave: saveCompaction
1680
+ })
1681
+ ] })
1397
1682
  })
1398
1683
  ]
1399
1684
  })
@@ -1438,6 +1723,14 @@ window.__ModuleLoader__.load({
1438
1723
  requestFailed: "保存失败",
1439
1724
  catalogFailed: "无法加载模型目录。",
1440
1725
  conflict: "设置已在其他位置更改,请检查最新值后重试。",
1726
+ autoReview: "自动审查模型",
1727
+ autoReviewFollow: "跟随会话模型",
1728
+ autoReviewHelp: "为官方 auto-review(Auto 权限预设的逐调用审查)指定审查模型;需启用官方 auto-review 能力包。关闭时审查跟随当前会话模型。",
1729
+ autoReviewRouteHelp: "审查请求固定使用这里的 Provider/模型,与会话模型无关;保存后对下一次审查立即生效。",
1730
+ compaction: "压缩模型",
1731
+ compactionFollow: "跟随会话模型",
1732
+ compactionHelp: "为官方压缩(/compact 与官方自动压缩)指定摘要模型;关闭(两个字段都留空)时使用官方默认,即当前会话的目标模型。",
1733
+ compactionRouteHelp: "摘要请求固定使用这里的 Provider/模型,与会话目标模型无关;保存后对下一次压缩立即生效。保存时若恰有压缩进行中,可能被打断并在下次重试。",
1441
1734
  "reason.central-subagent-routing": "Alpha.4 没有全局子代理启动路由接口。",
1442
1735
  "reason.packaged-preset-roots": "Alpha.4 不支持插件提供额外 preset root。",
1443
1736
  "reason.tool-owner-suppression": "Alpha.4 没有工具所有者或来源抑制接口。",
@@ -1481,6 +1774,14 @@ window.__ModuleLoader__.load({
1481
1774
  requestFailed: "Save failed",
1482
1775
  catalogFailed: "Could not load the model catalog.",
1483
1776
  conflict: "Settings changed elsewhere. Review the latest values and retry.",
1777
+ autoReview: "Auto review model",
1778
+ autoReviewFollow: "Follows the session model",
1779
+ autoReviewHelp: "Pin the reviewer model for the official auto-review gate (per-call review under the Auto permission preset). Requires the official auto-review bundle. When off, reviews follow the session model.",
1780
+ autoReviewRouteHelp: "Review requests use exactly this provider/model regardless of the session model; saved changes apply to the very next review.",
1781
+ compaction: "Compaction model",
1782
+ compactionFollow: "Follows the conversation model",
1783
+ compactionHelp: "Pick the summarization model for official compaction (/compact and official automatic compaction). When off (both fields empty), the official default applies: the conversation target model.",
1784
+ compactionRouteHelp: "Summarization requests use exactly this provider/model regardless of the conversation target; saved changes apply to the very next compaction. Saving while a compaction is running may interrupt it; it retries next time.",
1484
1785
  "reason.central-subagent-routing": "Alpha.4 exposes no global Subagent start-routing seam.",
1485
1786
  "reason.packaged-preset-roots": "Alpha.4 exposes no plugin-owned preset root.",
1486
1787
  "reason.tool-owner-suppression": "Alpha.4 exposes no tool owner or provenance suppression seam.",
@@ -1505,6 +1806,7 @@ window.__ModuleLoader__.load({
1505
1806
  id: question.id,
1506
1807
  question: question.question,
1507
1808
  plan: question.detail,
1809
+ ...intent.callId === void 0 ? {} : { callId: intent.callId },
1508
1810
  approve,
1509
1811
  ...decline === void 0 ? {} : { decline }
1510
1812
  };
@@ -2785,7 +3087,80 @@ window.__ModuleLoader__.load({
2785
3087
  });
2786
3088
  }
2787
3089
  //#endregion
2788
- //#region node_modules/.pnpm/dsh-llm-providers-ui@https+_f1dadb1b56406564fc1bb8f2d953b82d/node_modules/dsh-llm-providers-ui/lib/order.js
3090
+ //#region src/client/picker/plan-preview.ts
3091
+ /** Registration id ui-plan uses for its `conversation.plan-review.actions` entry. */
3092
+ const PLAN_REVIEW_OPEN_ID = "@deepseek-ai/dsh-client-ui-plan";
3093
+ /** Identities whose preview was already opened this process (official parity: ui-plan's store keeps them too). */
3094
+ const opened = /* @__PURE__ */ new Set();
3095
+ /**
3096
+ * Stable identity of one review's sidebar preview.
3097
+ * @param sessionId - session that owns the review.
3098
+ * @param review - narrowed plan review.
3099
+ * @param requestKey - pending-question request key.
3100
+ * @returns `session:call:<callId>` for a logged plan, else `session:review:<requestKey>`.
3101
+ */
3102
+ function planPreviewIdentity(sessionId, review, requestKey) {
3103
+ const identity = review.callId === void 0 ? `review:${requestKey}` : `call:${review.callId}`;
3104
+ return `${String(sessionId)}:${identity}`;
3105
+ }
3106
+ function faceOf(slots, sessionId) {
3107
+ const entry = slots.entries("conversation.plan-review.actions").find((candidate) => candidate.options.id === PLAN_REVIEW_OPEN_ID && typeof candidate.inject === "function");
3108
+ if (entry === void 0 || entry.inject === void 0) return void 0;
3109
+ try {
3110
+ const face = entry.inject(sessionId);
3111
+ if (face === void 0 || typeof face.openReview !== "function") return void 0;
3112
+ if (face.hooks === void 0 || typeof face.hooks.sidebarMounted?.getSnapshot !== "function") return void 0;
3113
+ return face;
3114
+ } catch {
3115
+ return;
3116
+ }
3117
+ }
3118
+ /**
3119
+ * Bind the preview navigation to one slot registry.
3120
+ * @param slots - the live registry ledger.
3121
+ * @returns an idempotent binding usable from the card's render and effects.
3122
+ */
3123
+ function createPlanPreviewBinding(slots) {
3124
+ const open = (sessionId, review, requestKey) => {
3125
+ const face = faceOf(slots, sessionId);
3126
+ if (face === void 0) return false;
3127
+ opened.add(planPreviewIdentity(sessionId, review, requestKey));
3128
+ face.openReview(review, requestKey);
3129
+ return true;
3130
+ };
3131
+ return {
3132
+ available: () => slots.entries("conversation.plan-review.actions").some((candidate) => candidate.options.id === PLAN_REVIEW_OPEN_ID),
3133
+ open,
3134
+ autoOpen: (sessionId, review, requestKey) => {
3135
+ const identity = planPreviewIdentity(sessionId, review, requestKey);
3136
+ if (opened.has(identity)) return () => void 0;
3137
+ const face = faceOf(slots, sessionId);
3138
+ if (face === void 0) return () => void 0;
3139
+ const mounted = face.hooks.sidebarMounted;
3140
+ if (mounted.getSnapshot() !== void 0) {
3141
+ opened.add(identity);
3142
+ face.openReview(review, requestKey);
3143
+ return () => void 0;
3144
+ }
3145
+ let disposed = false;
3146
+ let openedHere = false;
3147
+ const unsubscribe = mounted.subscribe(() => {
3148
+ if (disposed || openedHere || opened.has(identity)) return;
3149
+ if (mounted.getSnapshot() === void 0) return;
3150
+ openedHere = true;
3151
+ opened.add(identity);
3152
+ unsubscribe();
3153
+ face.openReview(review, requestKey);
3154
+ });
3155
+ return () => {
3156
+ disposed = true;
3157
+ unsubscribe();
3158
+ };
3159
+ }
3160
+ };
3161
+ }
3162
+ //#endregion
3163
+ //#region node_modules/.pnpm/dsh-llm-providers-ui@https+++github.com+NOirBRight+dsh-llm-providers-ui+releases+downlo_f1dadb1b56406564fc1bb8f2d953b82d/node_modules/dsh-llm-providers-ui/lib/order.js
2789
3164
  /** Display order for installed provider cards when the user has not saved one. */
2790
3165
  const PROVIDER_ITEM_ORDER = [
2791
3166
  "llm-cursor",
@@ -3073,7 +3448,28 @@ window.__ModuleLoader__.load({
3073
3448
  };
3074
3449
  }
3075
3450
  /**
3076
- * Make the plan text this session's armed goal, replacing any unfinished goal.
3451
+ * Address the plan document exactly as the official opener does.
3452
+ *
3453
+ * A logged plan (`callId` present) resolves from `dsh-resource://plan/...`
3454
+ * for as long as the session log holds the call; before that the pending
3455
+ * review's own `dsh-resource://plan-review/...` address is the one that
3456
+ * opens its preview.
3457
+ *
3458
+ * @param sessionId - the session that owns the review.
3459
+ * @param ref - logged call identity plus the pending request key.
3460
+ * @returns The plan resource address.
3461
+ */
3462
+ function planDocumentAddress(sessionId, ref) {
3463
+ const encode = encodeURIComponent;
3464
+ return ref.callId === void 0 ? `dsh-resource://plan-review/${encode(sessionId)}/${encode(ref.requestKey)}` : `dsh-resource://plan/${encode(sessionId)}/${encode(ref.callId)}`;
3465
+ }
3466
+ /**
3467
+ * Make this plan the session's armed goal, replacing any unfinished goal.
3468
+ *
3469
+ * The objective is a short instruction carrying the plan document's address,
3470
+ * not the plan's raw markdown: goal objectives are injected into every round,
3471
+ * and a full plan would be truncated by length limits mid-sentence. The round
3472
+ * driver reads the plan from the address instead.
3077
3473
  *
3078
3474
  * Ordering mirrors the card's own commit-then-answer rule: a refusal here keeps
3079
3475
  * the Plan pending instead of approving work that no goal tracks. The replace
@@ -3082,17 +3478,18 @@ window.__ModuleLoader__.load({
3082
3478
  *
3083
3479
  * @param remote - the released goal remote, absent when no goal package is mounted.
3084
3480
  * @param sessionId - the session that owns both the review and the goal.
3085
- * @param plan - the plan markdown under review.
3481
+ * @param plan - the plan markdown under review (validated non-empty).
3482
+ * @param ref - the plan document identity used for its address.
3086
3483
  * @returns Whether the goal now tracks this plan, or why it does not.
3087
3484
  */
3088
- async function setPlanAsGoal(remote, sessionId, plan) {
3485
+ async function setPlanAsGoal(remote, sessionId, plan, ref) {
3089
3486
  if (remote === void 0) return { kind: "unsupported" };
3090
- const objective = plan.trim();
3091
- if (objective === "") return {
3487
+ if (plan.trim() === "") return {
3092
3488
  kind: "failed",
3093
3489
  code: "GOAL_INVALID_OBJECTIVE",
3094
3490
  message: "goal objective must be a non-empty string"
3095
3491
  };
3492
+ const objective = `持续推进当前plan直到完成(plan 文档:${planDocumentAddress(sessionId, ref)})`;
3096
3493
  const created = await remote.create(sessionId, { objective });
3097
3494
  if (created.ok) return { kind: "created" };
3098
3495
  if (created.error.code !== "GOAL_ALREADY_EXISTS") return {
@@ -3139,7 +3536,7 @@ window.__ModuleLoader__.load({
3139
3536
  };
3140
3537
  //#endregion
3141
3538
  //#region \0dsh-css:src/client/picker/PlanReviewCard.module.css.mjs
3142
- const css = ".BylfoW_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.BylfoW_card{width:100%;max-width:var(--dsh-chat-content-width);border:1px solid var(--dsw-alias-state-warn-secondary);background:var(--dsw-specific-input-major);max-height:min(60vh,520px);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;flex-direction:column;display:flex;overflow:visible}.BylfoW_card,.BylfoW_card *{box-sizing:border-box}.BylfoW_strip{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary);border-radius:20px 20px 0 0;flex-shrink:0;align-items:center;gap:8px;padding:10px 16px;font-size:13px;line-height:18px;display:flex}.BylfoW_dot{background:var(--dsw-alias-state-warn-primary);border-radius:50%;width:8px;height:8px}.BylfoW_stripTitle{flex:none;font-weight:600}.BylfoW_headerPicker{flex:0 auto;align-items:center;min-width:0;max-width:55%;margin-left:auto;display:flex}.BylfoW_headerPicker>*{min-width:0;max-width:100%}.BylfoW_body{overscroll-behavior:contain;flex:auto;min-height:0;padding:12px 16px 4px;font-size:14px;line-height:22px;overflow-y:auto}.BylfoW_footer{z-index:2;flex-direction:column;flex-shrink:0;gap:6px;padding:8px 16px 12px;display:flex;position:relative;overflow:visible}.BylfoW_feedback{min-height:0;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}.BylfoW_feedback:empty{display:none}.BylfoW_feedbackRow{align-items:center;gap:8px;min-width:0;display:flex}.BylfoW_feedbackInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-input-minor);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-xs-13);border-radius:8px;flex:auto;padding:0 10px}.BylfoW_feedbackInput::placeholder{color:var(--dsw-alias-label-tertiary)}.BylfoW_feedbackInput:disabled{opacity:.6}.BylfoW_bar{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;min-height:32px;display:flex}.BylfoW_picker{flex:16rem;min-width:0;max-width:16rem}.BylfoW_pickerError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px;display:flex}.BylfoW_actions{flex-wrap:nowrap;flex:none;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{white-space:nowrap;height:32px;min-height:32px;padding:0 10px}.BylfoW_discuss,.BylfoW_recover{color:var(--dsw-alias-label-secondary)}.BylfoW_discuss:hover:not(:disabled),.BylfoW_recover:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BylfoW_approve{padding:0 12px}@media (width<=720px){.BylfoW_frame{padding-right:max(10px, env(safe-area-inset-right));padding-bottom:max(10px, env(safe-area-inset-bottom));padding-left:max(10px, env(safe-area-inset-left))}.BylfoW_card{border-radius:16px}.BylfoW_strip,.BylfoW_body,.BylfoW_footer{padding-left:12px;padding-right:12px}.BylfoW_strip{flex-wrap:wrap;gap:6px}.BylfoW_headerPicker{flex:100%;max-width:100%;margin-left:0}.BylfoW_bar{justify-content:flex-end;gap:6px}.BylfoW_actions{flex:100%;justify-content:flex-end;gap:6px;min-width:0}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{overflow-wrap:anywhere;white-space:normal;flex:1 1 0;min-width:0;height:auto;padding:4px;line-height:14px}.BylfoW_feedbackInput{height:auto;min-height:32px}}";
3539
+ const css = ".BylfoW_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.BylfoW_card{width:100%;max-width:var(--dsh-chat-content-width);border:1px solid var(--dsw-alias-state-warn-secondary);background:var(--dsw-specific-input-major);max-height:min(60vh,520px);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;flex-direction:column;display:flex;overflow:visible}.BylfoW_card,.BylfoW_card *{box-sizing:border-box}.BylfoW_strip{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary);border-radius:20px 20px 0 0;flex-shrink:0;align-items:center;gap:8px;padding:10px 16px;font-size:13px;line-height:18px;display:flex}.BylfoW_dot{background:var(--dsw-alias-state-warn-primary);border-radius:50%;width:8px;height:8px}.BylfoW_stripTitle{flex:none;font-weight:600}.BylfoW_previewLink{color:inherit;font:inherit;cursor:pointer;opacity:.85;background:0 0;border:0;flex:none;align-items:center;gap:4px;padding:0;display:inline-flex}.BylfoW_previewLink:hover{opacity:1;text-decoration:underline}.BylfoW_previewLink:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:3px}.BylfoW_headerPicker{flex:0 auto;align-items:center;min-width:0;max-width:55%;margin-left:auto;display:flex}.BylfoW_headerPicker>*{min-width:0;max-width:100%}.BylfoW_body{overscroll-behavior:contain;flex:auto;min-height:0;padding:12px 16px 4px;font-size:14px;line-height:22px;overflow-y:auto}.BylfoW_summary{min-width:0}.BylfoW_summaryTitle{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:15px;font-weight:500;line-height:22px;overflow:hidden}.BylfoW_summaryText{-webkit-line-clamp:2;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;margin:8px 0 0;font-size:14px;line-height:24px;display:-webkit-box;overflow:hidden}.BylfoW_footer{z-index:2;flex-direction:column;flex-shrink:0;gap:6px;padding:8px 16px 12px;display:flex;position:relative;overflow:visible}.BylfoW_feedback{min-height:0;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}.BylfoW_feedback:empty{display:none}.BylfoW_feedbackRow{align-items:center;gap:8px;min-width:0;display:flex}.BylfoW_feedbackInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-input-minor);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-xs-13);border-radius:8px;flex:auto;padding:0 10px}.BylfoW_feedbackInput::placeholder{color:var(--dsw-alias-label-tertiary)}.BylfoW_feedbackInput:disabled{opacity:.6}.BylfoW_bar{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;min-height:32px;display:flex}.BylfoW_picker{flex:16rem;min-width:0;max-width:16rem}.BylfoW_pickerError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px;display:flex}.BylfoW_actions{flex-wrap:nowrap;flex:none;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{white-space:nowrap;height:32px;min-height:32px;padding:0 10px}.BylfoW_discuss,.BylfoW_recover{color:var(--dsw-alias-label-secondary)}.BylfoW_discuss:hover:not(:disabled),.BylfoW_recover:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BylfoW_approve{padding:0 12px}@media (width<=720px){.BylfoW_frame{padding-right:max(10px, env(safe-area-inset-right));padding-bottom:max(10px, env(safe-area-inset-bottom));padding-left:max(10px, env(safe-area-inset-left))}.BylfoW_card{border-radius:16px}.BylfoW_strip,.BylfoW_body,.BylfoW_footer{padding-left:12px;padding-right:12px}.BylfoW_strip{flex-wrap:wrap;gap:6px}.BylfoW_headerPicker{flex:100%;max-width:100%;margin-left:0}.BylfoW_bar{justify-content:flex-end;gap:6px}.BylfoW_actions{flex:100%;justify-content:flex-end;gap:6px;min-width:0}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{overflow-wrap:anywhere;white-space:normal;flex:1 1 0;min-width:0;height:auto;padding:4px;line-height:14px}.BylfoW_feedbackInput{height:auto;min-height:32px}}";
3143
3540
  const tagId = "dsh-model-switch/PlanReviewCard.module.css";
3144
3541
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
3145
3542
  const tag = document.createElement("style");
@@ -3166,9 +3563,13 @@ window.__ModuleLoader__.load({
3166
3563
  "keep": "BylfoW_keep",
3167
3564
  "picker": "BylfoW_picker",
3168
3565
  "pickerError": "BylfoW_pickerError",
3566
+ "previewLink": "BylfoW_previewLink",
3169
3567
  "recover": "BylfoW_recover",
3170
3568
  "strip": "BylfoW_strip",
3171
- "stripTitle": "BylfoW_stripTitle"
3569
+ "stripTitle": "BylfoW_stripTitle",
3570
+ "summary": "BylfoW_summary",
3571
+ "summaryText": "BylfoW_summaryText",
3572
+ "summaryTitle": "BylfoW_summaryTitle"
3172
3573
  };
3173
3574
  //#endregion
3174
3575
  //#region src/client/picker/PlanReviewCard.tsx
@@ -3285,11 +3686,12 @@ window.__ModuleLoader__.load({
3285
3686
  directory: pickerDirectoryViewOrdered(snapshot, props, order, props.catalogRoutes?.() ?? {}),
3286
3687
  t: props.t,
3287
3688
  goalRemote: props.goalRemote,
3689
+ planPreview: props.planPreview,
3288
3690
  ...props.resolveInteractionOperations === void 0 ? {} : { resolveInteractionOperations: props.resolveInteractionOperations },
3289
3691
  ...props.roleOf === void 0 ? {} : { roleOf: props.roleOf }
3290
3692
  }, props.matched.key);
3291
3693
  }
3292
- function PlanReviewState({ matched, review, available, providerLock, agentLocked, lockFailed, settingsUnavailableReason, directory, t, goalRemote, resolveInteractionOperations, roleOf }) {
3694
+ function PlanReviewState({ matched, review, available, providerLock, agentLocked, lockFailed, settingsUnavailableReason, directory, t, goalRemote, planPreview, resolveInteractionOperations, roleOf }) {
3293
3695
  const { snapshot, getDirectorySnapshot, load, select } = directory;
3294
3696
  const [execution, setExecution] = (0, react.useState)(snapshot.current ?? void 0);
3295
3697
  const [feedback, setFeedback] = (0, react.useState)("");
@@ -3305,6 +3707,26 @@ window.__ModuleLoader__.load({
3305
3707
  if (execution === void 0 && snapshot.current !== null) setExecution(snapshot.current);
3306
3708
  }, [execution, snapshot.current]);
3307
3709
  /**
3710
+ * The takeover hides the official panel, so this card drives ui-plan's
3711
+ * registered opener: the full plan opens in the right sidebar as soon as a
3712
+ * Session is on screen (identity-deduped inside the binding).
3713
+ */
3714
+ (0, react.useEffect)(() => planPreview.autoOpen(matched.sessionId, review, matched.key), [
3715
+ planPreview,
3716
+ matched.sessionId,
3717
+ matched.key,
3718
+ review
3719
+ ]);
3720
+ /** Official two-part summary: first line as title, first paragraph as body. */
3721
+ const summary = (0, react.useMemo)(() => {
3722
+ const title = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-line" });
3723
+ const description = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-paragraph" });
3724
+ return {
3725
+ title,
3726
+ description: description === title ? "" : description
3727
+ };
3728
+ }, [review.plan]);
3729
+ /**
3308
3730
  * Run one takeover action. `force` reaches past a terminal answer state: the
3309
3731
  * withdrawal action must stay reachable, or a rejected answer would leave the
3310
3732
  * card with no way back to the composer.
@@ -3357,7 +3779,9 @@ window.__ModuleLoader__.load({
3357
3779
  };
3358
3780
  const onApprove = () => {
3359
3781
  if (execution === void 0 || !executionAllowed || !available || busy || blocked) return;
3360
- settle(() => approveWith(execution));
3782
+ settle(async () => {
3783
+ await approveWith(execution);
3784
+ });
3361
3785
  };
3362
3786
  const goal = goalRemote();
3363
3787
  const goalReason = goal === void 0 ? t("plan.goalUnsupported") : void 0;
@@ -3370,7 +3794,10 @@ window.__ModuleLoader__.load({
3370
3794
  const onRunAsGoal = () => {
3371
3795
  if (execution === void 0 || !executionAllowed || !available || busy || blocked || goal === void 0) return;
3372
3796
  settle(async () => {
3373
- const handoff = await setPlanAsGoal(goal, matched.sessionId, review.plan);
3797
+ const handoff = await setPlanAsGoal(goal, matched.sessionId, review.plan, {
3798
+ ...review.callId === void 0 ? {} : { callId: review.callId },
3799
+ requestKey: matched.key
3800
+ });
3374
3801
  if (handoff.kind === "unsupported") throw new Error(t("plan.goalUnsupported"));
3375
3802
  if (handoff.kind === "failed") {
3376
3803
  const message = handoff.code === void 0 ? handoff.message : `${handoff.code}: ${handoff.message}`;
@@ -3397,6 +3824,15 @@ window.__ModuleLoader__.load({
3397
3824
  className: PlanReviewCard_module_css_default.stripTitle,
3398
3825
  children: t("plan.header")
3399
3826
  }),
3827
+ planPreview.available() && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3828
+ type: "button",
3829
+ className: PlanReviewCard_module_css_default.previewLink,
3830
+ "data-plan-preview-open": true,
3831
+ onClick: () => {
3832
+ planPreview.open(matched.sessionId, review, matched.key);
3833
+ },
3834
+ children: t("plan.openFull")
3835
+ }),
3400
3836
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3401
3837
  className: PlanReviewCard_module_css_default.headerPicker,
3402
3838
  "aria-label": t("plan.execution"),
@@ -3428,15 +3864,16 @@ window.__ModuleLoader__.load({
3428
3864
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3429
3865
  className: PlanReviewCard_module_css_default.body,
3430
3866
  "data-plan-review-scroll": true,
3431
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
3432
- text: review.plan,
3433
- labels: {
3434
- code: {
3435
- copyLabel: t("markdown.copy"),
3436
- copiedLabel: t("markdown.copied")
3437
- },
3438
- footnotes: t("markdown.footnotes")
3439
- }
3867
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3868
+ className: PlanReviewCard_module_css_default.summary,
3869
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3870
+ className: PlanReviewCard_module_css_default.summaryTitle,
3871
+ "data-plan-review-summary": true,
3872
+ children: summary.title
3873
+ }), summary.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3874
+ className: PlanReviewCard_module_css_default.summaryText,
3875
+ children: summary.description
3876
+ })]
3440
3877
  })
3441
3878
  }),
3442
3879
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -3581,6 +4018,7 @@ window.__ModuleLoader__.load({
3581
4018
  "choice.unavailable": "目录没有这个组合",
3582
4019
  "plan.kicker": "Plan",
3583
4020
  "plan.header": "计划待审",
4021
+ "plan.openFull": "查看完整计划",
3584
4022
  "plan.execution": "执行模型",
3585
4023
  "plan.approve": "确认执行",
3586
4024
  "plan.keep": "拒绝",
@@ -3636,6 +4074,7 @@ window.__ModuleLoader__.load({
3636
4074
  "choice.unavailable": "This combination is not in the catalog",
3637
4075
  "plan.kicker": "Plan",
3638
4076
  "plan.header": "Plan review",
4077
+ "plan.openFull": "View full plan",
3639
4078
  "plan.execution": "Execution model",
3640
4079
  "plan.approve": "Approve",
3641
4080
  "plan.keep": "Keep planning",
@@ -3805,6 +4244,7 @@ window.__ModuleLoader__.load({
3805
4244
  });
3806
4245
  });
3807
4246
  const resolveInteractionOperations = () => interactionOperationsFrom(scope);
4247
+ const planPreview = createPlanPreviewBinding(scope.slots);
3808
4248
  const rpcOf = () => {
3809
4249
  return scope.get("connection", false)?.rpc;
3810
4250
  };
@@ -3831,6 +4271,7 @@ window.__ModuleLoader__.load({
3831
4271
  subscribeMainDefaults: (listener) => mainDefaults.subscribe(listener),
3832
4272
  getMainDefaultsSnapshot: () => mainDefaults.getSnapshot(),
3833
4273
  goalRemote: () => goalRemoteFrom(scope),
4274
+ planPreview,
3834
4275
  hooks: {
3835
4276
  directory: directory.store,
3836
4277
  providerOrder: orderStore
@@ -3972,6 +4413,8 @@ window.__ModuleLoader__.load({
3972
4413
  const subagent = deriveConfigForm(owned, deriveSubagentSettings, SUBAGENT_SETTINGS_FIELDS);
3973
4414
  const search = deriveConfigForm(owned, deriveSearchSettings, SEARCH_SETTINGS_FIELDS);
3974
4415
  const image = deriveConfigForm(owned, deriveImageSettings, IMAGE_SETTINGS_FIELDS);
4416
+ const autoReview = deriveConfigForm(owned, deriveAutoReviewSettings, AUTO_REVIEW_SETTINGS_FIELDS);
4417
+ const compaction = deriveConfigForm(owned, deriveCompactionSettings, COMPACTION_SETTINGS_FIELDS);
3975
4418
  const saveMain = async (next, expectedRevision) => {
3976
4419
  if (!await mainForm.mutate([
3977
4420
  {
@@ -4036,13 +4479,15 @@ window.__ModuleLoader__.load({
4036
4479
  subagentSettings: subagent,
4037
4480
  searchSettings: search,
4038
4481
  imageSettings: image,
4482
+ autoReviewSettings: autoReview,
4483
+ compactionSettings: compaction,
4039
4484
  switchSettings: owned
4040
4485
  },
4041
4486
  capabilities: RUNTIME_CAPABILITIES,
4042
4487
  saveMain,
4043
4488
  setSubagent: (field, value) => value === void 0 ? subagent.unset(field) : subagent.set(field, value),
4044
4489
  setCapability: (route, field, value) => {
4045
- const scope = route === "search" ? search : image;
4490
+ const scope = route === "search" ? search : route === "image" ? image : route === "compaction" ? compaction : autoReview;
4046
4491
  return value === void 0 ? scope.unset(field) : scope.set(field, value);
4047
4492
  },
4048
4493
  setCompactOnSwitch: async (value) => {