@inventec/dsh-copilot-auth 1.2.11 → 1.2.13

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
@@ -33,7 +33,9 @@
33
33
 
34
34
  | 本插件 | DSH 实测版本 | authorization 服务 | 说明 |
35
35
  |---|---|---|---|
36
- | v1.2.11+ | `0.1.7-rc.2`+ | runtime 内置,插件不挂载 | **界面收敛:移除「重新授权」按钮与 `capabilities.reauthorize` 能力位**(逻辑冗余——已登录只需退出登录,未登录入口本就是「授权登录」;换号/重授权=先退出再登录两步)。其余同 v1.2.10 |
36
+ | v1.2.13+ | `0.1.7-rc.2`+ | runtime 内置,插件不挂载 | **修复模型弹窗勾选闪烁**:勾选/全选触发的物化期间弹窗保持挂载(历史实现切回 `previewing` 导致弹窗整体卸载重挂——卡片闪现「拉取预览中」、滚动位置丢失,实测探针元素直接从 DOM 消失);弹窗改固定高度三段式(头部/内部滚动/常驻操作栏),尺寸不再随增删列表变化;勾选走本地乐观更新(服务端回显到达后对齐)。其余同 v1.2.12 |
37
+ | v1.2.12 | `0.1.7-rc.2`+ | runtime 内置,插件不挂载 | **交互打磨**:「补充模型」的全选按钮在全选中切换为「取消全选」(任一取消勾选即恢复「全选」);「重建」风险提示精简为一行;成功路径的「技术详情」计数移除(与弹窗增删列表重复),技术详情仅在真实失败时展示。其余同 v1.2.11 |
38
+ | v1.2.11 | `0.1.7-rc.2`+ | runtime 内置,插件不挂载 | **界面收敛:移除「重新授权」按钮与 `capabilities.reauthorize` 能力位**(逻辑冗余——已登录只需退出登录,未登录入口本就是「授权登录」;换号/重授权=先退出再登录两步)。其余同 v1.2.10 |
37
39
  | v1.2.10 | `0.1.7-rc.2`+ | runtime 内置,插件不挂载 | **退出登录正式可用**:无进行中授权尝试且无未核实风险(风险锁存)时,经确认弹窗清除凭据并**删除后立即复核**(凭据未消失则如实报「退出未完成」);授权尝试进行中(begin 晚写窗口)与撤回/超时未核实期一律拒绝退出。`/status` 的 `authorization.capabilities.logout` 按可用性动态返回。经主人 2026-10-05 裁决替代 v1.2.8 D-01「退出全禁」策略 |
38
40
  | v1.2.9 | `0.1.7-rc.2`+(`0.2.0-rc.1` web 与 `0.2.0-rc.2` desktop 已实测) | runtime 内置,插件不挂载 | **修复 v1.2.8 授权页显示回归**:授权状态机漏接 `fetch`,页面恒显「未登录」、点「授权登录」恒「失败」且请求根本不发出(2026-10-04 实机实证,nginx 全量零 `POST /copilot-auth/start`)。另加:/status 加载失败退避自愈重试(60 秒转手动+「查询状态」)、失败原因分层展示(网络/网关/响应,不再裸「失败」)、已登录时服务端拒绝替换性授权(409 `already-configured`)且客户端自动恢复已登录视图 |
39
41
  | v1.2.8 | `0.1.7-rc.2`+(`0.2.0-rc.1` web 与 `0.2.0-rc.2` desktop 已实测) | runtime 内置,插件不挂载 | **协议 v2:诚实的授权语义+补充/重建双入口**。授权侧:等待中可「请求撤回」(结果如实显示待核实)、退出/重新授权在宿主可证明安全前禁用并说明、单实例 attempt、15 分钟等待上限、晚到授权成功不再写配置;模型侧:旧「刷新」拆为「补充模型」(候选默认不勾选、非破坏)与「重建模型列表」(二次确认+清 modelOverrides),预览 10 分钟绑定选择、operationId 幂等、配置并发编辑优先、崩溃可恢复(「结束旧配置意图」显式闭环),状态按 profile 隔离(旧全局状态只读提示);模型路由要求 `protocolVersion:2`,GET `/status` 零写探针;v1 函数族已从 state.mjs 移除。**已知缺陷**:授权状态机漏接 fetchImpl → 授权页恒「未登录/失败」(v1.2.9 修复) |
