@dsh-electron/dsh-plugin-multi-root-workspace 0.1.13 → 0.1.14

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.
Files changed (42) hide show
  1. package/CHANGELOG.en.md +17 -1
  2. package/CHANGELOG.md +17 -1
  3. package/README.en.md +8 -8
  4. package/README.md +8 -8
  5. package/detail/DETAIL.en.md +1 -0
  6. package/detail/DETAIL.md +1 -0
  7. package/detail/preview.svg +1 -0
  8. package/detail/preview.zh.svg +1 -0
  9. package/lib/client.js +392 -63
  10. package/lib/client.js.map +1 -1
  11. package/lib/{command-B9855H7y.js → command-Dcz6nULo.js} +25 -3
  12. package/lib/command.js +1 -1
  13. package/lib/{compat-Bg2HFVMX.js → compat-veDqCOoa.js} +3 -1
  14. package/lib/compat.js +1 -1
  15. package/lib/{fs-CfzJq2wd.js → fs-Uws0ZpmV.js} +38 -0
  16. package/lib/fs.js +1 -1
  17. package/lib/index.js +4 -4
  18. package/lib/{native-win32-2waCRkPI.js → native-win32-CRNXr11U.js} +2 -1
  19. package/lib/{protocol-CJOvAvOS.js → protocol-CnR1KTXy.js} +49 -7
  20. package/lib/{registry-Bv431TfO.js → registry-DR_sMuvS.js} +3 -3
  21. package/lib/{registry-lease-win32-DVTq9d4D.js → registry-lease-win32-DDO-c7ig.js} +2 -1
  22. package/lib/registry.js +2 -2
  23. package/lib/types/client/RootSwitcher.d.ts +2 -0
  24. package/lib/types/client/auto-review-settings.d.ts +18 -0
  25. package/lib/types/client/files-tree/FilesTree.d.ts +4 -1
  26. package/lib/types/client/files-tree/locales.d.ts +1 -1
  27. package/lib/types/client/locales.d.ts +12 -0
  28. package/lib/types/client/open-in-app/locales.d.ts +1 -1
  29. package/lib/types/client/skills-settings.d.ts +12 -0
  30. package/lib/types/client/styles.d.ts +1 -1
  31. package/lib/types/compat/auto-review-client.d.ts +58 -0
  32. package/lib/types/compat/connection-rpc.d.ts +12 -0
  33. package/lib/types/compat/dsh-version.d.ts +1 -1
  34. package/lib/types/compat/files-tree.d.ts +36 -0
  35. package/lib/types/compat/fs-patch.d.ts +6 -0
  36. package/lib/types/compat/koffi.d.ts +2 -0
  37. package/lib/types/fs.d.ts +3 -1
  38. package/locale/en.json +7 -0
  39. package/locale/zh.json +7 -0
  40. package/package.json +89 -82
  41. package/src/auto-review/README.en.md +1 -1
  42. package/src/auto-review/README.md +1 -1
