@matamt-dbg/dsh-studio 0.2.7 → 0.2.9
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/client.js +272 -63
- package/index.js +147 -4
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -115,8 +115,7 @@ function parsePreviewRequest(value) {
|
|
|
115
115
|
var import_react = __toESM(require("react"), 1);
|
|
116
116
|
|
|
117
117
|
// src/ui-styles.ts
|
|
118
|
-
var
|
|
119
|
-
.studio-ui {
|
|
118
|
+
var adapter = `.studio-ui {
|
|
120
119
|
--studio-bg: var(--dsw-alias-bg-base);
|
|
121
120
|
--studio-surface: var(--dsw-alias-bg-layer-1);
|
|
122
121
|
--studio-inset: var(--dsw-alias-bg-layer-2);
|
|
@@ -148,7 +147,9 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
148
147
|
min-width: 0;
|
|
149
148
|
overflow-wrap: anywhere;
|
|
150
149
|
}
|
|
151
|
-
|
|
150
|
+
`;
|
|
151
|
+
var studioStyles = `/* Only this adapter references host tokens. Studio never installs a global theme. */
|
|
152
|
+
${adapter}.studio-ui *, .studio-ui *::before, .studio-ui *::after { box-sizing: border-box; }
|
|
152
153
|
.studio-ui .studio-tool-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 12px; }
|
|
153
154
|
.studio-ui .studio-tool-card { display: flex; flex-direction: column; gap: 8px; padding: 14px; border: 1px solid var(--studio-line); border-radius: var(--studio-radius); cursor: pointer; min-width: 0; }
|
|
154
155
|
.studio-ui .studio-tool-card[data-selected="true"] { background: var(--studio-hover); border-color: var(--studio-ink); }
|
|
@@ -159,11 +160,6 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
159
160
|
.studio-ui .studio-selection-detail { padding: 16px; margin-top: 12px; border: 1px solid var(--studio-line); border-radius: var(--studio-radius); }
|
|
160
161
|
.studio-ui .studio-schema-tool { margin-top: 12px; padding: 10px; border: 1px solid var(--studio-line); border-radius: var(--studio-small-radius); }
|
|
161
162
|
.studio-ui .studio-schema-tool summary { cursor: pointer; overflow-wrap: anywhere; }
|
|
162
|
-
.studio-ui .studio-schema-fields { margin: 8px 0; }
|
|
163
|
-
.studio-ui .studio-schema-fields > div { display: grid; grid-template-columns: minmax(70px, 120px) minmax(0, 1fr); gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--studio-line); }
|
|
164
|
-
.studio-ui .studio-schema-fields dt { color: var(--studio-muted); overflow-wrap: anywhere; }
|
|
165
|
-
.studio-ui .studio-schema-fields dd { margin: 0; min-width: 0; }
|
|
166
|
-
.studio-ui .studio-schema-list { padding-inline-start: 20px; }
|
|
167
163
|
.studio-ui .studio-schema-meta { color: var(--studio-muted); font-size: 12px; }
|
|
168
164
|
.studio-ui .studio-row button[aria-pressed="true"] { background: var(--studio-hover); border-color: var(--studio-ink); }
|
|
169
165
|
.studio-ui .studio-tool-description { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
@@ -217,6 +213,14 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
217
213
|
.studio-ui .studio-service-panel[hidden] { display: none; }
|
|
218
214
|
.studio-ui .studio-service-panel > .studio-ui { max-width: 960px; margin: 0 auto; padding: 24px clamp(16px, 3vw, 40px) 48px; }
|
|
219
215
|
.studio-ui .studio-layout { display: grid; grid-template-columns: 208px minmax(0, 1fr); height: 100%; }
|
|
216
|
+
/* Version footer pinned to the bottom of the Studio navigation. */
|
|
217
|
+
.studio-ui .studio-nav-footer { display: flex; align-items: center; gap: 6px; margin-top: auto; padding: 12px 10px 0; color: var(--studio-subtle); font-size: 12px; }
|
|
218
|
+
.studio-ui .studio-icon-button { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: var(--studio-small-radius); background: none; color: var(--studio-info); cursor: pointer; }
|
|
219
|
+
.studio-ui .studio-icon-button:hover:not(:disabled) { background: var(--studio-hover); }
|
|
220
|
+
.studio-ui .studio-icon-button[data-tone=success] { color: var(--studio-success); }
|
|
221
|
+
.studio-ui .studio-icon-button[data-tone=error] { color: var(--studio-error); }
|
|
222
|
+
.studio-ui .studio-icon-button:disabled { cursor: default; opacity: 1; }
|
|
223
|
+
.studio-ui .studio-icon-button[aria-busy=true] { opacity: .5; }
|
|
220
224
|
.studio-ui nav.studio-nav { display: flex; flex-direction: column; flex-wrap: nowrap; gap: 2px; margin: 0; padding: 24px 12px; border-inline-end: .5px solid var(--studio-line); overflow-y: auto; }
|
|
221
225
|
.studio-ui .studio-nav-head { display: grid; gap: 2px; padding: 0 10px 8px; }
|
|
222
226
|
.studio-ui .studio-nav-title { font-size: 14px; }
|
|
@@ -597,7 +601,17 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
597
601
|
.studio-ui .studio-preview .studio-schema-tool { margin-top: 6px; padding: 8px 10px; background: var(--studio-bg); }
|
|
598
602
|
.studio-ui .studio-preview .studio-schema-tool summary { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
599
603
|
.studio-ui .studio-preview .studio-schema-tool p { font-size: 12px; }
|
|
600
|
-
.studio-ui .studio-
|
|
604
|
+
.studio-ui .studio-schema-params { display: grid; gap: 8px; margin-top: 8px; font-size: 12px; }
|
|
605
|
+
.studio-ui .studio-schema-param { display: grid; gap: 4px; min-width: 0; }
|
|
606
|
+
.studio-ui .studio-schema-param .studio-schema-param { margin-top: 4px; padding-inline-start: 10px; border-inline-start: 1px solid var(--studio-line); }
|
|
607
|
+
.studio-ui .studio-schema-param-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; min-width: 0; }
|
|
608
|
+
.studio-ui .studio-schema-param-head code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 500; overflow-wrap: anywhere; }
|
|
609
|
+
.studio-ui .studio-schema-required { color: var(--studio-warn); font-size: 11px; }
|
|
610
|
+
.studio-ui .studio-schema-param p { margin: 0; color: var(--studio-muted); line-height: 1.5; }
|
|
611
|
+
.studio-ui .studio-schema-constraints { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
612
|
+
.studio-ui .studio-schema-constraints li { padding: 0 6px; border-radius: var(--studio-small-radius); background: var(--studio-neutral-fill); color: var(--studio-muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; overflow-wrap: anywhere; }
|
|
613
|
+
.studio-ui .studio-schema-constraints li > span { color: var(--studio-subtle); }
|
|
614
|
+
.studio-ui .studio-schema-constraint { color: var(--studio-muted); overflow-wrap: anywhere; }
|
|
601
615
|
@container studio-shell (max-width: 900px) { .studio-ui .studio-preview { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 2fr) minmax(0, 1fr); } }
|
|
602
616
|
|
|
603
617
|
/* Width rules follow the Studio surface and its content column, which the host sidebar and the Studio navigation narrow. */
|
|
@@ -607,6 +621,7 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
607
621
|
.studio-ui nav.studio-nav { flex-direction: row; overflow-x: auto; padding: 8px 12px; border-inline-end: 0; border-bottom: .5px solid var(--studio-line); }
|
|
608
622
|
.studio-ui .studio-nav-title, .studio-ui .studio-nav-group { display: none; }
|
|
609
623
|
.studio-ui .studio-nav-item { flex: 0 0 auto; }
|
|
624
|
+
.studio-ui .studio-nav-footer { margin: 0 0 0 auto; padding: 0 0 0 8px; }
|
|
610
625
|
.studio-ui .studio-scroller { overflow: visible; }
|
|
611
626
|
}
|
|
612
627
|
@container studio-main (max-width: 560px) {
|
|
@@ -625,6 +640,13 @@ var studioStyles = `/* Only this adapter references host tokens. Studio never in
|
|
|
625
640
|
.studio-ui dd { margin-bottom: 8px; }
|
|
626
641
|
}
|
|
627
642
|
`;
|
|
643
|
+
var sidebarMarkStyles = `${adapter}
|
|
644
|
+
.studio-ui.studio-sidebar-glyph { display: inline-flex; color: inherit; line-height: 0; }
|
|
645
|
+
.studio-ui .studio-sidebar-dot { fill: var(--studio-info); }
|
|
646
|
+
/* order keeps the mark last even if the sidebar later appends its own label. */
|
|
647
|
+
.studio-ui.studio-sidebar-update { display: inline-flex; flex: none; align-items: center; order: 99; margin-left: auto; color: var(--studio-info); line-height: 0; }
|
|
648
|
+
.studio-ui.studio-sidebar-update[data-phase=failed] { color: var(--studio-error); }
|
|
649
|
+
`;
|
|
628
650
|
|
|
629
651
|
// src/ui.tsx
|
|
630
652
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -702,6 +724,9 @@ function SplitButton({ label, onClick, primary = false, disabled = false, action
|
|
|
702
724
|
}, children: action.label }, action.label)) })
|
|
703
725
|
] });
|
|
704
726
|
}
|
|
727
|
+
function IconButton({ label, tone = "info", disabled = false, busy = false, onClick, children }) {
|
|
728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "studio-icon-button", "data-tone": tone, title: label, "aria-label": label, "aria-busy": busy || void 0, disabled, onClick, children });
|
|
729
|
+
}
|
|
705
730
|
function DetailDialog({ open, title, subtitle, onClose, closeLabel, footer, wide = false, compact = false, children }) {
|
|
706
731
|
const ref = import_react.default.useRef(null);
|
|
707
732
|
const opener = import_react.default.useRef(null);
|
|
@@ -800,7 +825,7 @@ ${item.searchText ?? ""}`.toLowerCase().includes(text)));
|
|
|
800
825
|
// src/role-editor.tsx
|
|
801
826
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
802
827
|
function RoleEditor({ locale, roles, onChange, loadModels, defaultPersona = "", tools, hiddenTools = [], onHiddenToolsChange, delegates = true }) {
|
|
803
|
-
const t = (
|
|
828
|
+
const t = (ko3, en3, zh3) => locale.startsWith("ko") ? ko3 : locale.startsWith("zh") ? zh3 : en3;
|
|
804
829
|
const [selected, setSelected] = import_react3.default.useState();
|
|
805
830
|
const [catalog, setCatalog] = import_react3.default.useState();
|
|
806
831
|
const [error, setError] = import_react3.default.useState("");
|
|
@@ -984,7 +1009,7 @@ var import_react9 = __toESM(require("react"), 1);
|
|
|
984
1009
|
var import_react4 = __toESM(require("react"), 1);
|
|
985
1010
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
986
1011
|
function MasterExtensionsEditor({ locale, actions }) {
|
|
987
|
-
const t = (
|
|
1012
|
+
const t = (ko3, en3, zh3) => locale.startsWith("ko") ? ko3 : locale.startsWith("zh") ? zh3 : en3;
|
|
988
1013
|
const [text, setText] = import_react4.default.useState("[]");
|
|
989
1014
|
const [error, setError] = import_react4.default.useState("");
|
|
990
1015
|
const [busy, setBusy] = import_react4.default.useState(false);
|
|
@@ -1039,6 +1064,7 @@ var PACKAGE_NAME = "@matamt-dbg/dsh-studio";
|
|
|
1039
1064
|
var POLICY_PLUGIN = `${PACKAGE_NAME}/policy`;
|
|
1040
1065
|
var ROLE_PLUGIN = `${PACKAGE_NAME}/roles`;
|
|
1041
1066
|
var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
|
|
1067
|
+
var STUDIO_VERSION = "0.2.9";
|
|
1042
1068
|
|
|
1043
1069
|
// src/delegation.ts
|
|
1044
1070
|
var ROLE_TOOL = "subagent_role";
|
|
@@ -1467,7 +1493,7 @@ var import_react6 = __toESM(require("react"), 1);
|
|
|
1467
1493
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1468
1494
|
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
1469
1495
|
function PresetList({ locale, api, revision, onEdit, onCopy }) {
|
|
1470
|
-
const t = (
|
|
1496
|
+
const t = (ko3, en3, zh3) => locale.startsWith("ko") ? ko3 : locale.startsWith("zh") ? zh3 : en3;
|
|
1471
1497
|
const [load, setLoad] = import_react6.default.useState({ phase: "loading" });
|
|
1472
1498
|
const [action, setAction] = import_react6.default.useState();
|
|
1473
1499
|
const [deleting, setDeleting] = import_react6.default.useState();
|
|
@@ -1629,7 +1655,7 @@ var import_react7 = __toESM(require("react"), 1);
|
|
|
1629
1655
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1630
1656
|
var defaultProvidedTools = [];
|
|
1631
1657
|
function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProvidedChange, catalog, catalogError, onPreview, onRequestChange, initialRequest }) {
|
|
1632
|
-
const t = (
|
|
1658
|
+
const t = (ko3, en3, zh3) => locale.startsWith("ko") ? ko3 : locale.startsWith("zh") ? zh3 : en3;
|
|
1633
1659
|
const base = initialRequest?.preset ?? "studio-master";
|
|
1634
1660
|
const [toolOverrides, setToolOverrides] = import_react7.default.useState(renameLegacyRoleKey(initialRequest?.toolOverrides) ?? {});
|
|
1635
1661
|
const [sections, setSections] = import_react7.default.useState(initialRequest?.sections ?? {});
|
|
@@ -1806,7 +1832,7 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
|
|
|
1806
1832
|
result.tools.length ? result.tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "studio-schema-tool", children: [
|
|
1807
1833
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: tool.name }),
|
|
1808
1834
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-tool-description", children: tool.description }),
|
|
1809
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: tool.parameters })
|
|
1835
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: tool.parameters, requiredLabel: t("\uD544\uC218", "required", "\u5FC5\u586B") })
|
|
1810
1836
|
] }, tool.name)) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-muted", children: labels.empty })
|
|
1811
1837
|
] })
|
|
1812
1838
|
] })
|
|
@@ -1815,16 +1841,47 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
|
|
|
1815
1841
|
)
|
|
1816
1842
|
] });
|
|
1817
1843
|
}
|
|
1818
|
-
function SchemaValue({ value }) {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1844
|
+
function SchemaValue({ value, requiredLabel }) {
|
|
1845
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "studio-schema-params", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaBody, { schema: value, requiredLabel }) });
|
|
1846
|
+
}
|
|
1847
|
+
var STRUCTURAL_KEYS = /* @__PURE__ */ new Set(["type", "description", "properties", "items", "required"]);
|
|
1848
|
+
function schemaType(schema) {
|
|
1849
|
+
if (Array.isArray(schema.type)) return schema.type.join(" | ");
|
|
1850
|
+
if (typeof schema.type === "string") return schema.type;
|
|
1851
|
+
return Array.isArray(schema.enum) ? "enum" : "";
|
|
1852
|
+
}
|
|
1853
|
+
function constraintText(value) {
|
|
1854
|
+
if (Array.isArray(value) && value.every((entry) => entry === null || typeof entry !== "object")) return value.map(String).join(", ");
|
|
1855
|
+
return value !== null && typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
1856
|
+
}
|
|
1857
|
+
function SchemaBody({ schema, requiredLabel }) {
|
|
1858
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-schema-constraint", children: constraintText(schema) });
|
|
1859
|
+
const row = schema;
|
|
1860
|
+
const required = Array.isArray(row.required) ? row.required : [];
|
|
1861
|
+
const properties = row.properties && typeof row.properties === "object" && !Array.isArray(row.properties) ? Object.entries(row.properties) : [];
|
|
1862
|
+
const constraints = Object.entries(row).filter(([key]) => !STRUCTURAL_KEYS.has(key) || key === "properties" && !properties.length || key === "required" && !properties.length);
|
|
1863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1864
|
+
constraints.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "studio-schema-constraints", children: constraints.map(([key, entry]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { children: [
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: key }),
|
|
1866
|
+
" ",
|
|
1867
|
+
constraintText(entry)
|
|
1868
|
+
] }, key)) }),
|
|
1869
|
+
properties.map(([name, child]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaParam, { name, schema: child, required: required.includes(name), requiredLabel }, name)),
|
|
1870
|
+
row.items !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaParam, { name: "items", schema: row.items, requiredLabel })
|
|
1871
|
+
] });
|
|
1872
|
+
}
|
|
1873
|
+
function SchemaParam({ name, schema, required, requiredLabel }) {
|
|
1874
|
+
const row = schema && typeof schema === "object" && !Array.isArray(schema) ? schema : void 0;
|
|
1875
|
+
const type = row ? schemaType(row) : "";
|
|
1876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-schema-param", children: [
|
|
1877
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-schema-param-head", children: [
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: name }),
|
|
1879
|
+
type && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-schema-meta", children: type }),
|
|
1880
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-schema-required", children: requiredLabel })
|
|
1881
|
+
] }),
|
|
1882
|
+
typeof row?.description === "string" && row.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-tool-description", children: row.description }),
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaBody, { schema: row ? Object.fromEntries(Object.entries(row).filter(([key]) => key !== "type" && key !== "description")) : schema, requiredLabel })
|
|
1884
|
+
] });
|
|
1828
1885
|
}
|
|
1829
1886
|
function parameterFields(schema, prefix = "") {
|
|
1830
1887
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return [];
|
|
@@ -1841,7 +1898,7 @@ function parameterFields(schema, prefix = "") {
|
|
|
1841
1898
|
// src/detail-layout.tsx
|
|
1842
1899
|
var import_react8 = __toESM(require("react"), 1);
|
|
1843
1900
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1844
|
-
function DetailLayout({ title, subtitle, navigation, pages, selected, onSelect }) {
|
|
1901
|
+
function DetailLayout({ title, subtitle, navigation, pages, selected, onSelect, footer }) {
|
|
1845
1902
|
const id = import_react8.default.useId();
|
|
1846
1903
|
const scroller = import_react8.default.useRef(null);
|
|
1847
1904
|
import_react8.default.useLayoutEffect(() => {
|
|
@@ -1866,7 +1923,8 @@ function DetailLayout({ title, subtitle, navigation, pages, selected, onSelect }
|
|
|
1866
1923
|
children: page.label
|
|
1867
1924
|
}
|
|
1868
1925
|
)
|
|
1869
|
-
] }, page.id))
|
|
1926
|
+
] }, page.id)),
|
|
1927
|
+
footer
|
|
1870
1928
|
] }),
|
|
1871
1929
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "studio-scroller", ref: scroller, "data-studio-scroller": "", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "studio-content", children: pages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1872
1930
|
"section",
|
|
@@ -1892,8 +1950,8 @@ var seeds = [
|
|
|
1892
1950
|
{ name: "Researcher", role: "research", model: "inherit", reasoning: "inherit", spawn: "fresh", persona: "Investigate primary sources and cite the evidence." },
|
|
1893
1951
|
{ name: "Reviewer", role: "review", model: "inherit", reasoning: "inherit", spawn: "fork", persona: "Review correctness and identify concrete risks." }
|
|
1894
1952
|
];
|
|
1895
|
-
function OptimizationPrototype({ locale, catalog, catalogError, onPreview, presetActions, extensionActions }) {
|
|
1896
|
-
const t = (
|
|
1953
|
+
function OptimizationPrototype({ locale, catalog, catalogError, onPreview, presetActions, extensionActions, navFooter }) {
|
|
1954
|
+
const t = (ko3, en3, zh3) => locale.startsWith("ko") ? ko3 : locale.startsWith("zh") ? zh3 : en3;
|
|
1897
1955
|
const [page, setPage] = import_react9.default.useState("list");
|
|
1898
1956
|
const [common, setCommon] = import_react9.default.useState({ ...initial });
|
|
1899
1957
|
const [agents, setAgents] = import_react9.default.useState(() => seeds.map((a) => ({ ...a })));
|
|
@@ -1936,9 +1994,9 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
|
|
|
1936
1994
|
setSaving(false);
|
|
1937
1995
|
}
|
|
1938
1996
|
};
|
|
1939
|
-
const editPreset = (item,
|
|
1940
|
-
setEditing(
|
|
1941
|
-
setName(
|
|
1997
|
+
const editPreset = (item, copy3 = false) => {
|
|
1998
|
+
setEditing(copy3 ? { ...item, id: "" } : item);
|
|
1999
|
+
setName(copy3 ? `${item.name} Copy` : item.name);
|
|
1942
2000
|
setDescription(item.description);
|
|
1943
2001
|
setCommon({ ...initial, prompt: item.request.prompt, spill: item.conveniences?.spill ?? initial.spill });
|
|
1944
2002
|
setProvided([...item.request.tools]);
|
|
@@ -1965,7 +2023,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
|
|
|
1965
2023
|
{ id: "agents", label: t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagent settings", "\u5B50\u4EE3\u7406\u8BBE\u7F6E"), content: agentPage }
|
|
1966
2024
|
];
|
|
1967
2025
|
const tabId = import_react9.default.useId();
|
|
1968
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DetailLayout, { title: "DSH Studio", subtitle: t("\uC5D0\uC774\uC804\uD2B8 \uD504\uB9AC\uC14B \uD3B8\uC9D1\uAE30", "Agent preset editor", "\u4EE3\u7406\u9884\u8BBE\u7F16\u8F91\u5668"), navigation: t("Studio \uBA54\uB274", "Studio menu", "\u9884\u8BBE\u5BFC\u822A"), selected: page, onSelect: (next) => {
|
|
2026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DetailLayout, { footer: navFooter, title: "DSH Studio", subtitle: t("\uC5D0\uC774\uC804\uD2B8 \uD504\uB9AC\uC14B \uD3B8\uC9D1\uAE30", "Agent preset editor", "\u4EE3\u7406\u9884\u8BBE\u7F16\u8F91\u5668"), navigation: t("Studio \uBA54\uB274", "Studio menu", "\u9884\u8BBE\u5BFC\u822A"), selected: page, onSelect: (next) => {
|
|
1969
2027
|
if (next === "create" && editing) {
|
|
1970
2028
|
setEditing(void 0);
|
|
1971
2029
|
setName("");
|
|
@@ -2006,7 +2064,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
|
|
|
2006
2064
|
}
|
|
2007
2065
|
|
|
2008
2066
|
// src/shell.tsx
|
|
2009
|
-
var
|
|
2067
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
2010
2068
|
var import_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
|
|
2011
2069
|
|
|
2012
2070
|
// src/service-layout.tsx
|
|
@@ -2050,8 +2108,145 @@ function ServiceLayout({ locale, services, renderSlot }) {
|
|
|
2050
2108
|
] });
|
|
2051
2109
|
}
|
|
2052
2110
|
|
|
2053
|
-
// src/
|
|
2111
|
+
// src/update-store.ts
|
|
2112
|
+
function createUpdateStore(actions, current) {
|
|
2113
|
+
let state = { phase: "idle", current };
|
|
2114
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2115
|
+
const set = (next) => {
|
|
2116
|
+
state = next;
|
|
2117
|
+
listeners.forEach((listener) => listener());
|
|
2118
|
+
};
|
|
2119
|
+
return {
|
|
2120
|
+
getSnapshot: () => state,
|
|
2121
|
+
subscribe(listener) {
|
|
2122
|
+
listeners.add(listener);
|
|
2123
|
+
return () => {
|
|
2124
|
+
listeners.delete(listener);
|
|
2125
|
+
};
|
|
2126
|
+
},
|
|
2127
|
+
async refresh(force = false) {
|
|
2128
|
+
if (state.phase === "updating" || state.phase === "installed") return;
|
|
2129
|
+
try {
|
|
2130
|
+
const status = await actions.status(force);
|
|
2131
|
+
const phase = () => state.phase;
|
|
2132
|
+
if (phase() === "updating" || phase() === "installed") return;
|
|
2133
|
+
if (status.installed) {
|
|
2134
|
+
set({ phase: "installed", current: status.current, version: status.installed });
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
const version = status.available && !status.blocked ? status.available : void 0;
|
|
2138
|
+
set({ phase: "idle", current: status.current, ...version ? { version } : {} });
|
|
2139
|
+
} catch {
|
|
2140
|
+
}
|
|
2141
|
+
},
|
|
2142
|
+
async update() {
|
|
2143
|
+
if (state.phase !== "idle" && state.phase !== "failed") return;
|
|
2144
|
+
const version = state.version;
|
|
2145
|
+
if (!version) return;
|
|
2146
|
+
set({ phase: "updating", current: state.current, version });
|
|
2147
|
+
try {
|
|
2148
|
+
const result = await actions.update(version);
|
|
2149
|
+
if (result.status === "restart-required" || result.status === "applied") set({ phase: "installed", current: state.current, version: result.version });
|
|
2150
|
+
else set({ phase: "failed", current: state.current, version, message: result.message ?? result.status });
|
|
2151
|
+
} catch (error) {
|
|
2152
|
+
set({ phase: "failed", current: state.current, version, message: error instanceof Error ? error.message : String(error) });
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/update-indicator.tsx
|
|
2159
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
2160
|
+
var import_react_dom = require("react-dom");
|
|
2054
2161
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2162
|
+
var ko2 = {
|
|
2163
|
+
available: (v) => `v${v}\uB85C \uC5C5\uB370\uC774\uD2B8`,
|
|
2164
|
+
updating: (v) => `v${v} \uC124\uCE58 \uC911`,
|
|
2165
|
+
installed: (v) => `v${v}\uB97C \uC124\uCE58\uD588\uC2B5\uB2C8\uB2E4. DSH\uB97C \uB2E4\uC2DC \uC2DC\uC791\uD558\uBA74 \uC801\uC6A9\uB429\uB2C8\uB2E4.`,
|
|
2166
|
+
failed: (v, message2) => `v${v}\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uB824\uBA74 \uB204\uB974\uC138\uC694. (${message2})`
|
|
2167
|
+
};
|
|
2168
|
+
var en2 = {
|
|
2169
|
+
available: (v) => `Update to v${v}`,
|
|
2170
|
+
updating: (v) => `Installing v${v}`,
|
|
2171
|
+
installed: (v) => `Installed v${v}. Restart DSH to use it.`,
|
|
2172
|
+
failed: (v, message2) => `Could not update to v${v}. Select to try again. (${message2})`
|
|
2173
|
+
};
|
|
2174
|
+
var zh2 = {
|
|
2175
|
+
available: (v) => `\u66F4\u65B0\u5230 v${v}`,
|
|
2176
|
+
updating: (v) => `\u6B63\u5728\u5B89\u88C5 v${v}`,
|
|
2177
|
+
installed: (v) => `\u5DF2\u5B89\u88C5 v${v}\u3002\u91CD\u542F DSH \u540E\u751F\u6548`,
|
|
2178
|
+
failed: (v, message2) => `\u65E0\u6CD5\u66F4\u65B0\u5230 v${v}\u3002\u70B9\u51FB\u91CD\u8BD5\uFF08${message2}\uFF09`
|
|
2179
|
+
};
|
|
2180
|
+
var copy2 = (locale) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
2181
|
+
function useUpdateState(store) {
|
|
2182
|
+
return import_react11.default.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
2183
|
+
}
|
|
2184
|
+
function updateLabel(state, locale) {
|
|
2185
|
+
const t = copy2(locale);
|
|
2186
|
+
if (state.phase === "updating") return t.updating(state.version);
|
|
2187
|
+
if (state.phase === "installed") return t.installed(state.version);
|
|
2188
|
+
if (state.phase === "failed") return t.failed(state.version, state.message);
|
|
2189
|
+
return state.version ? t.available(state.version) : void 0;
|
|
2190
|
+
}
|
|
2191
|
+
function UpdateGlyph({ phase, size = 14 }) {
|
|
2192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { cx: "8", cy: "8", r: "6.5" }),
|
|
2194
|
+
phase === "installed" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M5.2 8.2l1.9 1.9 3.7-4" }) : phase === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M8 4.8v3.8M8 11.2v.01" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M8 11V5.2M5.4 7.6L8 5l2.6 2.6" })
|
|
2195
|
+
] });
|
|
2196
|
+
}
|
|
2197
|
+
function VersionFooter({ store, locale }) {
|
|
2198
|
+
const state = useUpdateState(store);
|
|
2199
|
+
const label = updateLabel(state, locale);
|
|
2200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "studio-nav-footer", children: [
|
|
2201
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "studio-mono", children: [
|
|
2202
|
+
"v",
|
|
2203
|
+
state.current
|
|
2204
|
+
] }),
|
|
2205
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2206
|
+
IconButton,
|
|
2207
|
+
{
|
|
2208
|
+
label,
|
|
2209
|
+
tone: state.phase === "failed" ? "error" : state.phase === "installed" ? "success" : "info",
|
|
2210
|
+
disabled: state.phase === "updating" || state.phase === "installed",
|
|
2211
|
+
busy: state.phase === "updating",
|
|
2212
|
+
onClick: () => {
|
|
2213
|
+
void store.update();
|
|
2214
|
+
},
|
|
2215
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UpdateGlyph, { phase: state.phase })
|
|
2216
|
+
}
|
|
2217
|
+
)
|
|
2218
|
+
] });
|
|
2219
|
+
}
|
|
2220
|
+
function SidebarIcon({ size = 20, store, locale }) {
|
|
2221
|
+
const state = useUpdateState(store);
|
|
2222
|
+
const label = updateLabel(state, locale);
|
|
2223
|
+
const glyph = import_react11.default.useRef(null);
|
|
2224
|
+
const [row, setRow] = import_react11.default.useState(null);
|
|
2225
|
+
import_react11.default.useLayoutEffect(() => {
|
|
2226
|
+
setRow(glyph.current?.closest("button") ?? null);
|
|
2227
|
+
}, [size]);
|
|
2228
|
+
const wide = size <= 16;
|
|
2229
|
+
const marked = label !== void 0 && state.phase !== "installed";
|
|
2230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "studio-ui studio-sidebar-glyph", children: [
|
|
2232
|
+
marked && !wide && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: sidebarMarkStyles }),
|
|
2233
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { ref: glyph, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", "aria-hidden": "true", children: [
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "14", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "14", width: "7", height: "7", rx: "2" }),
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17.5 14v7M14 17.5h7" }),
|
|
2238
|
+
marked && !wide && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { className: "studio-sidebar-dot", cx: "21", cy: "3", r: "3", stroke: "none" })
|
|
2239
|
+
] })
|
|
2240
|
+
] }),
|
|
2241
|
+
marked && wide && row && (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "studio-ui studio-sidebar-update", "data-phase": state.phase, title: label, role: "img", "aria-label": label, children: [
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: sidebarMarkStyles }),
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UpdateGlyph, { phase: state.phase, size: 14 })
|
|
2244
|
+
] }), row)
|
|
2245
|
+
] });
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
// src/shell.tsx
|
|
2249
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2055
2250
|
var inject = ["slots", "locale", "remote"];
|
|
2056
2251
|
var panel = "local-dsh-studio";
|
|
2057
2252
|
async function apply(ctx) {
|
|
@@ -2072,7 +2267,18 @@ async function apply(ctx) {
|
|
|
2072
2267
|
invocation: { kind: "direct" },
|
|
2073
2268
|
parameters: [{ name: "request", wire: "request", source: "json", codec: { mode: "strict", typeSymbol: "PreviewRequest", create: () => ({ parse: parsePreviewRequest }) } }],
|
|
2074
2269
|
result: { mode: "src-json" }
|
|
2075
|
-
}, ...["
|
|
2270
|
+
}, ...["updateStatus", "updateStudio"].map((method) => ({
|
|
2271
|
+
id: `${PACKAGE_NAME}#studioCatalog/${method}`,
|
|
2272
|
+
service: "studioCatalog",
|
|
2273
|
+
namespace: "studioCatalog",
|
|
2274
|
+
method,
|
|
2275
|
+
invocation: { kind: "direct" },
|
|
2276
|
+
parameters: [{ name: method === "updateStatus" ? "force" : "version", wire: method === "updateStatus" ? "force" : "version", source: "json", codec: { mode: "strict", typeSymbol: "string", create: () => ({ parse: (value) => {
|
|
2277
|
+
if (typeof value !== "string") throw new TypeError("Expected a string");
|
|
2278
|
+
return value;
|
|
2279
|
+
} }) } }],
|
|
2280
|
+
result: { mode: "src-json" }
|
|
2281
|
+
})), ...["listPresets", "savePreset", "applyPreset", "unapplyPreset", "roleModels", "deletePreset", "readExtensions", "saveExtensions"].map((method) => ({
|
|
2076
2282
|
id: `${PACKAGE_NAME}#studioCatalog/${method}`,
|
|
2077
2283
|
service: "studioCatalog",
|
|
2078
2284
|
namespace: "studioCatalog",
|
|
@@ -2096,35 +2302,35 @@ async function apply(ctx) {
|
|
|
2096
2302
|
};
|
|
2097
2303
|
ctx.effect(() => ctx.slots.subscribe("local.dsh-studio.services", syncServices));
|
|
2098
2304
|
ctx.effect(() => ctx.locale.subscribe(syncServices));
|
|
2305
|
+
const updateActions = /* @__PURE__ */ (() => {
|
|
2306
|
+
const call = async (method, arg) => {
|
|
2307
|
+
const service = ctx.get("remote.studioCatalog");
|
|
2308
|
+
const fn = service?.[method];
|
|
2309
|
+
if (!fn) throw new Error("Studio update API unavailable");
|
|
2310
|
+
const result = await fn(arg);
|
|
2311
|
+
if (!result.ok) throw new Error(result.error?.message ?? "Update request failed");
|
|
2312
|
+
return result.value;
|
|
2313
|
+
};
|
|
2314
|
+
return {
|
|
2315
|
+
status: (force) => call("updateStatus", force ? "force" : ""),
|
|
2316
|
+
update: (version) => call("updateStudio", version)
|
|
2317
|
+
};
|
|
2318
|
+
})();
|
|
2319
|
+
const updates = createUpdateStore(updateActions, STUDIO_VERSION);
|
|
2320
|
+
void updates.refresh();
|
|
2099
2321
|
function StudioServices({ renderSlot }) {
|
|
2100
|
-
const items =
|
|
2322
|
+
const items = import_react12.default.useSyncExternalStore((listener) => {
|
|
2101
2323
|
serviceListeners.add(listener);
|
|
2102
2324
|
return () => {
|
|
2103
2325
|
serviceListeners.delete(listener);
|
|
2104
2326
|
};
|
|
2105
2327
|
}, () => services);
|
|
2106
|
-
const locale =
|
|
2107
|
-
return /* @__PURE__ */ (0,
|
|
2328
|
+
const locale = import_react12.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
|
|
2329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StudioSurface, { className: "studio-shell", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { className: "studio-page", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ServiceLayout, { locale, services: items, renderSlot }) }) });
|
|
2108
2330
|
}
|
|
2109
2331
|
function Icon({ size = 20 }) {
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
{
|
|
2113
|
-
width: size,
|
|
2114
|
-
height: size,
|
|
2115
|
-
viewBox: "0 0 24 24",
|
|
2116
|
-
fill: "none",
|
|
2117
|
-
stroke: "currentColor",
|
|
2118
|
-
strokeWidth: "1.7",
|
|
2119
|
-
"aria-hidden": "true",
|
|
2120
|
-
children: [
|
|
2121
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2122
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "14", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2123
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "14", width: "7", height: "7", rx: "2" }),
|
|
2124
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17.5 14v7M14 17.5h7" })
|
|
2125
|
-
]
|
|
2126
|
-
}
|
|
2127
|
-
);
|
|
2332
|
+
const locale = import_react12.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
|
|
2333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SidebarIcon, { size, store: updates, locale });
|
|
2128
2334
|
}
|
|
2129
2335
|
ctx.slots.inject(
|
|
2130
2336
|
"main",
|
|
@@ -2140,10 +2346,10 @@ async function apply(ctx) {
|
|
|
2140
2346
|
)
|
|
2141
2347
|
);
|
|
2142
2348
|
function OptimizationPage() {
|
|
2143
|
-
const locale =
|
|
2144
|
-
const [catalog, setCatalog] =
|
|
2145
|
-
const [catalogError, setCatalogError] =
|
|
2146
|
-
|
|
2349
|
+
const locale = import_react12.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
|
|
2350
|
+
const [catalog, setCatalog] = import_react12.default.useState();
|
|
2351
|
+
const [catalogError, setCatalogError] = import_react12.default.useState("");
|
|
2352
|
+
import_react12.default.useEffect(() => {
|
|
2147
2353
|
let active = true;
|
|
2148
2354
|
const remote2 = ctx.get("remote.studioCatalog");
|
|
2149
2355
|
if (!remote2) {
|
|
@@ -2161,7 +2367,7 @@ async function apply(ctx) {
|
|
|
2161
2367
|
active = false;
|
|
2162
2368
|
};
|
|
2163
2369
|
}, []);
|
|
2164
|
-
const presetActions =
|
|
2370
|
+
const presetActions = import_react12.default.useMemo(() => {
|
|
2165
2371
|
const call = async (method, ...args) => {
|
|
2166
2372
|
const service = ctx.get("remote.studioCatalog");
|
|
2167
2373
|
const result = await service[method](...args);
|
|
@@ -2177,7 +2383,7 @@ async function apply(ctx) {
|
|
|
2177
2383
|
delete: (id) => call("deletePreset", id)
|
|
2178
2384
|
};
|
|
2179
2385
|
}, []);
|
|
2180
|
-
const extensionActions =
|
|
2386
|
+
const extensionActions = import_react12.default.useMemo(() => {
|
|
2181
2387
|
const call = async (method, ...args) => {
|
|
2182
2388
|
const service = ctx.get("remote.studioCatalog");
|
|
2183
2389
|
const result = await service[method](...args);
|
|
@@ -2188,7 +2394,10 @@ async function apply(ctx) {
|
|
|
2188
2394
|
setCatalog(await call("saveExtensions", payload));
|
|
2189
2395
|
} };
|
|
2190
2396
|
}, []);
|
|
2191
|
-
|
|
2397
|
+
import_react12.default.useEffect(() => {
|
|
2398
|
+
void updates.refresh();
|
|
2399
|
+
}, []);
|
|
2400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OptimizationPrototype, { navFooter: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(VersionFooter, { store: updates, locale }), extensionActions, presetActions, locale, catalog, catalogError, onPreview: async (request) => {
|
|
2192
2401
|
const service = ctx.get("remote.studioCatalog");
|
|
2193
2402
|
const response = await service.preview(request);
|
|
2194
2403
|
if (!response.ok) throw new Error(response.error?.message ?? "Preview failed");
|
package/index.js
CHANGED
|
@@ -56,6 +56,7 @@ var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
|
|
|
56
56
|
function currentPluginName(name) {
|
|
57
57
|
return name === LEGACY_PACKAGE_NAME || name.startsWith(`${LEGACY_PACKAGE_NAME}/`) ? PACKAGE_NAME + name.slice(LEGACY_PACKAGE_NAME.length) : name;
|
|
58
58
|
}
|
|
59
|
+
var STUDIO_VERSION = "0.2.9";
|
|
59
60
|
|
|
60
61
|
// src/delegation.ts
|
|
61
62
|
var ROLE_TOOL = "subagent_role";
|
|
@@ -383,7 +384,7 @@ var MasterExtensions = class {
|
|
|
383
384
|
};
|
|
384
385
|
|
|
385
386
|
// src/host/shell.ts
|
|
386
|
-
import { dirname as dirname3, join as
|
|
387
|
+
import { dirname as dirname3, join as join3 } from "node:path";
|
|
387
388
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
388
389
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
389
390
|
|
|
@@ -1170,9 +1171,142 @@ var PresetStore = class {
|
|
|
1170
1171
|
}
|
|
1171
1172
|
};
|
|
1172
1173
|
|
|
1174
|
+
// src/host/studio-update.ts
|
|
1175
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1176
|
+
import { join as join2 } from "node:path";
|
|
1177
|
+
import { evaluatePluginCompatibility, getDshRuntimeVersion } from "@deepseek-ai/dsh-app-boot";
|
|
1178
|
+
|
|
1179
|
+
// src/update-check.ts
|
|
1180
|
+
var STABLE = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
1181
|
+
function compareStable(a, b) {
|
|
1182
|
+
const x = STABLE.exec(a);
|
|
1183
|
+
const y = STABLE.exec(b);
|
|
1184
|
+
if (!x || !y) return Number(Boolean(x)) - Number(Boolean(y));
|
|
1185
|
+
for (let i = 1; i <= 3; i++) {
|
|
1186
|
+
const diff = Number(x[i]) - Number(y[i]);
|
|
1187
|
+
if (diff) return Math.sign(diff);
|
|
1188
|
+
}
|
|
1189
|
+
return 0;
|
|
1190
|
+
}
|
|
1191
|
+
function isNewer(candidate, current) {
|
|
1192
|
+
return STABLE.test(candidate) && compareStable(candidate, current.split("-")[0]) > 0;
|
|
1193
|
+
}
|
|
1194
|
+
function pickUpdate(document, current, compatible) {
|
|
1195
|
+
const latest = document["dist-tags"]?.latest;
|
|
1196
|
+
const candidates = Object.entries(document.versions ?? {}).filter(([version, manifest]) => isNewer(version, current) && !manifest.deprecated).sort(([a], [b]) => compareStable(b, a));
|
|
1197
|
+
const available = candidates.find(([, manifest]) => compatible(manifest))?.[0];
|
|
1198
|
+
const incompatibleLatest = latest !== void 0 && isNewer(latest, current) && latest !== available && candidates.some(([version]) => version === latest) ? latest : void 0;
|
|
1199
|
+
return { ...latest ? { latest } : {}, ...available ? { available } : {}, ...incompatibleLatest ? { incompatibleLatest } : {} };
|
|
1200
|
+
}
|
|
1201
|
+
function packumentUrl(registry, name) {
|
|
1202
|
+
return `${registry.replace(/\/+$/, "")}/${name.replace("/", "%2f")}`;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// src/host/studio-update.ts
|
|
1206
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
1207
|
+
var CACHE_MS = 10 * 6e4;
|
|
1208
|
+
var StudioUpdater = class {
|
|
1209
|
+
constructor(ctx, fetcher = globalThis.fetch) {
|
|
1210
|
+
this.ctx = ctx;
|
|
1211
|
+
this.fetcher = fetcher;
|
|
1212
|
+
}
|
|
1213
|
+
cached;
|
|
1214
|
+
installing;
|
|
1215
|
+
manager() {
|
|
1216
|
+
return this.ctx.get("pluginManager");
|
|
1217
|
+
}
|
|
1218
|
+
/** Read the current status, reusing a recent registry answer unless `force`. */
|
|
1219
|
+
status(force = false) {
|
|
1220
|
+
if (!force && this.cached && Date.now() - this.cached.at < CACHE_MS) return this.cached.status;
|
|
1221
|
+
const status = this.check();
|
|
1222
|
+
this.cached = { at: Date.now(), status };
|
|
1223
|
+
void status.catch(() => {
|
|
1224
|
+
if (this.cached?.status === status) this.cached = void 0;
|
|
1225
|
+
});
|
|
1226
|
+
return status;
|
|
1227
|
+
}
|
|
1228
|
+
async check() {
|
|
1229
|
+
const result = { current: STUDIO_VERSION };
|
|
1230
|
+
let runtimeVersion;
|
|
1231
|
+
try {
|
|
1232
|
+
runtimeVersion = getDshRuntimeVersion();
|
|
1233
|
+
result.runtimeVersion = runtimeVersion;
|
|
1234
|
+
} catch {
|
|
1235
|
+
}
|
|
1236
|
+
const { source, installed } = await this.profilePackage();
|
|
1237
|
+
if (source) result.source = source;
|
|
1238
|
+
if (installed && installed !== STUDIO_VERSION) result.installed = installed;
|
|
1239
|
+
const baseline = installed && isNewer(installed, STUDIO_VERSION) ? installed : STUDIO_VERSION;
|
|
1240
|
+
const manager = this.manager();
|
|
1241
|
+
if (!manager) result.blocked = "no-plugin-manager";
|
|
1242
|
+
else if (!source) result.blocked = "not-profile-dependency";
|
|
1243
|
+
try {
|
|
1244
|
+
const registries = manager ? await manager.registries().catch(() => void 0) : void 0;
|
|
1245
|
+
const registry = registries?.registry ?? registries?.resolved ?? DEFAULT_REGISTRY;
|
|
1246
|
+
const response = await this.fetcher(packumentUrl(registry, PACKAGE_NAME), {
|
|
1247
|
+
headers: { accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8" },
|
|
1248
|
+
signal: AbortSignal.timeout(15e3)
|
|
1249
|
+
});
|
|
1250
|
+
if (!response.ok) throw new Error(`Registry answered ${response.status}`);
|
|
1251
|
+
const document = await response.json();
|
|
1252
|
+
Object.assign(result, pickUpdate(document, baseline, (manifest) => {
|
|
1253
|
+
try {
|
|
1254
|
+
return evaluatePluginCompatibility({ name: PACKAGE_NAME, version: "0.0.0", ...manifest }, {}, runtimeVersion) === void 0;
|
|
1255
|
+
} catch {
|
|
1256
|
+
return false;
|
|
1257
|
+
}
|
|
1258
|
+
}));
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
1261
|
+
}
|
|
1262
|
+
return result;
|
|
1263
|
+
}
|
|
1264
|
+
/** How the profile declares Studio and which version its files hold now. */
|
|
1265
|
+
async profilePackage() {
|
|
1266
|
+
const dir = this.ctx.get("profileContext")?.dir ?? process.env.DSH_PROFILE_DIR;
|
|
1267
|
+
if (!dir) return {};
|
|
1268
|
+
const json2 = async (path) => {
|
|
1269
|
+
try {
|
|
1270
|
+
return JSON.parse(await readFile3(path, "utf8"));
|
|
1271
|
+
} catch {
|
|
1272
|
+
return void 0;
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
const manifest = await json2(join2(dir, "package.json"));
|
|
1276
|
+
const source = manifest?.dependencies?.[PACKAGE_NAME];
|
|
1277
|
+
const installed = (await json2(join2(dir, "node_modules", ...PACKAGE_NAME.split("/"), "package.json")))?.version;
|
|
1278
|
+
return { ...source ? { source } : {}, ...typeof installed === "string" ? { installed } : {} };
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Install one exact version offered by {@link status}. The running Studio keeps its code until DSH restarts.
|
|
1282
|
+
* @param version Exact version; must equal the current offer so arbitrary specs never reach pnpm.
|
|
1283
|
+
*/
|
|
1284
|
+
update(version) {
|
|
1285
|
+
if (this.installing) return this.installing;
|
|
1286
|
+
const run = (async () => {
|
|
1287
|
+
const status = await this.status();
|
|
1288
|
+
if (status.available !== version) throw new Error(`Version ${version} is not the offered update`);
|
|
1289
|
+
if (status.blocked) throw new Error(`Studio cannot update this install (${status.blocked})`);
|
|
1290
|
+
const manager = this.manager();
|
|
1291
|
+
const result = await manager.installBundle(`${PACKAGE_NAME}@${version}`, { enabled: true });
|
|
1292
|
+
const installed = result.version ?? version;
|
|
1293
|
+
if (result.application === "failed" || result.application === "cancelled") {
|
|
1294
|
+
const detail = result.error?.diagnostic ?? result.error?.code ?? result.packageResult?.output?.trim().split("\n").slice(-3).join("\n");
|
|
1295
|
+
return { status: result.application, version: installed, ...detail ? { message: detail } : {} };
|
|
1296
|
+
}
|
|
1297
|
+
this.cached = void 0;
|
|
1298
|
+
return { status: result.application === "applied" ? "applied" : "restart-required", version: installed };
|
|
1299
|
+
})();
|
|
1300
|
+
this.installing = run;
|
|
1301
|
+
return run.finally(() => {
|
|
1302
|
+
this.installing = void 0;
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1173
1307
|
// src/host/shell.ts
|
|
1174
|
-
var _preview_dec, _saveExtensions_dec, _readExtensions_dec, _read_dec, _deletePreset_dec, _roleModels_dec, _unapplyPreset_dec, _applyPreset_dec, _savePreset_dec, _listPresets_dec, _a, _init;
|
|
1175
|
-
var StudioCatalog = class extends (_a = TypertRemoteService, _listPresets_dec = [Remote], _savePreset_dec = [Remote], _applyPreset_dec = [Remote], _unapplyPreset_dec = [Remote], _roleModels_dec = [Remote], _deletePreset_dec = [Remote], _read_dec = [Remote], _readExtensions_dec = [Remote], _saveExtensions_dec = [Remote], _preview_dec = [Remote], _a) {
|
|
1308
|
+
var _preview_dec, _saveExtensions_dec, _readExtensions_dec, _read_dec, _deletePreset_dec, _updateStudio_dec, _updateStatus_dec, _roleModels_dec, _unapplyPreset_dec, _applyPreset_dec, _savePreset_dec, _listPresets_dec, _a, _init;
|
|
1309
|
+
var StudioCatalog = class extends (_a = TypertRemoteService, _listPresets_dec = [Remote], _savePreset_dec = [Remote], _applyPreset_dec = [Remote], _unapplyPreset_dec = [Remote], _roleModels_dec = [Remote], _updateStatus_dec = [Remote], _updateStudio_dec = [Remote], _deletePreset_dec = [Remote], _read_dec = [Remote], _readExtensions_dec = [Remote], _saveExtensions_dec = [Remote], _preview_dec = [Remote], _a) {
|
|
1176
1310
|
constructor(ctx) {
|
|
1177
1311
|
super(ctx, "studioCatalog");
|
|
1178
1312
|
__runInitializers(_init, 5, this);
|
|
@@ -1182,8 +1316,9 @@ var StudioCatalog = class extends (_a = TypertRemoteService, _listPresets_dec =
|
|
|
1182
1316
|
__publicField(this, "stopped", false);
|
|
1183
1317
|
__publicField(this, "extensions");
|
|
1184
1318
|
__publicField(this, "changes", Promise.resolve());
|
|
1319
|
+
__publicField(this, "updater", new StudioUpdater(this.ctx));
|
|
1185
1320
|
const storePath = studioStorePath(process.env, ctx.get("profileContext"));
|
|
1186
|
-
this.extensions = new MasterExtensions(
|
|
1321
|
+
this.extensions = new MasterExtensions(join3(dirname3(storePath), "master-extensions.json"));
|
|
1187
1322
|
this.store = new PresetStore(ctx, storePath);
|
|
1188
1323
|
this.snapshot = new Promise((resolve2) => {
|
|
1189
1324
|
setImmediate(resolve2);
|
|
@@ -1219,6 +1354,12 @@ var StudioCatalog = class extends (_a = TypertRemoteService, _listPresets_dec =
|
|
|
1219
1354
|
if (!service) throw new Error("Model catalog API unavailable");
|
|
1220
1355
|
return service.modelCatalog();
|
|
1221
1356
|
}
|
|
1357
|
+
async updateStatus(force) {
|
|
1358
|
+
return this.updater.status(force === "force");
|
|
1359
|
+
}
|
|
1360
|
+
async updateStudio(version) {
|
|
1361
|
+
return this.updater.update(version);
|
|
1362
|
+
}
|
|
1222
1363
|
async deletePreset(id) {
|
|
1223
1364
|
return this.store.delete(id);
|
|
1224
1365
|
}
|
|
@@ -1319,6 +1460,8 @@ __decorateElement(_init, 1, "savePreset", _savePreset_dec, StudioCatalog);
|
|
|
1319
1460
|
__decorateElement(_init, 1, "applyPreset", _applyPreset_dec, StudioCatalog);
|
|
1320
1461
|
__decorateElement(_init, 1, "unapplyPreset", _unapplyPreset_dec, StudioCatalog);
|
|
1321
1462
|
__decorateElement(_init, 1, "roleModels", _roleModels_dec, StudioCatalog);
|
|
1463
|
+
__decorateElement(_init, 1, "updateStatus", _updateStatus_dec, StudioCatalog);
|
|
1464
|
+
__decorateElement(_init, 1, "updateStudio", _updateStudio_dec, StudioCatalog);
|
|
1322
1465
|
__decorateElement(_init, 1, "deletePreset", _deletePreset_dec, StudioCatalog);
|
|
1323
1466
|
__decorateElement(_init, 1, "read", _read_dec, StudioCatalog);
|
|
1324
1467
|
__decorateElement(_init, 1, "readExtensions", _readExtensions_dec, StudioCatalog);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matamt-dbg/dsh-studio",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "DSH Studio: build, edit and apply DeepSeek Harness agent presets — tools, prompts, Configs and role-based subagents — from the web GUI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|