package/lib/client.js CHANGED
@@ -193,11 +193,11 @@ function reduce(state, event) {
193
193
  const p = state.preview;
194
194
  if (event.type === "select") {
195
195
  return [{
196
- name: "previewing",
196
+ name: "confirming",
197
197
  flags: state.flags ?? initial.flags,
198
- operation: p.operation,
199
- catalogSource: p.catalogSource,
200
- stale: false
198
+ preview: p,
199
+ materializing: true,
200
+ staleNotice: state.staleNotice
201
201
  }, {
202
202
  type: "preview",
203
203
  operation: p.operation,
@@ -207,12 +207,19 @@ function reduce(state, event) {
207
207
  confirmEmpty: event.confirmEmpty === true
208
208
  }];
209
209
  }
210
+ if (event.type === "preview-ok") {
211
+ return [{ name: "confirming", flags: state.flags ?? initial.flags, preview: event.preview, staleNotice: state.stale === true, materializing: false }, null];
212
+ }
213
+ if (event.type === "preview-fail") {
214
+ return [{ name: "failed", flags: state.flags ?? initial.flags, error: event.error }, null];
215
+ }
210
216
  if (event.type === "start") {
211
217
  return [{
212
- name: "previewing",
213
- operation: event.operation === "rebuild" ? "rebuild" : p.operation,
214
- catalogSource: event.catalogSource,
215
- stale: false
218
+ name: "confirming",
219
+ flags: state.flags ?? initial.flags,
220
+ preview: p,
221
+ materializing: true,
222
+ staleNotice: state.staleNotice
216
223
  }, {
217
224
  type: "preview",
218
225
  operation: event.operation === "rebuild" ? "rebuild" : p.operation,
@@ -220,6 +227,7 @@ function reduce(state, event) {
220
227
  }];
221
228
  }
222
229
  if (event.type === "confirm") {
230
+ if (state.materializing) return [state, null];
223
231
  const isRebuild = p.operation === "rebuild";
224
232
  const emptyTarget = isRebuild && (p.diff?.targetView?.models ?? []).length === 0;
225
233
  if (isRebuild && event.second !== true) return [state, null];
@@ -593,8 +601,9 @@ var DICTS = {
593
601
  rebuildTitle: "Rebuild model list",
594
602
  candidates: "Models available to add",
595
603
  selectAll: "Select all",
604
+ selectNone: "Deselect all",
596
605
  supplementRisk: "Existing models and customizations will be kept. Only selected models will be added.",
597
- rebuildRisk: "This rebuilds Copilot model configuration from the verified account list and clears the model customizations below. Other provider settings remain unchanged.",
606
+ rebuildRisk: "Rebuilding clears model parameters and overrides. Other provider settings remain unchanged.",
598
607
  clearRisk: "This clears the Copilot model list and its model customizations. Confirm clearing separately.",
599
608
  secondConfirm: "This is destructive. Click again to confirm.",
600
609
  applyChanges: "Apply changes",
@@ -676,8 +685,9 @@ var DICTS = {
676
685
  rebuildTitle: "\u91CD\u5EFA\u6A21\u578B\u5217\u8868",
677
686
  candidates: "\u53EF\u65B0\u589E\u7684\u6A21\u578B",
678
687
  selectAll: "\u5168\u9009",
688
+ selectNone: "\u53D6\u6D88\u5168\u9009",
679
689
  supplementRisk: "\u5C06\u4FDD\u7559\u73B0\u6709\u6A21\u578B\u53CA\u5B9A\u5236\uFF0C\u53EA\u6DFB\u52A0\u4F60\u52FE\u9009\u7684\u6A21\u578B\u3002",
680
- rebuildRisk: "\u5C06\u6309\u672C\u6B21\u53EF\u4FE1\u8D26\u53F7\u5217\u8868\u91CD\u5EFA Copilot \u6A21\u578B\u914D\u7F6E\uFF0C\u5E76\u6E05\u9664\u4E0B\u5217\u6A21\u578B\u53C2\u6570\u4E0E\u8986\u76D6\u914D\u7F6E\u3002\u5176\u4ED6\u63D0\u4F9B\u65B9\u8BBE\u7F6E\u4E0D\u53D8\u3002",
690
+ rebuildRisk: "\u91CD\u5EFA\u5C06\u6E05\u9664\u73B0\u6709\u6A21\u578B\u53C2\u6570\u4E0E\u8986\u76D6\u914D\u7F6E\uFF0C\u5176\u4ED6\u63D0\u4F9B\u65B9\u8BBE\u7F6E\u4E0D\u53D8\u3002",
681
691
  clearRisk: "\u672C\u6B21\u5C06\u6E05\u7A7A Copilot \u6A21\u578B\u5217\u8868\u5E76\u6E05\u9664\u5176\u6A21\u578B\u5B9A\u5236\u3002\u8BF7\u5355\u72EC\u786E\u8BA4\u6E05\u7A7A\u3002",
682
692
  secondConfirm: "\u6B64\u64CD\u4F5C\u5177\u6709\u7834\u574F\u6027\uFF0C\u8BF7\u518D\u6B21\u70B9\u51FB\u786E\u8BA4\u3002",
683
693
  applyChanges: "\u5E94\u7528\u66F4\u6539",
@@ -851,13 +861,21 @@ function sampleThemeSurface() {
851
861
  const bg = m ? `rgb(${m[1].split(",").slice(0, 3).join(",")})` : "#fff";
852
862
  return { bg, fg: cs.color || "inherit" };
853
863
  }
854
- function RefreshModal({ t, flow, onSelect, onConfirm, onCancel, onOverlay }) {
864
+ function RefreshModal({ t, flow, materializing, onSelect, onConfirm, onCancel, onOverlay }) {
855
865
  const p = flow.preview;
856
866
  const diff = p.diff ?? {};
857
867
  const isRebuild = p.operation === "rebuild";
858
868
  const emptyTarget = isRebuild && (diff.targetView?.models ?? []).length === 0;
859
869
  const candidates = diff.candidates ?? [];
860
- const selectedIds = new Set(diff.added ?? []);
870
+ const [localSel, setLocalSel] = (0, import_react.useState)(null);
871
+ (0, import_react.useEffect)(() => {
872
+ setLocalSel(null);
873
+ }, [p.diff]);
874
+ const selectedIds = new Set(localSel ?? (diff.added ?? []));
875
+ const emitSel = (ids) => {
876
+ setLocalSel(new Set(ids));
877
+ onSelect(ids);
878
+ };
861
879
  const [stage, setStage] = (0, import_react.useState)(0);
862
880
  const cancelRef = (0, import_react.useRef)(null);
863
881
  const surface = (0, import_react.useRef)(null);
@@ -892,111 +910,122 @@ function RefreshModal({ t, flow, onSelect, onConfirm, onCancel, onOverlay }) {
892
910
  p.catalogSource === "latest" ? t("srcLatest") : p.catalogSource === "overlay" ? t("srcOverlay") : t("srcLocal")
893
911
  ].filter(Boolean).join(" \xB7 ");
894
912
  const list = (items, style, render) => items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.6 }, children: t("none") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: items.map((x, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: { ...style, ...styles.mono }, children: render ? render(x) : x }, x?.id ?? x ?? i)) });
895
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.modalMask, role: "dialog", "aria-modal": "true", onKeyDown: escCancel, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.modal, background: surface.current.bg, color: surface.current.fg }, children: [
896
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { style: styles.modalTitle, children: t(isRebuild ? "rebuildTitle" : "supplementTitle") }),
897
- flow.staleNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
898
- "\u26A0 ",
899
- t("previewStale")
900
- ] }),
901
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: sourceLine }),
902
- p.evidence?.stale === true && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
903
- "\u26A0 ",
904
- t("srcStale")
905
- ] }),
906
- !isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
907
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
908
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("candidates") }),
909
- "\uFF08",
910
- candidates.length,
911
- "\uFF09",
912
- candidates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, height: 24, marginLeft: 10, fontSize: 12 }, onClick: () => onSelect(candidates), children: t("selectAll") })
913
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.modalMask, role: "dialog", "aria-modal": "true", onKeyDown: escCancel, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.modal, background: surface.current.bg, color: surface.current.fg, height: "min(80vh, 680px)", padding: 0, overflow: "hidden" }, children: [
914
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "18px 20px 6px" }, children: [
915
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { style: styles.modalTitle, children: t(isRebuild ? "rebuildTitle" : "supplementTitle") }),
916
+ flow.staleNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
917
+ "\u26A0 ",
918
+ t("previewStale")
913
919
  ] }),
