@ddtcorex/dsh-maestro-config 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js
CHANGED
|
@@ -2176,6 +2176,18 @@ var t = {
|
|
|
2176
2176
|
shadowLv3: "var(--dsw-shadow-lv3)",
|
|
2177
2177
|
scrollbarL2: "var(--dsw-alias-scrollbar-bg-l2)"
|
|
2178
2178
|
};
|
|
2179
|
+
var TAB_ICON_PATHS = {
|
|
2180
|
+
globe: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20M2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10A15 15 0 0 1 12 2z",
|
|
2181
|
+
git: "M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5 0-1.2-.4-2.3-1-3 0-1 0-2 0-3s-1 0-2 1a11 11 0 0 0-6 0c-1-1-2-1-2-1 0 1 0 2 0 3-.6.7-1 1.8-1 3 0 3.5 3 5.5 6 5.5-.4.3-.7.7-.9 1.2-.2.5-.3 1-.3 1.5V22",
|
|
2182
|
+
search: "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-3.5-3.5",
|
|
2183
|
+
shield: "M12 2l7 4v5c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-4z",
|
|
2184
|
+
ban: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM4 12h16",
|
|
2185
|
+
cpu: "M5 12H2a2 2 0 0 1 2-2h2M12 5V2a2 2 0 0 1 2 2v2M19 12h2a2 2 0 0 1-2 2h-2M12 19v2a2 2 0 0 1-2-2v-2M8 8h8v8H8z",
|
|
2186
|
+
bell: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0"
|
|
2187
|
+
};
|
|
2188
|
+
function TabIcon({ name, size = 14 }) {
|
|
2189
|
+
return (0, import_react.createElement)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: { flex: "none" } }, (0, import_react.createElement)("path", { d: TAB_ICON_PATHS[name] }));
|
|
2190
|
+
}
|
|
2179
2191
|
function Button({
|
|
2180
2192
|
variant = "ghost",
|
|
2181
2193
|
size = "md",
|
|
@@ -2520,14 +2532,15 @@ function ReviewModelSelector({
|
|
|
2520
2532
|
position: "absolute",
|
|
2521
2533
|
top: "calc(100% + 8px)",
|
|
2522
2534
|
left: "0",
|
|
2523
|
-
minWidth: "300px",
|
|
2524
|
-
maxWidth: "360px",
|
|
2535
|
+
minWidth: "min(300px, calc(100vw - 32px))",
|
|
2536
|
+
maxWidth: "min(360px, calc(100vw - 24px))",
|
|
2525
2537
|
background: t.bgLayer2,
|
|
2526
2538
|
border: `1px solid ${t.borderL2}`,
|
|
2527
2539
|
borderRadius: "12px",
|
|
2528
2540
|
boxShadow: t.shadowLv3,
|
|
2529
2541
|
zIndex: "20",
|
|
2530
|
-
padding: "6px"
|
|
2542
|
+
padding: "6px",
|
|
2543
|
+
boxSizing: "border-box"
|
|
2531
2544
|
};
|
|
2532
2545
|
const rowStyle2 = {
|
|
2533
2546
|
width: "100%",
|
|
@@ -2551,7 +2564,7 @@ function ReviewModelSelector({
|
|
|
2551
2564
|
const modelLabel = selectedProvider === "" ? "Select model" : value?.model ?? "Select model";
|
|
2552
2565
|
return (0, import_react.createElement)(
|
|
2553
2566
|
"div",
|
|
2554
|
-
{ ref: rootRef, "data-maestro-trigger-wrap": "", style: { position: "relative", display: "inline-block", maxWidth: "100%" } },
|
|
2567
|
+
{ ref: rootRef, "data-maestro-trigger-wrap": "", style: { position: "relative", display: "inline-block", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" } },
|
|
2555
2568
|
label ? (0, import_react.createElement)("span", { style: fieldLabelStyle }, label) : null,
|
|
2556
2569
|
(0, import_react.createElement)(
|
|
2557
2570
|
"button",
|
|
@@ -2570,8 +2583,10 @@ function ReviewModelSelector({
|
|
|
2570
2583
|
alignItems: "center",
|
|
2571
2584
|
gap: 8,
|
|
2572
2585
|
cursor: "pointer",
|
|
2573
|
-
maxWidth:
|
|
2574
|
-
|
|
2586
|
+
maxWidth: "min(320px, 100%)",
|
|
2587
|
+
minWidth: 0,
|
|
2588
|
+
whiteSpace: "nowrap",
|
|
2589
|
+
boxSizing: "border-box"
|
|
2575
2590
|
},
|
|
2576
2591
|
onClick: () => {
|
|
2577
2592
|
setOpen((v) => !v);
|
|
@@ -2977,6 +2992,143 @@ function NamedTunnelSetupNote() {
|
|
|
2977
2992
|
(0, import_react.createElement)("ol", { style: { margin: "4px 0", paddingLeft: 20, fontSize: 12, color: t.labelSecondary, lineHeight: "18px" } }, (0, import_react.createElement)("li", null, "cloudflared tunnel login"), (0, import_react.createElement)("li", null, "cloudflared tunnel create dsh-maestro-webhook"), (0, import_react.createElement)("li", null, "cloudflared tunnel route dns dsh-maestro-webhook <your-hostname>"), (0, import_react.createElement)("li", null, "Paste the printed Tunnel ID, credentials file path and hostname below."))
|
|
2978
2993
|
);
|
|
2979
2994
|
}
|
|
2995
|
+
function PlaceholderMappingsEditor({ rows, onChange }) {
|
|
2996
|
+
const updateRow = (index, field, value) => {
|
|
2997
|
+
onChange(rows.map((row, i) => i === index ? { ...row, [field]: value } : row));
|
|
2998
|
+
};
|
|
2999
|
+
const removeRow = (index) => onChange(rows.filter((_, i) => i !== index));
|
|
3000
|
+
const addRow = () => onChange([...rows, { pattern: "", suggestion: "" }]);
|
|
3001
|
+
return (0, import_react.createElement)(
|
|
3002
|
+
"div",
|
|
3003
|
+
{ "data-maestro-placeholders": "", style: { display: "flex", flexDirection: "column", gap: 12, paddingTop: 8 } },
|
|
3004
|
+
// Header — count + primary Add (stacks on mobile via CSS)
|
|
3005
|
+
(0, import_react.createElement)(
|
|
3006
|
+
"div",
|
|
3007
|
+
{ "data-maestro-placeholders-header": "", style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, padding: "4px 0" } },
|
|
3008
|
+
(0, import_react.createElement)(
|
|
3009
|
+
"div",
|
|
3010
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
3011
|
+
(0, import_react.createElement)("div", { style: { fontSize: 14, fontWeight: 600, color: t.labelPrimary, lineHeight: "20px" } }, `Placeholder mappings \u2014 ${rows.length} mapped`),
|
|
3012
|
+
(0, import_react.createElement)("div", { style: { fontSize: 12, color: t.labelSecondary, lineHeight: "16px", marginTop: 2 } }, "Blocked pattern \u2192 placeholder suggestion, one mapping per row")
|
|
3013
|
+
),
|
|
3014
|
+
(0, import_react.createElement)(Button, { variant: "primary", size: "md", onClick: addRow, "data-maestro-placeholders-add": "" }, "+ Add mapping")
|
|
3015
|
+
),
|
|
3016
|
+
rows.length === 0 ? (0, import_react.createElement)(
|
|
3017
|
+
"div",
|
|
3018
|
+
{
|
|
3019
|
+
"data-maestro-placeholders-empty": "",
|
|
3020
|
+
style: {
|
|
3021
|
+
display: "flex",
|
|
3022
|
+
flexDirection: "column",
|
|
3023
|
+
alignItems: "center",
|
|
3024
|
+
gap: 10,
|
|
3025
|
+
padding: "20px 16px",
|
|
3026
|
+
borderRadius: 12,
|
|
3027
|
+
border: `1px dashed ${t.borderL2}`,
|
|
3028
|
+
background: "transparent",
|
|
3029
|
+
textAlign: "center"
|
|
3030
|
+
}
|
|
3031
|
+
},
|
|
3032
|
+
(0, import_react.createElement)("div", { style: { fontSize: 13, color: t.labelSecondary, lineHeight: "18px" } }, "No placeholder mappings yet \u2014 add your first mapping"),
|
|
3033
|
+
(0, import_react.createElement)(Button, { variant: "outline", size: "md", onClick: addRow }, "+ Add mapping")
|
|
3034
|
+
) : (0, import_react.createElement)(
|
|
3035
|
+
"div",
|
|
3036
|
+
{ "data-maestro-placeholders-list": "", style: { display: "flex", flexDirection: "column", gap: 12 } },
|
|
3037
|
+
...rows.map(
|
|
3038
|
+
(row, i) => (0, import_react.createElement)(
|
|
3039
|
+
"div",
|
|
3040
|
+
{
|
|
3041
|
+
key: i,
|
|
3042
|
+
"data-maestro-mapping-card": "",
|
|
3043
|
+
style: {
|
|
3044
|
+
display: "flex",
|
|
3045
|
+
flexDirection: "column",
|
|
3046
|
+
gap: 12,
|
|
3047
|
+
padding: 12,
|
|
3048
|
+
borderRadius: 12,
|
|
3049
|
+
border: `1px solid ${t.borderL2}`,
|
|
3050
|
+
background: t.bgLayer1,
|
|
3051
|
+
boxSizing: "border-box"
|
|
3052
|
+
}
|
|
3053
|
+
},
|
|
3054
|
+
// Card header: index badge + preview + X (same as Review's project card header)
|
|
3055
|
+
(0, import_react.createElement)(
|
|
3056
|
+
"div",
|
|
3057
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 } },
|
|
3058
|
+
(0, import_react.createElement)(
|
|
3059
|
+
"div",
|
|
3060
|
+
{ style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0, flex: 1 } },
|
|
3061
|
+
(0, import_react.createElement)(
|
|
3062
|
+
"span",
|
|
3063
|
+
{
|
|
3064
|
+
style: {
|
|
3065
|
+
flex: "none",
|
|
3066
|
+
width: 24,
|
|
3067
|
+
height: 24,
|
|
3068
|
+
borderRadius: 12,
|
|
3069
|
+
background: "var(--dsw-alias-bg-module-platform, #F5F6F7)",
|
|
3070
|
+
display: "inline-flex",
|
|
3071
|
+
alignItems: "center",
|
|
3072
|
+
justifyContent: "center",
|
|
3073
|
+
fontSize: 11,
|
|
3074
|
+
fontWeight: 600,
|
|
3075
|
+
color: t.labelSecondary
|
|
3076
|
+
}
|
|
3077
|
+
},
|
|
3078
|
+
String(i + 1)
|
|
3079
|
+
),
|
|
3080
|
+
(0, import_react.createElement)(
|
|
3081
|
+
"span",
|
|
3082
|
+
{
|
|
3083
|
+
style: {
|
|
3084
|
+
fontSize: 12,
|
|
3085
|
+
fontFamily: "ui-monospace, monospace",
|
|
3086
|
+
color: row.pattern ? t.labelPrimary : t.labelTertiary,
|
|
3087
|
+
overflow: "hidden",
|
|
3088
|
+
textOverflow: "ellipsis",
|
|
3089
|
+
whiteSpace: "nowrap",
|
|
3090
|
+
minWidth: 0
|
|
3091
|
+
}
|
|
3092
|
+
},
|
|
3093
|
+
row.pattern ? row.suggestion ? `${row.pattern} \u2192 ${row.suggestion}` : `${row.pattern} \u2192 \u2026` : "New mapping"
|
|
3094
|
+
)
|
|
3095
|
+
),
|
|
3096
|
+
(0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: () => removeRow(i), "aria-label": `Remove mapping ${i + 1}`, title: "Remove mapping" }, "\u2715")
|
|
3097
|
+
),
|
|
3098
|
+
// Fields grid — 2-col desktop, 1-col mobile (same as Review's project grid)
|
|
3099
|
+
(0, import_react.createElement)(
|
|
3100
|
+
"div",
|
|
3101
|
+
{ "data-maestro-mapping-grid": "", style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 } },
|
|
3102
|
+
(0, import_react.createElement)(
|
|
3103
|
+
"label",
|
|
3104
|
+
{ style: fieldLabelStyle, "data-maestro-field": "" },
|
|
3105
|
+
"Blocked pattern",
|
|
3106
|
+
(0, import_react.createElement)(FieldInput, {
|
|
3107
|
+
value: row.pattern,
|
|
3108
|
+
placeholder: "example-project",
|
|
3109
|
+
onChange: (e) => updateRow(i, "pattern", e.target.value),
|
|
3110
|
+
"aria-label": `Blocked pattern ${i + 1}`,
|
|
3111
|
+
style: { width: "100%" }
|
|
3112
|
+
})
|
|
3113
|
+
),
|
|
3114
|
+
(0, import_react.createElement)(
|
|
3115
|
+
"label",
|
|
3116
|
+
{ style: fieldLabelStyle, "data-maestro-field": "" },
|
|
3117
|
+
"Placeholder",
|
|
3118
|
+
(0, import_react.createElement)(FieldInput, {
|
|
3119
|
+
value: row.suggestion,
|
|
3120
|
+
placeholder: "my-project",
|
|
3121
|
+
onChange: (e) => updateRow(i, "suggestion", e.target.value),
|
|
3122
|
+
"aria-label": `Placeholder suggestion ${i + 1}`,
|
|
3123
|
+
style: { width: "100%" }
|
|
3124
|
+
})
|
|
3125
|
+
)
|
|
3126
|
+
)
|
|
3127
|
+
)
|
|
3128
|
+
)
|
|
3129
|
+
)
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
2980
3132
|
function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
2981
3133
|
const [status, setStatus] = (0, import_react.useState)(null);
|
|
2982
3134
|
const [proxyStatus, setProxyStatus] = (0, import_react.useState)(null);
|
|
@@ -2991,34 +3143,49 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
2991
3143
|
const [showLanPin, setShowLanPin] = (0, import_react.useState)(false);
|
|
2992
3144
|
const [guard, setGuard] = (0, import_react.useState)({});
|
|
2993
3145
|
const [patternsText, setPatternsText] = (0, import_react.useState)("");
|
|
2994
|
-
const [
|
|
3146
|
+
const [placeholderRows, setPlaceholderRows] = (0, import_react.useState)([]);
|
|
2995
3147
|
const [supervisorCfg, setSupervisorCfg] = (0, import_react.useState)({});
|
|
2996
3148
|
const [notifierCfg, setNotifierCfg] = (0, import_react.useState)({});
|
|
2997
3149
|
const [activeTab, setActiveTab] = (0, import_react.useState)("tunnel");
|
|
2998
3150
|
(0, import_react.useEffect)(() => {
|
|
2999
3151
|
const css = `
|
|
3000
|
-
/*
|
|
3001
|
-
[data-maestro-
|
|
3152
|
+
/* Model override dropdown \u2014 prevent right-edge overlap */
|
|
3153
|
+
[data-maestro-control] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
3154
|
+
[data-maestro-project-card] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
3155
|
+
[data-maestro-trigger-wrap] { min-width:0; }
|
|
3156
|
+
/* Maestro nested tabs \u2014 unified with dsh-maestro-jobs (maestro-design pill bar) */
|
|
3157
|
+
[data-maestro-tabs] { display:flex; gap:6px; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; touch-action:pan-x; padding:2px 2px 8px; margin:0 -2px 4px; border-bottom:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.08)); }
|
|
3002
3158
|
[data-maestro-tabs]::-webkit-scrollbar { display:none; width:0; height:0; }
|
|
3003
|
-
[data-maestro-tab] { flex:none;
|
|
3004
|
-
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); }
|
|
3159
|
+
[data-maestro-tab] { flex:none; min-width:fit-content; min-height:40px; padding:0 14px; border-radius:999px; border:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.12)); background:transparent; color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px; font-weight:500; font-family:inherit; white-space:nowrap; display:inline-flex; align-items:center; justify-content:center; gap:6px; cursor:pointer; -webkit-tap-highlight-color:transparent; transition: background 150ms ease, color 150ms ease, border-color 150ms ease; touch-action:manipulation; }
|
|
3160
|
+
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); font-weight:600; }
|
|
3005
3161
|
[data-maestro-tab]:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,.06)); }
|
|
3006
3162
|
[data-maestro-tab][data-active="true"]:hover { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); }
|
|
3007
3163
|
[data-maestro-tab]:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary, #4f6ef7); outline-offset:1px; }
|
|
3164
|
+
[data-maestro-tab]:active { transform: scale(.97); }
|
|
3008
3165
|
[data-maestro-panel] { width:100%; min-width:0; box-sizing:border-box; }
|
|
3009
3166
|
/* label/input overlap fix: flex column gap + full width */
|
|
3010
3167
|
[data-maestro-panel] label { gap:6px !important; }
|
|
3011
3168
|
[data-maestro-row]:last-child { border-bottom:none !important; }
|
|
3012
3169
|
[data-maestro-panel] label > span { width:100% !important; box-sizing:border-box !important; }
|
|
3170
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3171
|
+
[data-maestro-tab] { transition: none !important; }
|
|
3172
|
+
[data-maestro-tab]:active { transform: none !important; }
|
|
3173
|
+
}
|
|
3013
3174
|
@media (max-width: 640px) {
|
|
3014
3175
|
[data-maestro-settings-card] { max-width:100% !important; gap:6px !important; padding:0 2px !important; }
|
|
3015
|
-
[data-maestro-tabs] { gap:6px !important; padding:
|
|
3016
|
-
[data-maestro-tab] { height:
|
|
3017
|
-
|
|
3018
|
-
[data-maestro-
|
|
3176
|
+
[data-maestro-tabs] { gap:6px !important; padding:2px 2px 8px !important; margin:0 -2px 8px !important; }
|
|
3177
|
+
[data-maestro-tab] { min-height:40px !important; height:auto !important; padding:0 12px !important; font-size:13px !important; }
|
|
3178
|
+
/* Placeholder mappings \u2014 card design unified with Review project cards (header X, grid fields) */
|
|
3179
|
+
[data-maestro-placeholders-header] { flex-direction: column !important; align-items: stretch !important; }
|
|
3180
|
+
[data-maestro-placeholders-header] [data-maestro-placeholders-add] { width: 100% !important; justify-content: center !important; }
|
|
3181
|
+
[data-maestro-placeholders-list] { gap: 12px !important; }
|
|
3182
|
+
[data-maestro-mapping-card] { padding:10px !important; }
|
|
3183
|
+
[data-maestro-mapping-grid] { grid-template-columns:1fr !important; gap:12px !important; }
|
|
3019
3184
|
[data-maestro-qr-row] { flex-direction:column !important; align-items:flex-start !important; }
|
|
3020
3185
|
[data-maestro-trigger-wrap] { max-width:100% !important; }
|
|
3021
3186
|
[data-maestro-menu] { min-width:0 !important; max-width:calc(100vw - 32px) !important; left:0 !important; right:auto !important; }
|
|
3187
|
+
[data-maestro-control] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
3188
|
+
[data-maestro-project-card] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
3022
3189
|
[data-maestro-panel] label { gap:8px !important; }
|
|
3023
3190
|
div[data-maestro-row] { flex-direction:column !important; align-items:stretch !important; padding:12px 0 !important; }
|
|
3024
3191
|
[data-maestro-row-text] { padding-right:0 !important; }
|
|
@@ -3031,7 +3198,7 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3031
3198
|
[data-maestro-project-profile-row] > label { flex:1 1 100% !important; width:100% !important; }
|
|
3032
3199
|
}
|
|
3033
3200
|
@media (max-width: 390px) {
|
|
3034
|
-
[data-maestro-tab] { height:
|
|
3201
|
+
[data-maestro-tab] { min-height:38px !important; height:auto !important; padding:0 10px !important; font-size:12px !important; }
|
|
3035
3202
|
}
|
|
3036
3203
|
`;
|
|
3037
3204
|
const tag = document.createElement("style");
|
|
@@ -3083,15 +3250,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3083
3250
|
setError(e.message ?? String(e));
|
|
3084
3251
|
}
|
|
3085
3252
|
};
|
|
3086
|
-
const commitPlaceholders = async () => {
|
|
3253
|
+
const commitPlaceholders = async (rows) => {
|
|
3087
3254
|
setError(null);
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
if (
|
|
3092
|
-
|
|
3093
|
-
setError(`placeholders JSON invalid: ${e.message ?? String(e)}`);
|
|
3094
|
-
return;
|
|
3255
|
+
const obj = {};
|
|
3256
|
+
for (const row of rows) {
|
|
3257
|
+
const pattern = (row.pattern ?? "").trim();
|
|
3258
|
+
if (!pattern) continue;
|
|
3259
|
+
obj[pattern] = (row.suggestion ?? "").trim();
|
|
3095
3260
|
}
|
|
3096
3261
|
try {
|
|
3097
3262
|
await cfgSet("guardBlacklist", { placeholders: obj });
|
|
@@ -3139,16 +3304,12 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3139
3304
|
call(MAESTRO_ENDPOINTS.getConfig, {}).then((saved) => setConfig((prev) => ({ ...prev, ...saved }))).catch(() => {
|
|
3140
3305
|
});
|
|
3141
3306
|
if (configRpcCall) {
|
|
3142
|
-
configRpcCall("get", { domain: "supervisor" }).then((res) => {
|
|
3143
|
-
if (res?.ok && res.value?.model) setConfig((prev) => ({ ...prev, supervisorModel: res.value.model }));
|
|
3144
|
-
}).catch(() => {
|
|
3145
|
-
});
|
|
3146
3307
|
Promise.all([cfgGet("guard").catch(() => ({})), cfgGet("guardBlacklist").catch(() => ({ patterns: [], placeholders: {} })), cfgGet("supervisor").catch(() => ({})), cfgGet("notifier").catch(() => ({}))]).then(([g, bl, sup, not]) => {
|
|
3147
3308
|
setGuard(g ?? {});
|
|
3148
3309
|
const pats = Array.isArray(bl?.patterns) ? bl.patterns : [];
|
|
3149
3310
|
const ph = bl?.placeholders && typeof bl.placeholders === "object" ? bl.placeholders : {};
|
|
3150
3311
|
setPatternsText(pats.join("\n"));
|
|
3151
|
-
|
|
3312
|
+
setPlaceholderRows(Object.entries(ph).map(([pattern, suggestion]) => ({ pattern, suggestion: String(suggestion) })));
|
|
3152
3313
|
setSupervisorCfg(sup ?? {});
|
|
3153
3314
|
setNotifierCfg(not ?? {});
|
|
3154
3315
|
}).catch(() => {
|
|
@@ -3251,13 +3412,6 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3251
3412
|
const saveField = async (field, value) => {
|
|
3252
3413
|
setError(null);
|
|
3253
3414
|
setConfig((prev) => ({ ...prev, [field]: value }));
|
|
3254
|
-
if (field === "supervisorModel" && configRpcCall) {
|
|
3255
|
-
try {
|
|
3256
|
-
const res = await configRpcCall("set", { domain: "supervisor", patch: { model: value } });
|
|
3257
|
-
if (res?.ok) return;
|
|
3258
|
-
} catch {
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
3415
|
try {
|
|
3262
3416
|
await call(MAESTRO_ENDPOINTS.saveConfig, { [field]: value });
|
|
3263
3417
|
} catch (err) {
|
|
@@ -3265,13 +3419,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3265
3419
|
}
|
|
3266
3420
|
};
|
|
3267
3421
|
const TABS = [
|
|
3268
|
-
{ id: "tunnel", label: "Tunnel" },
|
|
3269
|
-
{ id: "gitlab", label: "GitLab" },
|
|
3270
|
-
{ id: "review", label: "Review" },
|
|
3271
|
-
{ id: "guard", label: "Guard" },
|
|
3272
|
-
{ id: "blacklist", label: "Blacklist" },
|
|
3273
|
-
{ id: "supervisor", label: "Supervisor" },
|
|
3274
|
-
{ id: "notifier", label: "Notifier" }
|
|
3422
|
+
{ id: "tunnel", label: "Tunnel", icon: "globe" },
|
|
3423
|
+
{ id: "gitlab", label: "GitLab", icon: "git" },
|
|
3424
|
+
{ id: "review", label: "Review", icon: "search" },
|
|
3425
|
+
{ id: "guard", label: "Guard", icon: "shield" },
|
|
3426
|
+
{ id: "blacklist", label: "Blacklist", icon: "ban" },
|
|
3427
|
+
{ id: "supervisor", label: "Supervisor", icon: "cpu" },
|
|
3428
|
+
{ id: "notifier", label: "Notifier", icon: "bell" }
|
|
3275
3429
|
];
|
|
3276
3430
|
const tabContents = {
|
|
3277
3431
|
tunnel: (0, import_react.createElement)(
|
|
@@ -3309,7 +3463,6 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3309
3463
|
{ style: { display: "flex", flexDirection: "column" } },
|
|
3310
3464
|
(0, import_react.createElement)(ToggleRow, { title: "Re-review on push", description: "When new commits are pushed, trigger an automatic re-review.", checked: config.autoRereviewOnPush === true, onChange: (v) => saveField("autoRereviewOnPush", v) }),
|
|
3311
3465
|
(0, import_react.createElement)(SettingRow, { title: "Global review model", description: "Model for automated reviews. Empty = DSH default.", control: (0, import_react.createElement)(ReviewModelSelector, { value: config.reviewModel ?? null, catalog, fallbackValue: catalog?.current ?? null, fallbackLabel: "Use DSH default", onChange: (v) => saveField("reviewModel", v), label: null }) }),
|
|
3312
|
-
(0, import_react.createElement)(SettingRow, { title: "Supervisor model", description: "Model for auto-fixing DSH Web crashes.", control: (0, import_react.createElement)(ReviewModelSelector, { value: config.supervisorModel ?? null, catalog, fallbackValue: catalog?.current ?? null, fallbackLabel: "Use DSH default", onChange: (v) => saveField("supervisorModel", v), label: null }) }),
|
|
3313
3466
|
(0, import_react.createElement)(ProjectMappingsEditor, { mappings: config.projectMappings ?? [], onChange: (mappings) => saveField("projectMappings", mappings), catalog, globalReviewModel: config.reviewModel ?? null })
|
|
3314
3467
|
),
|
|
3315
3468
|
guard: (0, import_react.createElement)(
|
|
@@ -3335,11 +3488,17 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3335
3488
|
"div",
|
|
3336
3489
|
{ style: { ...rowStyle, flexDirection: "column", alignItems: "stretch", gap: 8, borderBottom: "none" } },
|
|
3337
3490
|
(0, import_react.createElement)("div", { style: rowTitleStyle }, "Placeholder mappings"),
|
|
3338
|
-
(0, import_react.createElement)("div", { style: rowDescStyle }, "
|
|
3339
|
-
(0, import_react.createElement)(
|
|
3491
|
+
(0, import_react.createElement)("div", { style: rowDescStyle }, "Blocked pattern \u2192 placeholder suggestion. One mapping per row \u2014 no JSON needed."),
|
|
3492
|
+
(0, import_react.createElement)(PlaceholderMappingsEditor, {
|
|
3493
|
+
rows: placeholderRows,
|
|
3494
|
+
onChange: (rows) => {
|
|
3495
|
+
setPlaceholderRows(rows);
|
|
3496
|
+
commitPlaceholders(rows);
|
|
3497
|
+
}
|
|
3498
|
+
}),
|
|
3340
3499
|
(0, import_react.createElement)("div", { style: { marginTop: 8 } }, (0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
3341
3500
|
commitBlacklistPatterns(patternsText);
|
|
3342
|
-
commitPlaceholders();
|
|
3501
|
+
commitPlaceholders(placeholderRows);
|
|
3343
3502
|
} }, "Save Blacklist"))
|
|
3344
3503
|
)
|
|
3345
3504
|
),
|
|
@@ -3388,7 +3547,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3388
3547
|
(0, import_react.createElement)(
|
|
3389
3548
|
"div",
|
|
3390
3549
|
{ "data-maestro-tabs": "", role: "tablist", "aria-label": "Maestro settings sections" },
|
|
3391
|
-
...TABS.map((tab) => (0, import_react.createElement)("button", { key: tab.id, "data-maestro-tab": "", "data-active": String(activeTab === tab.id), role: "tab", "aria-selected": activeTab === tab.id, onClick: () =>
|
|
3550
|
+
...TABS.map((tab) => (0, import_react.createElement)("button", { key: tab.id, "data-maestro-tab": "", "data-active": String(activeTab === tab.id), role: "tab", "aria-selected": activeTab === tab.id, onClick: (e) => {
|
|
3551
|
+
setActiveTab(tab.id);
|
|
3552
|
+
try {
|
|
3553
|
+
e.currentTarget.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
|
3554
|
+
} catch {
|
|
3555
|
+
}
|
|
3556
|
+
} }, (0, import_react.createElement)(TabIcon, { name: tab.icon }), tab.label))
|
|
3392
3557
|
),
|
|
3393
3558
|
(0, import_react.createElement)("div", { "data-maestro-panel": activeTab, style: { display: "flex", flexDirection: "column", gap: 10, minWidth: 0 } }, tabContents[activeTab]),
|
|
3394
3559
|
error ? (0, import_react.createElement)("p", { style: { color: t.stateError, fontSize: 12, margin: "8px 0 0", padding: "8px 10px", borderRadius: 8, background: "color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent)", border: `1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent)` } }, error) : null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAisCH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;IAAE,OAAO,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,GAAG,CAAA;CAAE;;;;;;;;;mBAsYmE,GAAG;;gBAoBzK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maestro-card.d.ts","sourceRoot":"","sources":["../../../src/client/maestro-card.jsx"],"names":[],"mappings":"AAweA;;;;;;;;
|
|
1
|
+
{"version":3,"file":"maestro-card.d.ts","sourceRoot":"","sources":["../../../src/client/maestro-card.jsx"],"names":[],"mappings":"AAweA;;;;;;;;gBA2bC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddtcorex/dsh-maestro-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Maestro Config — shared settings service for the dsh-maestro-* suite over the single namespaced store (~/.dsh/maestro/settings.json)",
|
|
6
6
|
"type": "module",
|
|
@@ -37,6 +37,26 @@ const t = {
|
|
|
37
37
|
scrollbarL2: 'var(--dsw-alias-scrollbar-bg-l2)',
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Nested pill tabs — unified with dsh-maestro-jobs (maestro-design: Minimalism & Swiss)
|
|
42
|
+
// Shared geometry: 40px min-height (44px jobs → 40px unified, touch-friendly ≥24px WCAG),
|
|
43
|
+
// 14px icon + 13px label gap 6, pill 999, border-l1, #EBEEF2 active, hover, focus ring.
|
|
44
|
+
// Icons: lucide-style 14px SVG, stroke 1.8, currentColor.
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
type TabIcon = 'globe' | 'git' | 'search' | 'shield' | 'ban' | 'cpu' | 'bell'
|
|
47
|
+
const TAB_ICON_PATHS: Record<TabIcon, string> = {
|
|
48
|
+
globe: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20M2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10A15 15 0 0 1 12 2z',
|
|
49
|
+
git: 'M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5 0-1.2-.4-2.3-1-3 0-1 0-2 0-3s-1 0-2 1a11 11 0 0 0-6 0c-1-1-2-1-2-1 0 1 0 2 0 3-.6.7-1 1.8-1 3 0 3.5 3 5.5 6 5.5-.4.3-.7.7-.9 1.2-.2.5-.3 1-.3 1.5V22',
|
|
50
|
+
search: 'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-3.5-3.5',
|
|
51
|
+
shield: 'M12 2l7 4v5c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-4z',
|
|
52
|
+
ban: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM4 12h16',
|
|
53
|
+
cpu: 'M5 12H2a2 2 0 0 1 2-2h2M12 5V2a2 2 0 0 1 2 2v2M19 12h2a2 2 0 0 1-2 2h-2M12 19v2a2 2 0 0 1-2-2v-2M8 8h8v8H8z',
|
|
54
|
+
bell: 'M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0',
|
|
55
|
+
}
|
|
56
|
+
function TabIcon({ name, size = 14 }: { name: TabIcon; size?: number }) {
|
|
57
|
+
return h('svg', { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true', style: { flex: 'none' } }, h('path', { d: TAB_ICON_PATHS[name] }))
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
// ---------------------------------------------------------------------------
|
|
41
61
|
// Lightweight DSH primitive mirrors (geometry + tokens identical to host)
|
|
42
62
|
// Usage is identical to @deepseek-ai/dsh-client-ui-primitives at runtime.
|
|
@@ -533,14 +553,15 @@ function ReviewModelSelector({
|
|
|
533
553
|
position: 'absolute',
|
|
534
554
|
top: 'calc(100% + 8px)',
|
|
535
555
|
left: '0',
|
|
536
|
-
minWidth: '300px',
|
|
537
|
-
maxWidth: '360px',
|
|
556
|
+
minWidth: 'min(300px, calc(100vw - 32px))',
|
|
557
|
+
maxWidth: 'min(360px, calc(100vw - 24px))',
|
|
538
558
|
background: t.bgLayer2 as string,
|
|
539
559
|
border: `1px solid ${t.borderL2}`,
|
|
540
560
|
borderRadius: '12px',
|
|
541
561
|
boxShadow: t.shadowLv3 as string,
|
|
542
562
|
zIndex: '20',
|
|
543
563
|
padding: '6px',
|
|
564
|
+
boxSizing: 'border-box' as string,
|
|
544
565
|
}
|
|
545
566
|
const rowStyle: Record<string, any> = {
|
|
546
567
|
width: '100%',
|
|
@@ -567,7 +588,7 @@ function ReviewModelSelector({
|
|
|
567
588
|
const modelLabel = selectedProvider === '' ? 'Select model' : (value?.model ?? 'Select model')
|
|
568
589
|
return h(
|
|
569
590
|
'div',
|
|
570
|
-
{ ref: rootRef as any, 'data-maestro-trigger-wrap': '', style: { position: 'relative', display: 'inline-block', maxWidth: '100%' } },
|
|
591
|
+
{ ref: rootRef as any, 'data-maestro-trigger-wrap': '', style: { position: 'relative', display: 'inline-block', maxWidth: '100%', minWidth: 0, boxSizing: 'border-box' as string } },
|
|
571
592
|
label ? h('span', { style: fieldLabelStyle }, label) : null,
|
|
572
593
|
h(
|
|
573
594
|
'button',
|
|
@@ -586,8 +607,10 @@ function ReviewModelSelector({
|
|
|
586
607
|
alignItems: 'center',
|
|
587
608
|
gap: 8,
|
|
588
609
|
cursor: 'pointer',
|
|
589
|
-
maxWidth:
|
|
610
|
+
maxWidth: 'min(320px, 100%)',
|
|
611
|
+
minWidth: 0,
|
|
590
612
|
whiteSpace: 'nowrap',
|
|
613
|
+
boxSizing: 'border-box' as string,
|
|
591
614
|
},
|
|
592
615
|
onClick: () => {
|
|
593
616
|
setOpen((v) => !v)
|
|
@@ -1054,6 +1077,150 @@ function NamedTunnelSetupNote() {
|
|
|
1054
1077
|
)
|
|
1055
1078
|
}
|
|
1056
1079
|
|
|
1080
|
+
// ---------------------------------------------------------------------------
|
|
1081
|
+
// PlaceholderMappingsEditor — row-based "blocked pattern → suggestion" mappings
|
|
1082
|
+
// (same interaction as ProjectMappingsEditor; no JSON editing for users)
|
|
1083
|
+
// ---------------------------------------------------------------------------
|
|
1084
|
+
function PlaceholderMappingsEditor({ rows, onChange }: { rows: { pattern: string; suggestion: string }[]; onChange: (rows: { pattern: string; suggestion: string }[]) => void }) {
|
|
1085
|
+
const updateRow = (index: number, field: 'pattern' | 'suggestion', value: string) => {
|
|
1086
|
+
onChange(rows.map((row, i) => (i === index ? { ...row, [field]: value } : row)))
|
|
1087
|
+
}
|
|
1088
|
+
const removeRow = (index: number) => onChange(rows.filter((_, i) => i !== index))
|
|
1089
|
+
const addRow = () => onChange([...rows, { pattern: '', suggestion: '' }])
|
|
1090
|
+
return h(
|
|
1091
|
+
'div',
|
|
1092
|
+
{ 'data-maestro-placeholders': '', style: { display: 'flex', flexDirection: 'column', gap: 12, paddingTop: 8 } },
|
|
1093
|
+
// Header — count + primary Add (stacks on mobile via CSS)
|
|
1094
|
+
h(
|
|
1095
|
+
'div',
|
|
1096
|
+
{ 'data-maestro-placeholders-header': '', style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, padding: '4px 0' } },
|
|
1097
|
+
h(
|
|
1098
|
+
'div',
|
|
1099
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
1100
|
+
h('div', { style: { fontSize: 14, fontWeight: 600, color: t.labelPrimary as string, lineHeight: '20px' } }, `Placeholder mappings — ${rows.length} mapped`),
|
|
1101
|
+
h('div', { style: { fontSize: 12, color: t.labelSecondary as string, lineHeight: '16px', marginTop: 2 } }, 'Blocked pattern → placeholder suggestion, one mapping per row'),
|
|
1102
|
+
),
|
|
1103
|
+
h(Button as any, { variant: 'primary', size: 'md', onClick: addRow, 'data-maestro-placeholders-add': '' }, '+ Add mapping'),
|
|
1104
|
+
),
|
|
1105
|
+
rows.length === 0
|
|
1106
|
+
? h(
|
|
1107
|
+
'div',
|
|
1108
|
+
{
|
|
1109
|
+
'data-maestro-placeholders-empty': '',
|
|
1110
|
+
style: {
|
|
1111
|
+
display: 'flex',
|
|
1112
|
+
flexDirection: 'column',
|
|
1113
|
+
alignItems: 'center',
|
|
1114
|
+
gap: 10,
|
|
1115
|
+
padding: '20px 16px',
|
|
1116
|
+
borderRadius: 12,
|
|
1117
|
+
border: `1px dashed ${t.borderL2}`,
|
|
1118
|
+
background: 'transparent',
|
|
1119
|
+
textAlign: 'center' as const,
|
|
1120
|
+
},
|
|
1121
|
+
},
|
|
1122
|
+
h('div', { style: { fontSize: 13, color: t.labelSecondary as string, lineHeight: '18px' } }, 'No placeholder mappings yet — add your first mapping'),
|
|
1123
|
+
h(Button as any, { variant: 'outline', size: 'md', onClick: addRow }, '+ Add mapping'),
|
|
1124
|
+
)
|
|
1125
|
+
: h(
|
|
1126
|
+
'div',
|
|
1127
|
+
{ 'data-maestro-placeholders-list': '', style: { display: 'flex', flexDirection: 'column', gap: 12 } },
|
|
1128
|
+
...rows.map((row, i) =>
|
|
1129
|
+
h(
|
|
1130
|
+
'div',
|
|
1131
|
+
{
|
|
1132
|
+
key: i,
|
|
1133
|
+
'data-maestro-mapping-card': '',
|
|
1134
|
+
style: {
|
|
1135
|
+
display: 'flex',
|
|
1136
|
+
flexDirection: 'column',
|
|
1137
|
+
gap: 12,
|
|
1138
|
+
padding: 12,
|
|
1139
|
+
borderRadius: 12,
|
|
1140
|
+
border: `1px solid ${t.borderL2}`,
|
|
1141
|
+
background: t.bgLayer1 as string,
|
|
1142
|
+
boxSizing: 'border-box' as const,
|
|
1143
|
+
},
|
|
1144
|
+
},
|
|
1145
|
+
// Card header: index badge + preview + X (same as Review's project card header)
|
|
1146
|
+
h(
|
|
1147
|
+
'div',
|
|
1148
|
+
{ style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 } },
|
|
1149
|
+
h(
|
|
1150
|
+
'div',
|
|
1151
|
+
{ style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flex: 1 } },
|
|
1152
|
+
h(
|
|
1153
|
+
'span',
|
|
1154
|
+
{
|
|
1155
|
+
style: {
|
|
1156
|
+
flex: 'none',
|
|
1157
|
+
width: 24,
|
|
1158
|
+
height: 24,
|
|
1159
|
+
borderRadius: 12,
|
|
1160
|
+
background: 'var(--dsw-alias-bg-module-platform, #F5F6F7)',
|
|
1161
|
+
display: 'inline-flex',
|
|
1162
|
+
alignItems: 'center',
|
|
1163
|
+
justifyContent: 'center',
|
|
1164
|
+
fontSize: 11,
|
|
1165
|
+
fontWeight: 600,
|
|
1166
|
+
color: t.labelSecondary as string,
|
|
1167
|
+
},
|
|
1168
|
+
},
|
|
1169
|
+
String(i + 1),
|
|
1170
|
+
),
|
|
1171
|
+
h(
|
|
1172
|
+
'span',
|
|
1173
|
+
{
|
|
1174
|
+
style: {
|
|
1175
|
+
fontSize: 12,
|
|
1176
|
+
fontFamily: 'ui-monospace, monospace',
|
|
1177
|
+
color: row.pattern ? (t.labelPrimary as string) : (t.labelTertiary as string),
|
|
1178
|
+
overflow: 'hidden',
|
|
1179
|
+
textOverflow: 'ellipsis',
|
|
1180
|
+
whiteSpace: 'nowrap',
|
|
1181
|
+
minWidth: 0,
|
|
1182
|
+
},
|
|
1183
|
+
},
|
|
1184
|
+
row.pattern ? (row.suggestion ? `${row.pattern} → ${row.suggestion}` : `${row.pattern} → …`) : 'New mapping',
|
|
1185
|
+
),
|
|
1186
|
+
),
|
|
1187
|
+
h(Button as any, { variant: 'outline', size: 'sm', onClick: () => removeRow(i), 'aria-label': `Remove mapping ${i + 1}`, title: 'Remove mapping' }, '✕'),
|
|
1188
|
+
),
|
|
1189
|
+
// Fields grid — 2-col desktop, 1-col mobile (same as Review's project grid)
|
|
1190
|
+
h(
|
|
1191
|
+
'div',
|
|
1192
|
+
{ 'data-maestro-mapping-grid': '', style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
1193
|
+
h(
|
|
1194
|
+
'label',
|
|
1195
|
+
{ style: fieldLabelStyle, 'data-maestro-field': '' },
|
|
1196
|
+
'Blocked pattern',
|
|
1197
|
+
h(FieldInput as any, {
|
|
1198
|
+
value: row.pattern,
|
|
1199
|
+
placeholder: 'example-project',
|
|
1200
|
+
onChange: (e: any) => updateRow(i, 'pattern', e.target.value),
|
|
1201
|
+
'aria-label': `Blocked pattern ${i + 1}`,
|
|
1202
|
+
style: { width: '100%' } as any,
|
|
1203
|
+
}),
|
|
1204
|
+
),
|
|
1205
|
+
h(
|
|
1206
|
+
'label',
|
|
1207
|
+
{ style: fieldLabelStyle, 'data-maestro-field': '' },
|
|
1208
|
+
'Placeholder',
|
|
1209
|
+
h(FieldInput as any, {
|
|
1210
|
+
value: row.suggestion,
|
|
1211
|
+
placeholder: 'my-project',
|
|
1212
|
+
onChange: (e: any) => updateRow(i, 'suggestion', e.target.value),
|
|
1213
|
+
'aria-label': `Placeholder suggestion ${i + 1}`,
|
|
1214
|
+
style: { width: '100%' } as any,
|
|
1215
|
+
}),
|
|
1216
|
+
),
|
|
1217
|
+
),
|
|
1218
|
+
),
|
|
1219
|
+
),
|
|
1220
|
+
),
|
|
1221
|
+
)
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1057
1224
|
// ---------------------------------------------------------------------------
|
|
1058
1225
|
// Main — DSH-native grouped settings (DisclosureRow per domain)
|
|
1059
1226
|
// ---------------------------------------------------------------------------
|
|
@@ -1071,35 +1238,50 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1071
1238
|
const [showLanPin, setShowLanPin] = useState(false)
|
|
1072
1239
|
const [guard, setGuard] = useState<any>({})
|
|
1073
1240
|
const [patternsText, setPatternsText] = useState('')
|
|
1074
|
-
const [
|
|
1241
|
+
const [placeholderRows, setPlaceholderRows] = useState<{ pattern: string; suggestion: string }[]>([])
|
|
1075
1242
|
const [supervisorCfg, setSupervisorCfg] = useState<any>({})
|
|
1076
1243
|
const [notifierCfg, setNotifierCfg] = useState<any>({})
|
|
1077
1244
|
const [activeTab, setActiveTab] = useState('tunnel')
|
|
1078
1245
|
// Mobile: inject responsive overrides once (mirrors dsh-maestro-mobile settings-sheet pill pattern + market catsWrap)
|
|
1079
1246
|
useEffect(() => {
|
|
1080
1247
|
const css = `
|
|
1081
|
-
/*
|
|
1082
|
-
[data-maestro-
|
|
1248
|
+
/* Model override dropdown — prevent right-edge overlap */
|
|
1249
|
+
[data-maestro-control] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
1250
|
+
[data-maestro-project-card] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
1251
|
+
[data-maestro-trigger-wrap] { min-width:0; }
|
|
1252
|
+
/* Maestro nested tabs — unified with dsh-maestro-jobs (maestro-design pill bar) */
|
|
1253
|
+
[data-maestro-tabs] { display:flex; gap:6px; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; touch-action:pan-x; padding:2px 2px 8px; margin:0 -2px 4px; border-bottom:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.08)); }
|
|
1083
1254
|
[data-maestro-tabs]::-webkit-scrollbar { display:none; width:0; height:0; }
|
|
1084
|
-
[data-maestro-tab] { flex:none;
|
|
1085
|
-
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); }
|
|
1255
|
+
[data-maestro-tab] { flex:none; min-width:fit-content; min-height:40px; padding:0 14px; border-radius:999px; border:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.12)); background:transparent; color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px; font-weight:500; font-family:inherit; white-space:nowrap; display:inline-flex; align-items:center; justify-content:center; gap:6px; cursor:pointer; -webkit-tap-highlight-color:transparent; transition: background 150ms ease, color 150ms ease, border-color 150ms ease; touch-action:manipulation; }
|
|
1256
|
+
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); font-weight:600; }
|
|
1086
1257
|
[data-maestro-tab]:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,.06)); }
|
|
1087
1258
|
[data-maestro-tab][data-active="true"]:hover { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); }
|
|
1088
1259
|
[data-maestro-tab]:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary, #4f6ef7); outline-offset:1px; }
|
|
1260
|
+
[data-maestro-tab]:active { transform: scale(.97); }
|
|
1089
1261
|
[data-maestro-panel] { width:100%; min-width:0; box-sizing:border-box; }
|
|
1090
1262
|
/* label/input overlap fix: flex column gap + full width */
|
|
1091
1263
|
[data-maestro-panel] label { gap:6px !important; }
|
|
1092
1264
|
[data-maestro-row]:last-child { border-bottom:none !important; }
|
|
1093
1265
|
[data-maestro-panel] label > span { width:100% !important; box-sizing:border-box !important; }
|
|
1266
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1267
|
+
[data-maestro-tab] { transition: none !important; }
|
|
1268
|
+
[data-maestro-tab]:active { transform: none !important; }
|
|
1269
|
+
}
|
|
1094
1270
|
@media (max-width: 640px) {
|
|
1095
1271
|
[data-maestro-settings-card] { max-width:100% !important; gap:6px !important; padding:0 2px !important; }
|
|
1096
|
-
[data-maestro-tabs] { gap:6px !important; padding:
|
|
1097
|
-
[data-maestro-tab] { height:
|
|
1098
|
-
|
|
1099
|
-
[data-maestro-
|
|
1272
|
+
[data-maestro-tabs] { gap:6px !important; padding:2px 2px 8px !important; margin:0 -2px 8px !important; }
|
|
1273
|
+
[data-maestro-tab] { min-height:40px !important; height:auto !important; padding:0 12px !important; font-size:13px !important; }
|
|
1274
|
+
/* Placeholder mappings — card design unified with Review project cards (header X, grid fields) */
|
|
1275
|
+
[data-maestro-placeholders-header] { flex-direction: column !important; align-items: stretch !important; }
|
|
1276
|
+
[data-maestro-placeholders-header] [data-maestro-placeholders-add] { width: 100% !important; justify-content: center !important; }
|
|
1277
|
+
[data-maestro-placeholders-list] { gap: 12px !important; }
|
|
1278
|
+
[data-maestro-mapping-card] { padding:10px !important; }
|
|
1279
|
+
[data-maestro-mapping-grid] { grid-template-columns:1fr !important; gap:12px !important; }
|
|
1100
1280
|
[data-maestro-qr-row] { flex-direction:column !important; align-items:flex-start !important; }
|
|
1101
1281
|
[data-maestro-trigger-wrap] { max-width:100% !important; }
|
|
1102
1282
|
[data-maestro-menu] { min-width:0 !important; max-width:calc(100vw - 32px) !important; left:0 !important; right:auto !important; }
|
|
1283
|
+
[data-maestro-control] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
1284
|
+
[data-maestro-project-card] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
1103
1285
|
[data-maestro-panel] label { gap:8px !important; }
|
|
1104
1286
|
div[data-maestro-row] { flex-direction:column !important; align-items:stretch !important; padding:12px 0 !important; }
|
|
1105
1287
|
[data-maestro-row-text] { padding-right:0 !important; }
|
|
@@ -1112,7 +1294,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1112
1294
|
[data-maestro-project-profile-row] > label { flex:1 1 100% !important; width:100% !important; }
|
|
1113
1295
|
}
|
|
1114
1296
|
@media (max-width: 390px) {
|
|
1115
|
-
[data-maestro-tab] { height:
|
|
1297
|
+
[data-maestro-tab] { min-height:38px !important; height:auto !important; padding:0 10px !important; font-size:12px !important; }
|
|
1116
1298
|
}
|
|
1117
1299
|
`
|
|
1118
1300
|
const tag = document.createElement('style')
|
|
@@ -1165,15 +1347,13 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1165
1347
|
setError(e.message ?? String(e))
|
|
1166
1348
|
}
|
|
1167
1349
|
}
|
|
1168
|
-
const commitPlaceholders = async () => {
|
|
1350
|
+
const commitPlaceholders = async (rows: { pattern: string; suggestion: string }[]) => {
|
|
1169
1351
|
setError(null)
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1175
|
-
setError(`placeholders JSON invalid: ${e.message ?? String(e)}`)
|
|
1176
|
-
return
|
|
1352
|
+
const obj: Record<string, string> = {}
|
|
1353
|
+
for (const row of rows) {
|
|
1354
|
+
const pattern = (row.pattern ?? '').trim()
|
|
1355
|
+
if (!pattern) continue
|
|
1356
|
+
obj[pattern] = (row.suggestion ?? '').trim()
|
|
1177
1357
|
}
|
|
1178
1358
|
try {
|
|
1179
1359
|
await cfgSet('guardBlacklist', { placeholders: obj })
|
|
@@ -1220,18 +1400,13 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1220
1400
|
.then((saved) => setConfig((prev: any) => ({ ...prev, ...saved })))
|
|
1221
1401
|
.catch(() => {})
|
|
1222
1402
|
if (configRpcCall) {
|
|
1223
|
-
configRpcCall('get', { domain: 'supervisor' })
|
|
1224
|
-
.then((res: any) => {
|
|
1225
|
-
if (res?.ok && res.value?.model) setConfig((prev: any) => ({ ...prev, supervisorModel: res.value.model }))
|
|
1226
|
-
})
|
|
1227
|
-
.catch(() => {})
|
|
1228
1403
|
Promise.all([cfgGet('guard').catch(() => ({})), cfgGet('guardBlacklist').catch(() => ({ patterns: [], placeholders: {} })), cfgGet('supervisor').catch(() => ({})), cfgGet('notifier').catch(() => ({}))])
|
|
1229
1404
|
.then(([g, bl, sup, not]) => {
|
|
1230
1405
|
setGuard(g ?? {})
|
|
1231
1406
|
const pats = Array.isArray((bl as any)?.patterns) ? (bl as any).patterns : []
|
|
1232
1407
|
const ph = (bl as any)?.placeholders && typeof (bl as any).placeholders === 'object' ? (bl as any).placeholders : {}
|
|
1233
1408
|
setPatternsText(pats.join('\n'))
|
|
1234
|
-
|
|
1409
|
+
setPlaceholderRows(Object.entries(ph).map(([pattern, suggestion]) => ({ pattern, suggestion: String(suggestion) })))
|
|
1235
1410
|
setSupervisorCfg(sup ?? {})
|
|
1236
1411
|
setNotifierCfg(not ?? {})
|
|
1237
1412
|
})
|
|
@@ -1336,12 +1511,6 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1336
1511
|
const saveField = async (field: string, value: unknown) => {
|
|
1337
1512
|
setError(null)
|
|
1338
1513
|
setConfig((prev: any) => ({ ...prev, [field]: value }))
|
|
1339
|
-
if (field === 'supervisorModel' && configRpcCall) {
|
|
1340
|
-
try {
|
|
1341
|
-
const res = await configRpcCall('set', { domain: 'supervisor', patch: { model: value } })
|
|
1342
|
-
if (res?.ok) return
|
|
1343
|
-
} catch {}
|
|
1344
|
-
}
|
|
1345
1514
|
try {
|
|
1346
1515
|
await call(MAESTRO_ENDPOINTS.saveConfig, { [field]: value })
|
|
1347
1516
|
} catch (err: any) {
|
|
@@ -1349,16 +1518,16 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1349
1518
|
}
|
|
1350
1519
|
}
|
|
1351
1520
|
|
|
1352
|
-
// Nested tabs
|
|
1353
|
-
const TABS = [
|
|
1354
|
-
{ id: 'tunnel', label: 'Tunnel' },
|
|
1355
|
-
{ id: 'gitlab', label: 'GitLab' },
|
|
1356
|
-
{ id: 'review', label: 'Review' },
|
|
1357
|
-
{ id: 'guard', label: 'Guard' },
|
|
1358
|
-
{ id: 'blacklist', label: 'Blacklist' },
|
|
1359
|
-
{ id: 'supervisor', label: 'Supervisor' },
|
|
1360
|
-
{ id: 'notifier', label: 'Notifier' },
|
|
1361
|
-
]
|
|
1521
|
+
// Nested tabs — unified pill bar with icons (maestro-design, matches dsh-maestro-jobs)
|
|
1522
|
+
const TABS: Array<{ id: string; label: string; icon: TabIcon }> = [
|
|
1523
|
+
{ id: 'tunnel', label: 'Tunnel', icon: 'globe' },
|
|
1524
|
+
{ id: 'gitlab', label: 'GitLab', icon: 'git' },
|
|
1525
|
+
{ id: 'review', label: 'Review', icon: 'search' },
|
|
1526
|
+
{ id: 'guard', label: 'Guard', icon: 'shield' },
|
|
1527
|
+
{ id: 'blacklist', label: 'Blacklist', icon: 'ban' },
|
|
1528
|
+
{ id: 'supervisor', label: 'Supervisor', icon: 'cpu' },
|
|
1529
|
+
{ id: 'notifier', label: 'Notifier', icon: 'bell' },
|
|
1530
|
+
]
|
|
1362
1531
|
|
|
1363
1532
|
const tabContents: Record<string, unknown> = {
|
|
1364
1533
|
tunnel: h(
|
|
@@ -1394,7 +1563,6 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1394
1563
|
{ style: { display: 'flex', flexDirection: 'column' } },
|
|
1395
1564
|
h(ToggleRow as any, { title: 'Re-review on push', description: 'When new commits are pushed, trigger an automatic re-review.', checked: config.autoRereviewOnPush === true, onChange: (v: boolean) => saveField('autoRereviewOnPush', v) }),
|
|
1396
1565
|
h(SettingRow as any, { title: 'Global review model', description: 'Model for automated reviews. Empty = DSH default.', control: h(ReviewModelSelector as any, { value: config.reviewModel ?? null, catalog, fallbackValue: catalog?.current ?? null, fallbackLabel: 'Use DSH default', onChange: (v: any) => saveField('reviewModel', v), label: null }) }),
|
|
1397
|
-
h(SettingRow as any, { title: 'Supervisor model', description: 'Model for auto-fixing DSH Web crashes.', control: h(ReviewModelSelector as any, { value: config.supervisorModel ?? null, catalog, fallbackValue: catalog?.current ?? null, fallbackLabel: 'Use DSH default', onChange: (v: any) => saveField('supervisorModel', v), label: null }) }),
|
|
1398
1566
|
h(ProjectMappingsEditor as any, { mappings: config.projectMappings ?? [], onChange: (mappings: any) => saveField('projectMappings', mappings), catalog, globalReviewModel: config.reviewModel ?? null }),
|
|
1399
1567
|
),
|
|
1400
1568
|
guard: h(
|
|
@@ -1416,9 +1584,15 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1416
1584
|
),
|
|
1417
1585
|
h('div', { style: { ...rowStyle, flexDirection:'column', alignItems:'stretch', gap: 8, borderBottom:'none' } as any },
|
|
1418
1586
|
h('div', { style: rowTitleStyle }, 'Placeholder mappings'),
|
|
1419
|
-
h('div', { style: rowDescStyle }, '
|
|
1420
|
-
h(
|
|
1421
|
-
|
|
1587
|
+
h('div', { style: rowDescStyle }, 'Blocked pattern → placeholder suggestion. One mapping per row — no JSON needed.'),
|
|
1588
|
+
h(PlaceholderMappingsEditor as any, {
|
|
1589
|
+
rows: placeholderRows,
|
|
1590
|
+
onChange: (rows: any) => {
|
|
1591
|
+
setPlaceholderRows(rows)
|
|
1592
|
+
commitPlaceholders(rows)
|
|
1593
|
+
},
|
|
1594
|
+
}),
|
|
1595
|
+
h('div', { style: { marginTop: 8 } }, h(Button as any, { variant: 'outline', size: 'sm', onClick: () => { commitBlacklistPatterns(patternsText); commitPlaceholders(placeholderRows) } }, 'Save Blacklist')),
|
|
1422
1596
|
),
|
|
1423
1597
|
),
|
|
1424
1598
|
supervisor: h(
|
|
@@ -1455,7 +1629,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1455
1629
|
),
|
|
1456
1630
|
h('style', {}, '[data-maestro-logo]{background:#0A84FF !important; background-color:#0A84FF !important; color:#fff !important;}'),
|
|
1457
1631
|
h('div', { 'data-maestro-tabs': '', role:'tablist', 'aria-label':'Maestro settings sections' },
|
|
1458
|
-
...TABS.map(tab => h('button', { key: tab.id, 'data-maestro-tab':'', 'data-active': String(activeTab===tab.id), role:'tab', 'aria-selected': activeTab===tab.id, onClick: () => setActiveTab(tab.id) }, tab.label))
|
|
1632
|
+
...TABS.map(tab => h('button', { key: tab.id, 'data-maestro-tab':'', 'data-active': String(activeTab===tab.id), role:'tab', 'aria-selected': activeTab===tab.id, onClick: (e: any) => { setActiveTab(tab.id); try { e.currentTarget.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) } catch {} } }, h(TabIcon as any, { name: tab.icon }), tab.label))
|
|
1459
1633
|
),
|
|
1460
1634
|
h('div', { 'data-maestro-panel': activeTab, style: { display:'flex', flexDirection:'column', gap:10, minWidth:0 } }, tabContents[activeTab] as any),
|
|
1461
1635
|
error ? h('p', { style: { color: t.stateError as string, fontSize: 12, margin: '8px 0 0', padding: '8px 10px', borderRadius: 8, background: 'color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent)', border: `1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent)` } }, error) : null,
|
|
@@ -578,15 +578,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
578
578
|
call(MAESTRO_ENDPOINTS.getConfig, {})
|
|
579
579
|
.then(saved => setConfig(prev => ({ ...prev, ...saved })))
|
|
580
580
|
.catch(() => { /* first run, no config saved yet — keep defaults */ })
|
|
581
|
-
// Supervisor model may be stored via generic config service when review not installed — try fallback
|
|
582
581
|
if (configRpcCall) {
|
|
583
|
-
configRpcCall('get', { domain: 'supervisor' })
|
|
584
|
-
.then(res => {
|
|
585
|
-
if (res?.ok && res.value?.model) {
|
|
586
|
-
setConfig(prev => ({ ...prev, supervisorModel: res.value.model }))
|
|
587
|
-
}
|
|
588
|
-
})
|
|
589
|
-
.catch(() => { /* supervisor domain not yet set or config service unavailable */ })
|
|
590
582
|
// Task 3: load Guard/Blacklist/Supervisor/Notifier domains
|
|
591
583
|
Promise.all([
|
|
592
584
|
cfgGet('guard').catch(() => ({})),
|
|
@@ -688,16 +680,6 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
688
680
|
const saveField = async (field, value) => {
|
|
689
681
|
setError(null)
|
|
690
682
|
setConfig(prev => ({ ...prev, [field]: value }))
|
|
691
|
-
// Supervisor model can be saved via generic config service when review not installed (independent install)
|
|
692
|
-
if (field === 'supervisorModel' && configRpcCall) {
|
|
693
|
-
try {
|
|
694
|
-
const res = await configRpcCall('set', { domain: 'supervisor', patch: { model: value } })
|
|
695
|
-
if (res?.ok) return
|
|
696
|
-
// Fall through to review RPC if generic set fails
|
|
697
|
-
} catch (e) {
|
|
698
|
-
// Fall through to review RPC
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
683
|
try {
|
|
702
684
|
await call(MAESTRO_ENDPOINTS.saveConfig, { [field]: value })
|
|
703
685
|
} catch (err) {
|
|
@@ -817,19 +799,6 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
817
799
|
}),
|
|
818
800
|
),
|
|
819
801
|
|
|
820
|
-
h('div', { style: sectionStyle },
|
|
821
|
-
h('h4', { style: headingStyle }, 'Supervisor LLM'),
|
|
822
|
-
h('p', { style: captionStyle }, 'Model used by the supervisor debug-agent to auto-fix DSH Web crashes. Empty = DSH default (or Review model if set). Uses the same provider catalog as Review.'),
|
|
823
|
-
h(ReviewModelSelector, {
|
|
824
|
-
value: config.supervisorModel ?? null,
|
|
825
|
-
catalog,
|
|
826
|
-
fallbackValue: catalog?.current ?? null,
|
|
827
|
-
fallbackLabel: 'Use DSH default',
|
|
828
|
-
onChange: v => saveField('supervisorModel', v),
|
|
829
|
-
label: 'Supervisor model',
|
|
830
|
-
}),
|
|
831
|
-
),
|
|
832
|
-
|
|
833
802
|
h('div', { style: sectionStyle },
|
|
834
803
|
h('h4', { style: headingStyle }, 'Projects'),
|
|
835
804
|
h(ProjectMappingsEditor, { mappings: config.projectMappings ?? [], onChange: mappings => saveField('projectMappings', mappings), catalog, globalReviewModel: config.reviewModel ?? null }),
|