@matamt-dbg/dsh-studio 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +89 -2
- package/batch.js +62 -0
- package/client.js +2111 -0
- package/cordis.patch.yml +3 -0
- package/index.js +1195 -0
- package/package.json +68 -4
- package/policy.js +159 -0
- package/roles.js +129 -0
package/client.js
ADDED
|
@@ -0,0 +1,2111 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({id: '@matamt-dbg/dsh-studio', factory: (require) => { const module = { exports: {} }; const exports = module.exports;
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/shell.tsx
|
|
32
|
+
var shell_exports = {};
|
|
33
|
+
__export(shell_exports, {
|
|
34
|
+
apply: () => apply,
|
|
35
|
+
inject: () => inject
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(shell_exports);
|
|
38
|
+
|
|
39
|
+
// src/config-overrides.ts
|
|
40
|
+
var object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
41
|
+
function validateConfigOverrides(value) {
|
|
42
|
+
if (!object(value)) throw new Error("Config overrides must be an object");
|
|
43
|
+
const visit = (v, depth = 0) => {
|
|
44
|
+
if (depth > 32) throw new Error("Config nesting exceeds 32");
|
|
45
|
+
if (typeof v === "number" && !Number.isFinite(v)) throw new Error("Invalid Config number");
|
|
46
|
+
if (v !== null && !["object", "string", "number", "boolean"].includes(typeof v)) throw new Error("Config must be JSON");
|
|
47
|
+
if (Array.isArray(v)) v.forEach((child) => visit(child, depth + 1));
|
|
48
|
+
else if (object(v)) for (const [key, child] of Object.entries(v)) {
|
|
49
|
+
if (["__proto__", "prototype", "constructor"].includes(key)) throw new Error("Unsafe Config key");
|
|
50
|
+
visit(child, depth + 1);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
for (const patch of Object.values(value)) {
|
|
54
|
+
if (!object(patch)) throw new Error("Plugin override must be an object");
|
|
55
|
+
visit(patch);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/provider-fields.ts
|
|
60
|
+
var field = (key, type, value, minimum) => ({ key, type, ...value === void 0 ? {} : { value }, ...minimum === void 0 ? {} : { minimum } });
|
|
61
|
+
var providerFields = {
|
|
62
|
+
"@deepseek-ai/dsh-compaction-basic": [field("thresholdRatio", "number", 0.8, 0), field("headroomTokens", "number", 65536, 1), field("retainRatio", "number", 0.16, 0), field("retainTokens", "number", void 0, 0), field("summarizationProvider", "string", ""), field("summarizationModel", "string", ""), field("maxTokens", "number", void 0, 1), field("compactionRetries", "number", 1, 0), field("maxOverflowRetries", "number", 1, 0), field("auto", "boolean", true)],
|
|
63
|
+
"@deepseek-ai/dsh-compaction-tool-result-pruner": [field("thresholdChars", "number", 8192, 1), field("headChars", "number", 4096, 0), field("tailChars", "number", 1024, 0)],
|
|
64
|
+
"@deepseek-ai/dsh-agent-tool-presentation": [{ key: "mode", type: "string", options: ["native", "ptc"] }],
|
|
65
|
+
"@deepseek-ai/dsh-persona": [field("prefix", "string"), field("suffix", "string", ""), field("includeRuntimeContext", "boolean", true)],
|
|
66
|
+
"@deepseek-ai/dsh-agent-instructions": [field("maxBytes", "number", 65536), field("maxSourceBytes", "number", void 0, 1), field("projectRootMarkers", "string[]"), field("instructionFileCandidates", "string[]"), field("localInstructionFileCandidates", "string[]")],
|
|
67
|
+
"@deepseek-ai/dsh-time-context": [field("timeZone", "string"), field("refreshIntervalMs", "number", void 0, 0)],
|
|
68
|
+
"@deepseek-ai/dsh-skill-filesystem": [field("providerName", "string", "filesystem"), field("includeDefaultRoots", "boolean", true), field("dshHome", "string"), field("agentsHome", "string"), field("customSkillDirs", "string[]", []), field("bundledSkillDir", "string"), field("watch", "boolean", true), field("watchUsePolling", "boolean", false), field("watchStabilityThresholdMs", "number", 200, 0), field("watchPollIntervalMs", "number", 100, 1), field("watchMaxProjects", "number", 128, 1), field("watchFollowSymlinks", "boolean", true)]
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/execution-defaults.ts
|
|
72
|
+
var record = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
73
|
+
var names = /* @__PURE__ */ new Set(["timeoutMs", "timeout_ms"]);
|
|
74
|
+
function validateExecutionDefaults(value) {
|
|
75
|
+
if (!record(value) || Object.keys(value).some((key) => !["defaults", "batch"].includes(key)) || !record(value.defaults)) throw new Error("Invalid execution defaults");
|
|
76
|
+
if (value.batch !== void 0 && (!record(value.batch) || Object.keys(value.batch).some((key) => !["tool", "parameter", "maxItems"].includes(key)) || value.batch.tool !== "read_batch" || typeof value.batch.parameter !== "string" || !value.batch.parameter || ["__proto__", "prototype", "constructor"].includes(value.batch.parameter) || !Number.isSafeInteger(value.batch.maxItems) || value.batch.maxItems < 1)) throw new Error("Invalid batch limit");
|
|
77
|
+
for (const [tool, fields] of Object.entries(value.defaults)) {
|
|
78
|
+
if (!tool || ["__proto__", "prototype", "constructor"].includes(tool) || !record(fields)) throw new Error("Invalid execution defaults");
|
|
79
|
+
for (const [field2, number] of Object.entries(fields)) if (!names.has(field2) || typeof number !== "number" || !Number.isFinite(number) || number <= 0) throw new Error(`Invalid execution default: ${tool}.${field2}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/prompt-composition.ts
|
|
84
|
+
function parsePreviewRequest(value) {
|
|
85
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid preview request");
|
|
86
|
+
const row = value;
|
|
87
|
+
const strings = (input) => Array.isArray(input) && input.every((item) => typeof item === "string");
|
|
88
|
+
if (typeof row.preset !== "string" || !strings(row.providers) || !strings(row.tools) || typeof row.prompt !== "string" || typeof row.model !== "string") throw new Error("Invalid preview request");
|
|
89
|
+
const record2 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
90
|
+
if (row.persona !== void 0 && typeof row.persona !== "string") throw new Error("Invalid persona");
|
|
91
|
+
if (row.sections !== void 0 && (!record2(row.sections) || Object.values(row.sections).some((v) => typeof v !== "string"))) throw new Error("Invalid section overrides");
|
|
92
|
+
if (row.toolOverrides !== void 0 && (!record2(row.toolOverrides) || Object.values(row.toolOverrides).some((v) => !record2(v) || Object.keys(v).some((k) => !["description", "parameters"].includes(k)) || v.description !== void 0 && typeof v.description !== "string" || v.parameters !== void 0 && (!record2(v.parameters) || Object.values(v.parameters).some((p) => typeof p !== "string"))))) throw new Error("Invalid tool overrides");
|
|
93
|
+
if (row.providerConfigs !== void 0 && (!record2(row.providerConfigs) || Object.values(row.providerConfigs).some((v) => !record2(v)))) throw new Error("Invalid provider configs");
|
|
94
|
+
if (row.configOverrides !== void 0) validateConfigOverrides(row.configOverrides);
|
|
95
|
+
if (row.execution !== void 0) validateExecutionDefaults(row.execution);
|
|
96
|
+
return {
|
|
97
|
+
...row.configOverrides !== void 0 ? { configOverrides: row.configOverrides } : {},
|
|
98
|
+
...row.execution !== void 0 ? { execution: row.execution } : {},
|
|
99
|
+
preset: row.preset,
|
|
100
|
+
providers: [...row.providers],
|
|
101
|
+
tools: [...row.tools],
|
|
102
|
+
prompt: row.prompt,
|
|
103
|
+
model: row.model,
|
|
104
|
+
...row.persona !== void 0 ? { persona: row.persona } : {},
|
|
105
|
+
...row.sections !== void 0 ? { sections: row.sections } : {},
|
|
106
|
+
...row.toolOverrides !== void 0 ? { toolOverrides: row.toolOverrides } : {},
|
|
107
|
+
...row.providerConfigs !== void 0 ? { providerConfigs: row.providerConfigs } : {}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/ui.tsx
|
|
112
|
+
var import_react = __toESM(require("react"), 1);
|
|
113
|
+
|
|
114
|
+
// src/ui-styles.ts
|
|
115
|
+
var studioStyles = `/* Only this adapter references host tokens. Studio never installs a global theme. */
|
|
116
|
+
.studio-ui {
|
|
117
|
+
--studio-bg: var(--dsw-alias-bg-base);
|
|
118
|
+
--studio-surface: var(--dsw-alias-bg-layer-1);
|
|
119
|
+
--studio-inset: var(--dsw-alias-bg-layer-2);
|
|
120
|
+
--studio-ink: var(--dsw-alias-label-primary);
|
|
121
|
+
--studio-muted: var(--dsw-alias-label-secondary);
|
|
122
|
+
--studio-subtle: var(--dsw-alias-label-tertiary);
|
|
123
|
+
--studio-line: var(--dsw-alias-border-l2);
|
|
124
|
+
--studio-control-line: var(--dsw-alias-border-l3);
|
|
125
|
+
--studio-accent: var(--dsw-alias-brand-primary);
|
|
126
|
+
--studio-hover: var(--dsw-alias-interactive-bg-hover);
|
|
127
|
+
--studio-pressed: var(--dsw-alias-interactive-bg-active);
|
|
128
|
+
--studio-primary-fill: var(--dsw-alias-button-primary-fill);
|
|
129
|
+
--studio-primary-hover: var(--dsw-alias-button-primary-hover);
|
|
130
|
+
--studio-on-primary: var(--dsw-alias-label-primary-foreground);
|
|
131
|
+
--studio-focus: var(--dsw-focus-ring-color);
|
|
132
|
+
--studio-error: var(--dsw-alias-state-error-primary);
|
|
133
|
+
--studio-success: var(--dsw-alias-state-success-primary);
|
|
134
|
+
--studio-warn: var(--dsw-alias-state-warn-primary);
|
|
135
|
+
--studio-info: var(--dsw-alias-state-business-primary);
|
|
136
|
+
--studio-neutral-fill: var(--dsw-alias-bg-module-platform);
|
|
137
|
+
--studio-radius: 12px;
|
|
138
|
+
--studio-control-radius: var(--dsw-radius-md);
|
|
139
|
+
--studio-small-radius: var(--dsw-radius-sm);
|
|
140
|
+
--studio-gap: 16px;
|
|
141
|
+
color: var(--studio-ink);
|
|
142
|
+
font: inherit;
|
|
143
|
+
font-size: 13px;
|
|
144
|
+
line-height: 1.6;
|
|
145
|
+
min-width: 0;
|
|
146
|
+
overflow-wrap: anywhere;
|
|
147
|
+
}
|
|
148
|
+
.studio-ui *, .studio-ui *::before, .studio-ui *::after { box-sizing: border-box; }
|
|
149
|
+
.studio-ui .studio-tool-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 12px; }
|
|
150
|
+
.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; }
|
|
151
|
+
.studio-ui .studio-tool-card[data-selected="true"] { background: var(--studio-hover); border-color: var(--studio-ink); }
|
|
152
|
+
.studio-ui .studio-card-excerpt { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; font-weight: 400; color: var(--studio-muted); }
|
|
153
|
+
.studio-ui .studio-tool-card strong { overflow-wrap: anywhere; }
|
|
154
|
+
.studio-ui .studio-detail-dialog { width: min(760px, calc(100vw - 32px)); max-height: calc(100dvh - 48px); overflow: auto; padding: 0; color: var(--studio-ink); background: var(--studio-bg); border: 1px solid var(--studio-line); border-radius: var(--studio-radius); }
|
|
155
|
+
.studio-ui .studio-detail-dialog::backdrop { background: var(--studio-muted); opacity: 0.45; }
|
|
156
|
+
.studio-ui .studio-selection-detail { padding: 16px; margin-top: 12px; border: 1px solid var(--studio-line); border-radius: var(--studio-radius); }
|
|
157
|
+
.studio-ui .studio-schema-tool { margin-top: 12px; padding: 10px; border: 1px solid var(--studio-line); border-radius: var(--studio-small-radius); }
|
|
158
|
+
.studio-ui .studio-schema-tool summary { cursor: pointer; overflow-wrap: anywhere; }
|
|
159
|
+
.studio-ui .studio-schema-fields { margin: 8px 0; }
|
|
160
|
+
.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); }
|
|
161
|
+
.studio-ui .studio-schema-fields dt { color: var(--studio-muted); overflow-wrap: anywhere; }
|
|
162
|
+
.studio-ui .studio-schema-fields dd { margin: 0; min-width: 0; }
|
|
163
|
+
.studio-ui .studio-schema-list { padding-inline-start: 20px; }
|
|
164
|
+
.studio-ui .studio-schema-meta { color: var(--studio-muted); font-size: 12px; }
|
|
165
|
+
.studio-ui .studio-row button[aria-pressed="true"] { background: var(--studio-hover); border-color: var(--studio-ink); }
|
|
166
|
+
.studio-ui .studio-tool-description { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
167
|
+
.studio-ui .studio-tool-card strong { font-weight: 500; }
|
|
168
|
+
.studio-ui .studio-comparison { margin-top: 24px; }
|
|
169
|
+
.studio-ui .studio-comparison-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: var(--studio-gap); align-items: start; }
|
|
170
|
+
.studio-ui .studio-comparison-grid > section { min-width: 0; }
|
|
171
|
+
.studio-ui .studio-comparison h4 { font-size: 14px; font-weight: 500; margin: 8px 0; }
|
|
172
|
+
.studio-ui .studio-comparison-panel { border: 1px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); padding: 6px; overflow: hidden; }
|
|
173
|
+
.studio-ui .studio-comparison-native-row { display: grid; grid-template-columns: 8px minmax(0, 1fr) auto 12px; gap: 12px; padding: 12px; align-items: center; border-radius: var(--studio-radius); }
|
|
174
|
+
.studio-ui .studio-comparison-native-row:first-child { background: var(--studio-hover); }
|
|
175
|
+
.studio-ui .studio-comparison-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--studio-success); align-self: start; margin-top: 8px; }
|
|
176
|
+
.studio-ui .studio-comparison-label > div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
177
|
+
.studio-ui .studio-comparison-secondary, .studio-ui .studio-comparison-metrics, .studio-ui .studio-comparison-chevron { color: var(--studio-muted); }
|
|
178
|
+
.studio-ui .studio-comparison-metrics { text-align: right; font-size: 12px; white-space: nowrap; }
|
|
179
|
+
.studio-ui .studio-comparison-chevron { font-size: 20px; }
|
|
180
|
+
.studio-ui .studio-comparison-panel .studio-catalog-row { padding: 10px; }
|
|
181
|
+
.studio-ui .studio-comparison-panel .studio-catalog-row:first-child { border-top: 0; }
|
|
182
|
+
.studio-ui .studio-comparison-snapshot { background: var(--studio-inset); border-radius: var(--studio-small-radius); padding: 8px; margin-top: 8px; }
|
|
183
|
+
.studio-ui .studio-comparison-navigation { color: var(--studio-muted); }
|
|
184
|
+
.studio-ui.studio-catalog { width: min(336px, calc(100vw - 32px)); max-height: 65vh; overflow: auto; padding: 8px; }
|
|
185
|
+
.studio-ui .studio-catalog-row { padding: 8px 0; border-top: 1px solid var(--studio-line); }
|
|
186
|
+
.studio-ui .studio-catalog-row p { margin: 4px 0; }
|
|
187
|
+
.studio-ui .studio-catalog-meta { color: var(--studio-muted); font-size: 12px; }
|
|
188
|
+
.studio-ui .studio-catalog-branch .studio-catalog-branch { margin-left: 12px; padding-left: 8px; border-left: 1px solid var(--studio-line); }
|
|
189
|
+
.studio-ui .studio-catalog-task, .studio-ui .studio-catalog-row pre { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
190
|
+
.studio-ui .studio-catalog-expand { color: var(--studio-ink); background: transparent; border: 0; border-radius: var(--studio-small-radius); padding: 4px 8px; font: inherit; cursor: pointer; }
|
|
191
|
+
.studio-ui .studio-catalog-expand:hover { background: var(--studio-hover); }
|
|
192
|
+
.studio-ui .studio-catalog-expand:focus-visible { outline: 2px solid var(--studio-focus); }
|
|
193
|
+
.studio-ui.studio-catalog-launch fieldset { border: 0; padding: 0; margin: 0 0 12px; }
|
|
194
|
+
.studio-ui.studio-catalog-launch textarea { min-height: 100px; }
|
|
195
|
+
|
|
196
|
+
.studio-ui h1, .studio-ui h2, .studio-ui h3, .studio-ui h4, .studio-ui strong, .studio-ui legend { font-weight: 500; }
|
|
197
|
+
.studio-ui h1 { font-size: 28px; line-height: 1.3; margin: 8px 0 12px; }
|
|
198
|
+
.studio-ui h2 { font-size: 18px; line-height: 1.4; margin: 0 0 12px; }
|
|
199
|
+
.studio-ui h3 { font-size: 14px; line-height: 1.5; margin: 16px 0 8px; }
|
|
200
|
+
.studio-ui h4 { font-size: 13px; line-height: 1.5; margin: 0; }
|
|
201
|
+
.studio-ui p { margin: 8px 0 16px; }
|
|
202
|
+
.studio-ui .studio-muted, .studio-ui dt { color: var(--studio-muted); }
|
|
203
|
+
.studio-ui .studio-hint { font-size: 12px; margin: 0; }
|
|
204
|
+
.studio-ui .studio-grow { flex: 1 1 auto; min-width: 0; }
|
|
205
|
+
.studio-ui .studio-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
206
|
+
|
|
207
|
+
/* Page frame: navigation and content scroll independently, so selecting a section never moves the navigation. */
|
|
208
|
+
.studio-ui.studio-shell { height: 100%; overflow: hidden; container: studio-shell / inline-size; }
|
|
209
|
+
.studio-ui .studio-page { height: 100%; background: var(--studio-bg); }
|
|
210
|
+
.studio-ui .studio-services { display: flex; flex-direction: column; height: 100%; min-height: 0; }
|
|
211
|
+
.studio-ui .studio-service-nav { display: flex; flex: 0 0 auto; gap: 8px; padding: 12px 16px; overflow-x: auto; border-bottom: .5px solid var(--studio-line); }
|
|
212
|
+
.studio-ui .studio-service-nav .studio-nav-item { white-space: nowrap; flex-shrink: 0; }
|
|
213
|
+
.studio-ui .studio-service-panel { flex: 1; min-height: 0; overflow-y: auto; }
|
|
214
|
+
.studio-ui .studio-service-panel[hidden] { display: none; }
|
|
215
|
+
.studio-ui .studio-service-panel > .studio-ui { max-width: 960px; margin: 0 auto; padding: 24px clamp(16px, 3vw, 40px) 48px; }
|
|
216
|
+
.studio-ui .studio-layout { display: grid; grid-template-columns: 208px minmax(0, 1fr); height: 100%; }
|
|
217
|
+
.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; }
|
|
218
|
+
.studio-ui .studio-nav-head { display: grid; gap: 2px; padding: 0 10px 8px; }
|
|
219
|
+
.studio-ui .studio-nav-title { font-size: 14px; }
|
|
220
|
+
.studio-ui .studio-nav-subtitle { color: var(--studio-subtle); font-size: 12px; }
|
|
221
|
+
.studio-ui .studio-nav-group, .studio-ui .studio-list-group { display: flex; align-items: center; gap: 6px; padding: 16px 10px 4px; color: var(--studio-subtle); font-size: 12px; }
|
|
222
|
+
.studio-ui .studio-nav-badge { padding: 0 6px; border: .5px solid var(--studio-control-line); border-radius: 999px; font-size: 11px; line-height: 16px; }
|
|
223
|
+
.studio-ui :is(.studio-nav-item, .studio-list-item) { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 32px; padding: 5px 10px; border: 0; border-radius: var(--studio-control-radius); background: none; color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
224
|
+
.studio-ui :is(.studio-nav-item, .studio-list-item):hover { background: var(--studio-hover); }
|
|
225
|
+
.studio-ui :is(.studio-nav-item, .studio-list-item)[aria-current] { background: var(--studio-hover); font-weight: 500; }
|
|
226
|
+
.studio-ui .studio-scroller { min-width: 0; overflow-y: auto; scrollbar-gutter: stable; container: studio-main / inline-size; }
|
|
227
|
+
.studio-ui .studio-content { max-width: 960px; margin: 0 auto; padding: 24px clamp(16px, 3vw, 40px) 48px; }
|
|
228
|
+
.studio-ui .studio-feature-stack { display: grid; gap: 24px; }
|
|
229
|
+
.studio-ui .studio-page-stack { display: grid; gap: var(--studio-gap); min-width: 0; }
|
|
230
|
+
.studio-ui .studio-page-stack > p, .studio-ui .studio-detail > p { margin: 0; }
|
|
231
|
+
.studio-ui .studio-page-head h2 { margin: 0 0 4px; }
|
|
232
|
+
.studio-ui .studio-page-head p { margin: 0; }
|
|
233
|
+
.studio-ui .studio-page-head + * { margin-top: 0; }
|
|
234
|
+
.studio-ui section > .studio-page-head { margin-bottom: var(--studio-gap); }
|
|
235
|
+
.studio-ui .studio-page-head-actions { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--studio-gap); }
|
|
236
|
+
.studio-ui .studio-status-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0 0; }
|
|
237
|
+
.studio-ui .studio-note { margin: 0; padding: 6px 12px; border-radius: var(--studio-control-radius); background: var(--studio-hover); color: var(--studio-muted); font-size: 12px; }
|
|
238
|
+
.studio-ui .studio-section-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; }
|
|
239
|
+
.studio-ui .studio-section-head :is(h3, h4, p) { margin: 0; }
|
|
240
|
+
.studio-ui .studio-section-head p { margin-top: 2px; }
|
|
241
|
+
.studio-ui .studio-section-head-field { align-items: flex-end; }
|
|
242
|
+
.studio-ui .studio-section-head-field > label { margin: 0; }
|
|
243
|
+
.studio-ui .studio-panel-title { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 15px; }
|
|
244
|
+
.studio-ui h3.studio-section-title { margin: 0; font-size: 18px; }
|
|
245
|
+
.studio-ui .studio-block-section { display: grid; gap: 8px; }
|
|
246
|
+
.studio-ui .studio-block-section > :is(h3, p) { margin: 0; }
|
|
247
|
+
|
|
248
|
+
/* Buttons follow the DSH outline and primary variants. */
|
|
249
|
+
.studio-ui .studio-button { display: inline-flex; align-items: center; justify-content: center; gap: 4px; height: 32px; padding: 0 12px; margin: 2px 4px 2px 0; border: .5px solid var(--studio-control-line); border-radius: var(--studio-control-radius); background: transparent; color: var(--studio-ink); font: inherit; font-weight: 500; line-height: 20px; white-space: nowrap; cursor: pointer; }
|
|
250
|
+
.studio-ui .studio-button:hover:not(:disabled) { background: var(--studio-hover); }
|
|
251
|
+
.studio-ui .studio-button:active:not(:disabled) { background: var(--studio-pressed); }
|
|
252
|
+
.studio-ui .studio-button.studio-primary { border-color: transparent; background: var(--studio-primary-fill); color: var(--studio-on-primary); }
|
|
253
|
+
.studio-ui .studio-button.studio-primary:hover:not(:disabled) { background: var(--studio-primary-hover); }
|
|
254
|
+
.studio-ui .studio-button.studio-small { height: 28px; padding: 0 10px; font-size: 12px; line-height: 18px; border-radius: var(--studio-small-radius); }
|
|
255
|
+
.studio-ui [role=switch][aria-checked=true] { border-color: var(--studio-ink); }
|
|
256
|
+
.studio-ui .studio-inline-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
257
|
+
.studio-ui .studio-inline-actions .studio-button, .studio-ui.studio-modal-footer .studio-button { margin: 0; }
|
|
258
|
+
.studio-ui.studio-modal-footer { display: flex; justify-content: flex-end; gap: 8px; }
|
|
259
|
+
.studio-ui :is(button, input, textarea, select):focus-visible { outline: 2px solid var(--studio-focus, var(--studio-accent)); outline-offset: 2px; }
|
|
260
|
+
.studio-ui :is(button, input, textarea, select):disabled { cursor: not-allowed; opacity: .4; }
|
|
261
|
+
|
|
262
|
+
/* Tabs follow the Plugins page: tertiary labels with a primary underline. */
|
|
263
|
+
.studio-ui .studio-tabs { position: sticky; top: 0; z-index: 2; display: flex; align-items: flex-end; gap: 22px; margin: 0; padding-top: 8px; border-bottom: .5px solid var(--studio-line); background: var(--studio-bg); overflow-x: auto; scrollbar-width: none; }
|
|
264
|
+
.studio-ui .studio-tab { position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 7px 1px 9px; border: 0; background: transparent; color: var(--studio-subtle); font: inherit; line-height: 20px; white-space: nowrap; cursor: pointer; }
|
|
265
|
+
.studio-ui .studio-tab:hover, .studio-ui .studio-tab[aria-selected=true] { color: var(--studio-ink); }
|
|
266
|
+
.studio-ui .studio-tab[aria-selected=true]::after { position: absolute; right: 0; bottom: 0; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: var(--studio-ink); content: ''; }
|
|
267
|
+
.studio-ui .studio-view-switch { max-width: 320px; }
|
|
268
|
+
.studio-ui .studio-tab-panel { min-height: calc(100vh - 48px); }
|
|
269
|
+
|
|
270
|
+
/* Forms. Field rules skip checkbox labels and inputs so host primitives such as Checkbox keep their own layout. */
|
|
271
|
+
.studio-ui fieldset { min-width: 0; margin: 16px 0; padding: 16px; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); }
|
|
272
|
+
.studio-ui legend { padding: 0 8px; font-size: 14px; line-height: 1.5; }
|
|
273
|
+
.studio-ui .studio-role-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--studio-gap); }
|
|
274
|
+
.studio-ui label:not(:has(> input[type=checkbox])) { display: grid; gap: 6px; margin: 12px 0; }
|
|
275
|
+
.studio-ui label:not([class]):has(> input[type=checkbox]) { display: flex; align-items: center; gap: 8px; margin: 8px 0; }
|
|
276
|
+
/* A preset field label wraps its control inline; the fieldset ancestor outranks the grid label rule above. */
|
|
277
|
+
.studio-ui fieldset label.studio-inline-label { display: block; }
|
|
278
|
+
.studio-ui input:not([type=checkbox]), .studio-ui textarea, .studio-ui select { width: 100%; min-width: 0; padding: 6px 10px; border: .5px solid var(--studio-control-line); border-radius: var(--studio-control-radius); background: var(--studio-bg); color: var(--studio-ink); font: inherit; }
|
|
279
|
+
.studio-ui input:not([type=checkbox]), .studio-ui select { min-height: 32px; }
|
|
280
|
+
/* Native select arrows hug the edge; draw an inset chevron in the text color instead. */
|
|
281
|
+
.studio-ui select:not([multiple]) { appearance: none; -webkit-appearance: none; padding-inline-end: 34px; background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position: right 17px top 50%, right 12px top 50%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; text-overflow: ellipsis; }
|
|
282
|
+
.studio-ui textarea { min-height: 144px; resize: vertical; }
|
|
283
|
+
.studio-ui .studio-field { display: grid; gap: 6px; margin: 12px 0; }
|
|
284
|
+
.studio-ui .studio-field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 0 var(--studio-gap); }
|
|
285
|
+
|
|
286
|
+
/* Prompt assembly map and native multi-select transfer lists. */
|
|
287
|
+
.studio-ui .studio-prompt-workbench { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: 20px; align-items: start; text-align: start; }
|
|
288
|
+
.studio-ui ol.studio-steps { margin: 0; padding-inline-start: 20px; }
|
|
289
|
+
.studio-ui .studio-page-stack > pre { margin: 0; }
|
|
290
|
+
.studio-ui .studio-page-stack > :is(.studio-field, label) { margin: 0; }
|
|
291
|
+
.studio-ui ol.studio-steps li { margin-bottom: 4px; }
|
|
292
|
+
.studio-ui ol.studio-prompt-stages { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
293
|
+
.studio-ui .studio-prompt-document { max-height: 680px; overflow-y: auto; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
294
|
+
.studio-ui .studio-prompt-section { display: grid; grid-template-columns: minmax(130px, 1fr) minmax(0, 3fr); gap: 18px; padding: 18px; border-bottom: .5px solid var(--studio-line); border-inline-start: 3px solid transparent; scroll-margin: 8px; }
|
|
295
|
+
.studio-ui .studio-prompt-section h3 { overflow-wrap: anywhere; }
|
|
296
|
+
.studio-ui .studio-prompt-section > p { margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
|
297
|
+
.studio-ui .studio-prompt-tools { padding: 18px; }
|
|
298
|
+
@media (max-width: 600px) { .studio-ui .studio-prompt-section { grid-template-columns: 1fr; gap: 8px; } }
|
|
299
|
+
.studio-ui .studio-prompt-section[data-selected=true] { border-inline-start-color: var(--studio-ink); background: var(--studio-hover); }
|
|
300
|
+
.studio-ui .studio-prompt-section h3 { margin: 0; font-size: 14px; font-weight: 500; }
|
|
301
|
+
.studio-ui .studio-prompt-section textarea, .studio-ui .studio-prompt-section .studio-history-content { margin-top: 12px; }
|
|
302
|
+
@media (max-width: 800px) {
|
|
303
|
+
.studio-ui .studio-prompt-workbench { grid-template-columns: minmax(0, 1fr); }
|
|
304
|
+
.studio-ui ol.studio-steps { margin: 0; padding-inline-start: 20px; }
|
|
305
|
+
.studio-ui .studio-page-stack > pre { margin: 0; }
|
|
306
|
+
.studio-ui .studio-page-stack > :is(.studio-field, label) { margin: 0; }
|
|
307
|
+
.studio-ui ol.studio-steps li { margin-bottom: 4px; }
|
|
308
|
+
.studio-ui ol.studio-prompt-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
309
|
+
}
|
|
310
|
+
.studio-ui .studio-prompt-stages .studio-pick { width: 100%; height: 100%; display: grid; gap: 6px; text-align: start; }
|
|
311
|
+
.studio-ui .studio-prompt-stages [aria-current=step] { border-color: var(--studio-ink); background: var(--studio-hover); }
|
|
312
|
+
.studio-ui .studio-tool-transfer { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 16px; }
|
|
313
|
+
.studio-ui .studio-transfer-column { min-width: 0; border: 1px solid var(--studio-line); border-radius: var(--studio-radius); }
|
|
314
|
+
.studio-ui .studio-transfer-items { display: grid; gap: 10px; max-height: 460px; overflow-y: auto; padding: 8px; }
|
|
315
|
+
.studio-ui .studio-transfer-actions { display: flex; flex-direction: column; justify-content: center; gap: 10px; }
|
|
316
|
+
.studio-ui .studio-prompt-stages { display: grid; gap: 6px; }
|
|
317
|
+
.studio-ui .studio-tool-transfer select { min-height: 260px; }
|
|
318
|
+
.studio-ui .studio-tool-transfer option { padding: 6px; }
|
|
319
|
+
.studio-ui .studio-transfer-actions { display: flex; flex-direction: column; justify-content: center; gap: 8px; }
|
|
320
|
+
@media (max-width: 640px) {
|
|
321
|
+
.studio-ui .studio-tool-transfer { grid-template-columns: minmax(0, 1fr); }
|
|
322
|
+
.studio-ui .studio-transfer-actions { flex-direction: row; }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Existing Studio surfaces. */
|
|
326
|
+
.studio-ui .studio-card, .studio-ui article { padding: 20px; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); min-width: 0; }
|
|
327
|
+
.studio-ui article + article { margin-top: var(--studio-gap); }
|
|
328
|
+
.studio-ui .studio-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--studio-gap); }
|
|
329
|
+
.studio-ui .studio-actions, .studio-ui nav { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--studio-gap); }
|
|
330
|
+
.studio-ui dl { display: grid; grid-template-columns: minmax(80px, 1fr) minmax(0, 3fr); gap: 8px 16px; margin: 16px 0; }
|
|
331
|
+
.studio-ui dd { margin: 0; min-width: 0; }
|
|
332
|
+
.studio-ui [role=alert] { margin: 0; padding: 8px 12px; border-inline-start: 2px solid var(--studio-error); color: var(--studio-error); }
|
|
333
|
+
.studio-ui [role=status] { color: var(--studio-muted); }
|
|
334
|
+
.studio-ui pre { max-width: 100%; overflow: auto; padding: 12px; border-radius: 8px; background: var(--studio-inset); font-size: 12px; line-height: 1.6; }
|
|
335
|
+
.studio-ui .studio-history-content { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
336
|
+
.studio-ui ol, .studio-ui ul { padding-inline-start: 20px; }
|
|
337
|
+
.studio-ui li { margin-bottom: 8px; }
|
|
338
|
+
.studio-ui .studio-agents { padding: 20px; }
|
|
339
|
+
.studio-ui .studio-timer { padding: 20px; border-radius: var(--studio-radius); background: var(--studio-inset); }
|
|
340
|
+
.studio-ui .studio-timer strong { font-size: 28px; line-height: 1.4; font-variant-numeric: tabular-nums; }
|
|
341
|
+
.studio-ui .studio-timer span { font-size: 13px; line-height: 1.6; }
|
|
342
|
+
|
|
343
|
+
/* Design mock: cards, lists, and tables. */
|
|
344
|
+
.studio-ui .studio-inline-state { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
345
|
+
.studio-ui .studio-notice-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
|
|
346
|
+
.studio-ui .studio-cards { display: grid; gap: 8px; }
|
|
347
|
+
.studio-ui .studio-component { min-width: 0; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
348
|
+
.studio-ui .studio-component-flat { padding: 4px 16px 16px; }
|
|
349
|
+
.studio-ui .studio-component-head { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; padding: 12px 16px; border: 0; border-radius: var(--studio-radius); background: none; color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
350
|
+
.studio-ui .studio-component-head[aria-expanded=true] { border-radius: var(--studio-radius) var(--studio-radius) 0 0; }
|
|
351
|
+
.studio-ui .studio-component-head:hover { background: var(--studio-hover); }
|
|
352
|
+
.studio-ui .studio-component-title { flex: 0 0 auto; font-size: 14px; font-weight: 500; }
|
|
353
|
+
.studio-ui .studio-component-summary { flex: 1 1 auto; min-width: 0; overflow: hidden; color: var(--studio-muted); text-overflow: ellipsis; white-space: nowrap; }
|
|
354
|
+
.studio-ui .studio-chevron { flex: 0 0 auto; color: var(--studio-muted); }
|
|
355
|
+
.studio-ui .studio-chevron[data-open=true] { transform: rotate(180deg); }
|
|
356
|
+
.studio-ui .studio-component-body { padding: 4px 16px 16px; border-top: .5px solid var(--studio-line); }
|
|
357
|
+
.studio-ui .studio-reason { margin: 12px 0; padding: 8px 12px; border-radius: var(--studio-control-radius); background: var(--studio-hover); color: var(--studio-muted); }
|
|
358
|
+
.studio-ui .studio-reason-warning { border-inline-start: 2px solid var(--studio-subtle); color: var(--studio-ink); }
|
|
359
|
+
.studio-ui .studio-effect { margin-top: 16px; padding-top: 12px; border-top: .5px solid var(--studio-line); }
|
|
360
|
+
.studio-ui .studio-effect span { color: var(--studio-muted); font-size: 12px; }
|
|
361
|
+
.studio-ui .studio-effect p { margin: 4px 0 0; }
|
|
362
|
+
.studio-ui .studio-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
|
|
363
|
+
.studio-ui .studio-card-actions .studio-button { margin: 0; }
|
|
364
|
+
.studio-ui .studio-card-actions:empty { display: none; }
|
|
365
|
+
.studio-ui .studio-blocks { margin: 0 0 8px; padding: 0; list-style: none; }
|
|
366
|
+
.studio-ui .studio-block { margin: 0; padding: 12px 0; border-bottom: .5px solid var(--studio-line); }
|
|
367
|
+
.studio-ui .studio-block-head { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; }
|
|
368
|
+
.studio-ui .studio-block-name { flex: 1 1 200px; margin: 0; }
|
|
369
|
+
.studio-ui .studio-block textarea { min-height: 72px; }
|
|
370
|
+
.studio-ui .studio-tool-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr)); gap: 8px var(--studio-gap); }
|
|
371
|
+
.studio-ui .studio-tool-groups fieldset { display: grid; align-content: start; gap: 8px; margin: 8px 0 0; padding: 8px 12px 12px; }
|
|
372
|
+
.studio-ui .studio-tool-groups legend { color: var(--studio-muted); font-size: 13px; }
|
|
373
|
+
.studio-ui .studio-targets { display: grid; gap: 8px; margin: 12px 0; }
|
|
374
|
+
.studio-ui .studio-target { padding: 8px 12px; border: .5px solid var(--studio-line); border-radius: var(--studio-control-radius); }
|
|
375
|
+
.studio-ui .studio-target-body { padding-inline-start: 26px; }
|
|
376
|
+
.studio-ui .studio-target .studio-field { margin: 8px 0; }
|
|
377
|
+
.studio-ui .studio-tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 8px; }
|
|
378
|
+
.studio-ui .studio-tile { display: grid; gap: 2px; padding: 12px 14px; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
379
|
+
.studio-ui .studio-tile:hover { background: var(--studio-hover); }
|
|
380
|
+
.studio-ui .studio-tile-title { display: flex; align-items: center; gap: 6px; font-weight: 500; }
|
|
381
|
+
.studio-ui .studio-plain-list { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
|
|
382
|
+
.studio-ui .studio-plain-list > li { margin: 0; }
|
|
383
|
+
.studio-ui .studio-list-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: .5px solid var(--studio-line); }
|
|
384
|
+
.studio-ui .studio-system-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
|
|
385
|
+
.studio-ui .studio-system-grid > li { margin: 0; }
|
|
386
|
+
.studio-ui .studio-system { display: grid; gap: 4px; padding: 16px; }
|
|
387
|
+
.studio-ui .studio-system > p { margin: 0; }
|
|
388
|
+
.studio-ui .studio-facts { grid-template-columns: minmax(96px, 140px) minmax(0, 1fr); gap: 6px 12px; margin: 8px 0 0; }
|
|
389
|
+
.studio-ui .studio-master-detail { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 24px; align-items: start; }
|
|
390
|
+
.studio-ui nav.studio-list { position: sticky; top: 0; display: flex; flex-direction: column; flex-wrap: nowrap; gap: 2px; margin: 0; }
|
|
391
|
+
.studio-ui .studio-list-group:first-child { padding-top: 0; }
|
|
392
|
+
.studio-ui .studio-list-text { display: grid; min-width: 0; }
|
|
393
|
+
.studio-ui .studio-list-text .studio-muted { font-size: 12px; font-weight: 400; }
|
|
394
|
+
.studio-ui .studio-detail { display: grid; gap: 12px; min-width: 0; }
|
|
395
|
+
.studio-ui .studio-detail > label { margin: 0; }
|
|
396
|
+
.studio-ui .studio-matrix-scroll { overflow-x: auto; }
|
|
397
|
+
.studio-ui .studio-matrix { width: 100%; border-collapse: collapse; }
|
|
398
|
+
.studio-ui .studio-matrix :is(th, td) { padding: 6px; border-bottom: .5px solid var(--studio-line); font-weight: 500; text-align: start; vertical-align: middle; }
|
|
399
|
+
.studio-ui .studio-matrix thead th { color: var(--studio-muted); font-size: 12px; }
|
|
400
|
+
.studio-ui .studio-matrix-cell { display: grid; align-content: center; width: 100%; min-height: 44px; padding: 6px 10px; border: 0; border-radius: var(--studio-control-radius); background: none; color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
401
|
+
.studio-ui .studio-matrix-cell:hover { background: var(--studio-hover); }
|
|
402
|
+
.studio-ui .studio-matrix-cell .studio-muted { font-size: 12px; }
|
|
403
|
+
.studio-ui .studio-checklist { margin: 0 0 12px; padding: 0; list-style: none; }
|
|
404
|
+
.studio-ui .studio-checklist li { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
|
|
405
|
+
.studio-ui .studio-simulate { margin: 16px 0 0; padding-top: 12px; border-top: .5px dashed var(--studio-line); }
|
|
406
|
+
.studio-ui .studio-pick-list { display: grid; gap: 6px; margin: 0 0 12px; padding: 0; list-style: none; }
|
|
407
|
+
.studio-ui .studio-pick-list > li { margin: 0; }
|
|
408
|
+
.studio-ui .studio-pick { display: grid; gap: 2px; width: 100%; padding: 10px 12px; border: .5px solid var(--studio-control-line); border-radius: var(--studio-control-radius); background: transparent; color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
409
|
+
.studio-ui .studio-pick:hover { background: var(--studio-hover); }
|
|
410
|
+
.studio-ui .studio-pick[aria-checked=true] { border-color: var(--studio-ink); background: var(--studio-hover); }
|
|
411
|
+
.studio-ui .studio-pick-title { display: flex; align-items: center; gap: 6px; }
|
|
412
|
+
|
|
413
|
+
/* Shared form rhythm: stacks own their spacing so paragraphs and fields do not add stray margins. */
|
|
414
|
+
.studio-ui .studio-stack { display: grid; gap: 12px; min-width: 0; }
|
|
415
|
+
.studio-ui .studio-stack > :is(p, label, .studio-field, .studio-note, fieldset) { margin: 0; }
|
|
416
|
+
.studio-ui .studio-form-section { display: grid; gap: 12px; min-width: 0; }
|
|
417
|
+
.studio-ui .studio-form-section > :is(p, label, .studio-field, .studio-note) { margin: 0; }
|
|
418
|
+
.studio-ui .studio-field .studio-field-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 8px; min-height: 28px; }
|
|
419
|
+
.studio-ui .studio-field .studio-field-head > label { display: block; margin: 0; }
|
|
420
|
+
.studio-ui .studio-field .studio-field-head .studio-button { margin: 0; }
|
|
421
|
+
.studio-ui .studio-field > .studio-hint { margin-top: -2px; }
|
|
422
|
+
.studio-ui .studio-count { margin-inline-start: 6px; color: var(--studio-subtle); font-size: 12px; font-weight: 400; }
|
|
423
|
+
.studio-ui .studio-button[aria-pressed="true"] { background: var(--studio-hover); border-color: var(--studio-ink); }
|
|
424
|
+
|
|
425
|
+
/* Status badges mirror the DSH Tag capsule: tinted fill, matching text, fixed geometry. */
|
|
426
|
+
.studio-ui .studio-badge { display: inline-flex; align-items: center; flex: 0 0 auto; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 500; line-height: 17px; white-space: nowrap; background: var(--studio-neutral-fill); color: var(--studio-muted); }
|
|
427
|
+
.studio-ui .studio-badge[data-tone=success] { background: color-mix(in srgb, var(--studio-success) 10%, transparent); color: var(--studio-success); }
|
|
428
|
+
.studio-ui .studio-badge[data-tone=warning] { background: color-mix(in srgb, var(--studio-warn) 12%, transparent); color: var(--studio-warn); }
|
|
429
|
+
.studio-ui .studio-badge[data-tone=info] { background: color-mix(in srgb, var(--studio-info) 10%, transparent); color: var(--studio-info); }
|
|
430
|
+
.studio-ui .studio-badge[data-tone=outline] { background: transparent; border: .5px solid var(--studio-control-line); color: var(--studio-subtle); }
|
|
431
|
+
|
|
432
|
+
/* Editor tabs and panels. */
|
|
433
|
+
.studio-ui .studio-editor-tabs { margin-top: 4px; }
|
|
434
|
+
.studio-ui .studio-tab-body { display: grid; align-content: start; gap: 24px; padding-top: 20px; min-width: 0; min-height: 70vh; }
|
|
435
|
+
.studio-ui .studio-tab-body[hidden] { display: none; }
|
|
436
|
+
.studio-ui .studio-tab-body > :is(p, .studio-note) { margin: 0; }
|
|
437
|
+
.studio-ui .studio-tab-body .studio-page-head h2 { font-size: 15px; }
|
|
438
|
+
|
|
439
|
+
/* Preset and role cards. */
|
|
440
|
+
.studio-ui .studio-tool-cards > article + article, .studio-ui .studio-transfer-items > article + article { margin-top: 0; }
|
|
441
|
+
.studio-ui article.studio-preset-card, .studio-ui article.studio-role-card { display: flex; flex-direction: column; gap: 6px; padding: 16px; }
|
|
442
|
+
.studio-ui .studio-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-width: 0; }
|
|
443
|
+
.studio-ui .studio-card-head :is(h3, strong) { margin: 0; font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
444
|
+
.studio-ui .studio-card-head > :first-child { margin-inline-end: auto; }
|
|
445
|
+
.studio-ui .studio-card-text { margin: 0; color: var(--studio-muted); }
|
|
446
|
+
.studio-ui .studio-card-meta { margin: 0; color: var(--studio-subtle); font-size: 12px; }
|
|
447
|
+
.studio-ui .studio-card-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: auto; padding-top: 10px; }
|
|
448
|
+
.studio-ui .studio-card-footer .studio-button { margin: 0; }
|
|
449
|
+
.studio-ui .studio-card-note { margin-top: auto; padding-top: 10px; }
|
|
450
|
+
.studio-ui .studio-card-footer .studio-card-footer-end { margin-inline-start: auto; }
|
|
451
|
+
.studio-ui .studio-tool-cards.studio-card-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
452
|
+
.studio-ui .studio-preset-warnings { display: flex; flex-direction: column; gap: 6px; margin: 0 0 12px; padding: 0; list-style: none; }
|
|
453
|
+
.studio-ui .studio-preset-warnings > li { display: flex; align-items: baseline; gap: 8px; padding: 6px 12px; border-radius: var(--studio-control-radius); background: var(--studio-hover); color: var(--studio-muted); font-size: 12px; }
|
|
454
|
+
|
|
455
|
+
/* Selection columns: a quiet header row and compact cards. */
|
|
456
|
+
.studio-ui .studio-transfer-column { display: flex; flex-direction: column; background: var(--studio-surface); }
|
|
457
|
+
.studio-ui .studio-transfer-column > .studio-section-head { padding: 10px 14px; border-bottom: .5px solid var(--studio-line); }
|
|
458
|
+
.studio-ui .studio-transfer-column > .studio-section-head .studio-panel-title { font-size: 13px; }
|
|
459
|
+
.studio-ui .studio-transfer-items { padding: 10px; gap: 8px; }
|
|
460
|
+
.studio-ui .studio-transfer-items > p { margin: 4px; }
|
|
461
|
+
.studio-ui .studio-transfer-items > .studio-card { display: grid; gap: 6px; padding: 12px 14px; background: var(--studio-bg); }
|
|
462
|
+
.studio-ui .studio-transfer-items > .studio-card > p { margin: 0; }
|
|
463
|
+
.studio-ui .studio-transfer-items > .studio-card .studio-panel-title { font-size: 13px; overflow-wrap: anywhere; }
|
|
464
|
+
.studio-ui .studio-transfer-items > .studio-card .studio-section-head p { font-size: 12px; }
|
|
465
|
+
.studio-ui .studio-selection-detail { display: grid; gap: 12px; margin-top: 4px; }
|
|
466
|
+
.studio-ui .studio-selection-detail > :is(p, label, .studio-field, .studio-note, section) { margin: 0; }
|
|
467
|
+
.studio-ui .studio-selection-detail .studio-section-head { margin-top: 8px; }
|
|
468
|
+
|
|
469
|
+
/* Config form: root object has no frame; nested objects use a quiet rule; each field reads label \u2192 state \u2192 input. */
|
|
470
|
+
.studio-ui fieldset.studio-config-root { margin: 4px 0 0; padding: 0; border: 0; }
|
|
471
|
+
.studio-ui fieldset.studio-config-root fieldset { margin: 8px 0; padding: 4px 0 4px 12px; border: 0; border-inline-start: .5px solid var(--studio-control-line); border-radius: 0; }
|
|
472
|
+
.studio-ui fieldset.studio-config-root legend { padding: 0; color: var(--studio-muted); font-size: 12px; }
|
|
473
|
+
.studio-ui .studio-config-field { margin: 10px 0; }
|
|
474
|
+
.studio-ui .studio-config-list { display: grid; }
|
|
475
|
+
.studio-ui .studio-config-list .studio-list-row { padding: 4px 0; }
|
|
476
|
+
.studio-ui .studio-config-list .studio-list-row:last-child { border-bottom: 0; }
|
|
477
|
+
.studio-ui .studio-config-list .studio-list-row input { flex: 1; min-width: 0; }
|
|
478
|
+
.studio-ui .studio-config-list .studio-list-row .studio-config-item { flex: 1; min-width: 0; margin: 0; padding: 0 0 0 2px; border: 0; }
|
|
479
|
+
.studio-ui .studio-config-key { flex: 0 0 auto; min-width: 0; overflow-wrap: anywhere; color: var(--studio-muted); }
|
|
480
|
+
.studio-ui .studio-config-state { color: var(--studio-subtle); font-size: 12px; margin-inline-start: auto; }
|
|
481
|
+
.studio-ui .studio-config-field[data-overridden=true] .studio-config-state { color: var(--studio-info); }
|
|
482
|
+
|
|
483
|
+
/* Collapsible advanced block, styled like a component card. */
|
|
484
|
+
.studio-ui details.studio-disclosure { border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
485
|
+
.studio-ui details.studio-disclosure > summary { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-radius: var(--studio-radius); cursor: pointer; list-style: none; font-weight: 500; }
|
|
486
|
+
.studio-ui details.studio-disclosure > summary::-webkit-details-marker { display: none; }
|
|
487
|
+
.studio-ui details.studio-disclosure > summary::after { content: ''; width: 6px; height: 6px; margin-inline-start: auto; border-right: 1.3px solid var(--studio-muted); border-bottom: 1.3px solid var(--studio-muted); transform: rotate(45deg); }
|
|
488
|
+
.studio-ui details.studio-disclosure[open] > summary::after { transform: rotate(-135deg); }
|
|
489
|
+
.studio-ui details.studio-disclosure > summary:hover { background: var(--studio-hover); }
|
|
490
|
+
.studio-ui details.studio-disclosure > summary:focus-visible { outline: 2px solid var(--studio-focus); outline-offset: 2px; }
|
|
491
|
+
.studio-ui .studio-disclosure-summary { display: grid; gap: 0; }
|
|
492
|
+
.studio-ui .studio-disclosure-summary .studio-muted { font-size: 12px; font-weight: 400; }
|
|
493
|
+
.studio-ui .studio-disclosure-body { display: grid; gap: 12px; padding: 4px 16px 16px; border-top: .5px solid var(--studio-line); }
|
|
494
|
+
.studio-ui .studio-disclosure-body > :is(p, ol, pre, label, .studio-field, .studio-note) { margin: 0; }
|
|
495
|
+
.studio-ui .studio-disclosure-body ol { padding-top: 12px; }
|
|
496
|
+
.studio-ui .studio-disclosure-body li { margin-bottom: 4px; }
|
|
497
|
+
|
|
498
|
+
/* Dialog header and body spacing. */
|
|
499
|
+
.studio-ui .studio-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
500
|
+
.studio-ui .studio-dialog-head h2, .studio-ui .studio-dialog-head h3 { margin: 0; }
|
|
501
|
+
.studio-ui .studio-dialog-actions { justify-content: flex-end; }
|
|
502
|
+
.studio-ui .studio-selection-detail > h3 { margin: 0; font-size: 15px; }
|
|
503
|
+
|
|
504
|
+
/* Unified selection card: title row, optional mono subtitle, two-line excerpt, actions bottom-right. */
|
|
505
|
+
.studio-ui .studio-transfer-items { max-height: 520px; }
|
|
506
|
+
.studio-ui .studio-transfer-items > .studio-transfer-card { display: flex; flex-direction: column; gap: 4px; min-height: 0; padding: 12px 14px; }
|
|
507
|
+
.studio-ui .studio-transfer-card-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
508
|
+
.studio-ui .studio-transfer-card-head strong { flex: 1 1 auto; min-width: 0; overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
|
|
509
|
+
.studio-ui .studio-transfer-card-subtitle { overflow: hidden; color: var(--studio-subtle); text-overflow: ellipsis; white-space: nowrap; }
|
|
510
|
+
.studio-ui .studio-transfer-card .studio-card-excerpt { margin: 0; font-size: 12px; line-height: 1.55; }
|
|
511
|
+
.studio-ui .studio-transfer-card-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: auto; padding-top: 6px; }
|
|
512
|
+
.studio-ui .studio-transfer-card-actions .studio-button { margin: 0; }
|
|
513
|
+
.studio-ui .studio-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
514
|
+
|
|
515
|
+
/* Split button: main action joined to a caret menu. */
|
|
516
|
+
.studio-ui .studio-split { position: relative; display: inline-flex; }
|
|
517
|
+
.studio-ui .studio-split .studio-button { margin: 0; }
|
|
518
|
+
.studio-ui .studio-split[data-menu=true] > .studio-button:first-child { border-start-end-radius: 0; border-end-end-radius: 0; }
|
|
519
|
+
.studio-ui .studio-split .studio-split-caret { width: 26px; padding: 0; margin-inline-start: -.5px; border-start-start-radius: 0; border-end-start-radius: 0; }
|
|
520
|
+
.studio-ui .studio-split .studio-button.studio-primary.studio-split-caret { border-inline-start: .5px solid var(--studio-on-primary); }
|
|
521
|
+
.studio-ui .studio-split-menu { position: absolute; top: calc(100% + 4px); right: 0; z-index: 5; display: grid; min-width: 140px; padding: 4px; border: .5px solid var(--studio-line); border-radius: var(--studio-control-radius); background: var(--studio-bg); }
|
|
522
|
+
.studio-ui .studio-split-menu button { padding: 6px 10px; border: 0; border-radius: var(--studio-small-radius); background: none; color: var(--studio-ink); font: inherit; font-size: 12px; text-align: start; white-space: nowrap; cursor: pointer; }
|
|
523
|
+
.studio-ui .studio-split-menu button:hover { background: var(--studio-hover); }
|
|
524
|
+
|
|
525
|
+
/* Detail dialog: header, scrolling body, optional footer. */
|
|
526
|
+
.studio-ui .studio-detail-dialog { width: min(680px, calc(100vw - 48px)); max-height: calc(100dvh - 64px); overflow: hidden; }
|
|
527
|
+
.studio-ui .studio-detail-dialog[open] { display: flex; }
|
|
528
|
+
.studio-ui .studio-dialog { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; width: 100%; }
|
|
529
|
+
.studio-ui .studio-dialog > header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 18px 20px 14px; border-bottom: .5px solid var(--studio-line); }
|
|
530
|
+
.studio-ui .studio-dialog > header h2 { margin: 0; font-size: 15px; overflow-wrap: anywhere; }
|
|
531
|
+
.studio-ui .studio-dialog > header p { margin: 2px 0 0; font-size: 12px; }
|
|
532
|
+
.studio-ui .studio-dialog > header .studio-button { margin: 0; flex: 0 0 auto; }
|
|
533
|
+
.studio-ui .studio-dialog .studio-dialog-body { flex: 1 1 auto; min-height: 0; margin: 0; border: 0; border-radius: 0; padding: 16px 20px 20px; overflow-y: auto; }
|
|
534
|
+
.studio-ui .studio-dialog > footer { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 20px; border-top: .5px solid var(--studio-line); }
|
|
535
|
+
.studio-ui .studio-dialog > footer .studio-button { margin: 0; }
|
|
536
|
+
.studio-ui .studio-dialog > footer .studio-button:first-child:not(:last-child) { margin-inline-end: auto; }
|
|
537
|
+
.studio-ui .studio-dialog-body .studio-field-grid .studio-field { margin: 0 0 12px; }
|
|
538
|
+
.studio-ui .studio-dialog-body fieldset.studio-config-root { margin: 0; }
|
|
539
|
+
.studio-ui .studio-dialog-body > .studio-button, .studio-ui .studio-dialog-body section > .studio-button { justify-self: start; margin: 0; }
|
|
540
|
+
.studio-ui .studio-dialog-body section { display: grid; gap: 8px; }
|
|
541
|
+
.studio-ui .studio-dialog-body section > .studio-field { margin: 0; }
|
|
542
|
+
|
|
543
|
+
/* Item picker: one list, rows stay in place when toggled; filters show selected or modified rows. */
|
|
544
|
+
.studio-ui .studio-picker { display: grid; gap: 10px; min-width: 0; }
|
|
545
|
+
.studio-ui .studio-picker-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
|
|
546
|
+
.studio-ui .studio-picker-bar input[type=search] { flex: 1 1 240px; width: auto; }
|
|
547
|
+
.studio-ui .studio-picker-filters { display: inline-flex; flex: 0 0 auto; padding: 2px; border-radius: var(--studio-control-radius); background: var(--studio-neutral-fill); }
|
|
548
|
+
.studio-ui .studio-picker-filter { display: inline-flex; align-items: center; height: 28px; padding: 0 10px; border: 0; border-radius: var(--studio-small-radius); background: none; color: var(--studio-muted); font: inherit; font-size: 12px; cursor: pointer; }
|
|
549
|
+
.studio-ui .studio-picker-filter[aria-checked=true] { background: var(--studio-bg); color: var(--studio-ink); font-weight: 500; }
|
|
550
|
+
.studio-ui .studio-picker-filter .studio-count { margin-inline-start: 4px; }
|
|
551
|
+
.studio-ui ul.studio-picker-list { display: grid; max-height: 480px; margin: 0; padding: 0; overflow-y: auto; list-style: none; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
552
|
+
.studio-ui .studio-picker-row { display: flex; align-items: center; gap: 8px; margin: 0; padding: 0 12px 0 0; border-bottom: .5px solid var(--studio-line); }
|
|
553
|
+
.studio-ui .studio-picker-row:last-child { border-bottom: 0; }
|
|
554
|
+
.studio-ui .studio-picker-row[data-selected=true] { background: var(--studio-hover); }
|
|
555
|
+
.studio-ui .studio-picker-row > .studio-button { margin: 0; flex: 0 0 auto; }
|
|
556
|
+
.studio-ui .studio-picker-toggle { display: flex; flex: 1 1 auto; align-items: flex-start; gap: 12px; min-width: 0; padding: 10px 4px 10px 14px; border: 0; background: none; color: var(--studio-ink); font: inherit; text-align: start; cursor: pointer; }
|
|
557
|
+
.studio-ui .studio-picker-toggle:focus-visible { outline-offset: -2px; }
|
|
558
|
+
.studio-ui .studio-picker-check { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; width: 18px; height: 18px; margin-top: 1px; border: 1px solid var(--studio-control-line); border-radius: 5px; color: transparent; }
|
|
559
|
+
.studio-ui .studio-picker-toggle[aria-checked=true] .studio-picker-check { border-color: var(--studio-primary-fill); background: var(--studio-primary-fill); color: var(--studio-on-primary); }
|
|
560
|
+
.studio-ui .studio-picker-text { display: grid; gap: 2px; min-width: 0; }
|
|
561
|
+
.studio-ui .studio-picker-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; font-weight: 500; overflow-wrap: anywhere; }
|
|
562
|
+
.studio-ui .studio-picker-subtitle { color: var(--studio-subtle); font-weight: 400; }
|
|
563
|
+
.studio-ui .studio-picker-description { display: -webkit-box; overflow: hidden; color: var(--studio-muted); font-size: 12px; line-height: 1.5; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
|
564
|
+
.studio-ui .studio-picker-empty { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0; padding: 14px; color: var(--studio-muted); }
|
|
565
|
+
.studio-ui .studio-picker-empty .studio-button { margin: 0; }
|
|
566
|
+
|
|
567
|
+
/* Prompt preview: sections read as a document on the left, tool schemas sit in a right rail. */
|
|
568
|
+
.studio-ui .studio-detail-dialog.studio-dialog-compact { width: min(440px, calc(100vw - 48px)); }
|
|
569
|
+
.studio-ui .studio-dialog-compact .studio-dialog > header { border-bottom: 0; padding-bottom: 0; }
|
|
570
|
+
.studio-ui .studio-dialog-compact .studio-dialog .studio-dialog-body { padding-top: 10px; padding-bottom: 4px; }
|
|
571
|
+
.studio-ui .studio-dialog-compact .studio-dialog > footer { border-top: 0; padding-bottom: 18px; }
|
|
572
|
+
.studio-ui .studio-dialog-compact .studio-dialog > footer .studio-button:first-child:not(:last-child) { margin-inline-end: 0; }
|
|
573
|
+
/* Preset identity: one card, short name beside a wider description, quiet labels. */
|
|
574
|
+
.studio-ui .studio-identity { display: grid; grid-template-columns: minmax(200px, 2fr) minmax(0, 3fr); gap: 12px var(--studio-gap); padding: 14px 16px; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
575
|
+
.studio-ui .studio-identity > label.studio-field { margin: 0; gap: 4px; }
|
|
576
|
+
.studio-ui .studio-identity > label.studio-field > span { color: var(--studio-subtle); font-size: 12px; }
|
|
577
|
+
.studio-ui .studio-identity input:not([type=checkbox]) { min-height: 36px; background: var(--studio-bg); }
|
|
578
|
+
.studio-ui .studio-identity .studio-identity-name input { font-size: 15px; font-weight: 500; }
|
|
579
|
+
@media (max-width: 720px) { .studio-ui .studio-identity { grid-template-columns: minmax(0, 1fr); } }
|
|
580
|
+
.studio-ui .studio-detail-dialog.studio-dialog-wide { width: min(1180px, calc(100vw - 48px)); height: calc(100dvh - 64px); }
|
|
581
|
+
.studio-ui .studio-dialog-wide .studio-dialog-body { display: flex; flex-direction: column; padding-bottom: 16px; }
|
|
582
|
+
.studio-ui .studio-preview { display: grid; flex: 1 1 auto; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; min-height: 0; }
|
|
583
|
+
.studio-ui .studio-preview .studio-prompt-document { max-height: none; min-height: 0; overflow-y: auto; border: .5px solid var(--studio-line); background: var(--studio-bg); }
|
|
584
|
+
.studio-ui .studio-preview .studio-prompt-section { display: block; padding: 14px 18px; border-inline-start: 0; }
|
|
585
|
+
.studio-ui .studio-preview .studio-prompt-section h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; color: var(--studio-muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; font-weight: 400; }
|
|
586
|
+
.studio-ui .studio-prompt-index { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--studio-neutral-fill); color: var(--studio-muted); font-family: inherit; font-size: 11px; }
|
|
587
|
+
.studio-ui .studio-preview .studio-prompt-section > p { font-size: 13px; line-height: 1.65; }
|
|
588
|
+
.studio-ui .studio-preview .studio-prompt-tools { min-height: 0; overflow-y: auto; padding: 12px; border: .5px solid var(--studio-line); border-radius: var(--studio-radius); background: var(--studio-surface); }
|
|
589
|
+
.studio-ui .studio-preview .studio-prompt-tools h3 { margin: 0 0 8px; font-size: 13px; }
|
|
590
|
+
.studio-ui .studio-preview .studio-schema-tool > summary { display: flex; align-items: center; gap: 8px; list-style: none; }
|
|
591
|
+
.studio-ui .studio-preview .studio-schema-tool > summary::-webkit-details-marker { display: none; }
|
|
592
|
+
.studio-ui .studio-preview .studio-schema-tool > summary::before { content: ''; width: 5px; height: 5px; border-right: 1.3px solid var(--studio-muted); border-bottom: 1.3px solid var(--studio-muted); transform: rotate(-45deg); }
|
|
593
|
+
.studio-ui .studio-preview .studio-schema-tool[open] > summary::before { transform: rotate(45deg); }
|
|
594
|
+
.studio-ui .studio-preview .studio-schema-tool { margin-top: 6px; padding: 8px 10px; background: var(--studio-bg); }
|
|
595
|
+
.studio-ui .studio-preview .studio-schema-tool summary { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
596
|
+
.studio-ui .studio-preview .studio-schema-tool p { font-size: 12px; }
|
|
597
|
+
.studio-ui .studio-preview .studio-schema-fields > div { grid-template-columns: minmax(60px, 90px) minmax(0, 1fr); font-size: 12px; }
|
|
598
|
+
@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); } }
|
|
599
|
+
|
|
600
|
+
/* Width rules follow the Studio surface and its content column, which the host sidebar and the Studio navigation narrow. */
|
|
601
|
+
@container studio-shell (max-width: 760px) {
|
|
602
|
+
.studio-ui .studio-page { overflow-y: auto; }
|
|
603
|
+
.studio-ui .studio-layout { grid-template-columns: 1fr; height: auto; }
|
|
604
|
+
.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); }
|
|
605
|
+
.studio-ui .studio-nav-title, .studio-ui .studio-nav-group { display: none; }
|
|
606
|
+
.studio-ui .studio-nav-item { flex: 0 0 auto; }
|
|
607
|
+
.studio-ui .studio-scroller { overflow: visible; }
|
|
608
|
+
}
|
|
609
|
+
@container studio-main (max-width: 560px) {
|
|
610
|
+
.studio-ui .studio-tool-cards.studio-card-pair { grid-template-columns: minmax(0, 1fr); }
|
|
611
|
+
}
|
|
612
|
+
@container studio-main (max-width: 640px) {
|
|
613
|
+
.studio-ui .studio-master-detail { grid-template-columns: 1fr; }
|
|
614
|
+
.studio-ui nav.studio-list { position: static; flex-direction: row; flex-wrap: wrap; }
|
|
615
|
+
.studio-ui .studio-list-group { display: none; }
|
|
616
|
+
.studio-ui .studio-component-summary { display: none; }
|
|
617
|
+
.studio-ui .studio-facts { grid-template-columns: 1fr; gap: 4px; }
|
|
618
|
+
}
|
|
619
|
+
@media (max-width: 480px) {
|
|
620
|
+
.studio-ui .studio-card, .studio-ui article, .studio-ui .studio-agents { padding: 12px; }
|
|
621
|
+
.studio-ui dl { grid-template-columns: 1fr; gap: 4px; }
|
|
622
|
+
.studio-ui dd { margin-bottom: 8px; }
|
|
623
|
+
}
|
|
624
|
+
`;
|
|
625
|
+
|
|
626
|
+
// src/ui.tsx
|
|
627
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
628
|
+
function StudioSurface({ children, className = "" }) {
|
|
629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `studio-ui ${className}`, children: [
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: studioStyles }),
|
|
631
|
+
children
|
|
632
|
+
] });
|
|
633
|
+
}
|
|
634
|
+
function Button({ primary = false, small = false, className = "", type = "button", ...props }) {
|
|
635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...props, type, className: `studio-button ${primary ? "studio-primary" : ""} ${small ? "studio-small" : ""} ${className}` });
|
|
636
|
+
}
|
|
637
|
+
function ChangeIndicator({ locale }) {
|
|
638
|
+
const labels = { ko: "\uBCC0\uACBD\uB428", en: "Modified", zh: "\u5DF2\u4FEE\u6539" };
|
|
639
|
+
const text = labels[locale.startsWith("ko") ? "ko" : locale.startsWith("zh") ? "zh" : "en"];
|
|
640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "studio-schema-meta", "data-studio-modified": "true", children: text });
|
|
641
|
+
}
|
|
642
|
+
function PageHead({ title, description, actions, children }) {
|
|
643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: `studio-page-head ${actions ? "studio-page-head-actions" : ""}`, children: [
|
|
644
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
|
|
646
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "studio-muted", children: description }),
|
|
647
|
+
children
|
|
648
|
+
] }),
|
|
649
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "studio-inline-actions", children: actions })
|
|
650
|
+
] });
|
|
651
|
+
}
|
|
652
|
+
function SectionHead({ title, description, actions, field: field2 = false }) {
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `studio-section-head ${field2 ? "studio-section-head-field" : ""}`, children: [
|
|
654
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "studio-panel-title", children: title }),
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "studio-muted", children: description })
|
|
657
|
+
] }) : typeof title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "studio-panel-title", children: title }) : title,
|
|
658
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "studio-inline-actions", children: actions })
|
|
659
|
+
] });
|
|
660
|
+
}
|
|
661
|
+
function Note({ children }) {
|
|
662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "studio-note", role: "note", children });
|
|
663
|
+
}
|
|
664
|
+
function Notice({ children, action }) {
|
|
665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "alert", className: "studio-notice-row", children: [
|
|
666
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children }),
|
|
667
|
+
action
|
|
668
|
+
] });
|
|
669
|
+
}
|
|
670
|
+
function Badge({ tone = "neutral", children }) {
|
|
671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "studio-badge", "data-tone": tone, children });
|
|
672
|
+
}
|
|
673
|
+
function SplitButton({ label, onClick, primary = false, disabled = false, actions = [], menuLabel }) {
|
|
674
|
+
const [open, setOpen] = import_react.default.useState(false);
|
|
675
|
+
const root = import_react.default.useRef(null);
|
|
676
|
+
const menuId = import_react.default.useId();
|
|
677
|
+
import_react.default.useEffect(() => {
|
|
678
|
+
if (!open) return;
|
|
679
|
+
const close = (event) => {
|
|
680
|
+
if (!root.current?.contains(event.target)) setOpen(false);
|
|
681
|
+
};
|
|
682
|
+
const escape = (event) => {
|
|
683
|
+
if (event.key === "Escape") setOpen(false);
|
|
684
|
+
};
|
|
685
|
+
document.addEventListener("pointerdown", close);
|
|
686
|
+
document.addEventListener("keydown", escape);
|
|
687
|
+
return () => {
|
|
688
|
+
document.removeEventListener("pointerdown", close);
|
|
689
|
+
document.removeEventListener("keydown", escape);
|
|
690
|
+
};
|
|
691
|
+
}, [open]);
|
|
692
|
+
const menu = actions.length > 0;
|
|
693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { ref: root, className: "studio-split", "data-menu": menu, children: [
|
|
694
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, { small: true, primary, disabled, onClick, children: label }),
|
|
695
|
+
menu && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, { small: true, primary, className: "studio-split-caret", disabled, "aria-label": menuLabel, "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((value) => !value), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
696
|
+
menu && open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { id: menuId, role: "menu", className: "studio-split-menu", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "menuitem", disabled: action.disabled, onClick: () => {
|
|
697
|
+
setOpen(false);
|
|
698
|
+
action.onSelect();
|
|
699
|
+
}, children: action.label }, action.label)) })
|
|
700
|
+
] });
|
|
701
|
+
}
|
|
702
|
+
function DetailDialog({ open, title, subtitle, onClose, closeLabel, footer, wide = false, compact = false, children }) {
|
|
703
|
+
const ref = import_react.default.useRef(null);
|
|
704
|
+
const opener = import_react.default.useRef(null);
|
|
705
|
+
const titleId = import_react.default.useId();
|
|
706
|
+
import_react.default.useEffect(() => {
|
|
707
|
+
const node = ref.current;
|
|
708
|
+
if (!node) return;
|
|
709
|
+
if (open && !node.open) {
|
|
710
|
+
opener.current = document.activeElement;
|
|
711
|
+
if (typeof node.showModal === "function") node.showModal();
|
|
712
|
+
else node.setAttribute("open", "");
|
|
713
|
+
} else if (!open && node.open) {
|
|
714
|
+
if (typeof node.close === "function") node.close();
|
|
715
|
+
else node.removeAttribute("open");
|
|
716
|
+
opener.current?.focus?.();
|
|
717
|
+
}
|
|
718
|
+
}, [open]);
|
|
719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dialog", { ref, className: `studio-detail-dialog ${wide ? "studio-dialog-wide" : compact ? "studio-dialog-compact" : ""}`, "aria-labelledby": titleId, onCancel: (event) => {
|
|
720
|
+
event.preventDefault();
|
|
721
|
+
onClose();
|
|
722
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "studio-dialog", children: [
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { children: [
|
|
724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: titleId, children: title }),
|
|
726
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "studio-muted", children: subtitle })
|
|
727
|
+
] }),
|
|
728
|
+
closeLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, { small: true, onClick: onClose, children: closeLabel })
|
|
729
|
+
] }),
|
|
730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "studio-dialog-body studio-selection-detail", children }),
|
|
731
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("footer", { children: footer })
|
|
732
|
+
] }) });
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// src/role-editor.tsx
|
|
736
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
737
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
738
|
+
function RoleEditor({ locale, roles, onChange, loadModels, defaultPersona = "" }) {
|
|
739
|
+
const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
740
|
+
const [selected, setSelected] = import_react2.default.useState();
|
|
741
|
+
const [catalog, setCatalog] = import_react2.default.useState();
|
|
742
|
+
const [error, setError] = import_react2.default.useState("");
|
|
743
|
+
const [loading, setLoading] = import_react2.default.useState(false);
|
|
744
|
+
const refresh = import_react2.default.useCallback(async () => {
|
|
745
|
+
if (!loadModels) return;
|
|
746
|
+
setLoading(true);
|
|
747
|
+
setError("");
|
|
748
|
+
try {
|
|
749
|
+
setCatalog(await loadModels());
|
|
750
|
+
} catch (e) {
|
|
751
|
+
setError(String(e));
|
|
752
|
+
} finally {
|
|
753
|
+
setLoading(false);
|
|
754
|
+
}
|
|
755
|
+
}, [loadModels]);
|
|
756
|
+
import_react2.default.useEffect(() => {
|
|
757
|
+
void refresh();
|
|
758
|
+
}, [refresh]);
|
|
759
|
+
const models = (catalog?.groups ?? []).flatMap((group) => group.models.map((model2) => ({ ...model2, value: `${group.id}/${model2.id}`, label: `${group.name} \xB7 ${model2.name}` })));
|
|
760
|
+
const role = selected === void 0 ? void 0 : roles[selected];
|
|
761
|
+
const model = models.find((model2) => model2.value === role?.model);
|
|
762
|
+
const update2 = (patch) => onChange(roles.map((role2, index) => index === selected ? { ...role2, ...patch } : role2));
|
|
763
|
+
const field2 = (label, content) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "studio-field", children: [
|
|
764
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: label }),
|
|
765
|
+
content
|
|
766
|
+
] });
|
|
767
|
+
const close = () => setSelected(void 0);
|
|
768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
769
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionHead, { title: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { className: "studio-panel-title", children: [
|
|
770
|
+
t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagents", "\u5B50\u4EE3\u7406"),
|
|
771
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-count", children: roles.length })
|
|
772
|
+
] }), description: t("\uBC14\uAFBC \uB0B4\uC6A9\uC740 \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uACE0 DSH\uC5D0 \uB2E4\uC2DC \uBC18\uC601\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Save the preset and reapply it to DSH after changes.", "\u4FEE\u6539\u540E\u9700\u4FDD\u5B58\u9884\u8BBE\u5E76\u91CD\u65B0\u5E94\u7528\u5230 DSH\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, disabled: loading || !loadModels, onClick: () => void refresh(), children: loading ? t("\uBAA8\uB378 \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading models\u2026", "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u2026") : t("\uBAA8\uB378 \uBAA9\uB85D \uC0C8\uB85C\uACE0\uCE68", "Refresh models", "\u5237\u65B0\u6A21\u578B\u5217\u8868") }),
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, onClick: () => {
|
|
775
|
+
setSelected(roles.length);
|
|
776
|
+
onChange([...roles, { name: "", role: "", model: "inherit", reasoning: "inherit", spawn: "fresh", persona: "" }]);
|
|
777
|
+
}, children: t("\uC5ED\uD560 \uCD94\uAC00", "Add role", "\u6DFB\u52A0\u89D2\u8272") })
|
|
778
|
+
] }) }),
|
|
779
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Note, { children: error }),
|
|
780
|
+
catalog?.failures.map((failure) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Note, { children: [
|
|
781
|
+
failure.name,
|
|
782
|
+
": ",
|
|
783
|
+
failure.message
|
|
784
|
+
] }, failure.name)),
|
|
785
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Note, { children: t(
|
|
786
|
+
"DSH\uC758 \uAE30\uBCF8 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uB3C4\uAD6C(subagent, subagent_fork, list_subagent_models)\uB97C subagent_role \uD558\uB098\uB85C \uD1B5\uD569\uD574 \uC81C\uACF5\uD569\uB2C8\uB2E4. \uAE30\uBCF8 \uB3C4\uAD6C\uB294 \uC790\uB3D9\uC73C\uB85C \uBE60\uC9C0\uACE0, subagent_role\uC758 \uC124\uBA85\uACFC \uC778\uC790\uB294 \uD504\uB86C\uD504\uD2B8\xB7\uB3C4\uAD6C \uD0ED\uC758 \uB3C4\uAD6C \uBAA9\uB85D\uC5D0\uC11C \uD655\uC778\uD558\uACE0 \uC218\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
787
|
+
"Studio provides the DSH default subagent tools (subagent, subagent_fork, list_subagent_models) as a single subagent_role tool. The default tools are removed automatically; review or edit subagent_role in the tool list on the Prompts & tools tab.",
|
|
788
|
+
"\u5C06 DSH \u9ED8\u8BA4\u5B50\u4EE3\u7406\u5DE5\u5177\uFF08subagent\u3001subagent_fork\u3001list_subagent_models\uFF09\u5408\u5E76\u4E3A\u4E00\u4E2A subagent_role \u5DE5\u5177\u63D0\u4F9B\u3002\u9ED8\u8BA4\u5DE5\u5177\u4F1A\u88AB\u81EA\u52A8\u79FB\u9664\uFF1B\u53EF\u5728\u201C\u63D0\u793A\u8BCD\u4E0E\u5DE5\u5177\u201D\u9875\u7684\u5DE5\u5177\u5217\u8868\u4E2D\u67E5\u770B\u6216\u7F16\u8F91 subagent_role\u3002"
|
|
789
|
+
) }),
|
|
790
|
+
!roles.length && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-muted", role: "status", children: t("\uC815\uC758\uB41C \uC5ED\uD560\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774 \uC0C1\uD0DC\uC5D0\uC11C\uB294 subagent_role\uC774 \uBD80\uBAA8\uC640 \uAC19\uC740 \uBAA8\uB378\xB7\uCD94\uB860\xB7\uC9C0\uCE68\uC73C\uB85C \uC0C8 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4.", "No roles defined. subagent_role then starts a new subagent with the same model, reasoning and instructions as the parent.", "\u5C1A\u672A\u5B9A\u4E49\u89D2\u8272\u3002\u6B64\u65F6 subagent_role \u4F1A\u4EE5\u4E0E\u7236\u4EE3\u7406\u76F8\u540C\u7684\u6A21\u578B\u3001\u63A8\u7406\u548C\u6307\u4EE4\u542F\u52A8\u65B0\u7684\u5B50\u4EE3\u7406\u3002") }),
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "studio-tool-cards studio-card-pair", children: roles.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("article", { className: "studio-role-card", children: [
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-card-head", children: [
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: item.name || t("\uC774\uB984 \uC5C6\uC74C", "Untitled", "\u672A\u547D\u540D") }),
|
|
794
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { tone: "outline", children: item.spawn === "fork" ? t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30", "Continue parent", "\u7EE7\u627F\u7236\u5BF9\u8BDD") : t("\uC0C8 \uB300\uD654", "New conversation", "\u65B0\u5BF9\u8BDD") })
|
|
795
|
+
] }),
|
|
796
|
+
item.role && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-card-text studio-mono", children: item.role }),
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "studio-card-meta", children: [
|
|
798
|
+
item.model === "inherit" ? t("\uBD80\uBAA8 \uBAA8\uB378 \uC0AC\uC6A9", "Inherit parent model", "\u7EE7\u627F\u7236\u7EA7\u6A21\u578B") : models.find((model2) => model2.value === item.model)?.label ?? item.model,
|
|
799
|
+
" \xB7 ",
|
|
800
|
+
t("\uCD94\uB860", "Reasoning", "\u63A8\u7406"),
|
|
801
|
+
" ",
|
|
802
|
+
item.reasoning === "inherit" ? t("\uAE30\uBCF8", "inherit", "\u9ED8\u8BA4") : item.reasoning
|
|
803
|
+
] }),
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "studio-card-footer", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, "aria-haspopup": "dialog", onClick: () => setSelected(index), children: t("\uD3B8\uC9D1", "Edit", "\u7F16\u8F91") }) })
|
|
805
|
+
] }, index)) }),
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
807
|
+
DetailDialog,
|
|
808
|
+
{
|
|
809
|
+
open: role !== void 0,
|
|
810
|
+
title: role?.name || t("\uC0C8 \uC5ED\uD560", "New role", "\u65B0\u89D2\u8272"),
|
|
811
|
+
subtitle: t("\uC5ED\uD560 \uD3B8\uC9D1", "Edit role", "\u7F16\u8F91\u89D2\u8272"),
|
|
812
|
+
onClose: close,
|
|
813
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, onClick: () => {
|
|
815
|
+
onChange(roles.filter((_, index) => index !== selected));
|
|
816
|
+
close();
|
|
817
|
+
}, children: t("\uC5ED\uD560 \uC0AD\uC81C", "Remove role", "\u79FB\u9664\u89D2\u8272") }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, primary: true, onClick: close, children: t("\uC644\uB8CC", "Done", "\u5B8C\u6210") })
|
|
819
|
+
] }),
|
|
820
|
+
children: role && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-field-grid", children: [
|
|
822
|
+
field2(t("\uC774\uB984", "Name", "\u540D\u79F0"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: role.name, onChange: (e) => update2({ name: e.target.value }) })),
|
|
823
|
+
field2(t("\uC5ED\uD560 ID", "Role", "\u89D2\u8272"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "studio-mono", value: role.role, onChange: (e) => update2({ role: e.target.value }) }))
|
|
824
|
+
] }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-field-grid", children: [
|
|
826
|
+
field2(t("\uBAA8\uB378", "Model", "\u6A21\u578B"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.model, onChange: (e) => update2({ model: e.target.value, reasoning: "inherit" }), children: [
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "inherit", children: t("\uBD80\uBAA8 \uBAA8\uB378 \uC0AC\uC6A9", "Inherit parent model", "\u7EE7\u627F\u7236\u7EA7\u6A21\u578B") }),
|
|
828
|
+
role.model !== "inherit" && !model && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: role.model, disabled: true, children: [
|
|
829
|
+
role.model,
|
|
830
|
+
" \xB7 ",
|
|
831
|
+
t("\uBAA9\uB85D\uC5D0 \uC5C6\uC74C \xB7 \uBC18\uC601\uD560 \uB54C \uD655\uC778", "Not confirmed in catalog \xB7 checked on apply", "\u76EE\u5F55\u4E2D\u672A\u786E\u8BA4 \xB7 \u5E94\u7528\u65F6\u9A8C\u8BC1")
|
|
832
|
+
] }),
|
|
833
|
+
models.map((model2) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: model2.value, children: model2.label }, model2.value))
|
|
834
|
+
] })),
|
|
835
|
+
field2(t("\uCD94\uB860 \uC218\uC900", "Reasoning", "\u63A8\u7406\u7EA7\u522B"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.reasoning, disabled: !model, onChange: (e) => update2({ reasoning: e.target.value }), children: [
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "inherit", children: role.model === "inherit" ? t("\uBD80\uBAA8 \uC124\uC815 \uC0AC\uC6A9", "Inherit parent setting", "\u7EE7\u627F\u7236\u7EA7\u8BBE\u7F6E") : t("\uBAA8\uB378 \uAE30\uBCF8\uAC12", "Model default", "\u6A21\u578B\u9ED8\u8BA4\u503C") }),
|
|
837
|
+
role.reasoning !== "inherit" && !model?.reasoning?.efforts.some((e) => e.id === role.reasoning) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: role.reasoning, disabled: true, children: [
|
|
838
|
+
role.reasoning,
|
|
839
|
+
" \xB7 ",
|
|
840
|
+
t("\uC9C0\uC6D0 \uC5EC\uBD80 \uD655\uC778 \uD544\uC694", "Check support", "\u9700\u786E\u8BA4\u652F\u6301")
|
|
841
|
+
] }),
|
|
842
|
+
model?.reasoning?.efforts.map((e) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: e.id, children: e.name }, e.id))
|
|
843
|
+
] })),
|
|
844
|
+
field2(t("\uC2DC\uC791 \uBC29\uC2DD", "Spawn mode", "\u751F\u6210\u65B9\u5F0F"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.spawn, onChange: (e) => update2({ spawn: e.target.value }), children: [
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fresh", children: t("\uC0C8 \uB300\uD654 (Fresh)", "New conversation (Fresh)", "\u65B0\u5BF9\u8BDD\uFF08Fresh\uFF09") }),
|
|
846
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fork", children: t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30 (Fork)", "Continue parent (Fork)", "\u7EE7\u627F\u7236\u5BF9\u8BDD\uFF08Fork\uFF09") })
|
|
847
|
+
] }))
|
|
848
|
+
] }),
|
|
849
|
+
field2(t("\uC5ED\uD560 \uC9C0\uCE68 (persona)", "User instructions (persona)", "\u7528\u6237\u6307\u4EE4\uFF08persona\uFF09"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { rows: 6, value: role.persona, placeholder: defaultPersona, onChange: (e) => update2({ persona: e.target.value }) })),
|
|
850
|
+
!role.persona && defaultPersona && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-muted studio-hint", children: t("\uD750\uB9B0 \uAE00\uC528\uB294 \uD504\uB9AC\uC14B\uC758 \uAE30\uBCF8 persona\uC785\uB2C8\uB2E4. \uBE44\uC6CC \uB450\uBA74 \uC774 \uB0B4\uC6A9\uC774 \uADF8\uB300\uB85C \uC4F0\uC785\uB2C8\uB2E4.", "The dimmed text is the preset default persona; it is used while this field is empty.", "\u6D45\u8272\u6587\u5B57\u662F\u9884\u8BBE\u7684\u9ED8\u8BA4 persona\uFF0C\u7559\u7A7A\u65F6\u4F7F\u7528\u8BE5\u5185\u5BB9\u3002") })
|
|
851
|
+
] })
|
|
852
|
+
}
|
|
853
|
+
)
|
|
854
|
+
] });
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/optimization-prototype.tsx
|
|
858
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
859
|
+
|
|
860
|
+
// src/master-extensions-editor.tsx
|
|
861
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
862
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
863
|
+
function MasterExtensionsEditor({ locale, actions }) {
|
|
864
|
+
const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
865
|
+
const [text, setText] = import_react3.default.useState("[]");
|
|
866
|
+
const [error, setError] = import_react3.default.useState("");
|
|
867
|
+
const [busy, setBusy] = import_react3.default.useState(false);
|
|
868
|
+
const [loaded, setLoaded] = import_react3.default.useState(false);
|
|
869
|
+
import_react3.default.useEffect(() => {
|
|
870
|
+
let active = true;
|
|
871
|
+
if (actions) actions.read().then((value) => {
|
|
872
|
+
if (active) {
|
|
873
|
+
setText(JSON.stringify(value, null, 2));
|
|
874
|
+
setLoaded(true);
|
|
875
|
+
}
|
|
876
|
+
}, (e) => {
|
|
877
|
+
if (active) setError(String(e));
|
|
878
|
+
});
|
|
879
|
+
return () => {
|
|
880
|
+
active = false;
|
|
881
|
+
};
|
|
882
|
+
}, [actions]);
|
|
883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-page-stack", children: [
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageHead, { title: t("\uB3C4\uAD6C \uC81C\uACF5\uC790", "Tool providers", "\u5DE5\u5177\u63D0\u4F9B\u8005"), description: t("\uC124\uCE58\uB41C \uD50C\uB7EC\uADF8\uC778\uC758 \uB3C4\uAD6C\uB97C Studio \uB3C4\uAD6C \uBAA9\uB85D\uC5D0 \uB4F1\uB85D\uD569\uB2C8\uB2E4. \uB4F1\uB85D\uD55C \uB3C4\uAD6C\uB294 \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uACE0\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Register installed plugin tools in the Studio tool list so presets can select them.", "\u5C06\u5DF2\u5B89\u88C5\u63D2\u4EF6\u7684\u5DE5\u5177\u6CE8\u518C\u5230 Studio \u5DE5\u5177\u5217\u8868\uFF0C\u4F9B\u9884\u8BBE\u9009\u62E9") }),
|
|
885
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t("\uB4F1\uB85D\uD558\uBA74 \uD50C\uB7EC\uADF8\uC778 \uCF54\uB4DC\uAC00 \uC2E4\uD589\uB418\uBBC0\uB85C \uC2E0\uB8B0\uD558\uB294 \uD50C\uB7EC\uADF8\uC778\uB9CC \uCD94\uAC00\uD558\uC138\uC694. \uD328\uD0A4\uC9C0\uB97C \uC124\uCE58\uD558\uC9C0\uB294 \uC54A\uC73C\uBA70, \uC124\uC815\uC740 \uC774 \uCEF4\uD4E8\uD130\uC5D0 \uD3C9\uBB38\uC73C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4.", "Register installed provider compositions as JSON. This does not install packages or generate tool code. Registration executes plugin code: add trusted providers only. Settings are stored locally as plaintext. Applied presets are not automatically changed.", "\u4EE5 JSON \u6CE8\u518C\u5DF2\u5B89\u88C5\u7684\u63D0\u4F9B\u8005\u914D\u7F6E\u3002\u4E0D\u5B89\u88C5\u8F6F\u4EF6\u5305\u6216\u751F\u6210\u5DE5\u5177\u4EE3\u7801\u3002\u6CE8\u518C\u4F1A\u6267\u884C\u63D2\u4EF6\u4EE3\u7801\uFF0C\u8BF7\u4EC5\u6DFB\u52A0\u53EF\u4FE1\u63D0\u4F9B\u8005\u3002\u8BBE\u7F6E\u4EE5\u660E\u6587\u4FDD\u5B58\u5728\u672C\u5730\u3002\u5DF2\u5E94\u7528\u7684\u9884\u8BBE\u4E0D\u4F1A\u81EA\u52A8\u6539\u53D8\u3002") }),
|
|
886
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("ol", { className: "studio-steps", children: [
|
|
887
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uD50C\uB7EC\uADF8\uC778\uC774 \uD604\uC7AC DSH \uD504\uB85C\uD544\uC5D0 \uC124\uCE58\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778\uD569\uB2C8\uB2E4.", "Ensure the plugin is installed in this DSH profile. Packages are not installed automatically.", "\u786E\u8BA4\u63D2\u4EF6\u5DF2\u5B89\u88C5\u5728\u5F53\u524D DSH \u914D\u7F6E\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002") }),
|
|
888
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uC544\uB798 \uBC30\uC5F4\uC5D0 id(\uACE0\uC720\uD55C \uC18C\uBB38\uC790 \uC2DD\uBCC4\uC790), name(\uD328\uD0A4\uC9C0 \uC774\uB984), config(\uD50C\uB7EC\uADF8\uC778 \uC124\uC815)\uB97C \uC785\uB825\uD569\uB2C8\uB2E4.", "Add an entry with id (unique lowercase identifier), name (exact package name), and config (public plugin settings).", "\u5728\u6570\u7EC4\u4E2D\u586B\u5199 id\uFF08\u552F\u4E00\u5C0F\u5199\u6807\u8BC6\u7B26\uFF09\u3001name\uFF08\u51C6\u786E\u7684\u8F6F\u4EF6\u5305\u540D\uFF09\u548C config\uFF08\u63D2\u4EF6\u516C\u5F00\u8BBE\u7F6E\uFF09\u3002") }),
|
|
889
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uD655\uC778 \uD6C4 \uB4F1\uB85D\uC744 \uB204\uB974\uBA74 \uB3C4\uAD6C \uBAA9\uB85D\uC774 \uAC31\uC2E0\uB429\uB2C8\uB2E4. \uD544\uC694\uD55C \uB3C4\uAD6C\uB97C \uACE8\uB77C \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uC138\uC694.", "Validate and update master to refresh the tool list, then select the tools and save your preset.", "\u9A8C\u8BC1\u5E76\u66F4\u65B0\u4E3B\u9884\u8BBE\u540E\uFF0C\u9009\u62E9\u6240\u9700\u5DE5\u5177\u5E76\u4FDD\u5B58\u9884\u8BBE\u3002") })
|
|
890
|
+
] }),
|
|
891
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted", children: t("\uC608\uC2DC: \uC124\uCE58\uB41C subagent \uD50C\uB7EC\uADF8\uC778\uC744 \uB2E4\uB978 \uB3C4\uAD6C \uC774\uB984\uC73C\uB85C \uB4F1\uB85D", "Example: register the installed subagent provider under a distinct tool name", "\u793A\u4F8B\uFF1A\u4F7F\u7528\u4E0D\u540C\u5DE5\u5177\u540D\u6CE8\u518C\u5DF2\u5B89\u88C5\u7684 subagent \u63D0\u4F9B\u8005") }),
|
|
892
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { children: JSON.stringify([{ id: "extra-agent", name: "@deepseek-ai/dsh-tool-subagent", config: { provider: "spawn", toolName: "studio_extra_agent" } }], null, 2) }),
|
|
893
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t("\uBAA9\uB85D \uC804\uCCB4\uAC00 \uC0C8 \uB0B4\uC6A9\uC73C\uB85C \uBC14\uB01D\uB2C8\uB2E4. \uAE30\uC874 \uD56D\uBAA9\uC744 \uC720\uC9C0\uD558\uB824\uBA74 \uBC30\uC5F4\uC5D0 \uB0A8\uACA8 \uB450\uACE0, \uBAA8\uB450 \uC9C0\uC6B0\uB824\uBA74 []\uB97C \uB4F1\uB85D\uD558\uC138\uC694. \uB3C4\uAD6C \uC774\uB984\uC774 \uACB9\uCE58\uC9C0 \uC54A\uAC8C \uD558\uC138\uC694.", "Saving replaces the entire extension list. Keep existing entries to retain them; [] removes all added providers only. Avoid existing tool names. Missing plugin service dependencies can prevent activation.", "\u4FDD\u5B58\u4F1A\u66FF\u6362\u6574\u4E2A\u9644\u52A0\u63D0\u4F9B\u8005\u5217\u8868\u3002\u4FDD\u7559\u5DF2\u6709\u6761\u76EE\u4EE5\u514D\u5220\u9664\uFF1B\u4FDD\u5B58 [] \u4EC5\u79FB\u9664\u5168\u90E8\u9644\u52A0\u63D0\u4F9B\u8005\u3002\u907F\u514D\u5DE5\u5177\u91CD\u540D\uFF1B\u7F3A\u5C11\u4F9D\u8D56\u670D\u52A1\u53EF\u80FD\u5BFC\u81F4\u6FC0\u6D3B\u5931\u8D25\u3002") }),
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "studio-field", children: [
|
|
895
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("\uB4F1\uB85D \uBAA9\uB85D (JSON)", "Provider composition", "\u63D0\u4F9B\u8005\u914D\u7F6E") }),
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("textarea", { rows: 6, className: "studio-mono", value: text, disabled: !loaded || busy, onChange: (event) => setText(event.target.value) })
|
|
897
|
+
] }),
|
|
898
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "studio-inline-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { disabled: !loaded || busy, onClick: async () => {
|
|
899
|
+
if (!actions) return;
|
|
900
|
+
setBusy(true);
|
|
901
|
+
setError("");
|
|
902
|
+
try {
|
|
903
|
+
await actions.save(text);
|
|
904
|
+
} catch (e) {
|
|
905
|
+
setError(String(e));
|
|
906
|
+
} finally {
|
|
907
|
+
setBusy(false);
|
|
908
|
+
}
|
|
909
|
+
}, children: t("\uD655\uC778 \uD6C4 \uB4F1\uB85D", "Validate and update master", "\u9A8C\u8BC1\u5E76\u66F4\u65B0\u4E3B\u9884\u8BBE") }) }),
|
|
910
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", children: error })
|
|
911
|
+
] });
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// src/config-editor.tsx
|
|
915
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
916
|
+
|
|
917
|
+
// src/change-indicator.tsx
|
|
918
|
+
function hasChangedOverride(base, override) {
|
|
919
|
+
if (override === void 0) return false;
|
|
920
|
+
if (override !== null && typeof override === "object" && !Array.isArray(override)) {
|
|
921
|
+
const source = base !== null && typeof base === "object" ? base : {};
|
|
922
|
+
return Object.entries(override).some(([key, value]) => hasChangedOverride(source[key], value));
|
|
923
|
+
}
|
|
924
|
+
return JSON.stringify(base) !== JSON.stringify(override);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/item-picker.tsx
|
|
928
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
929
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
930
|
+
function ItemPicker({ label, items, selected, onChange, labels, renderDetails, isModified, hasDetails }) {
|
|
931
|
+
const [query, setQuery] = import_react4.default.useState("");
|
|
932
|
+
const [filter, setFilter] = import_react4.default.useState("all");
|
|
933
|
+
const [detail, setDetail] = import_react4.default.useState();
|
|
934
|
+
const chosen = new Set(selected);
|
|
935
|
+
const modified = (name) => chosen.has(name) && (isModified?.(name) ?? false);
|
|
936
|
+
const text = query.trim().toLowerCase();
|
|
937
|
+
const visible = items.filter((item) => (filter === "all" || (filter === "selected" ? chosen.has(item.name) : modified(item.name))) && (!text || `${item.name}
|
|
938
|
+
${item.title ?? ""}
|
|
939
|
+
${item.description}
|
|
940
|
+
${item.searchText ?? ""}`.toLowerCase().includes(text)));
|
|
941
|
+
const counts = { all: items.length, selected: items.filter((item) => chosen.has(item.name)).length, modified: items.filter((item) => modified(item.name)).length };
|
|
942
|
+
const toggle = (name) => onChange(chosen.has(name) ? selected.filter((value) => value !== name) : [...selected, name]);
|
|
943
|
+
const open = items.find((item) => item.name === detail && chosen.has(item.name));
|
|
944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "studio-picker", children: [
|
|
945
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "studio-picker-bar", children: [
|
|
946
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "search", "aria-label": labels.search, placeholder: labels.searchHint, value: query, onChange: (event) => setQuery(event.target.value) }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "studio-picker-filters", role: "radiogroup", "aria-label": labels.filter, children: ["all", "selected", "modified"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", role: "radio", "aria-checked": filter === value, className: "studio-picker-filter", onClick: () => setFilter(value), children: [
|
|
948
|
+
labels[value],
|
|
949
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-count", children: counts[value] })
|
|
950
|
+
] }, value)) })
|
|
951
|
+
] }),
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("ul", { className: "studio-picker-list", "aria-label": label, children: [
|
|
953
|
+
visible.map((item) => {
|
|
954
|
+
const on = chosen.has(item.name);
|
|
955
|
+
const blocked = !on && item.disabledReason !== void 0;
|
|
956
|
+
const details = on && renderDetails !== void 0 && (hasDetails?.(item.name) ?? true);
|
|
957
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "studio-picker-row", "data-selected": on, children: [
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", role: "switch", "aria-checked": on, disabled: blocked, className: "studio-picker-toggle", "aria-label": `${item.title ?? item.name}`, onClick: () => toggle(item.name), children: [
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-check", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3.5 8.5l3 3 6-7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "studio-picker-text", children: [
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "studio-picker-title", children: [
|
|
962
|
+
item.title ?? item.name,
|
|
963
|
+
item.subtitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-subtitle studio-mono", children: item.subtitle })
|
|
964
|
+
] }),
|
|
965
|
+
(item.disabledReason && !on ? item.disabledReason : item.description) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-description", children: item.disabledReason && !on ? item.disabledReason : item.description })
|
|
966
|
+
] })
|
|
967
|
+
] }),
|
|
968
|
+
modified(item.name) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-badge", "data-tone": "info", "data-studio-modified": "true", children: labels.modifiedTag }),
|
|
969
|
+
details && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { small: true, "aria-label": `${labels.settings}: ${item.name}`, "aria-haspopup": "dialog", onClick: () => setDetail(item.name), children: labels.settings })
|
|
970
|
+
] }, item.name);
|
|
971
|
+
}),
|
|
972
|
+
!visible.length && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "studio-picker-empty", role: "status", children: [
|
|
973
|
+
text ? labels.noResults : labels.empty,
|
|
974
|
+
(text || filter !== "all") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { small: true, onClick: () => {
|
|
975
|
+
setQuery("");
|
|
976
|
+
setFilter("all");
|
|
977
|
+
}, children: labels.clear })
|
|
978
|
+
] })
|
|
979
|
+
] }),
|
|
980
|
+
renderDetails && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DetailDialog, { open: open !== void 0, title: open?.title ?? open?.name, subtitle: open?.subtitle, closeLabel: labels.done, onClose: () => setDetail(void 0), children: open && renderDetails(open.name) })
|
|
981
|
+
] });
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// src/config-editor.tsx
|
|
985
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
986
|
+
var copy = {
|
|
987
|
+
en: {
|
|
988
|
+
list: "Configs",
|
|
989
|
+
reset: "Reset override",
|
|
990
|
+
unavailable: "Schema unavailable; editing is disabled.",
|
|
991
|
+
inherited: "Base value (not overridden)",
|
|
992
|
+
overridden: "Override",
|
|
993
|
+
unset: "Not set",
|
|
994
|
+
unsupported: "This schema type is not yet supported by the form. Existing values are preserved; remove the Config to reset them.",
|
|
995
|
+
json: "Config",
|
|
996
|
+
invalid: "Enter valid JSON.",
|
|
997
|
+
object: "Enter a JSON object.",
|
|
998
|
+
number: "Enter a valid number.",
|
|
999
|
+
picker: { filter: "Show", search: "Search execution settings", searchHint: "Search plugin names, fields or descriptions", all: "All", selected: "On", modified: "Modified", settings: "Edit", done: "Done", empty: "No Configs", noResults: "No matching results.", modifiedTag: "Modified", clear: "Show all" },
|
|
1000
|
+
items: { add: "Add", remove: "Remove", draft: "New item", key: "New key" }
|
|
1001
|
+
},
|
|
1002
|
+
ko: {
|
|
1003
|
+
list: "Config",
|
|
1004
|
+
reset: "\uAE30\uBCF8\uAC12\uC73C\uB85C",
|
|
1005
|
+
unavailable: "\uC2A4\uD0A4\uB9C8\uB97C \uC77D\uC744 \uC218 \uC5C6\uC5B4 \uD3B8\uC9D1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
1006
|
+
inherited: "\uAE30\uBCF8\uAC12",
|
|
1007
|
+
overridden: "\uBCC0\uACBD\uB428",
|
|
1008
|
+
unset: "\uBBF8\uC124\uC815",
|
|
1009
|
+
unsupported: "\uC774 \uD615\uC2DD\uC740 \uC544\uC9C1 \uD3B8\uC9D1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uAE30\uC874 \uAC12\uC740 \uC720\uC9C0\uB418\uBA70, Config\uB97C \uB044\uBA74 \uCD08\uAE30\uD654\uB429\uB2C8\uB2E4.",
|
|
1010
|
+
json: "Config",
|
|
1011
|
+
invalid: "\uC62C\uBC14\uB978 JSON\uC744 \uC785\uB825\uD558\uC138\uC694.",
|
|
1012
|
+
object: "JSON \uAC1D\uCCB4\uB97C \uC785\uB825\uD558\uC138\uC694.",
|
|
1013
|
+
number: "\uC62C\uBC14\uB978 \uC22B\uC790\uB97C \uC785\uB825\uD558\uC138\uC694.",
|
|
1014
|
+
picker: { filter: "\uBCF4\uAE30", search: "\uC124\uC815 \uAC80\uC0C9", searchHint: "\uD50C\uB7EC\uADF8\uC778 \uC774\uB984, \uD544\uB4DC, \uC124\uBA85\uC73C\uB85C \uAC80\uC0C9", all: "\uC804\uCCB4", selected: "\uCF1C\uC9D0", modified: "\uBCC0\uACBD\uB428", settings: "\uC124\uC815", done: "\uC644\uB8CC", empty: "\uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.", noResults: "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", modifiedTag: "\uBCC0\uACBD\uB428", clear: "\uC804\uCCB4 \uBCF4\uAE30" },
|
|
1015
|
+
items: { add: "\uCD94\uAC00", remove: "\uC0AD\uC81C", draft: "\uC0C8 \uD56D\uBAA9", key: "\uC0C8 \uD0A4" }
|
|
1016
|
+
},
|
|
1017
|
+
zh: {
|
|
1018
|
+
list: "Config",
|
|
1019
|
+
reset: "\u91CD\u7F6E\u8986\u76D6",
|
|
1020
|
+
unavailable: "\u67B6\u6784\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u7F16\u8F91",
|
|
1021
|
+
inherited: "\u57FA\u7840\u503C\uFF08\u672A\u8986\u76D6\uFF09",
|
|
1022
|
+
overridden: "\u8986\u76D6",
|
|
1023
|
+
unset: "\u672A\u8BBE\u7F6E",
|
|
1024
|
+
unsupported: "\u8868\u5355\u6682\u4E0D\u652F\u6301\u6B64\u8BBE\u7F6E\u7C7B\u578B\u3002\u4FDD\u7559\u73B0\u6709\u503C\uFF1B\u5173\u95ED Config \u53EF\u91CD\u7F6E\u3002",
|
|
1025
|
+
json: "Config",
|
|
1026
|
+
invalid: "\u8BF7\u8F93\u5165\u6709\u6548\u7684 JSON",
|
|
1027
|
+
object: "\u8BF7\u8F93\u5165 JSON \u5BF9\u8C61",
|
|
1028
|
+
number: "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
|
|
1029
|
+
picker: { filter: "\u663E\u793A", search: "\u641C\u7D22\u6267\u884C\u8BBE\u7F6E", searchHint: "\u6309\u63D2\u4EF6\u540D\u79F0\u3001\u5B57\u6BB5\u6216\u63CF\u8FF0\u641C\u7D22", all: "\u5168\u90E8", selected: "\u5DF2\u5F00\u542F", modified: "\u5DF2\u4FEE\u6539", settings: "\u8BBE\u7F6E", done: "\u5B8C\u6210", empty: "\u6CA1\u6709 Config", noResults: "\u6CA1\u6709\u5339\u914D\u7ED3\u679C\u3002", modifiedTag: "\u5DF2\u4FEE\u6539", clear: "\u663E\u793A\u5168\u90E8" },
|
|
1030
|
+
items: { add: "\u6DFB\u52A0", remove: "\u5220\u9664", draft: "\u65B0\u9879", key: "\u65B0\u952E" }
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
var own = (value, key) => isObject(value) && Object.hasOwn(value, key);
|
|
1034
|
+
function isObject(value) {
|
|
1035
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1036
|
+
}
|
|
1037
|
+
function at(value, path) {
|
|
1038
|
+
return path.reduce((node, key) => own(node, key) ? node[key] : void 0, value);
|
|
1039
|
+
}
|
|
1040
|
+
function has(value, path) {
|
|
1041
|
+
return path.length === 0 || own(at(value, path.slice(0, -1)), path[path.length - 1]);
|
|
1042
|
+
}
|
|
1043
|
+
function update(value, path, next, reset = false) {
|
|
1044
|
+
if (!path.length) return next === void 0 ? {} : next;
|
|
1045
|
+
const [key, ...rest] = path;
|
|
1046
|
+
const result = { ...value };
|
|
1047
|
+
if (rest.length) {
|
|
1048
|
+
const child = update(isObject(value[key]) ? value[key] : {}, rest, next, reset);
|
|
1049
|
+
if (reset && !Object.keys(child).length) delete result[key];
|
|
1050
|
+
else Object.defineProperty(result, key, { value: child, enumerable: true, writable: true, configurable: true });
|
|
1051
|
+
} else if (reset) delete result[key];
|
|
1052
|
+
else Object.defineProperty(result, key, { value: next, enumerable: true, writable: true, configurable: true });
|
|
1053
|
+
return result;
|
|
1054
|
+
}
|
|
1055
|
+
function merged(base, override) {
|
|
1056
|
+
if (!isObject(base) || !isObject(override)) return override === void 0 ? base : override;
|
|
1057
|
+
return Object.fromEntries([.../* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(override)])].map((key) => [key, own(override, key) ? merged(base[key], override[key]) : base[key]]));
|
|
1058
|
+
}
|
|
1059
|
+
function resolve(schema, root) {
|
|
1060
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1061
|
+
while (typeof schema.$ref === "string") {
|
|
1062
|
+
const ref = schema.$ref;
|
|
1063
|
+
if (!ref.startsWith("#/") || seen.has(ref)) return schema;
|
|
1064
|
+
seen.add(ref);
|
|
1065
|
+
const target = at(root, ref.slice(2).split("/").map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~")));
|
|
1066
|
+
if (!isObject(target)) return schema;
|
|
1067
|
+
const { $ref: _, ...siblings } = schema;
|
|
1068
|
+
schema = { ...target, ...siblings };
|
|
1069
|
+
}
|
|
1070
|
+
return schema;
|
|
1071
|
+
}
|
|
1072
|
+
function pathLabel(path) {
|
|
1073
|
+
return path.reduce((text, segment) => /^\d+$/.test(segment) ? `${text}[${segment}]` : `${text}.${segment}`);
|
|
1074
|
+
}
|
|
1075
|
+
var loaderBranch = (branch) => isObject(branch) && branch.$ref === "#/$defs/loaderExpression";
|
|
1076
|
+
function unwrapExpression(raw, root) {
|
|
1077
|
+
const schema = resolve(raw, root);
|
|
1078
|
+
if (!Array.isArray(schema.anyOf)) return schema;
|
|
1079
|
+
const literal = schema.anyOf.filter((branch) => !loaderBranch(branch));
|
|
1080
|
+
if (literal.length !== 1 || literal.length === schema.anyOf.length || !isObject(literal[0])) return schema;
|
|
1081
|
+
const { anyOf: _, ...metadata } = schema;
|
|
1082
|
+
return { ...resolve(literal[0], root), ...metadata };
|
|
1083
|
+
}
|
|
1084
|
+
var scalarTypes = ["string", "number", "integer", "boolean"];
|
|
1085
|
+
function scalarType(schema, root) {
|
|
1086
|
+
const resolved = unwrapExpression(schema, root);
|
|
1087
|
+
const types = (Array.isArray(resolved.type) ? resolved.type : [resolved.type]).filter((type) => type !== "null");
|
|
1088
|
+
return types.length === 1 && typeof types[0] === "string" ? types[0] : void 0;
|
|
1089
|
+
}
|
|
1090
|
+
function renderable(schema, root) {
|
|
1091
|
+
if (schema.const !== void 0 || Array.isArray(schema.enum)) return schema;
|
|
1092
|
+
const type = scalarType(schema, root);
|
|
1093
|
+
if (type !== void 0 && scalarTypes.includes(type)) return { ...schema, type };
|
|
1094
|
+
if (type === "object" && !own(schema, "patternProperties") && (isObject(schema.properties) || isObject(schema.additionalProperties))) return { ...schema, type };
|
|
1095
|
+
if (type === "array" && isObject(schema.items)) return { ...schema, type };
|
|
1096
|
+
return void 0;
|
|
1097
|
+
}
|
|
1098
|
+
function unionBranches(raw, root, depth = 0) {
|
|
1099
|
+
if (depth > 8) return void 0;
|
|
1100
|
+
const schema = unwrapExpression(raw, root);
|
|
1101
|
+
if (Array.isArray(schema.anyOf)) {
|
|
1102
|
+
const branches = [];
|
|
1103
|
+
for (const branch2 of schema.anyOf) {
|
|
1104
|
+
const nested = unionBranches(branch2, root, depth + 1);
|
|
1105
|
+
if (nested === void 0) return void 0;
|
|
1106
|
+
branches.push(...nested);
|
|
1107
|
+
}
|
|
1108
|
+
return branches;
|
|
1109
|
+
}
|
|
1110
|
+
const types = Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type];
|
|
1111
|
+
if (schema.type !== void 0 && !types.some((type) => type !== "null")) return [];
|
|
1112
|
+
const branch = renderable(schema, root);
|
|
1113
|
+
return branch === void 0 ? void 0 : [branch];
|
|
1114
|
+
}
|
|
1115
|
+
function matchesChoice(choice, value) {
|
|
1116
|
+
if (choice.const !== void 0) return Object.is(choice.const, value);
|
|
1117
|
+
if (Array.isArray(choice.enum)) return choice.enum.some((item) => Object.is(item, value));
|
|
1118
|
+
if (choice.type === "object") return isObject(value);
|
|
1119
|
+
if (choice.type === "array") return Array.isArray(value);
|
|
1120
|
+
if (choice.type === "integer") return typeof value === "number" && Number.isInteger(value);
|
|
1121
|
+
if (choice.type === "number") return typeof value === "number";
|
|
1122
|
+
if (choice.type === "boolean") return typeof value === "boolean";
|
|
1123
|
+
return choice.type === "string" && typeof value === "string";
|
|
1124
|
+
}
|
|
1125
|
+
function choiceLabel(choice) {
|
|
1126
|
+
if (choice.const !== void 0) return typeof choice.const === "string" ? choice.const : JSON.stringify(choice.const);
|
|
1127
|
+
if (Array.isArray(choice.enum)) return choice.enum.map((item) => typeof item === "string" ? item : JSON.stringify(item)).join(", ");
|
|
1128
|
+
if (typeof choice.title === "string") return choice.title;
|
|
1129
|
+
return String(choice.type ?? "value");
|
|
1130
|
+
}
|
|
1131
|
+
function seedChoice(choice, fallback) {
|
|
1132
|
+
if (matchesChoice(choice, fallback)) return fallback;
|
|
1133
|
+
if (matchesChoice(choice, choice.default)) return choice.default;
|
|
1134
|
+
if (choice.type === "object") return {};
|
|
1135
|
+
if (choice.type === "array") return [];
|
|
1136
|
+
if (choice.type === "number" || choice.type === "integer") return typeof choice.minimum === "number" ? choice.minimum : 0;
|
|
1137
|
+
return choice.type === "boolean" ? false : "";
|
|
1138
|
+
}
|
|
1139
|
+
function emptyValue(raw, root) {
|
|
1140
|
+
const schema = unwrapExpression(raw, root);
|
|
1141
|
+
if (Array.isArray(schema.anyOf)) {
|
|
1142
|
+
const branches = unionBranches(schema, root);
|
|
1143
|
+
const first = branches?.[0];
|
|
1144
|
+
if (first !== void 0) return emptyValue(first, root);
|
|
1145
|
+
}
|
|
1146
|
+
if (schema.const !== void 0) return schema.const;
|
|
1147
|
+
if (Array.isArray(schema.enum) && schema.enum.length) return schema.enum[0];
|
|
1148
|
+
if (schema.default !== void 0 && schema.default !== null) return JSON.parse(JSON.stringify(schema.default));
|
|
1149
|
+
if (schema.type === "object") return {};
|
|
1150
|
+
if (schema.type === "array") return [];
|
|
1151
|
+
if (schema.type === "boolean") return false;
|
|
1152
|
+
if (schema.type === "number" || schema.type === "integer") return typeof schema.minimum === "number" ? schema.minimum : 0;
|
|
1153
|
+
return "";
|
|
1154
|
+
}
|
|
1155
|
+
function Field({ schema: raw, root, path, base, override, change, labels, entryId, depth = 0, locked = false, bare = false, labelPath }) {
|
|
1156
|
+
const keys = labelPath ?? path;
|
|
1157
|
+
const inherited = merged(at(base, path), at(override, path));
|
|
1158
|
+
const expression = isObject(inherited) && own(inherited, "__jsExpr");
|
|
1159
|
+
let schema = expression ? resolve(raw, root) : unwrapExpression(raw, root);
|
|
1160
|
+
const alternatives = expression ? void 0 : unionBranches(schema, root);
|
|
1161
|
+
if (alternatives?.length === 1) {
|
|
1162
|
+
const { anyOf: _, ...metadata } = schema;
|
|
1163
|
+
schema = { ...metadata, ...alternatives[0] };
|
|
1164
|
+
}
|
|
1165
|
+
if (inherited !== null && Array.isArray(schema.type)) {
|
|
1166
|
+
const types = schema.type.filter((type) => type !== "null");
|
|
1167
|
+
if (types.length === 1) schema = { ...schema, type: types[0] };
|
|
1168
|
+
}
|
|
1169
|
+
const disabled = locked || schema.readOnly === true;
|
|
1170
|
+
const overridden = path.length > 0 && has(override, path);
|
|
1171
|
+
const current = inherited === void 0 ? schema.default : inherited;
|
|
1172
|
+
const label = `${entryId}: ${keys.length ? pathLabel(keys) : labels.json}`;
|
|
1173
|
+
const id = import_react5.default.useId();
|
|
1174
|
+
const [draft, setDraft] = import_react5.default.useState("");
|
|
1175
|
+
const [chosen, setChosen] = import_react5.default.useState();
|
|
1176
|
+
const union = alternatives !== void 0 && alternatives.length > 1 ? alternatives : void 0;
|
|
1177
|
+
const properties = isObject(schema.properties) ? schema.properties : void 0;
|
|
1178
|
+
const values = !properties && !own(schema, "patternProperties") && isObject(schema.additionalProperties) ? schema.additionalProperties : void 0;
|
|
1179
|
+
const items = schema.type === "array" && isObject(schema.items) ? schema.items : void 0;
|
|
1180
|
+
const reset = overridden && !bare && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { small: true, disabled, "aria-label": `${labels.reset}: ${label}`, onClick: () => change(path, void 0, true), children: labels.reset });
|
|
1181
|
+
if (properties) return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { disabled, className: bare ? "studio-config-item" : path.length ? void 0 : "studio-config-root", children: [
|
|
1182
|
+
!bare && keys.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { children: typeof schema.title === "string" ? schema.title : keys[keys.length - 1] }),
|
|
1183
|
+
!bare && typeof schema.description === "string" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "studio-muted", children: schema.description }),
|
|
1184
|
+
reset,
|
|
1185
|
+
Object.entries(properties).map(([key, child]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { schema: isObject(child) ? child : { readOnly: child === false }, root, path: [...path, key], labelPath: [...keys, key], base, override, change, labels, entryId, depth: depth + 1, locked: disabled }, key))
|
|
1186
|
+
] });
|
|
1187
|
+
const scalarControl = (target, value, ariaLabel, controlId, onValue) => {
|
|
1188
|
+
const choices = target.const !== void 0 ? [target.const] : Array.isArray(target.enum) ? target.enum : void 0;
|
|
1189
|
+
if (choices) {
|
|
1190
|
+
const selected = choices.findIndex((item) => JSON.stringify(item) === JSON.stringify(value));
|
|
1191
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { id: controlId, "aria-label": ariaLabel, value: String(selected), disabled, onChange: (event) => onValue(choices[Number(event.target.value)]), children: [
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "-1", disabled: true, children: value === void 0 ? labels.unset : JSON.stringify(value) }),
|
|
1193
|
+
choices.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: index, children: typeof item === "string" ? item : JSON.stringify(item) }, index))
|
|
1194
|
+
] });
|
|
1195
|
+
}
|
|
1196
|
+
if (target.type === "boolean") {
|
|
1197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { id: controlId, "aria-label": ariaLabel, value: typeof value === "boolean" ? String(value) : "", disabled, onChange: (event) => onValue(event.target.value === "true"), children: [
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", disabled: true, children: labels.unset }),
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "true", children: "true" }),
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "false", children: "false" })
|
|
1201
|
+
] });
|
|
1202
|
+
}
|
|
1203
|
+
if (target.type === "number" || target.type === "integer") {
|
|
1204
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { id: controlId, "aria-label": ariaLabel, type: "number", disabled, value: typeof value === "number" ? value : "", step: target.type === "integer" ? 1 : "any", min: typeof target.minimum === "number" ? target.minimum : void 0, max: typeof target.maximum === "number" ? target.maximum : void 0, onChange: (event) => {
|
|
1205
|
+
const number = event.target.valueAsNumber;
|
|
1206
|
+
if (Number.isFinite(number) && (target.type !== "integer" || Number.isInteger(number))) {
|
|
1207
|
+
event.target.setCustomValidity("");
|
|
1208
|
+
onValue(number);
|
|
1209
|
+
} else event.target.setCustomValidity(labels.number);
|
|
1210
|
+
} });
|
|
1211
|
+
}
|
|
1212
|
+
if (target.type === "string") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { id: controlId, "aria-label": ariaLabel, type: target.format === "password" || target.writeOnly === true ? "password" : "text", disabled, value: typeof value === "string" ? value : "", onChange: (event) => onValue(event.target.value) });
|
|
1213
|
+
return void 0;
|
|
1214
|
+
};
|
|
1215
|
+
const unionControl = (options) => {
|
|
1216
|
+
const optionLabels = options.map(choiceLabel).map((text, index, all) => all.indexOf(text) === index ? text : `${text} ${index + 1}`);
|
|
1217
|
+
const implicit = options.findIndex((choice) => matchesChoice(choice, current));
|
|
1218
|
+
const selected = chosen !== void 0 && chosen < options.length ? chosen : implicit;
|
|
1219
|
+
const branch = selected >= 0 ? options[selected] : void 0;
|
|
1220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { id, "aria-label": label, disabled, value: String(selected), onChange: (event) => {
|
|
1222
|
+
const index = Number(event.target.value);
|
|
1223
|
+
const option = options[index];
|
|
1224
|
+
if (option === void 0) return;
|
|
1225
|
+
setChosen(index);
|
|
1226
|
+
if (option.const !== void 0) change(path, option.const);
|
|
1227
|
+
else if (Array.isArray(option.enum)) {
|
|
1228
|
+
if (option.enum.length) change(path, option.enum[0]);
|
|
1229
|
+
} else if (!matchesChoice(option, current)) change(path, seedChoice(option, schema.default));
|
|
1230
|
+
}, children: [
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "-1", disabled: true, children: current === void 0 ? labels.unset : JSON.stringify(current) }),
|
|
1232
|
+
options.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: index, children: optionLabels[index] }, index))
|
|
1233
|
+
] }),
|
|
1234
|
+
branch === void 0 || branch.const !== void 0 || Array.isArray(branch.enum) ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { bare: true, schema: branch, root, path, labelPath: [...keys, "value"], base, override, change, labels, entryId, depth: depth + 1, locked: disabled })
|
|
1235
|
+
] });
|
|
1236
|
+
};
|
|
1237
|
+
const listControl = (itemSchema) => {
|
|
1238
|
+
const entries = Array.isArray(current) ? current : [];
|
|
1239
|
+
const write = (next) => change(path, next);
|
|
1240
|
+
const edit = (index) => (itemPath, next, resetLeaf) => {
|
|
1241
|
+
const source = entries[index];
|
|
1242
|
+
const edited = itemPath.length ? update(isObject(source) ? source : {}, itemPath, next, resetLeaf) : next;
|
|
1243
|
+
write(entries.map((value, at2) => at2 === index ? edited : value));
|
|
1244
|
+
};
|
|
1245
|
+
const typed = scalarType(itemSchema, root) === "string";
|
|
1246
|
+
const commit = () => {
|
|
1247
|
+
const text = draft.trim();
|
|
1248
|
+
if (!text) return;
|
|
1249
|
+
write([...entries, text]);
|
|
1250
|
+
setDraft("");
|
|
1251
|
+
};
|
|
1252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-config-list", children: [
|
|
1253
|
+
entries.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-list-row", children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { bare: true, schema: itemSchema, root, path: [], labelPath: [...keys, String(index)], base: value, override: value, change: edit(index), labels, entryId, depth: depth + 1, locked: disabled }),
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { small: true, disabled, "aria-label": `${labels.items.remove}: ${label}[${index}]`, onClick: () => write(entries.filter((_, at2) => at2 !== index)), children: labels.items.remove })
|
|
1256
|
+
] }, index)),
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-list-row", children: [
|
|
1258
|
+
typed ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { id, "aria-label": `${labels.items.draft}: ${label}`, placeholder: labels.items.draft, disabled, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
|
|
1259
|
+
if (event.key === "Enter") {
|
|
1260
|
+
event.preventDefault();
|
|
1261
|
+
commit();
|
|
1262
|
+
}
|
|
1263
|
+
} }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { id, className: "studio-muted studio-hint", children: choiceLabel(itemSchema) }),
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { small: true, disabled: disabled || typed && !draft.trim(), "aria-label": `${labels.items.add}: ${label}`, onClick: () => typed ? commit() : write([...entries, emptyValue(itemSchema, root)]), children: labels.items.add })
|
|
1265
|
+
] })
|
|
1266
|
+
] });
|
|
1267
|
+
};
|
|
1268
|
+
const dictControl = (valueSchema) => {
|
|
1269
|
+
const entries = isObject(current) ? current : {};
|
|
1270
|
+
const write = (next) => change(path, next);
|
|
1271
|
+
const edit = (key) => (valuePath, next, resetLeaf) => {
|
|
1272
|
+
const source = entries[key];
|
|
1273
|
+
const edited = valuePath.length ? update(isObject(source) ? source : {}, valuePath, next, resetLeaf) : next;
|
|
1274
|
+
write({ ...entries, [key]: edited });
|
|
1275
|
+
};
|
|
1276
|
+
const commit = () => {
|
|
1277
|
+
const key = draft.trim();
|
|
1278
|
+
if (!key || own(entries, key)) return;
|
|
1279
|
+
write({ ...entries, [key]: emptyValue(valueSchema, root) });
|
|
1280
|
+
setDraft("");
|
|
1281
|
+
};
|
|
1282
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-config-list", children: [
|
|
1283
|
+
Object.entries(entries).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-list-row", children: [
|
|
1284
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "studio-mono studio-config-key", children: key }),
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { bare: true, schema: valueSchema, root, path: [], labelPath: [...keys, key], base: value, override: value, change: edit(key), labels, entryId, depth: depth + 1, locked: disabled }),
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { small: true, disabled, "aria-label": `${labels.items.remove}: ${label}.${key}`, onClick: () => {
|
|
1287
|
+
const next = { ...entries };
|
|
1288
|
+
delete next[key];
|
|
1289
|
+
write(next);
|
|
1290
|
+
}, children: labels.items.remove })
|
|
1291
|
+
] }, key)),
|
|
1292
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-list-row", children: [
|
|
1293
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { id, "aria-label": `${labels.items.key}: ${label}`, placeholder: labels.items.key, disabled, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
|
|
1294
|
+
if (event.key === "Enter") {
|
|
1295
|
+
event.preventDefault();
|
|
1296
|
+
commit();
|
|
1297
|
+
}
|
|
1298
|
+
} }),
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { small: true, disabled: disabled || !draft.trim(), "aria-label": `${labels.items.add}: ${label}`, onClick: commit, children: labels.items.add })
|
|
1300
|
+
] })
|
|
1301
|
+
] });
|
|
1302
|
+
};
|
|
1303
|
+
let input;
|
|
1304
|
+
if (expression) input = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", "aria-label": label, children: labels.unsupported });
|
|
1305
|
+
else if (union) input = unionControl(union);
|
|
1306
|
+
else if (values) input = dictControl(values);
|
|
1307
|
+
else if (items) input = listControl(items);
|
|
1308
|
+
else input = (depth > 16 ? void 0 : scalarControl(schema, current, label, id, (next) => change(path, next))) ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", "aria-label": label, children: labels.unsupported });
|
|
1309
|
+
if (bare) return input;
|
|
1310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-field studio-config-field", "data-overridden": overridden, children: [
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "studio-field-head", children: [
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: id, className: "studio-mono", children: typeof schema.title === "string" ? schema.title : keys[keys.length - 1] ?? labels.json }),
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "studio-config-state", children: overridden ? labels.overridden : labels.inherited }),
|
|
1314
|
+
reset
|
|
1315
|
+
] }),
|
|
1316
|
+
typeof schema.description === "string" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "studio-muted studio-hint", children: schema.description }),
|
|
1317
|
+
input
|
|
1318
|
+
] });
|
|
1319
|
+
}
|
|
1320
|
+
function comparisonBase(raw, root, base, depth = 0) {
|
|
1321
|
+
if (!raw || !root || depth > 16) return base;
|
|
1322
|
+
let schema = resolve(raw, root);
|
|
1323
|
+
if (Array.isArray(schema.anyOf)) {
|
|
1324
|
+
const literal = schema.anyOf.filter((branch) => !isObject(branch) || branch.$ref !== "#/$defs/loaderExpression");
|
|
1325
|
+
if (literal.length === 1 && literal.length < schema.anyOf.length && isObject(literal[0])) schema = resolve(literal[0], root);
|
|
1326
|
+
}
|
|
1327
|
+
const value = base === void 0 ? schema.default : base;
|
|
1328
|
+
if (isObject(schema.properties) && (value === void 0 || isObject(value))) {
|
|
1329
|
+
return { ...isObject(value) ? value : {}, ...Object.fromEntries(Object.entries(schema.properties).filter(([, child]) => isObject(child)).map(([key, child]) => [key, comparisonBase(child, root, isObject(value) ? value[key] : void 0, depth + 1)])) };
|
|
1330
|
+
}
|
|
1331
|
+
return value;
|
|
1332
|
+
}
|
|
1333
|
+
function ConfigEditor({ entries, value, onChange, locale }) {
|
|
1334
|
+
const labels = copy[locale.startsWith("ko") ? "ko" : locale.startsWith("zh") ? "zh" : "en"];
|
|
1335
|
+
const items = [
|
|
1336
|
+
...entries.map((entry) => ({
|
|
1337
|
+
name: entry.id,
|
|
1338
|
+
title: entry.name,
|
|
1339
|
+
subtitle: entry.id,
|
|
1340
|
+
description: "",
|
|
1341
|
+
searchText: JSON.stringify(entry.schema ?? {}),
|
|
1342
|
+
...entry.error || !entry.schema ? { disabledReason: entry.error || labels.unavailable } : {}
|
|
1343
|
+
})),
|
|
1344
|
+
...Object.keys(value).filter((id) => !entries.some((entry) => entry.id === id)).map((id) => ({ name: id, title: id, description: labels.unavailable }))
|
|
1345
|
+
];
|
|
1346
|
+
const selected = items.filter((item) => own(value, item.name)).map((item) => item.name);
|
|
1347
|
+
const change = (names2) => onChange(Object.fromEntries([
|
|
1348
|
+
...Object.entries(value).filter(([id]) => names2.includes(id)),
|
|
1349
|
+
...names2.filter((id) => !own(value, id)).map((id) => [id, {}])
|
|
1350
|
+
]));
|
|
1351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "studio-stack", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1352
|
+
ItemPicker,
|
|
1353
|
+
{
|
|
1354
|
+
label: labels.list,
|
|
1355
|
+
items,
|
|
1356
|
+
selected,
|
|
1357
|
+
onChange: change,
|
|
1358
|
+
labels: labels.picker,
|
|
1359
|
+
hasDetails: (id) => entries.some((entry) => entry.id === id && entry.schema && !entry.error),
|
|
1360
|
+
isModified: (id) => {
|
|
1361
|
+
const entry = entries.find((item) => item.id === id);
|
|
1362
|
+
return !!entry && own(value, id) && hasChangedOverride(comparisonBase(entry.schema, entry.schema, entry.config), value[id]);
|
|
1363
|
+
},
|
|
1364
|
+
renderDetails: (id) => {
|
|
1365
|
+
const entry = entries.find((item) => item.id === id);
|
|
1366
|
+
return entry?.schema && own(value, id) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { schema: entry.schema, root: entry.schema, path: [], base: entry.config, override: value[id], entryId: id, labels, change: (path, next, reset) => onChange({ ...value, [id]: update(value[id], path, next, reset) }) }) : null;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
) });
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// src/preset-manager.tsx
|
|
1373
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
1374
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1375
|
+
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
1376
|
+
function PresetList({ locale, api, revision, onEdit, onCopy }) {
|
|
1377
|
+
const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
1378
|
+
const [load, setLoad] = import_react6.default.useState({ phase: "loading" });
|
|
1379
|
+
const [action, setAction] = import_react6.default.useState();
|
|
1380
|
+
const [deleting, setDeleting] = import_react6.default.useState();
|
|
1381
|
+
const [confirming, setConfirming] = import_react6.default.useState(false);
|
|
1382
|
+
const request = import_react6.default.useRef(0);
|
|
1383
|
+
const refresh = import_react6.default.useCallback(async () => {
|
|
1384
|
+
if (!api) return;
|
|
1385
|
+
const ticket = ++request.current;
|
|
1386
|
+
setLoad((old) => ({ phase: "loading", ...old.items ? { items: old.items } : {} }));
|
|
1387
|
+
try {
|
|
1388
|
+
const items2 = await api.list();
|
|
1389
|
+
if (ticket === request.current) setLoad({ phase: "ready", items: items2 });
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
if (ticket === request.current) setLoad((old) => ({ phase: "failed", error: message(error), ...old.items ? { items: old.items } : {} }));
|
|
1392
|
+
}
|
|
1393
|
+
}, [api]);
|
|
1394
|
+
import_react6.default.useEffect(() => {
|
|
1395
|
+
void refresh();
|
|
1396
|
+
return () => {
|
|
1397
|
+
request.current++;
|
|
1398
|
+
};
|
|
1399
|
+
}, [refresh, revision]);
|
|
1400
|
+
const busy = action !== void 0 && action.error === void 0;
|
|
1401
|
+
const run = async (id, kind, perform) => {
|
|
1402
|
+
if (busy) return;
|
|
1403
|
+
setAction({ id, kind });
|
|
1404
|
+
try {
|
|
1405
|
+
await perform();
|
|
1406
|
+
} catch (error) {
|
|
1407
|
+
setAction({ id, kind, error: message(error) });
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
setAction(void 0);
|
|
1411
|
+
await refresh();
|
|
1412
|
+
};
|
|
1413
|
+
const items = load.items ?? [];
|
|
1414
|
+
const failedName = action?.error !== void 0 ? items.find((item) => item.id === action.id)?.name ?? deleting?.name ?? action.id : "";
|
|
1415
|
+
const failure = action?.error === void 0 ? "" : action.kind === "apply" ? t(`${failedName}\uC744(\uB97C) \uBC18\uC601\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC774\uC804\uC5D0 \uBC18\uC601\uD55C \uAD6C\uC131\uC740 \uADF8\uB300\uB85C \uC720\uC9C0\uB429\uB2C8\uB2E4.`, `Could not apply ${failedName}. A previously applied configuration stays in effect.`, `\u65E0\u6CD5\u5E94\u7528 ${failedName}\u3002\u4E4B\u524D\u5DF2\u5E94\u7528\u7684\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8`) : action.kind === "unapply" ? t(`${failedName}\uC758 \uBC18\uC601\uC744 \uD574\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uBC18\uC601 \uC0C1\uD0DC\uB294 \uADF8\uB300\uB85C\uC785\uB2C8\uB2E4.`, `Could not unapply ${failedName}. Its applied state did not change.`, `\u65E0\u6CD5\u53D6\u6D88\u5E94\u7528 ${failedName}\u3002\u5E94\u7528\u72B6\u6001\u672A\u6539\u53D8`) : t(`${failedName}\uC744(\uB97C) \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B\uC740 \uADF8\uB300\uB85C \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4.`, `Could not delete ${failedName}. The preset was not deleted.`, `\u65E0\u6CD5\u5220\u9664 ${failedName}\u3002\u9884\u8BBE\u672A\u88AB\u5220\u9664`);
|
|
1416
|
+
const pending = (item, kind) => busy && action?.id === item.id && action.kind === kind;
|
|
1417
|
+
const status = (item) => item.status === "applied" ? t("\uBC18\uC601\uB428", "Applied", "\u5DF2\u5E94\u7528") : item.status === "modified" ? t("\uB2E4\uC2DC \uBC18\uC601 \uD544\uC694", "Needs reapply", "\u9700\u8981\u91CD\u65B0\u5E94\u7528") : t("\uBC18\uC601 \uC548 \uB428", "Not applied", "\u672A\u5E94\u7528");
|
|
1418
|
+
const tone = { applied: "success", modified: "warning", draft: "neutral" };
|
|
1419
|
+
const warnings = [...items.reduce((groups, item) => item.applyWarning ? groups.set(item.applyWarning, [...groups.get(item.applyWarning) ?? [], item.name]) : groups, /* @__PURE__ */ new Map())];
|
|
1420
|
+
const retry = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: load.phase === "loading", onClick: () => void refresh(), children: t("\uB2E4\uC2DC \uC2DC\uB3C4", "Retry", "\u91CD\u8BD5") });
|
|
1421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PageHead, { title: t("\uD504\uB9AC\uC14B \uBAA9\uB85D", "Preset list", "\u9884\u8BBE\u5217\u8868"), description: t("\uC800\uC7A5\uD55C \uD504\uB9AC\uC14B\uC744 DSH\uC5D0 \uBC18\uC601\uD558\uBA74 \uC0C8 \uC138\uC158\uC5D0\uC11C \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Apply saved configurations to DSH agent presets or delete them.", "\u5C06\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E\u5E94\u7528\u5230 DSH \u4EE3\u7406\u9884\u8BBE\u6216\u5220\u9664\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { disabled: busy || !api || load.phase === "loading", onClick: () => void refresh(), children: load.phase === "loading" && load.items ? t("\uC0C8\uB85C\uACE0\uCE68 \uC911\u2026", "Refreshing\u2026", "\u5237\u65B0\u4E2D\u2026") : t("\uC0C8\uB85C\uACE0\uCE68", "Refresh", "\u5237\u65B0") }) }),
|
|
1423
|
+
!api && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Notice, { children: t("Studio \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC544 \uD504\uB9AC\uC14B\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Presets are unavailable because the Studio Host API is not connected.", "Studio Host API \u672A\u8FDE\u63A5\uFF0C\u65E0\u6CD5\u52A0\u8F7D\u9884\u8BBE") }),
|
|
1424
|
+
api && load.phase === "loading" && !load.items && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", className: "studio-muted", children: t("\uD504\uB9AC\uC14B\uC744 \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading presets\u2026", "\u6B63\u5728\u52A0\u8F7D\u9884\u8BBE\u2026") }),
|
|
1425
|
+
load.phase === "failed" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Notice, { action: retry, children: load.items ? t(`\uBAA9\uB85D\uC744 \uC0C8\uB85C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD574 \uC774\uC804 \uBAA9\uB85D\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4. (${load.error})`, `Could not reload the list. Showing the last loaded list. (${load.error})`, `\u65E0\u6CD5\u91CD\u65B0\u52A0\u8F7D\u5217\u8868\uFF0C\u6B63\u5728\u663E\u793A\u4E0A\u6B21\u52A0\u8F7D\u7684\u5217\u8868\uFF08${load.error}\uFF09`) : t(`\uD504\uB9AC\uC14B \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uC5D0\uB294 \uC601\uD5A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. (${load.error})`, `Could not load presets. Saved presets were not changed. (${load.error})`, `\u65E0\u6CD5\u52A0\u8F7D\u9884\u8BBE\uFF0C\u5DF2\u4FDD\u5B58\u7684\u9884\u8BBE\u672A\u88AB\u66F4\u6539\uFF08${load.error}\uFF09`) }),
|
|
1426
|
+
failure && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, onClick: () => setAction(void 0), children: t("\uB2EB\uAE30", "Dismiss", "\u5173\u95ED") }), children: [
|
|
1427
|
+
failure,
|
|
1428
|
+
" (",
|
|
1429
|
+
action.error,
|
|
1430
|
+
")"
|
|
1431
|
+
] }),
|
|
1432
|
+
load.phase === "ready" && !items.length && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uC0C8\uB85C \uB9CC\uB4E4\uC5B4 \uBCF4\uC138\uC694.", "No saved presets. Create one from Create preset.", "\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u9884\u8BBE\u3002\u8BF7\u4ECE\u521B\u5EFA\u9884\u8BBE\u83DC\u5355\u5F00\u59CB\u3002") }),
|
|
1433
|
+
warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "studio-preset-warnings", "aria-label": t("\uC8FC\uC758\uC0AC\uD56D", "Notices", "\u6CE8\u610F\u4E8B\u9879"), children: warnings.map(([text, names2]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: "warning", children: t("\uC8FC\uC758", "Notice", "\u6CE8\u610F") }),
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
1436
|
+
text,
|
|
1437
|
+
" ",
|
|
1438
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "studio-card-meta", children: [
|
|
1439
|
+
"(",
|
|
1440
|
+
t("\uD574\uB2F9", "Affects", "\u6D89\u53CA"),
|
|
1441
|
+
": ",
|
|
1442
|
+
names2.join(", "),
|
|
1443
|
+
")"
|
|
1444
|
+
] })
|
|
1445
|
+
] })
|
|
1446
|
+
] }, text)) }),
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "studio-tool-cards studio-card-pair", "aria-busy": load.phase === "loading" || busy, children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("article", { className: "studio-preset-card", children: [
|
|
1448
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "studio-card-head", children: [
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: item.name }),
|
|
1450
|
+
item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: "outline", children: t("\uC77D\uAE30 \uC804\uC6A9", "Read-only", "\u53EA\u8BFB") }),
|
|
1451
|
+
item.template && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: "info", children: t("\uAE30\uBCF8 \uC81C\uACF5", "Built-in", "\u5185\u7F6E") }),
|
|
1452
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: tone[item.status], children: status(item) })
|
|
1453
|
+
] }),
|
|
1454
|
+
item.template ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: t("Studio\uAC00 \uAD8C\uC7A5\uD558\uB294 \uAE30\uBCF8 \uAD6C\uC131\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uD558\uAC70\uB098 \uBCF5\uC0AC\uD574 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Studio optimized default preset", "Studio \u63A8\u8350\u7684\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u53EF\u7F16\u8F91\u6216\u590D\u5236") }) : item.description && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: item.description }),
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "studio-card-meta", children: [
|
|
1456
|
+
t("\uB3C4\uAD6C", "Tools", "\u5DE5\u5177"),
|
|
1457
|
+
" ",
|
|
1458
|
+
item.request.tools.length,
|
|
1459
|
+
" \xB7 ",
|
|
1460
|
+
t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uC5ED\uD560", "Subagent roles", "\u5B50\u4EE3\u7406\u89D2\u8272"),
|
|
1461
|
+
" ",
|
|
1462
|
+
Array.isArray(item.agents) ? item.agents.length : 0
|
|
1463
|
+
] }),
|
|
1464
|
+
item.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-meta studio-card-note", children: t("DSH\uC5D0 \uC124\uCE58\uB41C \uBAA8\uB4E0 \uB3C4\uAD6C\uB97C \uB2F4\uC740 \uAE30\uC900 \uD504\uB9AC\uC14B\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uD558\uAC70\uB098 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Reference preset with every installed DSH tool. It cannot be edited or deleted.", "\u5305\u542B\u6240\u6709\u5DF2\u5B89\u88C5 DSH \u5DE5\u5177\u7684\u57FA\u51C6\u9884\u8BBE\uFF0C\u65E0\u6CD5\u7F16\u8F91\u6216\u5220\u9664") }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "studio-card-footer", children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || item.readOnly || !onEdit, onClick: () => onEdit?.(item), children: t("\uD3B8\uC9D1", "Edit", "\u7F16\u8F91") }),
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || !onCopy, onClick: () => onCopy?.(item), children: t("\uBCF5\uC0AC", "Create copy", "\u521B\u5EFA\u526F\u672C") }),
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || !api || item.readOnly || item.nonDeletable, title: item.nonDeletable ? t("\uAE30\uBCF8 \uC81C\uACF5 \uD504\uB9AC\uC14B\uC740 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Built-in presets cannot be deleted.", "\u5185\u7F6E\u9884\u8BBE\u65E0\u6CD5\u5220\u9664") : void 0, onClick: () => {
|
|
1468
|
+
setDeleting(item);
|
|
1469
|
+
setConfirming(true);
|
|
1470
|
+
}, children: t("\uC0AD\uC81C", "Delete", "\u5220\u9664") }),
|
|
1471
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "studio-card-footer-end", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1472
|
+
SplitButton,
|
|
1473
|
+
{
|
|
1474
|
+
primary: item.status !== "applied",
|
|
1475
|
+
disabled: busy || !api || !!item.readOnly,
|
|
1476
|
+
onClick: () => void run(item.id, "apply", () => api.apply(item.id)),
|
|
1477
|
+
menuLabel: t("\uBC18\uC601 \uC635\uC158", "Apply options", "\u5E94\u7528\u9009\u9879"),
|
|
1478
|
+
label: pending(item, "apply") ? t("\uBC18\uC601 \uC911\u2026", "Applying\u2026", "\u5E94\u7528\u4E2D\u2026") : pending(item, "unapply") ? t("\uD574\uC81C \uC911\u2026", "Unapplying\u2026", "\u53D6\u6D88\u4E2D\u2026") : item.status === "draft" ? t("DSH\uC5D0 \uBC18\uC601", "Apply to DSH", "\u5E94\u7528\u5230 DSH") : t("DSH\uC5D0 \uB2E4\uC2DC \uBC18\uC601", "Reapply to DSH", "\u91CD\u65B0\u5E94\u7528\u5230 DSH"),
|
|
1479
|
+
actions: item.status === "draft" || !api?.unapply ? [] : [{ label: t("\uBC18\uC601 \uD574\uC81C", "Unapply from DSH", "\u53D6\u6D88\u5E94\u7528\u5230 DSH"), onSelect: () => void run(item.id, "unapply", () => api.unapply(item.id)) }]
|
|
1480
|
+
}
|
|
1481
|
+
) })
|
|
1482
|
+
] })
|
|
1483
|
+
] }, item.id)) }),
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1485
|
+
DetailDialog,
|
|
1486
|
+
{
|
|
1487
|
+
compact: true,
|
|
1488
|
+
open: confirming,
|
|
1489
|
+
onClose: () => setConfirming(false),
|
|
1490
|
+
title: t("\uD504\uB9AC\uC14B \uC0AD\uC81C", "Delete preset", "\u5220\u9664\u9884\u8BBE"),
|
|
1491
|
+
subtitle: deleting?.name,
|
|
1492
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { disabled: busy, onClick: () => setConfirming(false), children: t("\uCDE8\uC18C", "Cancel", "\u53D6\u6D88") }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { primary: true, disabled: busy || !deleting, onClick: () => {
|
|
1495
|
+
const target = deleting;
|
|
1496
|
+
setConfirming(false);
|
|
1497
|
+
void run(target.id, "delete", () => api.delete(target.id)).then(() => setDeleting(void 0));
|
|
1498
|
+
}, children: t("\uC0AD\uC81C \uD655\uC778", "Confirm delete", "\u786E\u8BA4\u5220\u9664") })
|
|
1499
|
+
] }),
|
|
1500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uACFC DSH\uC5D0 \uBC18\uC601\uB41C \uD504\uB9AC\uC14B\uC744 \uD568\uAED8 \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uAE30\uC874 \uB300\uD654\uB294 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4.", "Delete the saved preset and its Studio-owned DSH registration. Existing conversations are not deleted.", "\u5220\u9664\u5DF2\u4FDD\u5B58\u9884\u8BBE\u53CA Studio \u6CE8\u518C\u7684 DSH \u9884\u8BBE\uFF0C\u4E0D\u5220\u9664\u73B0\u6709\u5BF9\u8BDD\u3002") })
|
|
1501
|
+
}
|
|
1502
|
+
)
|
|
1503
|
+
] });
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// src/package-name.ts
|
|
1507
|
+
var PACKAGE_NAME = "@matamt-dbg/dsh-studio";
|
|
1508
|
+
var POLICY_PLUGIN = `${PACKAGE_NAME}/policy`;
|
|
1509
|
+
var ROLE_PLUGIN = `${PACKAGE_NAME}/roles`;
|
|
1510
|
+
var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
|
|
1511
|
+
|
|
1512
|
+
// src/delegation.ts
|
|
1513
|
+
var ROLE_TOOL = "subagent_role";
|
|
1514
|
+
var LEGACY_ROLE_TOOL = "studio_role";
|
|
1515
|
+
var GENERIC_DELEGATION_TOOLS = ["subagent", "subagent_fork", "list_subagent_models"];
|
|
1516
|
+
var WITHDRAWN_TOOLS = ["task_run"];
|
|
1517
|
+
function delegationTools(tools, hasRoles = false) {
|
|
1518
|
+
const delegates = hasRoles || tools.some((name) => name === ROLE_TOOL || name === LEGACY_ROLE_TOOL || GENERIC_DELEGATION_TOOLS.includes(name));
|
|
1519
|
+
const rest = tools.filter((name) => name !== ROLE_TOOL && name !== LEGACY_ROLE_TOOL && !GENERIC_DELEGATION_TOOLS.includes(name) && !WITHDRAWN_TOOLS.includes(name));
|
|
1520
|
+
return delegates ? [...rest, ROLE_TOOL] : rest;
|
|
1521
|
+
}
|
|
1522
|
+
function renameLegacyRoleKey(entries) {
|
|
1523
|
+
if (!entries || !Object.hasOwn(entries, LEGACY_ROLE_TOOL)) return entries;
|
|
1524
|
+
const { [LEGACY_ROLE_TOOL]: legacy, ...rest } = entries;
|
|
1525
|
+
return Object.hasOwn(rest, ROLE_TOOL) ? rest : { ...rest, [ROLE_TOOL]: legacy };
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// src/optimized-preset.ts
|
|
1529
|
+
var BUILTIN_TOOL_PRESETS = ["standard", "ptc", "minimal", "cordis"];
|
|
1530
|
+
|
|
1531
|
+
// src/prompt-tools-prototype.tsx
|
|
1532
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
1533
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1534
|
+
var defaultProvidedTools = [];
|
|
1535
|
+
function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProvidedChange, catalog, catalogError, onPreview, onRequestChange, initialRequest }) {
|
|
1536
|
+
const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
1537
|
+
const base = initialRequest?.preset ?? "studio-master";
|
|
1538
|
+
const [toolOverrides, setToolOverrides] = import_react7.default.useState(renameLegacyRoleKey(initialRequest?.toolOverrides) ?? {});
|
|
1539
|
+
const [sections, setSections] = import_react7.default.useState(initialRequest?.sections ?? {});
|
|
1540
|
+
const providers = initialRequest?.providers ?? ["@deepseek-ai/dsh-persona"];
|
|
1541
|
+
const [providerConfigs, setProviderConfigs] = import_react7.default.useState(initialRequest?.providerConfigs ?? {});
|
|
1542
|
+
const [result, setResult] = import_react7.default.useState();
|
|
1543
|
+
const [resultKey, setResultKey] = import_react7.default.useState("");
|
|
1544
|
+
const [error, setError] = import_react7.default.useState("");
|
|
1545
|
+
const [previewOpen, setPreviewOpen] = import_react7.default.useState(false);
|
|
1546
|
+
const idBase = import_react7.default.useId();
|
|
1547
|
+
const closePreview = () => setPreviewOpen(false);
|
|
1548
|
+
const [busy, setBusy] = import_react7.default.useState(false);
|
|
1549
|
+
const presets = catalog?.presets ?? [];
|
|
1550
|
+
const toolSources = BUILTIN_TOOL_PRESETS.map((id) => presets.find((p) => p.id === id) ?? { id, name: id, tools: [], sections: [], error: "Preset unavailable" });
|
|
1551
|
+
const tools = catalog?.tools ?? [];
|
|
1552
|
+
const current = presets.find((preset) => preset.id === base);
|
|
1553
|
+
const selectedSections = new Set(tools.filter((tool) => provided.includes(tool.name)).flatMap((tool) => tool.promptSections?.map((section) => section.name) ?? []));
|
|
1554
|
+
const request = {
|
|
1555
|
+
...initialRequest,
|
|
1556
|
+
preset: base,
|
|
1557
|
+
providers,
|
|
1558
|
+
tools: provided,
|
|
1559
|
+
prompt,
|
|
1560
|
+
model: initialRequest?.model ?? "testLLM",
|
|
1561
|
+
toolOverrides: Object.fromEntries(Object.entries(toolOverrides).filter(([name]) => provided.includes(name))),
|
|
1562
|
+
sections: Object.fromEntries(Object.entries(sections).filter(([name]) => selectedSections.has(name))),
|
|
1563
|
+
providerConfigs: Object.fromEntries(Object.entries(providerConfigs).filter(([name]) => providers.includes(name)))
|
|
1564
|
+
};
|
|
1565
|
+
const personaFields = current?.promptProviders?.find((provider) => provider.name === providers[0])?.fields ?? [];
|
|
1566
|
+
const requestKey = JSON.stringify(request);
|
|
1567
|
+
import_react7.default.useEffect(() => {
|
|
1568
|
+
onRequestChange?.(request);
|
|
1569
|
+
}, [requestKey, onRequestChange]);
|
|
1570
|
+
const labels = { filter: t("\uBCF4\uAE30", "Show", "\u663E\u793A"), search: t("\uB3C4\uAD6C \uAC80\uC0C9", "Search tools", "\u641C\u7D22\u5DE5\u5177"), searchHint: t("\uC774\uB984, \uC124\uBA85, \uC778\uC790\uB85C \uAC80\uC0C9", "Search names, descriptions or parameters", "\u6309\u540D\u79F0\u3001\u63CF\u8FF0\u6216\u53C2\u6570\u641C\u7D22"), all: t("\uC804\uCCB4", "All", "\u5168\u90E8"), selected: t("\uC120\uD0DD\uB428", "Selected", "\u5DF2\u9009"), modified: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), settings: t("\uC124\uC815", "Details", "\u8BE6\u60C5"), done: t("\uC644\uB8CC", "Close", "\u5173\u95ED"), empty: t("\uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.", "No items", "\u65E0\u9879\u76EE"), noResults: t("\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No matching results.", "\u6CA1\u6709\u5339\u914D\u7ED3\u679C\u3002"), modifiedTag: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), clear: t("\uC804\uCCB4 \uBCF4\uAE30", "Show all", "\u663E\u793A\u5168\u90E8") };
|
|
1571
|
+
const presetTools = (presetId) => delegationTools(presets.find((p) => p.id === presetId)?.tools.map((tool) => tool.name) ?? []);
|
|
1572
|
+
const togglePreset = (presetId) => {
|
|
1573
|
+
const names2 = presetTools(presetId);
|
|
1574
|
+
onProvidedChange(includesPreset(presetId) ? provided.filter((name) => !names2.includes(name)) : [.../* @__PURE__ */ new Set([...provided, ...names2])]);
|
|
1575
|
+
};
|
|
1576
|
+
const includesPreset = (presetId) => {
|
|
1577
|
+
const names2 = presetTools(presetId);
|
|
1578
|
+
return names2.length > 0 && names2.every((name) => provided.includes(name));
|
|
1579
|
+
};
|
|
1580
|
+
const changeTools = (next) => onProvidedChange(delegationTools(next));
|
|
1581
|
+
import_react7.default.useEffect(() => {
|
|
1582
|
+
if (provided.some((name) => name === LEGACY_ROLE_TOOL || GENERIC_DELEGATION_TOOLS.includes(name) || WITHDRAWN_TOOLS.includes(name))) onProvidedChange(delegationTools(provided));
|
|
1583
|
+
}, []);
|
|
1584
|
+
const preview = async () => {
|
|
1585
|
+
if (!onPreview) return;
|
|
1586
|
+
setPreviewOpen(true);
|
|
1587
|
+
setBusy(true);
|
|
1588
|
+
setError("");
|
|
1589
|
+
setResult(void 0);
|
|
1590
|
+
try {
|
|
1591
|
+
const value = await onPreview(request);
|
|
1592
|
+
setResult(value);
|
|
1593
|
+
setResultKey(requestKey);
|
|
1594
|
+
} catch (cause) {
|
|
1595
|
+
setError(String(cause));
|
|
1596
|
+
} finally {
|
|
1597
|
+
setBusy(false);
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react7.default.Fragment, { children: [
|
|
1601
|
+
catalogError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: catalogError }) : !catalog ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: t("\uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading\u2026", "\u6B63\u5728\u52A0\u8F7D\u2026") }) : null,
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-form-section", children: [
|
|
1603
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uD504\uB86C\uD504\uD2B8", "Prompt composition", "\u63D0\u793A\u8BCD\u7EC4\u88C5"), description: t("\uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uC804\uB2EC\uD560 \uC9C0\uCE68\uC744 \uD3B8\uC9D1\uD569\uB2C8\uB2E4. \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC870\uB9BD \uACB0\uACFC\uB97C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Edit Persona and Studio instructions, then preview the assembled result.", "\u7F16\u8F91 Persona \u4E0E Studio \u4E13\u7528\u6307\u4EE4\uFF0C\u5E76\u9884\u89C8\u7EC4\u88C5\u7ED3\u679C\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !onPreview || !current || busy, onClick: () => void preview(), children: busy ? t("\uC870\uB9BD \uC911\u2026", "Assembling\u2026", "\u7EC4\u88C5\u4E2D\u2026") : t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Preview prompt", "\u9884\u89C8\u63D0\u793A\u8BCD") }) }),
|
|
1604
|
+
["prefix", "suffix"].map((key) => {
|
|
1605
|
+
const name = providers[0];
|
|
1606
|
+
const config = providerConfigs[name] ?? {};
|
|
1607
|
+
const original = personaFields.find((field2) => field2.key === key)?.value;
|
|
1608
|
+
const fieldId = `${idBase}-${key}`;
|
|
1609
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-field", children: [
|
|
1610
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-field-head", children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { htmlFor: fieldId, children: key === "prefix" ? t("\uAE30\uBCF8 \uC9C0\uCE68 (Persona)", "Persona instructions", "Persona \u57FA\u672C\u6307\u4EE4") : t("\uB05D\uC5D0 \uBD99\uC77C \uC9C0\uCE68 (Persona)", "Persona suffix", "Persona \u540E\u7F6E\u6307\u4EE4") }),
|
|
1612
|
+
Object.hasOwn(config, key) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChangeIndicator, { locale }),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !Object.hasOwn(config, key), onClick: () => {
|
|
1614
|
+
const next = { ...config };
|
|
1615
|
+
delete next[key];
|
|
1616
|
+
setProviderConfigs({ ...providerConfigs, [name]: next });
|
|
1617
|
+
}, children: t("\uC6D0\uB798\uB300\uB85C", "Use original", "\u4F7F\u7528\u539F\u59CB\u503C") })
|
|
1618
|
+
] }),
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { id: fieldId, rows: key === "prefix" ? 6 : 3, value: typeof config[key] === "string" ? config[key] : typeof original === "string" ? original : "", onChange: (e) => setProviderConfigs({ ...providerConfigs, [name]: { ...config, [key]: e.target.value } }) })
|
|
1620
|
+
] }, key);
|
|
1621
|
+
}),
|
|
1622
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "studio-field", children: [
|
|
1623
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: t("\uCD94\uAC00 \uC9C0\uCE68", "Additional Studio instructions", "Studio \u9644\u52A0\u6307\u4EE4") }),
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { rows: 6, value: prompt, onChange: (e) => onPromptChange(e.target.value) })
|
|
1625
|
+
] })
|
|
1626
|
+
] }),
|
|
1627
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-form-section", children: [
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), description: t("\uC5D0\uC774\uC804\uD2B8\uAC00 \uC4F8 \uB3C4\uAD6C\uB97C \uACE0\uB985\uB2C8\uB2E4. \uC124\uC815\uC5D0\uC11C \uBAA8\uB378\uC5D0 \uBCF4\uC774\uB294 \uC124\uBA85\uC744 \uBC14\uAFC0 \uC218 \uC788\uC73C\uBA70, \uB3C4\uAD6C \uB3D9\uC791\uC740 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Choose tools. Details edits model-facing descriptions only; tool behavior is unchanged.", "\u9009\u62E9\u5DE5\u5177\u3002\u8BE6\u60C5\u53EA\u7F16\u8F91\u6A21\u578B\u53EF\u89C1\u7684\u63CF\u8FF0\uFF0C\u5DE5\u5177\u884C\u4E3A\u4E0D\u53D8\u3002") }),
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-field", children: [
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: t("\uAE30\uBCF8 \uD504\uB9AC\uC14B\uC5D0\uC11C \uD55C \uBC88\uC5D0 \uCD94\uAC00", "Include a built-in preset tool set", "\u5F15\u5165\u5185\u7F6E\u9884\u8BBE\u5DE5\u5177\u96C6") }),
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "studio-inline-actions", children: toolSources.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !!p.error, "aria-pressed": includesPreset(p.id), onClick: () => togglePreset(p.id), children: p.id === "cordis" ? "creator (cordis)" : p.id }, p.id)) })
|
|
1632
|
+
] }),
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ItemPicker, { label: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), items: [...tools.map((tool) => ({ ...tool, searchText: JSON.stringify(tool.parameters), ...GENERIC_DELEGATION_TOOLS.includes(tool.name) ? { disabledReason: t(`${ROLE_TOOL}\uB85C \uD1B5\uD569\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uC704\uC784\uC740 ${ROLE_TOOL}\uC744 \uC120\uD0DD\uD558\uC138\uC694.`, `Merged into ${ROLE_TOOL}. Select ${ROLE_TOOL} for subagent delegation.`, `\u5DF2\u5408\u5E76\u5230 ${ROLE_TOOL}\u3002\u8BF7\u9009\u62E9 ${ROLE_TOOL} \u8FDB\u884C\u5B50\u4EE3\u7406\u59D4\u6D3E\u3002`) } : {} })), ...provided.filter((name) => !tools.some((tool) => tool.name === name)).map((name) => ({ name, description: t("\uD604\uC7AC \uC124\uCE58\uB41C \uB3C4\uAD6C \uBAA9\uB85D\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.", "Absent from current catalog", "\u4E0D\u5728\u5F53\u524D\u76EE\u5F55\u4E2D") }))], selected: provided, onChange: changeTools, labels, isModified: (name) => {
|
|
1634
|
+
const tool = tools.find((item) => item.name === name);
|
|
1635
|
+
const override = toolOverrides[name];
|
|
1636
|
+
const parameters = parameterFields(tool?.parameters);
|
|
1637
|
+
return !!(override?.description !== void 0 && override.description !== tool?.description || Object.entries(override?.parameters ?? {}).some(([path, text]) => text !== parameters.find((p) => p.path === path)?.description) || tool?.promptSections?.some((section) => sections[section.name] !== void 0 && sections[section.name] !== section.text));
|
|
1638
|
+
}, renderDetails: (name) => {
|
|
1639
|
+
const tool = tools.find((tool2) => tool2.name === name);
|
|
1640
|
+
const parameters = parameterFields(tool?.parameters);
|
|
1641
|
+
const override = toolOverrides[name];
|
|
1642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uB3C4\uAD6C \uC124\uBA85", "Tool description", "\u5DE5\u5177\u63CF\u8FF0"), description: t("\uBAA8\uB378\uC774 \uBCF4\uB294 \uB3C4\uAD6C \uC124\uBA85\uC785\uB2C8\uB2E4.", "The overall tool description sent to the model.", "\u53D1\u9001\u7ED9\u6A21\u578B\u7684\u5DE5\u5177\u6574\u4F53\u63CF\u8FF0\u3002") }),
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "studio-field", children: [
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-sr-only", children: t("\uB3C4\uAD6C \uC124\uBA85", "Tool description", "\u5DE5\u5177\u63CF\u8FF0") }),
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { value: override?.description ?? tool?.description ?? "", onChange: (e) => setToolOverrides({ ...toolOverrides, [name]: { ...override, description: e.target.value } }) })
|
|
1647
|
+
] }),
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uC0AC\uC6A9 \uC9C0\uCE68", "Tool usage instructions", "\u5DE5\u5177\u4F7F\u7528\u6307\u4EE4"), description: t("\uC2DC\uC2A4\uD15C \uD504\uB86C\uD504\uD2B8\uC5D0 \uB4E4\uC5B4\uAC00\uB294 \uC0AC\uC6A9 \uADDC\uCE59\uC785\uB2C8\uB2E4. \uAC19\uC740 \uC139\uC158\uC744 \uC4F0\uB294 \uB3C4\uAD6C\uB294 \uC774 \uC9C0\uCE68\uC744 \uD568\uAED8 \uC501\uB2C8\uB2E4.", "Usage rules included in the system prompt. Tools referencing the same section share these instructions.", "\u5305\u542B\u5728\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u7684\u4F7F\u7528\u89C4\u5219\u3002\u5F15\u7528\u540C\u4E00\u7AE0\u8282\u7684\u5DE5\u5177\u5171\u4EAB\u8FD9\u4E9B\u6307\u4EE4\u3002") }),
|
|
1649
|
+
!tool?.promptSections?.length && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: t("\uD3B8\uC9D1\uD560 \uC218 \uC788\uB294 \uC0AC\uC6A9 \uC9C0\uCE68\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.", "No separately editable usage instructions.", "\u6CA1\u6709\u53EF\u5355\u72EC\u7F16\u8F91\u7684\u4F7F\u7528\u6307\u4EE4\u3002") }),
|
|
1650
|
+
tool?.promptSections?.map((section) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { children: [
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "studio-field", children: [
|
|
1652
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: section.name }),
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { rows: 5, value: sections[section.name] ?? section.text, onChange: (e) => setSections({ ...sections, [section.name]: e.target.value }) })
|
|
1654
|
+
] }),
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !Object.hasOwn(sections, section.name), onClick: () => {
|
|
1656
|
+
const next = { ...sections };
|
|
1657
|
+
delete next[section.name];
|
|
1658
|
+
setSections(next);
|
|
1659
|
+
}, children: t("\uC6D0\uB798\uB300\uB85C", "Use original", "\u4F7F\u7528\u539F\u59CB\u503C") })
|
|
1660
|
+
] }, section.name)),
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uC778\uC790 \uC124\uBA85", "Parameter descriptions", "\u53C2\u6570\u63CF\u8FF0"), description: t("\uC124\uBA85 \uBB38\uAD6C\uB9CC \uBC14\uAFC0 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC774\uB984, \uD0C0\uC785, \uD544\uC218 \uC5EC\uBD80\uB294 \uADF8\uB300\uB85C\uC785\uB2C8\uB2E4.", "Edit only description text within the tool schema. Names, types, required status and constraints remain unchanged.", "\u4EC5\u7F16\u8F91\u5DE5\u5177\u5B9A\u4E49\u4E2D\u7684\u8BF4\u660E\u6587\u5B57\u3002\u540D\u79F0\u3001\u7C7B\u578B\u3001\u5FC5\u586B\u72B6\u6001\u4E0E\u7EA6\u675F\u4FDD\u6301\u4E0D\u53D8\u3002") }),
|
|
1662
|
+
!parameters.length && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: t("\uD3B8\uC9D1 \uAC00\uB2A5\uD55C \uC778\uC790\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No editable parameters.", "\u6CA1\u6709\u53EF\u7F16\u8F91\u7684\u53C2\u6570\u3002") }),
|
|
1663
|
+
parameters.map((parameter) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "studio-field", children: [
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
1665
|
+
parameter.path,
|
|
1666
|
+
" ",
|
|
1667
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "studio-schema-meta", children: [
|
|
1668
|
+
parameter.type,
|
|
1669
|
+
" \xB7 ",
|
|
1670
|
+
parameter.required ? t("\uD544\uC218", "required", "\u5FC5\u586B") : t("\uC120\uD0DD", "optional", "\u53EF\u9009")
|
|
1671
|
+
] })
|
|
1672
|
+
] }),
|
|
1673
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { "aria-label": parameter.path, value: override?.parameters?.[parameter.path] ?? parameter.description, onChange: (e) => setToolOverrides({ ...toolOverrides, [name]: { ...override, parameters: { ...override?.parameters, [parameter.path]: e.target.value } } }) })
|
|
1674
|
+
] }, parameter.path)),
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !override, onClick: () => {
|
|
1676
|
+
const next = { ...toolOverrides };
|
|
1677
|
+
delete next[name];
|
|
1678
|
+
setToolOverrides(next);
|
|
1679
|
+
}, children: t("\uC124\uBA85 \uBAA8\uB450 \uC6D0\uB798\uB300\uB85C", "Use original", "\u4F7F\u7528\u539F\u59CB\u503C") })
|
|
1680
|
+
] });
|
|
1681
|
+
} })
|
|
1682
|
+
] }),
|
|
1683
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1684
|
+
DetailDialog,
|
|
1685
|
+
{
|
|
1686
|
+
wide: true,
|
|
1687
|
+
open: previewOpen,
|
|
1688
|
+
title: t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Prompt result preview", "\u63D0\u793A\u8BCD\u7ED3\u679C\u9884\u89C8"),
|
|
1689
|
+
closeLabel: t("\uB2EB\uAE30", "Close preview", "\u5173\u95ED\u9884\u89C8"),
|
|
1690
|
+
onClose: closePreview,
|
|
1691
|
+
subtitle: result ? t(`\uC139\uC158 ${result.sections.length}\uAC1C \xB7 \uB3C4\uAD6C ${result.tools.length}\uAC1C`, `${result.sections.length} sections \xB7 ${result.tools.length} tools`, `${result.sections.length} \u4E2A\u7AE0\u8282 \xB7 ${result.tools.length} \u4E2A\u5DE5\u5177`) : void 0,
|
|
1692
|
+
children: [
|
|
1693
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "status", className: "studio-muted", children: t("\uC870\uB9BD \uC911\u2026", "Assembling\u2026", "\u7EC4\u88C5\u4E2D\u2026") }),
|
|
1694
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", children: error }),
|
|
1695
|
+
result && resultKey !== requestKey && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: t("\uC124\uC815\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uBBF8\uB9AC\uBCF4\uAE30\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.", "Configuration changed. Run preview again.", "\u914D\u7F6E\u5DF2\u66F4\u6539\uFF0C\u8BF7\u91CD\u65B0\u9884\u89C8\u3002") }),
|
|
1696
|
+
result && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-preview", "aria-label": t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Prompt preview", "\u63D0\u793A\u8BCD\u9884\u89C8"), children: [
|
|
1697
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "studio-prompt-document", tabIndex: 0, "aria-label": t("\uC870\uB9BD \uC21C\uC11C\uC640 \uB0B4\uC6A9", "Assembly order and content", "\u7EC4\u88C5\u987A\u5E8F\u548C\u5185\u5BB9"), children: result.sections.map((section, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-prompt-section", children: [
|
|
1698
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { children: [
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-prompt-index", children: index + 1 }),
|
|
1700
|
+
section.name
|
|
1701
|
+
] }),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-tool-description", children: section.text })
|
|
1703
|
+
] }, section.name)) }),
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("aside", { className: "studio-prompt-tools", children: [
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { children: [
|
|
1706
|
+
t("\uBAA8\uB378\uC5D0 \uC804\uB2EC\uB418\uB294 \uB3C4\uAD6C", "Model-facing tool schemas", "\u63D0\u4F9B\u7ED9\u6A21\u578B\u7684\u5DE5\u5177\u5B9A\u4E49"),
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-count", children: result.tools.length })
|
|
1708
|
+
] }),
|
|
1709
|
+
result.tools.length ? result.tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "studio-schema-tool", children: [
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: tool.name }),
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-tool-description", children: tool.description }),
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: tool.parameters })
|
|
1713
|
+
] }, tool.name)) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-muted", children: labels.empty })
|
|
1714
|
+
] })
|
|
1715
|
+
] })
|
|
1716
|
+
]
|
|
1717
|
+
}
|
|
1718
|
+
)
|
|
1719
|
+
] });
|
|
1720
|
+
}
|
|
1721
|
+
function SchemaValue({ value }) {
|
|
1722
|
+
if (Array.isArray(value)) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "studio-schema-list", children: value.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: entry }) }, index)) });
|
|
1723
|
+
if (value !== null && typeof value === "object") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dl", { className: "studio-schema-fields", children: Object.entries(value).map(([key, entry]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dt", { children: key }),
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { children: key === "properties" || key === "items" || key === "$defs" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { children: [
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: key }),
|
|
1727
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: entry })
|
|
1728
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SchemaValue, { value: entry }) })
|
|
1729
|
+
] }, key)) });
|
|
1730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-tool-description", children: String(value) });
|
|
1731
|
+
}
|
|
1732
|
+
function parameterFields(schema, prefix = "") {
|
|
1733
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return [];
|
|
1734
|
+
const row = schema;
|
|
1735
|
+
if (!row.properties || typeof row.properties !== "object" || Array.isArray(row.properties)) return [];
|
|
1736
|
+
return Object.entries(row.properties).flatMap(([key, value]) => {
|
|
1737
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
1738
|
+
const field2 = value;
|
|
1739
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1740
|
+
return [{ path, type: Array.isArray(field2.type) ? field2.type.join(" | ") : typeof field2.type === "string" ? field2.type : "\u2014", required: Array.isArray(row.required) && row.required.includes(key), description: typeof field2.description === "string" ? field2.description : "" }, ...parameterFields(field2, path)];
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// src/detail-layout.tsx
|
|
1745
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
1746
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1747
|
+
function DetailLayout({ title, subtitle, navigation, pages, selected, onSelect }) {
|
|
1748
|
+
const id = import_react8.default.useId();
|
|
1749
|
+
const scroller = import_react8.default.useRef(null);
|
|
1750
|
+
import_react8.default.useLayoutEffect(() => {
|
|
1751
|
+
if (scroller.current) scroller.current.scrollTop = 0;
|
|
1752
|
+
}, [selected]);
|
|
1753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "studio-layout", children: [
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("nav", { className: "studio-nav", "aria-label": navigation, children: [
|
|
1755
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "studio-nav-head", children: [
|
|
1756
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { className: "studio-nav-title", children: title }),
|
|
1757
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "studio-nav-subtitle", children: subtitle })
|
|
1758
|
+
] }),
|
|
1759
|
+
pages.map((page, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react8.default.Fragment, { children: [
|
|
1760
|
+
page.group && page.group !== pages[index - 1]?.group && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "studio-nav-group", children: page.group }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1762
|
+
"button",
|
|
1763
|
+
{
|
|
1764
|
+
type: "button",
|
|
1765
|
+
className: "studio-nav-item",
|
|
1766
|
+
"aria-current": selected === page.id ? "page" : void 0,
|
|
1767
|
+
"aria-controls": `${id}-${page.id}`,
|
|
1768
|
+
onClick: () => onSelect(page.id),
|
|
1769
|
+
children: page.label
|
|
1770
|
+
}
|
|
1771
|
+
)
|
|
1772
|
+
] }, page.id))
|
|
1773
|
+
] }),
|
|
1774
|
+
/* @__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)(
|
|
1775
|
+
"section",
|
|
1776
|
+
{
|
|
1777
|
+
id: `${id}-${page.id}`,
|
|
1778
|
+
"aria-label": page.label,
|
|
1779
|
+
hidden: selected !== page.id,
|
|
1780
|
+
children: page.content
|
|
1781
|
+
},
|
|
1782
|
+
page.id
|
|
1783
|
+
)) }) })
|
|
1784
|
+
] });
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// src/optimization-prototype.tsx
|
|
1788
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1789
|
+
var initial = { prompt: "Report evidence, uncertainty and remaining work.", tools: "read / grep / glob", spill: "2048", wait: "60000" };
|
|
1790
|
+
var seeds = [
|
|
1791
|
+
{ name: "Researcher", role: "research", model: "inherit", reasoning: "inherit", spawn: "fresh", persona: "Investigate primary sources and cite the evidence." },
|
|
1792
|
+
{ name: "Reviewer", role: "review", model: "inherit", reasoning: "inherit", spawn: "fork", persona: "Review correctness and identify concrete risks." }
|
|
1793
|
+
];
|
|
1794
|
+
function OptimizationPrototype({ locale, catalog, catalogError, onPreview, presetActions, extensionActions }) {
|
|
1795
|
+
const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
|
|
1796
|
+
const [page, setPage] = import_react9.default.useState("list");
|
|
1797
|
+
const [common, setCommon] = import_react9.default.useState({ ...initial });
|
|
1798
|
+
const [agents, setAgents] = import_react9.default.useState(() => seeds.map((a) => ({ ...a })));
|
|
1799
|
+
const [editing, setEditing] = import_react9.default.useState();
|
|
1800
|
+
const [provided, setProvided] = import_react9.default.useState(defaultProvidedTools);
|
|
1801
|
+
const [tab, setTab] = import_react9.default.useState("tools");
|
|
1802
|
+
const [name, setName] = import_react9.default.useState("");
|
|
1803
|
+
const [description, setDescription] = import_react9.default.useState("");
|
|
1804
|
+
const [draftKey, setDraftKey] = import_react9.default.useState(0);
|
|
1805
|
+
const [revision, setRevision] = import_react9.default.useState(0);
|
|
1806
|
+
const defaults = import_react9.default.useMemo(() => Object.fromEntries((catalog?.plugins ?? []).filter((p) => p.schema && ["tool-bash", "tool-pwsh", "tool-fs", "spill-policy"].includes(p.id)).map((p) => [p.id, {}])), [catalog]);
|
|
1807
|
+
const [configDraft, setConfigDraft] = import_react9.default.useState();
|
|
1808
|
+
const configOverrides = configDraft ?? defaults;
|
|
1809
|
+
const [request, setRequest] = import_react9.default.useState();
|
|
1810
|
+
const [saving, setSaving] = import_react9.default.useState(false);
|
|
1811
|
+
const [saveError, setSaveError] = import_react9.default.useState("");
|
|
1812
|
+
const save = async () => {
|
|
1813
|
+
if (saving || !presetActions || !request || !name.trim()) return;
|
|
1814
|
+
setSaving(true);
|
|
1815
|
+
setSaveError("");
|
|
1816
|
+
try {
|
|
1817
|
+
await presetActions.save(JSON.stringify({ ...editing?.id ? { id: editing.id } : {}, name: name.trim(), description, request: { ...request, configOverrides }, conveniences: { spill: common.spill }, agents }));
|
|
1818
|
+
setRevision((n) => n + 1);
|
|
1819
|
+
setPage("list");
|
|
1820
|
+
setName("");
|
|
1821
|
+
setDescription("");
|
|
1822
|
+
setConfigDraft(void 0);
|
|
1823
|
+
setCommon({ ...initial });
|
|
1824
|
+
setProvided([]);
|
|
1825
|
+
setAgents(seeds.map((a) => ({ ...a })));
|
|
1826
|
+
setEditing(void 0);
|
|
1827
|
+
setTab("tools");
|
|
1828
|
+
setDraftKey((n) => n + 1);
|
|
1829
|
+
} catch (error) {
|
|
1830
|
+
setSaveError(error instanceof Error ? error.message : String(error));
|
|
1831
|
+
} finally {
|
|
1832
|
+
setSaving(false);
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
const editPreset = (item, copy2 = false) => {
|
|
1836
|
+
setEditing(copy2 ? { ...item, id: "" } : item);
|
|
1837
|
+
setName(copy2 ? `${item.name} Copy` : item.name);
|
|
1838
|
+
setDescription(item.description);
|
|
1839
|
+
setCommon({ ...initial, prompt: item.request.prompt, spill: item.conveniences?.spill ?? initial.spill });
|
|
1840
|
+
setProvided([...item.request.tools]);
|
|
1841
|
+
setConfigDraft(item.request.configOverrides ?? {});
|
|
1842
|
+
setAgents(item.agents.map((role) => ({ ...role })));
|
|
1843
|
+
setRequest(item.request);
|
|
1844
|
+
setDraftKey((n) => n + 1);
|
|
1845
|
+
setPage("create");
|
|
1846
|
+
};
|
|
1847
|
+
const persona = "@deepseek-ai/dsh-persona";
|
|
1848
|
+
const presetPersona = request?.providerConfigs?.[persona]?.prefix;
|
|
1849
|
+
const masterPersona = catalog?.presets?.find((p) => p.id === (request?.preset ?? "studio-master"))?.promptProviders?.find((p) => p.name === persona)?.fields?.find((f) => f.key === "prefix")?.value;
|
|
1850
|
+
const defaultPersona = typeof presetPersona === "string" ? presetPersona : typeof masterPersona === "string" ? masterPersona : "";
|
|
1851
|
+
const agentPage = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RoleEditor, { locale, roles: agents, onChange: setAgents, loadModels: presetActions?.models, defaultPersona }, draftKey);
|
|
1852
|
+
const tabs = [
|
|
1853
|
+
{ id: "tools", label: t("\uD504\uB86C\uD504\uD2B8\xB7\uB3C4\uAD6C", "Prompts & tools", "\u63D0\u793A\u8BCD\u4E0E\u5DE5\u5177"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PromptToolsPrototype, { initialRequest: editing?.request, locale, catalog, catalogError, onPreview: onPreview ? (request2) => onPreview({ ...request2, configOverrides }) : void 0, onRequestChange: setRequest, prompt: common.prompt, onPromptChange: (value) => setCommon((c) => ({ ...c, prompt: value })), provided, onProvidedChange: setProvided }, draftKey) },
|
|
1854
|
+
{ id: "convenience", label: t("\uC2E4\uD589 \uC124\uC815", "Execution settings", "\u6267\u884C\u8BBE\u7F6E"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SectionHead, { title: t("\uC2E4\uD589 \uC124\uC815", "Execution settings", "\u6267\u884C\u8BBE\u7F6E"), description: t("\uD50C\uB7EC\uADF8\uC778 Config \uAC12\uC744 \uC774 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB9CC \uB36E\uC5B4\uC501\uB2C8\uB2E4. \uCF20 Config\uC5D0\uC11C \uBC14\uAFBC \uD56D\uBAA9\uB9CC \uC800\uC7A5\uB429\uB2C8\uB2E4.", "Override plugin Config values for this preset only. Only the fields you change in an enabled Config are saved.", "\u4EC5\u4E3A\u6B64\u9884\u8BBE\u8986\u76D6\u63D2\u4EF6 Config \u503C\u3002\u53EA\u4FDD\u5B58\u5DF2\u542F\u7528 Config \u4E2D\u4FEE\u6539\u7684\u5B57\u6BB5\u3002") }),
|
|
1856
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfigEditor, { locale, entries: catalog?.plugins ?? [], value: configOverrides, onChange: setConfigDraft })
|
|
1857
|
+
] }) },
|
|
1858
|
+
{ id: "agents", label: t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagent settings", "\u5B50\u4EE3\u7406\u8BBE\u7F6E"), content: agentPage }
|
|
1859
|
+
];
|
|
1860
|
+
const tabId = import_react9.default.useId();
|
|
1861
|
+
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", "Preset navigation", "\u9884\u8BBE\u5BFC\u822A"), selected: page, onSelect: (next) => {
|
|
1862
|
+
if (next === "create" && editing) {
|
|
1863
|
+
setEditing(void 0);
|
|
1864
|
+
setName("");
|
|
1865
|
+
setDescription("");
|
|
1866
|
+
setCommon({ ...initial });
|
|
1867
|
+
setProvided([]);
|
|
1868
|
+
setConfigDraft(void 0);
|
|
1869
|
+
setAgents(seeds.map((role) => ({ ...role })));
|
|
1870
|
+
setDraftKey((n) => n + 1);
|
|
1871
|
+
}
|
|
1872
|
+
setPage(next);
|
|
1873
|
+
}, pages: [
|
|
1874
|
+
{ id: "list", group: t("\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"), label: t("\uD504\uB9AC\uC14B \uBAA9\uB85D", "Preset list", "\u9884\u8BBE\u5217\u8868"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PresetList, { locale, api: presetActions, revision, onEdit: (item) => editPreset(item), onCopy: (item) => editPreset(item, true) }) },
|
|
1875
|
+
{ id: "create", group: t("\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"), label: editing ? t("\uD504\uB9AC\uC14B \uD3B8\uC9D1", "Edit preset", "\u7F16\u8F91\u9884\u8BBE") : t("\uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30", "Create preset", "\u521B\u5EFA\u9884\u8BBE"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "studio-page-stack", children: [
|
|
1876
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PageHead, { title: editing ? t("\uD504\uB9AC\uC14B \uD3B8\uC9D1", "Edit preset", "\u7F16\u8F91\u9884\u8BBE") : t("\uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30", "Create preset", "\u521B\u5EFA\u9884\u8BBE"), description: editing ? t("\uC800\uC7A5\uD55C \uB4A4 \uD504\uB9AC\uC14B \uBAA9\uB85D\uC5D0\uC11C \uB2E4\uC2DC \uBC18\uC601\uD574\uC57C DSH\uC5D0 \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Saving updates this preset. If it was applied, reapply it from the list to update DSH.", "\u4FDD\u5B58\u4F1A\u66F4\u65B0\u6B64\u9884\u8BBE\u3002\u82E5\u5DF2\u5E94\u7528\uFF0C\u9700\u8981\u5728\u5217\u8868\u4E2D\u91CD\u65B0\u5E94\u7528\u624D\u4F1A\u66F4\u65B0 DSH") : t("\uD504\uB86C\uD504\uD2B8, \uB3C4\uAD6C, \uC2E4\uD589 \uC124\uC815, \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uAD6C\uC131\uD574 \uC0C8 \uD504\uB9AC\uC14B\uC73C\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.", "Configure tools, execution settings and subagent roles, then save a new preset.", "\u914D\u7F6E\u5DE5\u5177\u3001\u6267\u884C\u8BBE\u7F6E\u548C\u5B50\u4EE3\u7406\u89D2\u8272\uFF0C\u5E76\u4FDD\u5B58\u4E3A\u65B0\u9884\u8BBE"), actions: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { primary: true, disabled: saving || !presetActions || !request || !name.trim(), onClick: () => void save(), children: saving ? t("\uC800\uC7A5 \uC911\u2026", "Saving\u2026", "\u4FDD\u5B58\u4E2D\u2026") : t("\uD504\uB9AC\uC14B \uC800\uC7A5", "Save preset", "\u4FDD\u5B58\u9884\u8BBE") }) }),
|
|
1877
|
+
saveError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Notice, { children: t(`\uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uD3B8\uC9D1\uD55C \uB0B4\uC6A9\uC740 \uD654\uBA74\uC5D0 \uADF8\uB300\uB85C \uC788\uC2B5\uB2C8\uB2E4. (${saveError})`, `Could not save the preset. Your edits remain on this screen. (${saveError})`, `\u65E0\u6CD5\u4FDD\u5B58\u9884\u8BBE\uFF0C\u7F16\u8F91\u5185\u5BB9\u4ECD\u4FDD\u7559\u5728\u6B64\u9875\u9762\uFF08${saveError}\uFF09`) }),
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "studio-identity", children: [
|
|
1879
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "studio-field studio-identity-name", children: [
|
|
1880
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: t("\uD504\uB9AC\uC14B \uC774\uB984", "Preset name", "\u9884\u8BBE\u540D\u79F0") }),
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { value: name, maxLength: 120, placeholder: t("\uC608: \uB9AC\uC11C\uCE58\uC6A9 \uC5D0\uC774\uC804\uD2B8", "e.g. Research agent", "\u4F8B\u5982\uFF1A\u7814\u7A76\u4EE3\u7406"), onChange: (e) => setName(e.target.value) })
|
|
1882
|
+
] }),
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "studio-field", children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: t("\uC124\uBA85", "Description", "\u63CF\u8FF0") }),
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { value: description, placeholder: t("\uC5B4\uB5A4 \uC791\uC5C5\uC5D0 \uC4F0\uB294 \uD504\uB9AC\uC14B\uC778\uC9C0 \uD55C \uC904\uB85C \uC801\uC5B4 \uC8FC\uC138\uC694 (\uC120\uD0DD)", "One line on what this preset is for (optional)", "\u4E00\u53E5\u8BDD\u8BF4\u660E\u6B64\u9884\u8BBE\u7684\u7528\u9014\uFF08\u53EF\u9009\uFF09"), onChange: (e) => setDescription(e.target.value) })
|
|
1886
|
+
] })
|
|
1887
|
+
] }),
|
|
1888
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "studio-tabs studio-editor-tabs", role: "tablist", "aria-label": t("\uD504\uB9AC\uC14B \uAD6C\uC131", "Preset configuration", "\u9884\u8BBE\u914D\u7F6E"), children: tabs.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", role: "tab", className: "studio-tab", id: `${tabId}-${item.id}-tab`, "aria-controls": `${tabId}-${item.id}`, "aria-selected": tab === item.id, tabIndex: tab === item.id ? 0 : -1, onClick: () => setTab(item.id), onKeyDown: (e) => {
|
|
1889
|
+
const next = e.key === "ArrowRight" ? (index + 1) % tabs.length : e.key === "ArrowLeft" ? (index + tabs.length - 1) % tabs.length : e.key === "Home" ? 0 : e.key === "End" ? tabs.length - 1 : -1;
|
|
1890
|
+
if (next < 0) return;
|
|
1891
|
+
e.preventDefault();
|
|
1892
|
+
setTab(tabs[next].id);
|
|
1893
|
+
document.getElementById(`${tabId}-${tabs[next].id}-tab`)?.focus();
|
|
1894
|
+
}, children: item.label }, item.id)) }),
|
|
1895
|
+
tabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("section", { role: "tabpanel", className: "studio-tab-body", id: `${tabId}-${item.id}`, "aria-labelledby": `${tabId}-${item.id}-tab`, hidden: tab !== item.id, children: item.content }, item.id))
|
|
1896
|
+
] }) },
|
|
1897
|
+
{ id: "providers", group: t("\uB3C4\uAD6C", "Tools", "\u5DE5\u5177"), label: t("\uB3C4\uAD6C \uC81C\uACF5\uC790", "Tool providers", "\u5DE5\u5177\u63D0\u4F9B\u8005"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MasterExtensionsEditor, { locale, actions: extensionActions }) }
|
|
1898
|
+
] });
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/shell.tsx
|
|
1902
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
1903
|
+
var import_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
|
|
1904
|
+
|
|
1905
|
+
// src/service-layout.tsx
|
|
1906
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
1907
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1908
|
+
var ko = { navigation: "Studio \uC11C\uBE44\uC2A4", empty: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC11C\uBE44\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." };
|
|
1909
|
+
var en = { navigation: "Studio services", empty: "No services are available." };
|
|
1910
|
+
var zh = { navigation: "Studio \u670D\u52A1", empty: "\u6CA1\u6709\u53EF\u7528\u7684\u670D\u52A1" };
|
|
1911
|
+
function ServiceLayout({ locale, services, renderSlot }) {
|
|
1912
|
+
const t = locale.startsWith("ko") ? ko : locale.startsWith("zh") ? zh : en;
|
|
1913
|
+
const [selection, setSelection] = import_react10.default.useState(null);
|
|
1914
|
+
const active = services.some((service) => service.id === selection) ? selection : services[0]?.id;
|
|
1915
|
+
import_react10.default.useEffect(() => {
|
|
1916
|
+
if (selection !== null && !services.some((service) => service.id === selection)) setSelection(null);
|
|
1917
|
+
}, [selection, services]);
|
|
1918
|
+
const id = import_react10.default.useId();
|
|
1919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "studio-services", children: [
|
|
1920
|
+
services.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("nav", { className: "studio-service-nav", "aria-label": t.navigation, children: services.map((service) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1921
|
+
"button",
|
|
1922
|
+
{
|
|
1923
|
+
type: "button",
|
|
1924
|
+
className: "studio-nav-item",
|
|
1925
|
+
"aria-current": service.id === active ? "page" : void 0,
|
|
1926
|
+
"aria-controls": `${id}-${service.id}`,
|
|
1927
|
+
onClick: () => setSelection(service.id),
|
|
1928
|
+
children: service.label
|
|
1929
|
+
},
|
|
1930
|
+
service.id
|
|
1931
|
+
)) }),
|
|
1932
|
+
!services.length && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "status", className: "studio-muted", children: t.empty }),
|
|
1933
|
+
services.map((service) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1934
|
+
"section",
|
|
1935
|
+
{
|
|
1936
|
+
className: "studio-service-panel",
|
|
1937
|
+
id: `${id}-${service.id}`,
|
|
1938
|
+
hidden: service.id !== active,
|
|
1939
|
+
children: renderSlot("local.dsh-studio.services", { active: service.id === active }, { only: service.id })
|
|
1940
|
+
},
|
|
1941
|
+
service.id
|
|
1942
|
+
))
|
|
1943
|
+
] });
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// src/shell.tsx
|
|
1947
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1948
|
+
var inject = ["slots", "locale", "remote"];
|
|
1949
|
+
var panel = "local-dsh-studio";
|
|
1950
|
+
async function apply(ctx) {
|
|
1951
|
+
const remote = ctx.get("remote");
|
|
1952
|
+
await remote.$mount({ package: PACKAGE_NAME, descriptors: [{
|
|
1953
|
+
id: `${PACKAGE_NAME}#studioCatalog/read`,
|
|
1954
|
+
service: "studioCatalog",
|
|
1955
|
+
namespace: "studioCatalog",
|
|
1956
|
+
method: "read",
|
|
1957
|
+
invocation: { kind: "direct" },
|
|
1958
|
+
parameters: [],
|
|
1959
|
+
result: { mode: "src-json" }
|
|
1960
|
+
}, {
|
|
1961
|
+
id: `${PACKAGE_NAME}#studioCatalog/preview`,
|
|
1962
|
+
service: "studioCatalog",
|
|
1963
|
+
namespace: "studioCatalog",
|
|
1964
|
+
method: "preview",
|
|
1965
|
+
invocation: { kind: "direct" },
|
|
1966
|
+
parameters: [{ name: "request", wire: "request", source: "json", codec: { mode: "strict", typeSymbol: "PreviewRequest", create: () => ({ parse: parsePreviewRequest }) } }],
|
|
1967
|
+
result: { mode: "src-json" }
|
|
1968
|
+
}, ...["listPresets", "savePreset", "applyPreset", "unapplyPreset", "roleModels", "deletePreset", "readExtensions", "saveExtensions"].map((method) => ({
|
|
1969
|
+
id: `${PACKAGE_NAME}#studioCatalog/${method}`,
|
|
1970
|
+
service: "studioCatalog",
|
|
1971
|
+
namespace: "studioCatalog",
|
|
1972
|
+
method,
|
|
1973
|
+
invocation: { kind: "direct" },
|
|
1974
|
+
parameters: ["listPresets", "readExtensions", "roleModels"].includes(method) ? [] : [{ name: ["savePreset", "saveExtensions"].includes(method) ? "payload" : "id", wire: ["savePreset", "saveExtensions"].includes(method) ? "payload" : "id", source: "json", codec: { mode: "strict", typeSymbol: "string", create: () => ({ parse: (value) => {
|
|
1975
|
+
if (typeof value !== "string") throw new TypeError("Expected a string");
|
|
1976
|
+
return value;
|
|
1977
|
+
} }) } }],
|
|
1978
|
+
result: { mode: "src-json" }
|
|
1979
|
+
}))] });
|
|
1980
|
+
ctx.effect(() => ctx.locale.addLanguage({ id: "ko", label: "\uD55C\uAD6D\uC5B4", fallback: "en" }));
|
|
1981
|
+
const serviceListeners = /* @__PURE__ */ new Set();
|
|
1982
|
+
let services = [];
|
|
1983
|
+
const syncServices = () => {
|
|
1984
|
+
services = ctx.slots.entriesOfSlot("local.dsh-studio.services").slice().sort((a, b) => (a.options.order ?? 0) - (b.options.order ?? 0)).map(({ options }) => ({
|
|
1985
|
+
id: options.id,
|
|
1986
|
+
label: (0, import_dsh_client_ui_slots.resolveSlotLabel)(options.label) ?? options.id
|
|
1987
|
+
}));
|
|
1988
|
+
serviceListeners.forEach((listener) => listener());
|
|
1989
|
+
};
|
|
1990
|
+
ctx.effect(() => ctx.slots.subscribe("local.dsh-studio.services", syncServices));
|
|
1991
|
+
ctx.effect(() => ctx.locale.subscribe(syncServices));
|
|
1992
|
+
function StudioServices({ renderSlot }) {
|
|
1993
|
+
const items = import_react11.default.useSyncExternalStore((listener) => {
|
|
1994
|
+
serviceListeners.add(listener);
|
|
1995
|
+
return () => {
|
|
1996
|
+
serviceListeners.delete(listener);
|
|
1997
|
+
};
|
|
1998
|
+
}, () => services);
|
|
1999
|
+
const locale = import_react11.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
|
|
2000
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StudioSurface, { className: "studio-shell", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("main", { className: "studio-page", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ServiceLayout, { locale, services: items, renderSlot }) }) });
|
|
2001
|
+
}
|
|
2002
|
+
function Icon({ size = 20 }) {
|
|
2003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2004
|
+
"svg",
|
|
2005
|
+
{
|
|
2006
|
+
width: size,
|
|
2007
|
+
height: size,
|
|
2008
|
+
viewBox: "0 0 24 24",
|
|
2009
|
+
fill: "none",
|
|
2010
|
+
stroke: "currentColor",
|
|
2011
|
+
strokeWidth: "1.7",
|
|
2012
|
+
"aria-hidden": "true",
|
|
2013
|
+
children: [
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2015
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "14", y: "3", width: "7", height: "7", rx: "2" }),
|
|
2016
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "14", width: "7", height: "7", rx: "2" }),
|
|
2017
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17.5 14v7M14 17.5h7" })
|
|
2018
|
+
]
|
|
2019
|
+
}
|
|
2020
|
+
);
|
|
2021
|
+
}
|
|
2022
|
+
ctx.slots.inject(
|
|
2023
|
+
"main",
|
|
2024
|
+
() => ctx.slots.register(
|
|
2025
|
+
{
|
|
2026
|
+
name: "main",
|
|
2027
|
+
key: panel,
|
|
2028
|
+
children: {
|
|
2029
|
+
"local.dsh-studio.services": { kind: "list", scope: "root" }
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
StudioServices
|
|
2033
|
+
)
|
|
2034
|
+
);
|
|
2035
|
+
function OptimizationPage() {
|
|
2036
|
+
const locale = import_react11.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
|
|
2037
|
+
const [catalog, setCatalog] = import_react11.default.useState();
|
|
2038
|
+
const [catalogError, setCatalogError] = import_react11.default.useState("");
|
|
2039
|
+
import_react11.default.useEffect(() => {
|
|
2040
|
+
let active = true;
|
|
2041
|
+
const remote2 = ctx.get("remote.studioCatalog");
|
|
2042
|
+
if (!remote2) {
|
|
2043
|
+
setCatalogError("Studio catalog API unavailable");
|
|
2044
|
+
return;
|
|
2045
|
+
}
|
|
2046
|
+
remote2.read().then((result) => {
|
|
2047
|
+
if (!active) return;
|
|
2048
|
+
if (result.ok) setCatalog(result.value);
|
|
2049
|
+
else setCatalogError(result.error?.message ?? "Catalog request failed");
|
|
2050
|
+
}, (error) => {
|
|
2051
|
+
if (active) setCatalogError(String(error));
|
|
2052
|
+
});
|
|
2053
|
+
return () => {
|
|
2054
|
+
active = false;
|
|
2055
|
+
};
|
|
2056
|
+
}, []);
|
|
2057
|
+
const presetActions = import_react11.default.useMemo(() => {
|
|
2058
|
+
const call = async (method, ...args) => {
|
|
2059
|
+
const service = ctx.get("remote.studioCatalog");
|
|
2060
|
+
const result = await service[method](...args);
|
|
2061
|
+
if (!result.ok) throw new Error(result.error?.message ?? "Preset request failed");
|
|
2062
|
+
return result.value;
|
|
2063
|
+
};
|
|
2064
|
+
return {
|
|
2065
|
+
list: () => call("listPresets"),
|
|
2066
|
+
save: (payload) => call("savePreset", payload),
|
|
2067
|
+
apply: (id) => call("applyPreset", id),
|
|
2068
|
+
models: () => call("roleModels"),
|
|
2069
|
+
unapply: (id) => call("unapplyPreset", id),
|
|
2070
|
+
delete: (id) => call("deletePreset", id)
|
|
2071
|
+
};
|
|
2072
|
+
}, []);
|
|
2073
|
+
const extensionActions = import_react11.default.useMemo(() => {
|
|
2074
|
+
const call = async (method, ...args) => {
|
|
2075
|
+
const service = ctx.get("remote.studioCatalog");
|
|
2076
|
+
const result = await service[method](...args);
|
|
2077
|
+
if (!result.ok) throw new Error(result.error?.message ?? "Master update failed");
|
|
2078
|
+
return result.value;
|
|
2079
|
+
};
|
|
2080
|
+
return { read: () => call("readExtensions"), save: async (payload) => {
|
|
2081
|
+
setCatalog(await call("saveExtensions", payload));
|
|
2082
|
+
} };
|
|
2083
|
+
}, []);
|
|
2084
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OptimizationPrototype, { extensionActions, presetActions, locale, catalog, catalogError, onPreview: async (request) => {
|
|
2085
|
+
const service = ctx.get("remote.studioCatalog");
|
|
2086
|
+
const response = await service.preview(request);
|
|
2087
|
+
if (!response.ok) throw new Error(response.error?.message ?? "Preview failed");
|
|
2088
|
+
return response.value;
|
|
2089
|
+
} });
|
|
2090
|
+
}
|
|
2091
|
+
ctx.slots.inject("local.dsh-studio.services", () => ctx.slots.register({
|
|
2092
|
+
name: "local.dsh-studio.services",
|
|
2093
|
+
id: "optimization-prototype",
|
|
2094
|
+
order: 0,
|
|
2095
|
+
label: () => ({ ko: "\uD504\uB9AC\uC14B", en: "Presets", zh: "\u9884\u8BBE" })[ctx.locale.getLocale().active] ?? "Presets"
|
|
2096
|
+
}, OptimizationPage));
|
|
2097
|
+
syncServices();
|
|
2098
|
+
ctx.slots.inject(
|
|
2099
|
+
"sidebar.panellist",
|
|
2100
|
+
() => ctx.slots.register(
|
|
2101
|
+
{
|
|
2102
|
+
name: "sidebar.panellist",
|
|
2103
|
+
id: panel,
|
|
2104
|
+
order: 20,
|
|
2105
|
+
label: "DSH Studio"
|
|
2106
|
+
},
|
|
2107
|
+
Icon
|
|
2108
|
+
)
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
2111
|
+
return module.exports; }});
|