914
- list(candidates, styles.added, (id) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
915
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedIds.has(id), onChange: () => {
916
- const next = new Set(selectedIds);
917
- if (next.has(id)) next.delete(id);
918
- else next.add(id);
919
- onSelect([...next]);
920
- } }),
921
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: id })
922
- ] })),
923
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: sourceLine }),
921
+ p.evidence?.stale === true && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
924
922
  "\u26A0 ",
925
- t("supplementRisk")
923
+ t("srcStale")
924
+ ] }),
925
+ materializing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
926
+ "\u24D8 ",
927
+ t("refreshing")
926
928
  ] })
927
929
  ] }),
928
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
929
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("addedModels") }),
930
- "\uFF08",
931
- (diff.added ?? []).length,
932
- "\uFF09"
933
- ] }),
934
- list(diff.added ?? [], styles.added),
935
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
936
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("removedModels") }),
937
- "\uFF08",
938
- (diff.removed ?? []).length,
939
- "\uFF09"
940
- ] }),
941
- list(diff.removed ?? [], styles.removed, (x) => `${x.id} \u2014 ${t(x.reason === "unresolvable" ? "removedUnresolvable" : "removedAccount")}`),
942
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
943
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("keptModels") }),
944
- "\uFF08",
945
- (diff.kept ?? []).length,
946
- "\uFF09"
947
- ] }),
948
- (diff.warnings ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
930
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, overflowY: "auto", minHeight: 0, scrollbarGutter: "stable", padding: "0 20px", opacity: materializing ? 0.55 : 1, pointerEvents: materializing ? "none" : "auto" }, children: [
931
+ !isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
932
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
933
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("candidates") }),
934
+ "\uFF08",
935
+ candidates.length,
936
+ "\uFF09",
937
+ candidates.length > 0 && (() => {
938
+ const allSelected = candidates.every((id) => selectedIds.has(id));
939
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, height: 24, marginLeft: 10, fontSize: 12 }, onClick: () => emitSel(allSelected ? [] : candidates), children: allSelected ? t("selectNone") : t("selectAll") });
940
+ })()
941
+ ] }),
942
+ list(candidates, styles.added, (id) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
943
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedIds.has(id), onChange: () => {
944
+ const next = new Set(selectedIds);
945
+ if (next.has(id)) next.delete(id);
946
+ else next.add(id);
947
+ emitSel([...next]);
948
+ } }),
949
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: id })
950
+ ] })),
951
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
952
+ "\u26A0 ",
953
+ t("supplementRisk")
954
+ ] })
955
+ ] }),
949
956
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
950
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("warnings") }),
957
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("addedModels") }),
951
958
  "\uFF08",