package/lib/client.js CHANGED
@@ -123,6 +123,48 @@ window.__ModuleLoader__.load({
123
123
  return typeof count === "number" && count > 0;
124
124
  }
125
125
  //#endregion
126
+ //#region src/compat/files-tree.ts
127
+ function nativeTreeRenderer(value) {
128
+ return typeof value === "function" ? value : void 0;
129
+ }
130
+ /** The factory consumes absolute, slash-separated keys and already-localized errors. */
131
+ function nativeTreeInput(state, failureLine, toggle, open) {
132
+ const root = state.root.replace(/[/\\]+$/, "");
133
+ const keyOf = (path) => path === state.root ? root : path;
134
+ const entries = [];
135
+ const directories = {};
136
+ for (const path of state.expanded) directories[keyOf(path)] = { loading: true };
137
+ for (const [path, level] of Object.entries(state.levels)) {
138
+ const key = keyOf(path);
139
+ if (level.kind === "loading") directories[key] = { loading: true };
140
+ else if (level.kind === "failed") directories[key] = { failure: failureLine(level.failure) };
141
+ else {
142
+ const status = {};
143
+ if (level.failure !== void 0) status.failure = failureLine(level.failure);
144
+ if (level.level.truncated) status.truncated = true;
145
+ directories[key] = status;
146
+ for (const entry of level.level.entries) entries.push({
147
+ path: `${path.replace(/[/\\]+$/, "")}/${entry.name}`,
148
+ name: entry.name,
149
+ meta: { kind: entry.type }
150
+ });
151
+ }
152
+ }
153
+ return {
154
+ root,
155
+ entries,
156
+ directories,
157
+ expanded: state.expanded.map(keyOf),
158
+ onToggle: (entry) => {
159
+ const parent = entry.path.slice(0, entry.path.lastIndexOf("/"));
160
+ toggle(parent === root ? state.root : parent, entry.path);
161
+ },
162
+ onOpen: (entry) => {
163
+ open(entry.path);
164
+ }
165
+ };
166
+ }
167
+ //#endregion
126
168
  //#region node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.js
127
169
  function getEnumValues(entries) {
128
170
  const numericValues = Object.values(entries).filter((v) => typeof v === "number");
@@ -5545,6 +5587,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5545
5587
  "skills.globalEnable": "启用附属根 Skills",
5546
5588
  "skills.globalHint": "控制所有附属目录的 Skill 发现与新调用;保留每个目录的独立选择。",
5547
5589
  "skills.settingsFailed": "设置保存失败,请重试。",
5590
+ "autoReview.title": "多根 Auto Review",
5591
+ "autoReview.experimental": "实验性",
5592
+ "autoReview.hint": "为附加根保留审核上下文并接管 Auto 审查;与插件管理页同名 Loader 行开关等价,默认关闭,仅适配 DSH 0.2.1-rc.2。",
5593
+ "autoReview.loadFailed": "无法读取插件状态。",
5594
+ "autoReview.restartRequired": "更改将在重启后生效。",
5595
+ "autoReview.settingsFailed": "设置保存失败,请重试。",
5548
5596
  "skills.userOnly": "仅用户调用",
5549
5597
  "panel.skills": "目录技能",
5550
5598
  "panel.skillsEnabled": "此目录技能已启用,点击停用",
@@ -5632,6 +5680,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5632
5680
  "skills.globalEnable": "Enable additional-root Skills",
5633
5681
  "skills.globalHint": "Controls discovery and new invocations for all additional folders, preserving each folder’s choice.",
5634
5682
  "skills.settingsFailed": "Could not save settings. Please try again.",
5683
+ "autoReview.title": "Multi-root Auto Review",
5684
+ "autoReview.experimental": "Experimental",
5685
+ "autoReview.hint": "Preserves multi-root context for Auto review and takes over the reviewer; equivalent to the same Loader row switch in the Plugin Manager. Off by default; adapted to DSH 0.2.1-rc.2 only.",
5686
+ "autoReview.loadFailed": "Could not read plugin state.",
5687
+ "autoReview.restartRequired": "The change takes effect after restart.",
5688
+ "autoReview.settingsFailed": "Could not save settings. Please try again.",
5635
5689
  "skills.userOnly": "User invocation only",
5636
5690
  "panel.skills": "Folder skills",
5637
5691
  "panel.skillsEnabled": "Skills enabled for this folder. Click to disable.",
@@ -5928,6 +5982,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5928
5982
  display: none;
5929
5983
  }
5930
5984
 
5985
+ /* Newer Files pages place the navigator beside the header instead of
5986
+ wrapping both in data-files-root. Target the page without hiding the
5987
+ portaled replacement or any of its rows. */
5988
+ [data-files-page]:has(.mrfw-fileLauncher) [data-files-path]:not([data-files-entry]) { order: -2; }
5989
+ [data-files-page]:has(.mrfw-rootSwitcher) [data-files-path]:not([data-files-entry]) { display: none; }
5990
+ [data-files-page]:has(.mrfw-rootSwitcher[data-root-kind="additional"]) [data-files-content],
5991
+ [data-files-page]:has(.mrfw-rootSwitcher[data-root-kind="additional"]) [data-files-reload] { display: none; }
5992
+ [data-files-page]:has(.mrfw-rootSwitcher[data-root-kind="additional"]) [data-slot="sidebar.right.tab.files.actions"] > *:has([data-open-target="directory"]:not(.mrfw-openSplit)),
5993
+ [data-files-page]:has(.mrfw-rootSwitcher[data-root-kind="additional"]) [data-open-target="directory"]:not(.mrfw-openSplit) { display: none; }
5994
+
5931
5995
  /* While the switcher names an additional root, the native open-in-app split
5932
5996
  button hides too: its slot props carry the pane's primary root, so it
5933
5997
  would always open the primary root no matter what the switcher selected.
@@ -6360,6 +6424,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6360
6424
  border-bottom: 0.5px solid var(--dsw-alias-border-l2);
6361
6425
  }
6362
6426
  .mrfw-skillsSettingsText { min-width: 0; }
6427
+ .mrfw-settingsTitleRow {
6428
+ display: flex;
6429
+ align-items: center;
6430
+ gap: 8px;
6431
+ }
6363
6432
  .mrfw-skillsSettingsTitle { font-size: 14px; line-height: 20px; }
6364
6433
  .mrfw-skillsSettingsDescription {
6365
6434
  margin-top: 4px;
@@ -6842,90 +6911,345 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6842
6911
  });
6843
6912
  }
6844
6913
  //#endregion
6914
+ //#region src/compat/auto-review-client.ts
6915
+ /** The module specifier `cordis.patch.yml` gives the optional row. */
6916
+ const AUTO_REVIEW_MODULE = "@dsh-electron/dsh-plugin-multi-root-workspace/auto-review";
6917
+ var AutoReviewSettingsForm = class {
6918
+ snapshot = { status: "unavailable" };
6919
+ listeners = /* @__PURE__ */ new Set();
6920
+ manager;
6921
+ stopEvents;
6922
+ epoch = 0;
6923
+ refreshSeq = 0;
6924
+ getSnapshot() {
6925
+ return this.snapshot;
6926
+ }
6927
+ subscribe(listener) {
6928
+ this.listeners.add(listener);
6929
+ return () => {
6930
+ this.listeners.delete(listener);
6931
+ };
6932
+ }
6933
+ publish(next) {
6934
+ this.snapshot = next;
6935
+ for (const listener of [...this.listeners]) listener();
6936
+ }
6937
+ attach(manager, remote) {
6938
+ this.detach();
6939
+ this.manager = manager;
6940
+ this.epoch++;
6941
+ this.publish({ status: "loading" });
6942
+ if (remote !== void 0) try {
6943
+ this.stopEvents = remote.$on("plugin-manager/changed", () => {
6944
+ this.refresh();
6945
+ });
6946
+ } catch {
6947
+ this.stopEvents = void 0;
6948
+ }
6949
+ this.refresh();
6950
+ }
6951
+ detach() {
6952
+ this.stopEvents?.();
6953
+ this.stopEvents = void 0;
6954
+ this.manager = void 0;
6955
+ this.epoch++;
6956
+ this.publish({ status: "unavailable" });
6957
+ }
6958
+ async refresh() {
6959
+ const manager = this.manager;
6960
+ const epoch = this.epoch;
6961
+ const seq = ++this.refreshSeq;
6962
+ if (manager === void 0) return;
6963
+ const result = await manager.listPlugins();
6964
+ if (manager !== this.manager || epoch !== this.epoch || seq !== this.refreshSeq) return;
6965
+ if (!result.ok) {
6966
+ this.publish({ status: "error" });
6967
+ return;
6968
+ }
6969
+ const entry = result.value.find((item) => item.moduleName === AUTO_REVIEW_MODULE);
6970
+ this.publish(entry === void 0 ? { status: "ready" } : {
6971
+ status: "ready",
6972
+ row: {
6973
+ entryId: entry.entryId,
6974
+ enabled: entry.enabled,
6975
+ writable: entry.readOnlyReason === void 0,
6976
+ ...entry.diagnostic === void 0 ? {} : { diagnostic: entry.diagnostic }
6977
+ }
6978
+ });
6979
+ }
6980
+ async setEnabled(enabled) {
6981
+ const manager = this.manager;
6982
+ const row = this.snapshot.status === "ready" ? this.snapshot.row : void 0;
6983
+ if (manager === void 0 || row === void 0) return "failed";
6984
+ const result = await manager.setPluginEnabled(row.entryId, enabled);
6985
+ await this.refresh();
6986
+ if (!result.ok) return "failed";
6987
+ const application = result.value.application;
6988
+ return application === "applied" || application === "restart-required" ? application : "failed";
6989
+ }
6990
+ };
6991
+ /**
6992
+ * Create the card's Auto Review handle and attach it when the host's
6993
+ * `pluginManager` namespace arrives. The returned form exists immediately with
6994
+ * status `unavailable` and publishes on every attach/detach/read, so callers
6995
+ * only need `subscribe` — no separate availability callback.
6996
+ * @param ctx - the client root context.
6997
+ * @returns the stable form the settings row renders.
6998
+ */
6999
+ function installAutoReviewSettings(ctx) {
7000
+ const form = new AutoReviewSettingsForm();
7001
+ clientInject(ctx, ["remote.pluginManager"], (scope) => {
7002
+ const manager = scope.get("remote.pluginManager");
7003
+ if (manager === void 0) return;
7004
+ const remote = scope.get("remote");
7005
+ form.attach(manager, remote);
7006
+ return () => {
7007
+ form.detach();
7008
+ };
7009
+ });
7010
+ return form;
7011
+ }
7012
+ //#endregion
7013
+ //#region src/client/auto-review-settings.tsx
7014
+ /**
7015
+ * Full-opacity hold for the card's message toasts — the same window upstream
7016
+ * gives a refusal banner, since these strings name what broke rather than
7017
+ * reporting a one-line limit.
7018
+ */
7019
+ const TOAST_HOLD_MS = 8e3;
7020
+ /**
7021
+ * The optional Auto Review row of the plugin settings card.
7022
+ *
7023
+ * Its switch is the Loader row's own enablement — the same write the Plugin
7024
+ * Manager's row switch performs — so the card can never disagree with the row
7025
+ * list about whether the companion is on. Feedback is a transient `Toast`
7026
+ * banner, never inline text: state-driven messages (a failed read, an entry
7027
+ * diagnostic) fire on entry and clear when their source resolves, while write
7028
+ * outcomes report once and fade. The row stays hidden entirely on hosts
7029
+ * without the `pluginManager` namespace or when the composition does not list
7030
+ * the optional entry.
7031
+ */
7032
+ function AutoReviewSettingsCard({ form, t }) {
7033
+ const snapshot = (0, react.useSyncExternalStore)((listener) => form.subscribe(listener), () => form.getSnapshot());
7034
+ const [busy, setBusy] = (0, react.useState)(false);
7035
+ const mounted = (0, react.useRef)(true);
7036
+ const toastSeq = (0, react.useRef)(0);
7037
+ const [toast, setToast] = (0, react.useState)(null);
7038
+ (0, react.useEffect)(() => {
7039
+ mounted.current = true;
7040
+ return () => {
7041
+ mounted.current = false;
7042
+ };
7043
+ }, []);
7044
+ const showToast = (0, react.useCallback)((kind, text) => {
7045
+ toastSeq.current += 1;
7046
+ setToast({
7047
+ seq: toastSeq.current,
7048
+ kind,
7049
+ text
7050
+ });
7051
+ }, []);
7052
+ const dismissToast = (0, react.useCallback)((kind) => {
7053
+ setToast((current) => current?.kind === kind ? null : current);
7054
+ }, []);
7055
+ const status = snapshot.status;
7056
+ const diagnostic = status === "ready" ? snapshot.row?.diagnostic : void 0;
7057
+ (0, react.useEffect)(() => {
7058
+ if (status === "error") showToast("load", t("autoReview.loadFailed"));
7059
+ else dismissToast("load");
7060
+ }, [
7061
+ status,
7062
+ t,
7063
+ showToast,
7064
+ dismissToast
7065
+ ]);
7066
+ (0, react.useEffect)(() => {
7067
+ if (diagnostic !== void 0 && diagnostic !== "") showToast("diagnostic", diagnostic);
7068
+ else dismissToast("diagnostic");
7069
+ }, [
7070
+ diagnostic,
7071
+ showToast,
7072
+ dismissToast
7073
+ ]);
7074
+ if (status === "unavailable") return null;
7075
+ const row = status === "ready" ? snapshot.row : void 0;
7076
+ if (status === "ready" && row === void 0) return null;
7077
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7078
+ className: "mrfw-skillsSettings",
7079
+ children: [
7080
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7081
+ className: "mrfw-skillsSettingsText",
7082
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7083
+ className: "mrfw-settingsTitleRow",
7084
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7085
+ className: "mrfw-skillsSettingsTitle",
7086
+ children: t("autoReview.title")
7087
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
7088
+ tone: "info",
7089
+ children: t("autoReview.experimental")
7090
+ })]
7091
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7092
+ className: "mrfw-skillsSettingsDescription",
7093
+ children: t("autoReview.hint")
7094
+ })]
7095
+ }),
7096
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
7097
+ label: t("autoReview.title"),
7098
+ checked: row?.enabled ?? false,
7099
+ disabled: busy || row?.writable !== true,
7100
+ onChange: (enabled) => {
7101
+ setBusy(true);
7102
+ form.setEnabled(enabled).then((result) => {
7103
+ if (!mounted.current) return;
7104
+ if (result === "restart-required") showToast("write", t("autoReview.restartRequired"));
7105
+ else if (result === "failed") showToast("write", t("autoReview.settingsFailed"));
7106
+ }).catch(() => {
7107
+ if (mounted.current) showToast("write", t("autoReview.settingsFailed"));
7108
+ }).finally(() => {
7109
+ if (mounted.current) setBusy(false);
7110
+ });
7111
+ }
7112
+ }),
7113
+ toast === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
7114
+ text: toast.text,
7115
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
7116
+ holdMs: TOAST_HOLD_MS,
7117
+ onDone: () => {
7118
+ setToast(null);
7119
+ }
7120
+ }, toast.seq)
7121
+ ]
7122
+ });
7123
+ }
7124
+ //#endregion
6845
7125
  //#region src/client/skills-settings.tsx
6846
7126
  const BUNDLE_KEY = "@dsh-electron/dsh-plugin-multi-root-workspace";
6847
7127
  function SkillsSettingsCard({ form, t }) {
6848
7128
  const snapshot = (0, react.useSyncExternalStore)((listener) => form.subscribe(listener), () => form.getSnapshot());
6849
- const [busy, setBusy] = (0, react.useState)(false), [error, setError] = (0, react.useState)();
7129
+ const [busy, setBusy] = (0, react.useState)(false);
6850
7130
  const mounted = (0, react.useRef)(true);
7131
+ const toastSeq = (0, react.useRef)(0);
7132
+ const [toast, setToast] = (0, react.useState)(null);
6851
7133
  (0, react.useEffect)(() => {
6852
7134
  mounted.current = true;
6853
7135
  return () => {
6854
7136
  mounted.current = false;
6855
7137
  };
6856
7138
  }, []);
7139
+ const showToast = (0, react.useCallback)((text) => {
7140
+ toastSeq.current += 1;
7141
+ setToast({
7142
+ seq: toastSeq.current,
7143
+ text
7144
+ });
7145
+ }, []);
6857
7146
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6858
7147
  className: "mrfw-skillsSettings",
6859
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6860
- className: "mrfw-skillsSettingsText",
6861
- children: [
6862
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7148
+ children: [
7149
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7150
+ className: "mrfw-skillsSettingsText",
7151
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6863
7152
  className: "mrfw-skillsSettingsTitle",
6864
7153
  children: t("skills.globalEnable")
6865
- }),
6866
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7154
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6867
7155
  className: "mrfw-skillsSettingsDescription",
6868
7156
  children: t("skills.globalHint")
6869
- }),
6870
- error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6871
- role: "alert",
6872
- children: error
6873
- }) : null
6874
- ]
6875
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
6876
- label: t("skills.globalEnable"),
6877
- checked: snapshot.value?.enabled ?? true,
6878
- disabled: busy || snapshot.status !== "ready" || !snapshot.writable,
6879
- onChange: (enabled) => {
6880
- setBusy(true);
6881
- setError(void 0);
6882
- form.mutate([{
6883
- op: "set",
6884
- path: ["enabled"],
6885
- value: enabled
6886
- }], snapshot.revision).then((ok) => {
6887
- if (mounted.current && !ok) setError(t("skills.settingsFailed"));
6888
- }).catch(() => {
6889
- if (mounted.current) setError(t("skills.settingsFailed"));
6890
- }).finally(() => {
6891
- if (mounted.current) setBusy(false);
6892
- });
6893
- }
6894
- })]
7157
+ })]
7158
+ }),
7159
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
7160
+ label: t("skills.globalEnable"),
7161
+ checked: snapshot.value?.enabled ?? true,
7162
+ disabled: busy || snapshot.status !== "ready" || !snapshot.writable,
7163
+ onChange: (enabled) => {
7164
+ setBusy(true);
7165
+ form.mutate([{
7166
+ op: "set",
7167
+ path: ["enabled"],
7168
+ value: enabled
7169
+ }], snapshot.revision).then((ok) => {
7170
+ if (mounted.current && !ok) showToast(t("skills.settingsFailed"));
7171
+ }).catch(() => {
7172
+ if (mounted.current) showToast(t("skills.settingsFailed"));
7173
+ }).finally(() => {
7174
+ if (mounted.current) setBusy(false);
7175
+ });
7176
+ }
7177
+ }),
7178
+ toast === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
7179
+ text: toast.text,
7180
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
7181
+ holdMs: 8e3,
7182
+ onDone: () => {
7183
+ setToast(null);
7184
+ }
7185
+ }, toast.seq)
7186
+ ]
6895
7187
  });