952
- diff.warnings.length,
959
+ (diff.added ?? []).length,
953
960
  "\uFF09"
954
961
  ] }),
955
- list(diff.warnings, styles.skipped, (w) => `${w.id ?? ""} \u2014 ${w.reason ?? ""}`)
956
- ] }),
957
- isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
958
- "\u26A0 ",
959
- t("rebuildRisk")
960
- ] }),
961
- emptyTarget && stage >= 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
962
- "\u26A0 ",
963
- t("clearRisk")
964
- ] }),
965
- stage === 1 && !emptyTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
966
- "\u26A0 ",
967
- t("secondConfirm")
968
- ] }),
969
- (p.skipped ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
970
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
971
- t("skippedModels"),
962
+ list(diff.added ?? [], styles.added),
963
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
964
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("removedModels") }),
972
965
  "\uFF08",
973
- p.skipped.length,
966
+ (diff.removed ?? []).length,
974
967
  "\uFF09"
975
968
  ] }),
976
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: p.skipped.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: styles.skipped, children: [
977
- s.id,
978
- " \u2014 ",
979
- s.reason
980
- ] }, s.id)) })
981
- ] }),
982
- p.catalogError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
983
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("techDetails") }),
984
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.mono, fontSize: 12 }, children: p.catalogError })
969
+ list(diff.removed ?? [], styles.removed, (x) => `${x.id} \u2014 ${t(x.reason === "unresolvable" ? "removedUnresolvable" : "removedAccount")}`),
970
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("keptModels") }),
972
+ "\uFF08",
973
+ (diff.kept ?? []).length,
974
+ "\uFF09"
975
+ ] }),
976
+ (diff.warnings ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
977
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
978
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("warnings") }),
979
+ "\uFF08",
980
+ diff.warnings.length,
981
+ "\uFF09"
982
+ ] }),
983
+ list(diff.warnings, styles.skipped, (w) => `${w.id ?? ""} \u2014 ${w.reason ?? ""}`)
984
+ ] }),
985
+ isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
986
+ "\u26A0 ",
987
+ t("rebuildRisk")
988
+ ] }),
989
+ emptyTarget && stage >= 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
990
+ "\u26A0 ",
991
+ t("clearRisk")
992
+ ] }),
993
+ stage === 1 && !emptyTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
994
+ "\u26A0 ",
995
+ t("secondConfirm")
996
+ ] }),
997
+ (p.skipped ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
998
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
999
+ t("skippedModels"),
1000
+ "\uFF08",
1001
+ p.skipped.length,
1002
+ "\uFF09"
1003
+ ] }),
1004
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: p.skipped.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: styles.skipped, children: [
1005
+ s.id,
1006
+ " \u2014 ",
1007
+ s.reason
1008
+ ] }, s.id)) })
1009
+ ] }),
1010
+ p.catalogError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
1011
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("techDetails") }),
1012
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.mono, fontSize: 12 }, children: p.catalogError })
1013
+ ] })
985
1014
  ] }),