6896
7188
  }
7189
+ /**
7190
+ * The bundle's one `plugins.bundle.config` cell: every plugin-level switch the
7191
+ * package offers, in display order. Each row owns its own form and write path —
7192
+ * Skills through its settings namespace, Auto Review through the Plugin
7193
+ * Manager's Loader-row enablement — so one cell never serializes their state.
7194
+ */
7195
+ function BundleSettingsCard({ form, autoReviewForm, t }) {
7196
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [form !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillsSettingsCard, {
7197
+ form,
7198
+ t
7199
+ }) : null, autoReviewForm !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoReviewSettingsCard, {
7200
+ form: autoReviewForm,
7201
+ t
7202
+ }) : null] });
7203
+ }
6897
7204
  function installSkillsSettingsCard(ctx, t) {
6898
- let current;
7205
+ let currentSkills;
7206
+ let currentAutoReview = false;
6899
7207
  let stop;
6900
7208
  const candidates = /* @__PURE__ */ new Map();
6901
7209
  const update = () => {
6902
- const chosen = [...candidates.entries()].sort(([a], [b]) => Number(b.get("configForms") !== void 0) - Number(a.get("configForms") !== void 0))[0];
6903
- if (chosen?.[1] === current) return;
7210
+ const skillsForm = [...candidates.entries()].sort(([a], [b]) => Number(b.get("configForms") !== void 0) - Number(a.get("configForms") !== void 0))[0]?.[1];
7211
+ const autoSnapshot = autoForm.getSnapshot();
7212
+ const autoAvailable = autoSnapshot.status === "loading" || autoSnapshot.status === "error" || autoSnapshot.status === "ready" && autoSnapshot.row !== void 0;
7213
+ if (skillsForm === void 0 && !autoAvailable) {
7214
+ if (currentSkills !== void 0 || currentAutoReview) {
7215
+ stop?.();
7216
+ stop = void 0;
7217
+ currentSkills = void 0;
7218
+ currentAutoReview = false;
7219
+ }
7220
+ return;
7221
+ }
7222
+ if (currentSkills === skillsForm && currentAutoReview === autoAvailable) return;
7223
+ const slots = ctx.slots;
7224
+ if (slots === void 0) return;
6904
7225
  stop?.();
6905
7226
  stop = void 0;
6906
- current = chosen?.[1];
6907
- if (!chosen) return;
6908
- const [scope, form] = chosen;
6909
- const slots = scope.slots;
6910
- const disposers = [slots.inject("settings.plugin.item", () => slots.register({
6911
- name: "settings.plugin.item",
6912
- key: "multi-root-skills",
7227
+ currentSkills = skillsForm;
7228
+ currentAutoReview = autoAvailable;
7229
+ const disposers = [slots.inject("plugins.bundle.config", () => slots.register({
7230
+ name: "plugins.bundle.config",
7231
+ key: BUNDLE_KEY,
6913
7232
  inject: () => ({
6914
- form,
7233
+ form: skillsForm,
7234
+ autoReviewForm: autoForm,
6915
7235
  t
6916
7236
  })
6917
- }, SkillsSettingsCard)), slots.inject("plugins.bundle.config", () => slots.register({
6918
- name: "plugins.bundle.config",
6919
- key: BUNDLE_KEY,
7237
+ }, BundleSettingsCard))];
7238
+ if (skillsForm !== void 0) disposers.push(slots.inject("settings.plugin.item", () => slots.register({
7239
+ name: "settings.plugin.item",
7240
+ key: "multi-root-skills",
6920
7241
  inject: () => ({
6921
- form,
7242
+ form: skillsForm,
6922
7243
  t
6923
7244
  })
6924
- }, SkillsSettingsCard))];
7245
+ }, SkillsSettingsCard)));
6925
7246
  stop = () => {
6926
7247
  for (const dispose of disposers) dispose();
6927
7248
  };
6928
7249
  };
7250
+ const autoForm = installAutoReviewSettings(ctx);
7251
+ const stopAutoWatch = autoForm.subscribe(update);
7252
+ update();
6929
7253
  for (const service of ["settingsScope", "configForms"]) clientInject(ctx, [service], (scope) => {
6930
7254
  const form = bindSkillsForm(scope);
6931
7255
  if (form === void 0) return;
@@ -6938,6 +7262,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6938
7262
  });
6939
7263
  ctx.effect(() => () => {
6940
7264
  stop?.();
7265
+ stopAutoWatch();
6941
7266
  candidates.clear();
6942
7267
  });
6943
7268
  }