986
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.modalActions, children: [
1015
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "8px 20px 16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.modalActions, children: [
987
1016
  p.catalogSource === "local" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, marginRight: "auto" }, onClick: onOverlay, children: t("overlayBtn") }),
988
1017
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ref: cancelRef, type: "button", style: { ...styles.button, ...styles.secondary }, onClick: onCancel, children: t("cancel") }),
989
1018
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
990
1019
  "button",
991
1020
  {
992
1021
  type: "button",
993
- style: { ...styles.button, ...styles.primary, ...p.evidence?.stale === true ? { opacity: 0.5, cursor: "not-allowed" } : null },
994
- disabled: p.evidence?.stale === true,
1022
+ style: { ...styles.button, ...styles.primary, ...p.evidence?.stale === true || materializing ? { opacity: 0.5, cursor: "not-allowed" } : null },
1023
+ disabled: p.evidence?.stale === true || materializing,
995
1024
  onClick: confirmClick,
996
1025
  children: t("applyChanges")
997
1026
  }
998
1027
  )
999
- ] })
1028
+ ] }) })
1000
1029
  ] }) });
1001
1030
  }
1002
1031
  function RetireDialog({ t, onConfirm, onCancel }) {
@@ -1229,12 +1258,9 @@ function CopilotSection({ t = (key) => DICTS.en[key] ?? key }) {
1229
1258
  ] }) : null;
1230
1259
  })(),
1231
1260
  ["recovery-needed", "rollback-conflict", "intent-retired"].includes(flow.result?.status) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: () => drive({ type: "retire-request" }), children: t("retireBtn") }) }),
1232
- (flow.result?.error || flow.result?.changes) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
1261
+ flow.result?.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
1233
1262
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("techDetails") }),
1234
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { ...styles.mono, fontSize: 12 }, children: [
1235
- flow.result?.error ?? "",
1236
- flow.result?.changes ? ` ${JSON.stringify(flow.result.changes)}` : ""
1237
- ] })
1263
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.mono, fontSize: 12 }, children: flow.result.error })
1238
1264
  ] })
1239
1265
  ] }),
1240
1266
  flow.name === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: flow.error === "state-corrupt" ? t("stateCorrupt") : flow.error })
@@ -1244,6 +1270,7 @@ function CopilotSection({ t = (key) => DICTS.en[key] ?? key }) {
1244
1270
  {
1245
1271
  t,
1246
1272
  flow,
1273
+ materializing: flow.materializing === true,
1247
1274
  onSelect: (selectedIds) => drive({ type: "select", selectedIds }),
1248
1275
  onConfirm: (opts) => drive({ type: "confirm", ...opts }),
1249
1276
  onCancel: () => drive({ type: "cancel" }),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inventec/dsh-copilot-auth",
3
- "version": "1.2.11",
4
- "description": "为内置 Copilot 提供方补设备码登录设置页,预置开箱路由;凭据入内置凭据库,模型目录兜底不覆盖定制。v1.2.11:移除「重新授权」按钮与能力位(已登录只需退出登录,未登录入口本就是授权登录)。v1.2.10:退出登录正式可用(协议 v2)。适配 DSH 0.1.7+(≤0.1.5 请用 1.1.x)。",
3
+ "version": "1.2.13",
4
+ "description": "为内置 Copilot 提供方补设备码登录设置页,预置开箱路由;凭据入内置凭据库,模型目录兜底不覆盖定制。v1.2.13:修复模型弹窗勾选闪烁(物化期间弹窗保持挂载+固定高度+乐观勾选+常驻操作栏)。v1.2.10:退出登录正式可用(协议 v2)。适配 DSH 0.1.7+(≤0.1.5 请用 1.1.x)。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "iasi",
@@ -95,13 +95,15 @@ export function reduce(state, event) {
95
95
  case "confirming": {
96
96
  const p = state.preview;
97
97
  if (event.type === "select") {
98
- // 选择变化:从原快照 materialize(服务端重算,沿用原有效期,不重新取数)
98
+ // 选择变化:从原快照 materialize(服务端重算,沿用原有效期,不重新取数)。
99
+ // 留在 confirming+materializing 标记——弹窗保持挂载、不卸载重挂;
100
+ // 历史实现切回 previewing 导致弹窗整体关闭再打开(勾选闪烁的根因,2026-10-05)。
99
101
  return [{
100
- name: "previewing",
102
+ name: "confirming",
101
103
  flags: state.flags ?? initial.flags,
102
- operation: p.operation,
103
- catalogSource: p.catalogSource,
104
- stale: false,
104
+ preview: p,
105
+ materializing: true,
106
+ staleNotice: state.staleNotice,
105
107
  }, {
106
108
  type: "preview",
107
109
  operation: p.operation,
@@ -111,13 +113,22 @@ export function reduce(state, event) {
111
113
  confirmEmpty: event.confirmEmpty === true,
112
114
  }];
113
115
  }
116
+ if (event.type === "preview-ok") {
117
+ // materialize/切源完成:预览原位替换(新 previewId 绑定新选择)
118
+ return [{ name: "confirming", flags: state.flags ?? initial.flags, preview: event.preview, staleNotice: state.stale === true, materializing: false }, null];
119
+ }
120
+ if (event.type === "preview-fail") {
121
+ return [{ name: "failed", flags: state.flags ?? initial.flags, error: event.error }, null];
122
+ }
114
123
  if (event.type === "start") {
115
- // 显式切源(overlay/local)或切换操作:生成全新预览(不隐式降级,Q7)
124
+ // 显式切源(overlay/local)或切换操作:生成全新预览(不隐式降级,Q7)。
125
+ // 同 select:留在 confirming 保持弹窗挂载。
116
126
  return [{
117
- name: "previewing",
118
- operation: event.operation === "rebuild" ? "rebuild" : p.operation,
119
- catalogSource: event.catalogSource,
120
- stale: false,
127
+ name: "confirming",
128
+ flags: state.flags ?? initial.flags,
129
+ preview: p,
130
+ materializing: true,
131
+ staleNotice: state.staleNotice,
121
132
  }, {
122
133
  type: "preview",
123
134
  operation: event.operation === "rebuild" ? "rebuild" : p.operation,
@@ -125,6 +136,7 @@ export function reduce(state, event) {
125
136
  }];
126
137
  }
127
138
  if (event.type === "confirm") {
139
+ if (state.materializing) return [state, null]; // 物化中不得用旧 previewId 应用
128
140
  const isRebuild = p.operation === "rebuild";
129
141
  const emptyTarget = isRebuild && (p.diff?.targetView?.models ?? []).length === 0;
130
142
  if (isRebuild && event.second !== true) return [state, null]; // 重建需二次确认