@@ -7004,7 +7329,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7004
7329
  const IconAccessReadOnly = maybeIcon(["PermissionIconReadOnlyRegular", "IconReadOnlyRegular"]);
7005
7330
  const IconAccessInherit = maybeIcon(["IconWorkspaceTreeOutline16", "IconWorkspaceTreeOutlineRegular"]);
7006
7331
  //#endregion
7007
- //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
7332
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.2.2-rc.1_@deepseek-ai+cordis@4.1.0/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
7008
7333
  /** The one Remote failure class shared by owners, the Gateway, and consumers. */
7009
7334
  /**
7010
7335
  * One Remote call failure: a real Error carrying its stable code and typed
@@ -7514,7 +7839,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7514
7839
  return n;
7515
7840
  }
7516
7841
  //#endregion
7517
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
7842
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.2-rc.1_@deepseek-ai+cordis@4.1.0/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
7518
7843
  /**
7519
7844
  * The `dsh-resource://file/…` address grammar: how a file is named across the
7520
7845
  * Sidebar and the resource model, built and parsed without touching a
@@ -7760,7 +8085,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7760
8085
  * has opened under it — the upstream body's scroll, seed, and render logic
7761
8086
  * verbatim, with the root arriving as a prop instead of `useSessions(cwd)`.
7762
8087
  */
7763
- function FilesTree({ tabId, sessionId, root, signal, useStore, actions, start, toggle, onOpen, t }) {
8088
+ function FilesTree({ tabId, sessionId, root, signal, useStore, actions, start, toggle, onOpen, t, nativeTree }) {
7764
8089
  const state = useStore((store) => store.byTab[tabId]);
7765
8090
  const bodyRef = (0, react.useRef)(null);
7766
8091
  const scrollTopRef = (0, react.useRef)(0);
@@ -7801,19 +8126,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7801
8126
  },
7802
8127
  t
7803
8128
  };
8129
+ const legacy = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
8130
+ className: css$1.level,
8131
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Level, {
8132
+ path: state.root,
8133
+ tree
8134
+ })
8135
+ });
8136
+ const content = nativeTree === void 0 ? legacy : nativeTree("sidebar.files.tree", nativeTreeInput(state, (failure) => failureLine(t, failure), tree.onToggle, tree.onOpen), { fallback: legacy });
7804
8137
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7805
8138
  ref: bodyRef,
7806
8139
  className: css$1.body,
7807
8140
  onScroll: (event) => {
7808
8141
  scrollTopRef.current = event.currentTarget.scrollTop;
7809
8142
  },
7810
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
7811
- className: css$1.level,
7812
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Level, {
7813
- path: state.root,
7814
- tree
7815
- })
7816
- })
8143
+ children: content
7817
8144
  });
7818
8145
  }
7819
8146
  //#endregion
@@ -7986,7 +8313,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7986
8313
  };
7987
8314
  }
7988
8315
  //#endregion
7989
- //#region node_modules/.pnpm/@deepseek-ai+dsh-host-open-in-app@0.2.2-alpha.2_@deepseek-ai+cordis@4.0.6-alpha.1_@deep_d76f08f4e35ff3a756a48d7d013379f6/node_modules/@deepseek-ai/dsh-host-open-in-app/lib/types/shared.js
8316
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-host-open-in-app@0.2.2-rc.1_@deepseek-ai+cordis@4.1.0_@deepseek-ai+dsh_33f3d65190f3ff17e4e9438df89ed28d/node_modules/@deepseek-ai/dsh-host-open-in-app/lib/types/shared.js
7990
8317
  var shared_exports = /* @__PURE__ */ __exportAll({
7991
8318
  OPEN_IN_APP_APPS_PATH: () => OPEN_IN_APP_APPS_PATH,
7992
8319
  OPEN_IN_APP_APPS_ROUTE: () => OPEN_IN_APP_APPS_ROUTE,
@@ -9668,7 +9995,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9668
9995
  sectionRef.current = wrapper?.closest("[data-dockkit-content]") ?? null;
9669
9996
  const content = sectionRef.current?.dataset.dockkitContent;
9670
9997
  setTabId(content !== void 0 && content !== "" ? content : fallbackTabId.current ??= `mrfw-${Math.random().toString(36).slice(2)}`);
9671
- setPane(wrapper?.closest("[data-files-root]") ?? null);
9998
+ setPane(wrapper?.closest("[data-files-page]") ?? wrapper?.closest("[data-files-root]") ?? null);
9672
9999
  }, []);
9673
10000
  const selected = (filesTree?.useTreeSelection ?? noTreeSelection)((selection) => tabId === void 0 ? void 0 : selection[tabId]) ?? "primary";
9674
10001
  const selectRoot = filesTree?.selectRoot;
@@ -9867,7 +10194,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9867
10194
  start: filesTree.face.start,
9868
10195
  toggle: filesTree.face.toggle,
9869
10196
  onOpen: filesTree.openFile,
9870
- t: filesTree.t
10197
+ t: filesTree.t,
10198
+ nativeTree: pane.hasAttribute("data-files-page") ? props.nativeTree : void 0
9871
10199
  }), pane) : null,
9872
10200
  dialogOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceFoldersDialog, {
9873
10201
  panel: props.panel,
@@ -9990,7 +10318,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9990
10318
  subscribeSession,
9991
10319
  t,
9992
10320
  openInApp: openInApp?.adapter,
9993
- filesTree
10321
+ filesTree,
10322
+ nativeTree: nativeTreeRenderer(props.renderFactorySlot)
9994
10323
  });
9995
10324
  }));
9996
10325
  }