opencode-navigator 0.27.2 → 0.27.3
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/CHANGELOG.md +6 -0
- package/README.md +5 -0
- package/dist/gui-experimental.cjs +1991 -1917
- package/dist/provider-limits.js +2 -4
- package/dist/tui.js +9 -9
- package/package.json +1 -1
|
@@ -1913,7 +1913,7 @@ function providerQuotaCapability(id, canonical) {
|
|
|
1913
1913
|
function quotaStatusMessage(input) {
|
|
1914
1914
|
const { model, snapshot, state } = input;
|
|
1915
1915
|
if (state.status === "error") return snapshot ? "Stale · refresh failed" : "Quota read failed · refresh to retry";
|
|
1916
|
-
if (
|
|
1916
|
+
if (snapshot?.availability === "ready" && (snapshot.windows.length > 0 || snapshot.balances?.length)) return input.showUpdatedAt ? `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()}` : void 0;
|
|
1917
1917
|
if (snapshot?.message) {
|
|
1918
1918
|
if (snapshot.availability === "stale") return `Stale · ${snapshot.message}`;
|
|
1919
1919
|
return snapshot.availability === "ready" ? `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()} · ${snapshot.message}` : snapshot.message;
|
|
@@ -1930,7 +1930,6 @@ function quotaStatusMessage(input) {
|
|
|
1930
1930
|
if (snapshot.availability === "unsupported") return "No documented quota bucket for this model";
|
|
1931
1931
|
if (snapshot.availability === "rate_limited") return "Provider rate-limited this read · try again later";
|
|
1932
1932
|
if (snapshot.availability === "stale") return "Stale provider data · refresh to update";
|
|
1933
|
-
if (snapshot.availability === "ready" && input.showReadyMessage && (snapshot.windows.length > 0 || snapshot.balances?.length)) return;
|
|
1934
1933
|
return `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()}`;
|
|
1935
1934
|
}
|
|
1936
1935
|
// src/entities/preferences/model/codex-account-bindings.ts
|
|
@@ -4714,7 +4713,7 @@ function preferencesIpc(pluginID) {
|
|
|
4714
4713
|
var main = (context) => {
|
|
4715
4714
|
const store = desktopPreferencesStore();
|
|
4716
4715
|
const readAccount = createMainAccountReader(context);
|
|
4717
|
-
const codex = createNodeCodexClient({ version: "0.27.
|
|
4716
|
+
const codex = createNodeCodexClient({ version: "0.27.3" });
|
|
4718
4717
|
context.onCleanup(codex.dispose);
|
|
4719
4718
|
context.provide(preferencesIpc(context.id), createMainPreferencesHandlers(store));
|
|
4720
4719
|
context.provide(localAccountIpc(context.id), { read: readAccount });
|
|
@@ -4722,7 +4721,7 @@ var main = (context) => {
|
|
|
4722
4721
|
const updateImpl = createMainPluginUpdate(context, () => updateProvider.changed());
|
|
4723
4722
|
const updateProvider = context.provide(pluginUpdateIpc(context.id), updateImpl);
|
|
4724
4723
|
context.provide(bugReportIpc(context.id), createMainBugReport(context.signal));
|
|
4725
|
-
context.log.write("info", `Navigator 0.27.
|
|
4724
|
+
context.log.write("info", `Navigator 0.27.3 Desktop main ready`);
|
|
4726
4725
|
};
|
|
4727
4726
|
// src/pages/navigator/ui/gui/context.tsx
|
|
4728
4727
|
var NavigatorGuiContext = (0, solid_js.createContext)();
|
|
@@ -5018,2012 +5017,2056 @@ function ActionsSection() {
|
|
|
5018
5017
|
}
|
|
5019
5018
|
});
|
|
5020
5019
|
}
|
|
5021
|
-
// src/
|
|
5022
|
-
var _tmpl$$55 = /*#__PURE__*/ (0, solid_js_web.template)(`<
|
|
5023
|
-
|
|
5024
|
-
|
|
5020
|
+
// src/shared/ui/gui/tabs.tsx
|
|
5021
|
+
var _tmpl$$55 = /*#__PURE__*/ (0, solid_js_web.template)(`<nav style=display:flex;gap:4px;flex-wrap:wrap>`);
|
|
5022
|
+
var _tmpl$2$37 = /*#__PURE__*/ (0, solid_js_web.template)(`<span>`);
|
|
5023
|
+
var _tmpl$3$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=opacity:0.6;font-weight:400>`);
|
|
5024
|
+
function GuiTabs(props) {
|
|
5025
|
+
const Button = props.ui.Button;
|
|
5026
|
+
function navigate(event) {
|
|
5027
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
5028
|
+
const enabled = props.options.filter((option) => !option.disabled);
|
|
5029
|
+
if (enabled.length === 0) return;
|
|
5030
|
+
event.preventDefault();
|
|
5031
|
+
event.stopPropagation();
|
|
5032
|
+
const next = (enabled.findIndex((option) => option.id === props.selected) + (event.key === "ArrowRight" ? 1 : -1) + enabled.length) % enabled.length;
|
|
5033
|
+
props.onSelect(enabled[next].id);
|
|
5034
|
+
event.currentTarget.querySelectorAll("button:not(:disabled)")[next]?.focus();
|
|
5035
|
+
}
|
|
5025
5036
|
return (() => {
|
|
5026
|
-
var _el$ = _tmpl$$55()
|
|
5027
|
-
|
|
5028
|
-
(0, solid_js_web.insert)(_el
|
|
5037
|
+
var _el$ = _tmpl$$55();
|
|
5038
|
+
_el$.$$keydown = navigate;
|
|
5039
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5040
|
+
get each() {
|
|
5041
|
+
return props.options.map((option) => option.id);
|
|
5042
|
+
},
|
|
5043
|
+
children: (id) => {
|
|
5044
|
+
const option = () => props.options.find((item) => item.id === id);
|
|
5045
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
5046
|
+
size: "small",
|
|
5047
|
+
get disabled() {
|
|
5048
|
+
return option().disabled;
|
|
5049
|
+
},
|
|
5050
|
+
get variant() {
|
|
5051
|
+
return props.selected === id ? "neutral" : "ghost-muted";
|
|
5052
|
+
},
|
|
5053
|
+
onClick: () => props.onSelect(id),
|
|
5054
|
+
get children() {
|
|
5055
|
+
return [(() => {
|
|
5056
|
+
var _el$2 = _tmpl$2$37();
|
|
5057
|
+
(0, solid_js_web.insert)(_el$2, () => option().label);
|
|
5058
|
+
(0, solid_js_web.effect)((_$p) => (0, solid_js_web.setStyleProperty)(_el$2, "font-weight", props.selected === id ? "600" : "400"));
|
|
5059
|
+
return _el$2;
|
|
5060
|
+
})(), (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5061
|
+
get when() {
|
|
5062
|
+
return option().count !== void 0;
|
|
5063
|
+
},
|
|
5064
|
+
get children() {
|
|
5065
|
+
var _el$3 = _tmpl$3$23();
|
|
5066
|
+
(0, solid_js_web.insert)(_el$3, () => option().count);
|
|
5067
|
+
return _el$3;
|
|
5068
|
+
}
|
|
5069
|
+
})];
|
|
5070
|
+
}
|
|
5071
|
+
});
|
|
5072
|
+
}
|
|
5073
|
+
}));
|
|
5074
|
+
(0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", props.label));
|
|
5075
|
+
return _el$;
|
|
5076
|
+
})();
|
|
5077
|
+
}
|
|
5078
|
+
(0, solid_js_web.delegateEvents)(["keydown"]);
|
|
5079
|
+
// src/shared/lib/icon-choices/index.ts
|
|
5080
|
+
var ICON_CHOICE_IDS = [
|
|
5081
|
+
"plus",
|
|
5082
|
+
"check",
|
|
5083
|
+
"circle",
|
|
5084
|
+
"star",
|
|
5085
|
+
"pin",
|
|
5086
|
+
"bolt",
|
|
5087
|
+
"book",
|
|
5088
|
+
"search",
|
|
5089
|
+
"code",
|
|
5090
|
+
"terminal",
|
|
5091
|
+
"gear",
|
|
5092
|
+
"shield",
|
|
5093
|
+
"lock",
|
|
5094
|
+
"unlock",
|
|
5095
|
+
"eye",
|
|
5096
|
+
"clock",
|
|
5097
|
+
"refresh",
|
|
5098
|
+
"history",
|
|
5099
|
+
"copy",
|
|
5100
|
+
"export",
|
|
5101
|
+
"edit",
|
|
5102
|
+
"fork",
|
|
5103
|
+
"list",
|
|
5104
|
+
"play",
|
|
5105
|
+
"pause",
|
|
5106
|
+
"stop",
|
|
5107
|
+
"rocket",
|
|
5108
|
+
"bug",
|
|
5109
|
+
"beaker",
|
|
5110
|
+
"wand",
|
|
5111
|
+
"cloud",
|
|
5112
|
+
"server",
|
|
5113
|
+
"folder",
|
|
5114
|
+
"file",
|
|
5115
|
+
"heart",
|
|
5116
|
+
"lightbulb",
|
|
5117
|
+
"arrow-up",
|
|
5118
|
+
"arrow-down",
|
|
5119
|
+
"warning",
|
|
5120
|
+
"close"
|
|
5121
|
+
];
|
|
5122
|
+
var choices = new Set(ICON_CHOICE_IDS);
|
|
5123
|
+
function isIconChoiceId(value) {
|
|
5124
|
+
return choices.has(value);
|
|
5125
|
+
}
|
|
5126
|
+
function iconChoiceLabel(id) {
|
|
5127
|
+
return id.replaceAll("-", " ");
|
|
5128
|
+
}
|
|
5129
|
+
// src/shared/ui/gui/icon.tsx
|
|
5130
|
+
var _tmpl$$54 = /*#__PURE__*/ (0, solid_js_web.template)(`<span aria-hidden=true style=display:inline-flex;width:18px;height:18px;flex-shrink:0;align-items:center;justify-content:center>`);
|
|
5131
|
+
var _tmpl$2$36 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg width=16 height=16 viewBox="0 0 24 26"fill=none stroke=currentColor stroke-width=1.7 stroke-linecap=round stroke-linejoin=round>`);
|
|
5132
|
+
var _tmpl$3$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path></svg>`, false, true, false);
|
|
5133
|
+
var native = {
|
|
5134
|
+
plus: "plus",
|
|
5135
|
+
check: "check",
|
|
5136
|
+
search: "magnifying-glass",
|
|
5137
|
+
code: "code",
|
|
5138
|
+
terminal: "terminal",
|
|
5139
|
+
gear: "settings-gear",
|
|
5140
|
+
shield: "shield",
|
|
5141
|
+
lock: "lock",
|
|
5142
|
+
eye: "eye",
|
|
5143
|
+
refresh: "refresh",
|
|
5144
|
+
copy: "copy",
|
|
5145
|
+
export: "share",
|
|
5146
|
+
edit: "edit",
|
|
5147
|
+
fork: "fork",
|
|
5148
|
+
list: "bullet-list",
|
|
5149
|
+
stop: "stop",
|
|
5150
|
+
beaker: "flask",
|
|
5151
|
+
server: "server",
|
|
5152
|
+
folder: "folder",
|
|
5153
|
+
file: "file-document",
|
|
5154
|
+
"arrow-up": "arrow-up",
|
|
5155
|
+
warning: "warning",
|
|
5156
|
+
close: "close"
|
|
5157
|
+
};
|
|
5158
|
+
var paths = {
|
|
5159
|
+
circle: ["M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0Z"],
|
|
5160
|
+
star: ["m12 3 2.7 5.5 6.1.9-4.4 4.3 1 6.1-5.4-2.9-5.4 2.9 1-6.1-4.4-4.3 6.1-.9Z"],
|
|
5161
|
+
pin: ["m9 3 6 0-1 6 4 4H6l4-4Z", "M12 13v8"],
|
|
5162
|
+
bolt: ["m13 2-8 12h6l-1 8 9-13h-7Z"],
|
|
5163
|
+
book: ["M3 4h7l2 2 2-2h7v15h-7l-2 2-2-2H3Z", "M12 6v15"],
|
|
5164
|
+
unlock: [
|
|
5165
|
+
"M7 10V7a5 5 0 0 1 9-3",
|
|
5166
|
+
"M5 10h14v11H5Z",
|
|
5167
|
+
"M12 14v3"
|
|
5168
|
+
],
|
|
5169
|
+
clock: ["M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0Z", "M12 7v5l3 2"],
|
|
5170
|
+
history: [
|
|
5171
|
+
"M4 8a9 9 0 1 1-1 7",
|
|
5172
|
+
"M4 3v5h5",
|
|
5173
|
+
"M12 7v5l3 2"
|
|
5174
|
+
],
|
|
5175
|
+
play: ["m7 4 13 8-13 8Z"],
|
|
5176
|
+
pause: ["M8 4v16", "M16 4v16"],
|
|
5177
|
+
rocket: [
|
|
5178
|
+
"M9 16c0-8 6-13 12-13 0 6-5 12-13 12Z",
|
|
5179
|
+
"m9 8-5 1-2 6 6-1",
|
|
5180
|
+
"m16 15-1 5-6 2 1-6",
|
|
5181
|
+
"m5 17-3 5 5-3"
|
|
5182
|
+
],
|
|
5183
|
+
bug: [
|
|
5184
|
+
"M8 10h8v6a4 4 0 0 1-8 0Z",
|
|
5185
|
+
"M9 10V8a3 3 0 0 1 6 0v2",
|
|
5186
|
+
"M5 7l3 4M19 7l-3 4M3 14h5m8 0h5M5 21l4-3m6 0 4 3M12 11v9"
|
|
5187
|
+
],
|
|
5188
|
+
wand: ["m4 20 13-13 3 3L7 23Z", "M5 3v6M2 6h6M18 1v4M16 3h4"],
|
|
5189
|
+
cloud: ["M7 19a5 5 0 1 1 0-10 6 6 0 0 1 11-1 5.5 5.5 0 0 1 0 11Z"],
|
|
5190
|
+
heart: ["M12 21 3.5 12.5a5.5 5.5 0 0 1 8.5-7 5.5 5.5 0 0 1 8.5 7Z"],
|
|
5191
|
+
lightbulb: ["M9 18v-2a7 7 0 1 1 6 0v2Z", "M9 21h6M10 24h4"],
|
|
5192
|
+
"arrow-down": ["M12 3v18", "m5 14 7 7 7-7"]
|
|
5193
|
+
};
|
|
5194
|
+
function GuiIcon(props) {
|
|
5195
|
+
const Icon = props.ui.Icon;
|
|
5196
|
+
const id = () => isIconChoiceId(props.id) ? props.id : "bolt";
|
|
5197
|
+
return (() => {
|
|
5198
|
+
var _el$ = _tmpl$$54();
|
|
5199
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5200
|
+
get when() {
|
|
5201
|
+
return native[id()];
|
|
5202
|
+
},
|
|
5203
|
+
get fallback() {
|
|
5204
|
+
return (() => {
|
|
5205
|
+
var _el$2 = _tmpl$2$36();
|
|
5206
|
+
(0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5207
|
+
get each() {
|
|
5208
|
+
return paths[id()] ?? paths.bolt;
|
|
5209
|
+
},
|
|
5210
|
+
children: (path) => (() => {
|
|
5211
|
+
var _el$3 = _tmpl$3$22();
|
|
5212
|
+
(0, solid_js_web.setAttribute)(_el$3, "d", path);
|
|
5213
|
+
return _el$3;
|
|
5214
|
+
})()
|
|
5215
|
+
}));
|
|
5216
|
+
return _el$2;
|
|
5217
|
+
})();
|
|
5218
|
+
},
|
|
5219
|
+
children: (name) => (0, solid_js_web.createComponent)(Icon, {
|
|
5220
|
+
get name() {
|
|
5221
|
+
return name();
|
|
5222
|
+
},
|
|
5223
|
+
size: "small"
|
|
5224
|
+
})
|
|
5225
|
+
}));
|
|
5226
|
+
return _el$;
|
|
5227
|
+
})();
|
|
5228
|
+
}
|
|
5229
|
+
// src/shared/ui/gui/multiline-field.tsx
|
|
5230
|
+
var _tmpl$$53 = /*#__PURE__*/ (0, solid_js_web.template)(`<label style=display:grid;gap:8px><span></span><textarea style="width:100%;box-sizing:border-box;min-height:160px;max-height:40vh;resize:vertical;color:var(--v2-text-text-base, inherit);background:var(--v2-background-bg-base, transparent);border:0;caret-color:var(--v2-text-text-base, auto);border-radius:6px;padding:8px;font:inherit">`);
|
|
5231
|
+
function GuiMultilineField(props) {
|
|
5232
|
+
const id = (0, solid_js.createUniqueId)();
|
|
5233
|
+
const [focused, setFocused] = (0, solid_js.createSignal)(false);
|
|
5234
|
+
return (() => {
|
|
5235
|
+
var _el$ = _tmpl$$53(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
|
|
5236
|
+
(0, solid_js_web.setAttribute)(_el$, "for", id);
|
|
5237
|
+
(0, solid_js_web.insert)(_el$2, () => props.label);
|
|
5238
|
+
_el$3.$$input = (event) => props.onInput(event.currentTarget.value);
|
|
5239
|
+
_el$3.addEventListener("blur", () => setFocused(false));
|
|
5240
|
+
_el$3.addEventListener("focus", () => setFocused(true));
|
|
5241
|
+
(0, solid_js_web.setAttribute)(_el$3, "id", id);
|
|
5029
5242
|
(0, solid_js_web.effect)((_p$) => {
|
|
5030
|
-
var _v$ = props.
|
|
5031
|
-
_v$ !== _p$.e && (
|
|
5032
|
-
_v$2 !== _p$.t && (0, solid_js_web.
|
|
5033
|
-
_v$3 !== _p$.a && (0, solid_js_web.
|
|
5034
|
-
_v$4 !== _p$.o && (0, solid_js_web.
|
|
5035
|
-
_v$5 !== _p$.i && (0, solid_js_web.setStyleProperty)(_el$3, "width", _p$.i = _v$5);
|
|
5243
|
+
var _v$ = props.disabled, _v$2 = focused() ? "1px solid var(--v2-border-border-focus)" : "1px solid transparent", _v$3 = focused() ? "none" : "var(--v2-elevation-input)", _v$4 = props.disabled ? "0.5" : "1";
|
|
5244
|
+
_v$ !== _p$.e && (_el$3.disabled = _p$.e = _v$);
|
|
5245
|
+
_v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$3, "outline", _p$.t = _v$2);
|
|
5246
|
+
_v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$3, "box-shadow", _p$.a = _v$3);
|
|
5247
|
+
_v$4 !== _p$.o && (0, solid_js_web.setStyleProperty)(_el$3, "opacity", _p$.o = _v$4);
|
|
5036
5248
|
return _p$;
|
|
5037
5249
|
}, {
|
|
5038
5250
|
e: void 0,
|
|
5039
5251
|
t: void 0,
|
|
5040
5252
|
a: void 0,
|
|
5041
|
-
o: void 0
|
|
5042
|
-
i: void 0
|
|
5253
|
+
o: void 0
|
|
5043
5254
|
});
|
|
5255
|
+
(0, solid_js_web.effect)(() => _el$3.value = props.value);
|
|
5044
5256
|
return _el$;
|
|
5045
5257
|
})();
|
|
5046
5258
|
}
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
var _tmpl
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
const
|
|
5053
|
-
const limits = () => props.runtime.limits;
|
|
5054
|
-
const snapshot = () => limits()?.controller.snapshot();
|
|
5055
|
-
const state = () => limits()?.controller.state();
|
|
5056
|
-
const message = () => limits()?.selected() ? quotaStatusMessage({
|
|
5057
|
-
model: limits()?.selected(),
|
|
5058
|
-
snapshot: snapshot(),
|
|
5059
|
-
state: state() ?? { status: "idle" },
|
|
5060
|
-
hasAdapter: Boolean(limits()?.controller.current().adapter),
|
|
5061
|
-
showReadyMessage: true
|
|
5062
|
-
}) : "Select a model in chat to view its provider limits.";
|
|
5063
|
-
const canLink = () => {
|
|
5064
|
-
const model = limits()?.selected();
|
|
5065
|
-
return model && props.onLinkAccount && limits()?.codex && model.hostConnection?.status === "ready" && canLinkCodexAccount(model) && (!model.accountID || snapshot()?.availability === "unauthenticated" && model.accountSource === "binding");
|
|
5066
|
-
};
|
|
5259
|
+
(0, solid_js_web.delegateEvents)(["input"]);
|
|
5260
|
+
// src/shared/ui/gui/group-control.tsx
|
|
5261
|
+
var _tmpl$$52 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=group style=display:flex;gap:8px;flex-wrap:wrap>`);
|
|
5262
|
+
function GuiGroupControl(props) {
|
|
5263
|
+
const Select = props.ui.Select;
|
|
5264
|
+
const TextInput = props.ui.TextInput;
|
|
5067
5265
|
const Button = props.ui.Button;
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
}
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5266
|
+
const [draft, setDraft] = (0, solid_js.createSignal)("");
|
|
5267
|
+
const [creating, setCreating] = (0, solid_js.createSignal)(false);
|
|
5268
|
+
(0, solid_js.createEffect)(() => setDraft(props.value ?? ""));
|
|
5269
|
+
return (() => {
|
|
5270
|
+
var _el$ = _tmpl$$52();
|
|
5271
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Select, {
|
|
5272
|
+
get label() {
|
|
5273
|
+
return `${props.label} existing group`;
|
|
5274
|
+
},
|
|
5275
|
+
get value() {
|
|
5276
|
+
return (0, solid_js_web.memo)(() => !!props.groups.includes(draft()))() ? draft() : "";
|
|
5277
|
+
},
|
|
5278
|
+
get options() {
|
|
5279
|
+
return [{
|
|
5280
|
+
value: "",
|
|
5281
|
+
label: "Ungrouped"
|
|
5282
|
+
}, ...props.groups.map((value) => ({
|
|
5283
|
+
value,
|
|
5284
|
+
label: value
|
|
5285
|
+
}))];
|
|
5286
|
+
},
|
|
5287
|
+
onChange: (value) => {
|
|
5288
|
+
setDraft(value);
|
|
5289
|
+
setCreating(false);
|
|
5290
|
+
},
|
|
5291
|
+
get disabled() {
|
|
5292
|
+
return props.disabled;
|
|
5293
|
+
}
|
|
5294
|
+
}), null);
|
|
5295
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
|
|
5296
|
+
size: "small",
|
|
5297
|
+
variant: "ghost",
|
|
5298
|
+
get disabled() {
|
|
5299
|
+
return props.disabled;
|
|
5300
|
+
},
|
|
5301
|
+
onClick: () => {
|
|
5302
|
+
setCreating(true);
|
|
5303
|
+
setDraft("");
|
|
5304
|
+
},
|
|
5305
|
+
children: "New group"
|
|
5306
|
+
}), null);
|
|
5307
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5308
|
+
get when() {
|
|
5309
|
+
return creating();
|
|
5310
|
+
},
|
|
5311
|
+
get children() {
|
|
5312
|
+
return (0, solid_js_web.createComponent)(TextInput, {
|
|
5313
|
+
get label() {
|
|
5314
|
+
return `${props.label} new group`;
|
|
5098
5315
|
},
|
|
5099
|
-
get
|
|
5100
|
-
return (
|
|
5101
|
-
size: "small",
|
|
5102
|
-
variant: "ghost",
|
|
5103
|
-
get onClick() {
|
|
5104
|
-
return props.onLinkAccount;
|
|
5105
|
-
},
|
|
5106
|
-
children: "Link Codex account"
|
|
5107
|
-
});
|
|
5108
|
-
}
|
|
5109
|
-
}),
|
|
5110
|
-
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5111
|
-
get when() {
|
|
5112
|
-
return state()?.error;
|
|
5316
|
+
get value() {
|
|
5317
|
+
return draft();
|
|
5113
5318
|
},
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
return _el$;
|
|
5118
|
-
}
|
|
5119
|
-
}),
|
|
5120
|
-
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5121
|
-
get when() {
|
|
5122
|
-
return message();
|
|
5319
|
+
onInput: setDraft,
|
|
5320
|
+
get disabled() {
|
|
5321
|
+
return props.disabled;
|
|
5123
5322
|
},
|
|
5124
|
-
get
|
|
5125
|
-
|
|
5126
|
-
(0, solid_js_web.insert)(_el$2, message);
|
|
5127
|
-
return _el$2;
|
|
5323
|
+
get invalid() {
|
|
5324
|
+
return draft().length > 64;
|
|
5128
5325
|
}
|
|
5129
|
-
})
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5326
|
+
});
|
|
5327
|
+
}
|
|
5328
|
+
}), null);
|
|
5329
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5330
|
+
get when() {
|
|
5331
|
+
return creating() || draft() !== (props.value ?? "");
|
|
5332
|
+
},
|
|
5333
|
+
get children() {
|
|
5334
|
+
return [(0, solid_js_web.createComponent)(Button, {
|
|
5335
|
+
size: "small",
|
|
5336
|
+
get disabled() {
|
|
5337
|
+
return props.disabled || draft().length > 64 || creating() && !draft().trim();
|
|
5133
5338
|
},
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
})
|
|
5154
|
-
];
|
|
5155
|
-
}
|
|
5156
|
-
});
|
|
5157
|
-
}
|
|
5158
|
-
// src/entities/mcp/model/status.ts
|
|
5159
|
-
function mcpToggleAction(status) {
|
|
5160
|
-
if (status === "pending") return;
|
|
5161
|
-
return status === "connected" ? "disconnect" : "connect";
|
|
5162
|
-
}
|
|
5163
|
-
// src/entities/mcp/model/grouping.ts
|
|
5164
|
-
var BUCKET_RANK$1 = {
|
|
5165
|
-
Favorites: 0,
|
|
5166
|
-
Ungrouped: 2
|
|
5167
|
-
};
|
|
5168
|
-
function mcpGroupToggleAction(items) {
|
|
5169
|
-
if (items.some((item) => mcpToggleAction(item.status) === "connect")) return "connect";
|
|
5170
|
-
return items.some((item) => mcpToggleAction(item.status) === "disconnect") ? "disconnect" : void 0;
|
|
5339
|
+
onClick: () => {
|
|
5340
|
+
props.save(draft().trim() || void 0);
|
|
5341
|
+
setCreating(false);
|
|
5342
|
+
},
|
|
5343
|
+
children: "Save group"
|
|
5344
|
+
}), (0, solid_js_web.createComponent)(Button, {
|
|
5345
|
+
size: "small",
|
|
5346
|
+
variant: "ghost",
|
|
5347
|
+
onClick: () => {
|
|
5348
|
+
setDraft(props.value ?? "");
|
|
5349
|
+
setCreating(false);
|
|
5350
|
+
},
|
|
5351
|
+
children: "Cancel"
|
|
5352
|
+
})];
|
|
5353
|
+
}
|
|
5354
|
+
}), null);
|
|
5355
|
+
(0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", `${props.label} grouping`));
|
|
5356
|
+
return _el$;
|
|
5357
|
+
})();
|
|
5171
5358
|
}
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
return
|
|
5359
|
+
// src/shared/ui/gui/settings-surface.tsx
|
|
5360
|
+
var _tmpl$$51 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-settings><style>\n[data-navigator-settings] \{ display: grid; gap: 32px; min-width: 0; container-type: inline-size; }\n[data-navigator-settings] [data-component="settings-row"] \{ display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; gap: 20px; }\n[data-navigator-settings] [data-slot="settings-row-copy"] \{ min-width: 0; overflow-wrap: anywhere; }\n[data-navigator-settings] :is(button, input, textarea, [role="switch"]) \{ scroll-margin-block: 96px; }\n[data-navigator-settings] [data-slot="settings-row-control"] \{ min-width: 0; max-width: 100%; width: 100%; flex-wrap: wrap; gap: 8px; }\n[data-navigator-settings] [data-slot="settings-row-control"] > * \{ min-width: 0; max-width: 100%; }\n[data-navigator-settings] [data-slot="settings-row-control"] > div:not([data-component]) \{ width: 100%; flex-wrap: wrap; }\n[data-navigator-settings] [data-component="button-v2"] \{ white-space: normal; height: auto; min-height: 24px; overflow-wrap: anywhere; }\n[data-navigator-settings] [data-component="text-input-v2"] \{ min-width: 0; max-width: 100%; }\n[data-navigator-settings] [data-sortable-item]:not(:last-of-type) > [data-component="settings-row"] \{ border-bottom: 0.5px solid var(--v2-border-border-base); }\n@container (max-width: 640px) \{\n [data-navigator-settings] [data-component="settings-row"] \{ grid-template-columns: minmax(0, 1fr); gap: 12px; }\n [data-navigator-settings] [data-slot="settings-row-control"] \{ justify-content: flex-start; }\n}\n`);
|
|
5361
|
+
function GuiSettingsSurface(props) {
|
|
5362
|
+
return (() => {
|
|
5363
|
+
var _el$ = _tmpl$$51();
|
|
5364
|
+
_el$.firstChild;
|
|
5365
|
+
(0, solid_js_web.insert)(_el$, () => props.children, null);
|
|
5366
|
+
return _el$;
|
|
5367
|
+
})();
|
|
5176
5368
|
}
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5369
|
+
// src/shared/ui/gui/sortable-focus.ts
|
|
5370
|
+
function createSortableFocus(props) {
|
|
5371
|
+
let focused;
|
|
5372
|
+
(0, solid_js.createEffect)(() => {
|
|
5373
|
+
const keys = props.keys();
|
|
5374
|
+
const disabled = props.disabled();
|
|
5375
|
+
const key = focused;
|
|
5376
|
+
if (!key || disabled || !keys.includes(key)) return;
|
|
5377
|
+
queueMicrotask(() => {
|
|
5378
|
+
if (focused !== key || props.disabled() || document.activeElement !== document.body) return;
|
|
5379
|
+
[...props.root().querySelectorAll("[data-sortable-item]")].find((node) => node.dataset.sortableItem === key)?.querySelector("button")?.focus({ preventScroll: true });
|
|
5380
|
+
});
|
|
5184
5381
|
});
|
|
5382
|
+
return {
|
|
5383
|
+
enter(event) {
|
|
5384
|
+
const target = event.target;
|
|
5385
|
+
focused = target.getAttribute("aria-label")?.startsWith("Reorder ") ? target.closest("[data-sortable-item]")?.dataset.sortableItem : void 0;
|
|
5386
|
+
},
|
|
5387
|
+
leave(event) {
|
|
5388
|
+
if (event.relatedTarget && !props.root().contains(event.relatedTarget)) focused = void 0;
|
|
5389
|
+
}
|
|
5390
|
+
};
|
|
5185
5391
|
}
|
|
5186
|
-
// src/
|
|
5187
|
-
function
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5392
|
+
// src/shared/ui/gui/sortable-interaction.ts
|
|
5393
|
+
function createSortableInteraction(props) {
|
|
5394
|
+
const [source, setSource] = (0, solid_js.createSignal)();
|
|
5395
|
+
const [target, setTarget] = (0, solid_js.createSignal)();
|
|
5396
|
+
const [announcement, setAnnouncement] = (0, solid_js.createSignal)("");
|
|
5397
|
+
let drag;
|
|
5398
|
+
const signature = () => JSON.stringify(props.keys());
|
|
5399
|
+
function cancel() {
|
|
5400
|
+
const previous = drag;
|
|
5401
|
+
drag = void 0;
|
|
5402
|
+
setSource(void 0);
|
|
5403
|
+
setTarget(void 0);
|
|
5404
|
+
if (previous && previous.pointer >= 0 && props.root().hasPointerCapture(previous.pointer)) props.root().releasePointerCapture(previous.pointer);
|
|
5405
|
+
}
|
|
5406
|
+
(0, solid_js.createEffect)(() => {
|
|
5407
|
+
source();
|
|
5408
|
+
if (drag && (props.disabled() || props.scope() !== drag.scope || signature() !== drag.keys)) cancel();
|
|
5200
5409
|
});
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
const [bulkStates, setBulkStates] = (0, solid_js.createSignal)({});
|
|
5207
|
-
const [selectedPresets, setSelectedPresets] = (0, solid_js.createSignal)({});
|
|
5208
|
-
const refreshing = /* @__PURE__ */ new Map();
|
|
5209
|
-
const mutations = /* @__PURE__ */ new Map();
|
|
5210
|
-
const mutationRetries = /* @__PURE__ */ new Map();
|
|
5211
|
-
const bulkGenerations = /* @__PURE__ */ new Map();
|
|
5212
|
-
const bulkRetries = /* @__PURE__ */ new Map();
|
|
5213
|
-
const selectedPresetStates = /* @__PURE__ */ new Map();
|
|
5214
|
-
const requests = createRequestState(options.signal);
|
|
5215
|
-
const serverRequests = createRequestState(options.signal);
|
|
5216
|
-
let activation = 0;
|
|
5217
|
-
let activeTarget;
|
|
5218
|
-
function changeMutationCount(current, offset) {
|
|
5219
|
-
setMutationCounts((values) => {
|
|
5220
|
-
const next = Math.max(0, (values[current.key] ?? 0) + offset);
|
|
5221
|
-
if (next === 0) {
|
|
5222
|
-
const copy = { ...values };
|
|
5223
|
-
delete copy[current.key];
|
|
5224
|
-
return copy;
|
|
5225
|
-
}
|
|
5226
|
-
return {
|
|
5227
|
-
...values,
|
|
5228
|
-
[current.key]: next
|
|
5229
|
-
};
|
|
5230
|
-
});
|
|
5231
|
-
}
|
|
5232
|
-
function setActive(current) {
|
|
5233
|
-
if (activeTarget === current.key) return;
|
|
5234
|
-
if (activeTarget) {
|
|
5235
|
-
bulkGenerations.set(activeTarget, (bulkGenerations.get(activeTarget) ?? 0) + 1);
|
|
5236
|
-
setBulkStates((values) => {
|
|
5237
|
-
const state = values[activeTarget];
|
|
5238
|
-
if (!state || state.status !== "running") return values;
|
|
5239
|
-
return {
|
|
5240
|
-
...values,
|
|
5241
|
-
[activeTarget]: {
|
|
5242
|
-
...state,
|
|
5243
|
-
status: "idle"
|
|
5244
|
-
}
|
|
5245
|
-
};
|
|
5246
|
-
});
|
|
5247
|
-
}
|
|
5248
|
-
activation += 1;
|
|
5249
|
-
requests.abortAll();
|
|
5250
|
-
serverRequests.abortAll();
|
|
5251
|
-
refreshing.clear();
|
|
5252
|
-
activeTarget = current.key;
|
|
5253
|
-
}
|
|
5254
|
-
function target() {
|
|
5255
|
-
return options.target();
|
|
5256
|
-
}
|
|
5257
|
-
function mutating(current = target()) {
|
|
5258
|
-
return (mutationCounts()[current.key] ?? 0) > 0;
|
|
5259
|
-
}
|
|
5260
|
-
function resetSelectedPreset(current) {
|
|
5261
|
-
selectedPresetStates.delete(current.key);
|
|
5262
|
-
setSelectedPresets((values) => {
|
|
5263
|
-
const next = { ...values };
|
|
5264
|
-
delete next[current.key];
|
|
5265
|
-
return next;
|
|
5266
|
-
});
|
|
5267
|
-
}
|
|
5268
|
-
function invalidatePresetOperation(current, name) {
|
|
5269
|
-
const state = bulkStates()[current.key];
|
|
5270
|
-
if (state?.action !== "preset" || state.preset !== name) return;
|
|
5271
|
-
bulkRetries.delete(current.key);
|
|
5272
|
-
setBulkStates((values) => ({
|
|
5273
|
-
...values,
|
|
5274
|
-
[current.key]: {
|
|
5275
|
-
...state,
|
|
5276
|
-
status: "idle",
|
|
5277
|
-
completed: 0,
|
|
5278
|
-
total: 0,
|
|
5279
|
-
failed: []
|
|
5280
|
-
}
|
|
5281
|
-
}));
|
|
5282
|
-
}
|
|
5283
|
-
function reconcileSelectedPreset(current, items) {
|
|
5284
|
-
const states = selectedPresetStates.get(current.key);
|
|
5285
|
-
const bulk = bulkStates()[current.key];
|
|
5286
|
-
if (!states || bulk?.action === "preset" && (bulk.status === "running" || bulk.status === "error")) return;
|
|
5287
|
-
if (items.some((item) => {
|
|
5288
|
-
const desired = states[item.name];
|
|
5289
|
-
if (!desired) return false;
|
|
5290
|
-
return (item.status === "connected" ? "enabled" : "disabled") !== desired;
|
|
5291
|
-
})) resetSelectedPreset(current);
|
|
5292
|
-
}
|
|
5293
|
-
function clearBulkFailure(current, name) {
|
|
5294
|
-
setBulkStates((values) => {
|
|
5295
|
-
const state = values[current.key];
|
|
5296
|
-
if (!state || state.status !== "error" || !state.failed.includes(name)) return values;
|
|
5297
|
-
const failed = state.failed.filter((candidate) => candidate !== name);
|
|
5298
|
-
bulkRetries.set(current.key, (bulkRetries.get(current.key) ?? []).filter((candidate) => candidate.name !== name));
|
|
5299
|
-
return {
|
|
5300
|
-
...values,
|
|
5301
|
-
[current.key]: {
|
|
5302
|
-
...state,
|
|
5303
|
-
status: failed.length > 0 ? "error" : "ready",
|
|
5304
|
-
failed
|
|
5305
|
-
}
|
|
5306
|
-
};
|
|
5307
|
-
});
|
|
5308
|
-
}
|
|
5309
|
-
function list(current = target()) {
|
|
5310
|
-
return options.cache === "source" ? source.list(current) : snapshots()[current.key] ?? source.list(current);
|
|
5311
|
-
}
|
|
5312
|
-
async function refresh(current = target(), force = false) {
|
|
5313
|
-
const pending = refreshing.get(current.key);
|
|
5314
|
-
if (pending && !force) return pending;
|
|
5315
|
-
const requestState = requests.start(current.key, "refresh MCP servers", current.key in snapshots(), force);
|
|
5316
|
-
if (!requestState) return pending;
|
|
5317
|
-
const request = source.refresh(current, force, requestState.signal).then((items) => {
|
|
5318
|
-
if (options.cache === "model" && requestState.isCurrent()) setSnapshots((value) => ({
|
|
5319
|
-
...value,
|
|
5320
|
-
[current.key]: items
|
|
5321
|
-
}));
|
|
5322
|
-
if (requestState.isCurrent()) reconcileSelectedPreset(current, items);
|
|
5323
|
-
requestState.succeed();
|
|
5324
|
-
return items;
|
|
5325
|
-
}).catch((error) => {
|
|
5326
|
-
requestState.fail(error);
|
|
5327
|
-
throw error;
|
|
5328
|
-
}).finally(() => {
|
|
5329
|
-
requestState.finish();
|
|
5330
|
-
if (refreshing.get(current.key) === request) refreshing.delete(current.key);
|
|
5331
|
-
});
|
|
5332
|
-
refreshing.set(current.key, request);
|
|
5333
|
-
return request;
|
|
5334
|
-
}
|
|
5335
|
-
async function changeServer(current, name, action, operation = `${action} MCP server`, refreshAfter = true) {
|
|
5336
|
-
const key = serverKey(current, name);
|
|
5337
|
-
const pending = mutations.get(key);
|
|
5338
|
-
if (pending) return pending;
|
|
5339
|
-
const requestState = serverRequests.start(key, operation, false);
|
|
5340
|
-
if (!requestState) return mutations.get(key);
|
|
5341
|
-
changeMutationCount(current, 1);
|
|
5342
|
-
const request = options.change(current, name, action, requestState.signal).then(() => {
|
|
5343
|
-
requestState.succeed();
|
|
5344
|
-
mutationRetries.delete(key);
|
|
5345
|
-
clearBulkFailure(current, name);
|
|
5346
|
-
}).catch((error) => {
|
|
5347
|
-
requestState.fail(error);
|
|
5348
|
-
if (!requestState.signal.aborted && !isAbortError(error)) mutationRetries.set(key, () => changeServer(current, name, action, operation));
|
|
5349
|
-
throw error;
|
|
5350
|
-
}).finally(() => {
|
|
5351
|
-
requestState.finish();
|
|
5352
|
-
changeMutationCount(current, -1);
|
|
5353
|
-
if (mutations.get(key) === request) mutations.delete(key);
|
|
5354
|
-
});
|
|
5355
|
-
mutations.set(key, request);
|
|
5356
|
-
await request;
|
|
5357
|
-
if (refreshAfter) await refresh(current, true);
|
|
5358
|
-
}
|
|
5359
|
-
function save(current, name, disabled) {
|
|
5360
|
-
if (!persist()) return;
|
|
5361
|
-
preferences.setDesiredMcpState(current.scope, name, disabled ? "disabled" : "enabled");
|
|
5362
|
-
}
|
|
5363
|
-
async function toggle(name) {
|
|
5364
|
-
const current = target();
|
|
5365
|
-
const item = list(current).find((candidate) => candidate.name === name);
|
|
5366
|
-
const action = item && mcpToggleAction(item.status);
|
|
5367
|
-
if (!action || mutations.has(serverKey(current, name))) return;
|
|
5368
|
-
activation += 1;
|
|
5369
|
-
resetSelectedPreset(current);
|
|
5370
|
-
save(current, name, action === "disconnect");
|
|
5371
|
-
await changeServer(current, name, action);
|
|
5372
|
-
}
|
|
5373
|
-
async function activate(current = target()) {
|
|
5374
|
-
setActive(current);
|
|
5375
|
-
const generation = ++activation;
|
|
5376
|
-
const hydration = preferences.load();
|
|
5377
|
-
if (!hydration) return;
|
|
5378
|
-
await hydration;
|
|
5379
|
-
const items = await refresh(current, true);
|
|
5380
|
-
if (!persist() || generation !== activation || target().key !== current.key) return;
|
|
5381
|
-
const results = await Promise.allSettled(items.map(async (item) => {
|
|
5382
|
-
if (!persist() || generation !== activation || target().key !== current.key) return;
|
|
5383
|
-
const desired = preferences.desiredMcpState(current.scope, item.name);
|
|
5384
|
-
const action = mcpToggleAction(item.status);
|
|
5385
|
-
if (desired === "disabled" && action === "disconnect") await changeServer(current, item.name, "disconnect", "restore MCP preference", false);
|
|
5386
|
-
if (desired === "enabled" && action === "connect") await changeServer(current, item.name, "connect", "restore MCP preference", false);
|
|
5387
|
-
}));
|
|
5388
|
-
const failed = options.signal?.aborted ? [] : results.flatMap((result, index) => result.status === "rejected" && !isAbortError(result.reason) ? [items[index].name] : []);
|
|
5389
|
-
if (failed.length > 0) options.notifications.show({
|
|
5390
|
-
variant: "warning",
|
|
5391
|
-
title: "MCP preferences",
|
|
5392
|
-
message: `Could not restore: ${failed.join(", ")}`
|
|
5393
|
-
});
|
|
5394
|
-
if (generation === activation && target().key === current.key) await refresh(current, true);
|
|
5410
|
+
function escape(event) {
|
|
5411
|
+
if (event.key !== "Escape") return;
|
|
5412
|
+
event.preventDefault();
|
|
5413
|
+
event.stopPropagation();
|
|
5414
|
+
cancel();
|
|
5395
5415
|
}
|
|
5396
|
-
|
|
5397
|
-
|
|
5416
|
+
(0, solid_js.createEffect)(() => {
|
|
5417
|
+
if (!source()) return;
|
|
5418
|
+
globalThis.window.addEventListener("keydown", escape, { capture: true });
|
|
5419
|
+
(0, solid_js.onCleanup)(() => globalThis.window.removeEventListener("keydown", escape, true));
|
|
5420
|
+
});
|
|
5421
|
+
(0, solid_js.onCleanup)(cancel);
|
|
5422
|
+
function hover(event) {
|
|
5423
|
+
if (!drag || event.pointerId !== drag.pointer) return;
|
|
5424
|
+
const node = document.elementFromPoint(event.clientX, event.clientY)?.closest("[data-sortable-item]");
|
|
5425
|
+
setTarget(node && props.root().contains(node) ? node.dataset.sortableItem : void 0);
|
|
5398
5426
|
}
|
|
5399
|
-
function
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5427
|
+
function start(event, id) {
|
|
5428
|
+
if (event.button !== 0 || props.disabled() || drag) return;
|
|
5429
|
+
event.preventDefault();
|
|
5430
|
+
event.stopPropagation();
|
|
5431
|
+
drag = {
|
|
5432
|
+
id,
|
|
5433
|
+
pointer: event.pointerId,
|
|
5434
|
+
scope: props.scope(),
|
|
5435
|
+
keys: signature()
|
|
5406
5436
|
};
|
|
5437
|
+
props.root().setPointerCapture(event.pointerId);
|
|
5438
|
+
setSource(id);
|
|
5439
|
+
setTarget(id);
|
|
5407
5440
|
}
|
|
5408
|
-
|
|
5409
|
-
if (
|
|
5410
|
-
|
|
5411
|
-
const
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5441
|
+
function end(event) {
|
|
5442
|
+
if (!drag || event.pointerId !== drag.pointer) return;
|
|
5443
|
+
hover(event);
|
|
5444
|
+
const current = drag;
|
|
5445
|
+
const destination = target();
|
|
5446
|
+
const valid = !props.disabled() && props.scope() === current.scope && signature() === current.keys;
|
|
5447
|
+
cancel();
|
|
5448
|
+
if (valid && destination && current.id !== destination) props.move(current.id, destination);
|
|
5449
|
+
}
|
|
5450
|
+
function key(event, id) {
|
|
5451
|
+
if (event.key === "Escape") {
|
|
5452
|
+
if (drag) {
|
|
5453
|
+
event.preventDefault();
|
|
5454
|
+
event.stopPropagation();
|
|
5455
|
+
cancel();
|
|
5421
5456
|
}
|
|
5422
|
-
}));
|
|
5423
|
-
if (changes.length === 0) {
|
|
5424
|
-
setBulkStates((values) => ({
|
|
5425
|
-
...values,
|
|
5426
|
-
[current.key]: {
|
|
5427
|
-
...operation,
|
|
5428
|
-
status: "ready",
|
|
5429
|
-
completed: 0,
|
|
5430
|
-
total: 0,
|
|
5431
|
-
failed: []
|
|
5432
|
-
}
|
|
5433
|
-
}));
|
|
5434
5457
|
return;
|
|
5435
5458
|
}
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
}
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
return {
|
|
5456
|
-
...values,
|
|
5457
|
-
[current.key]: {
|
|
5458
|
-
...state,
|
|
5459
|
-
completed: state.completed + 1
|
|
5460
|
-
}
|
|
5461
|
-
};
|
|
5462
|
-
});
|
|
5463
|
-
}
|
|
5464
|
-
}));
|
|
5465
|
-
if (bulkGenerations.get(current.key) !== generation) return;
|
|
5466
|
-
bulkRetries.set(current.key, retry);
|
|
5467
|
-
if (activeTarget === current.key) await refresh(current, true).catch(() => {});
|
|
5468
|
-
failed.sort((left, right) => left.localeCompare(right));
|
|
5469
|
-
setBulkStates((values) => ({
|
|
5470
|
-
...values,
|
|
5471
|
-
[current.key]: {
|
|
5472
|
-
...operation,
|
|
5473
|
-
status: failed.length > 0 ? "error" : "ready",
|
|
5474
|
-
completed: changes.length,
|
|
5475
|
-
total: changes.length,
|
|
5476
|
-
failed
|
|
5459
|
+
if (props.disabled()) return;
|
|
5460
|
+
if ([" ", "Enter"].includes(event.key) && !event.repeat) {
|
|
5461
|
+
event.preventDefault();
|
|
5462
|
+
event.stopPropagation();
|
|
5463
|
+
if (!drag) {
|
|
5464
|
+
drag = {
|
|
5465
|
+
id,
|
|
5466
|
+
pointer: -1,
|
|
5467
|
+
scope: props.scope(),
|
|
5468
|
+
keys: signature()
|
|
5469
|
+
};
|
|
5470
|
+
setSource(id);
|
|
5471
|
+
setTarget(id);
|
|
5472
|
+
setAnnouncement("Picked up. Use arrow keys, Space to drop, or Escape to cancel.");
|
|
5473
|
+
} else if (drag.pointer === -1 && drag.id === id) {
|
|
5474
|
+
const destination = target();
|
|
5475
|
+
const valid = props.scope() === drag.scope && signature() === drag.keys;
|
|
5476
|
+
cancel();
|
|
5477
|
+
if (valid && destination && destination !== id) props.move(id, destination);
|
|
5477
5478
|
}
|
|
5478
|
-
|
|
5479
|
-
if (failed.length > 0 && activeTarget === current.key) {
|
|
5480
|
-
let action = operation.action === "preset" ? `apply ${operation.preset}` : operation.action;
|
|
5481
|
-
if (operation.group) action += ` ${operation.group}`;
|
|
5482
|
-
options.notifications.show({
|
|
5483
|
-
variant: "warning",
|
|
5484
|
-
title: "MCP servers",
|
|
5485
|
-
message: `Could not ${action}: ${failed.join(", ")}`
|
|
5486
|
-
});
|
|
5479
|
+
return;
|
|
5487
5480
|
}
|
|
5481
|
+
if (drag?.pointer !== -1 || drag.id !== id || !["ArrowUp", "ArrowDown"].includes(event.key)) return;
|
|
5482
|
+
const keys = props.keys();
|
|
5483
|
+
const index = keys.indexOf(target() ?? id);
|
|
5484
|
+
const destination = keys[index + (event.key === "ArrowUp" ? -1 : 1)];
|
|
5485
|
+
if (!destination || index === -1) return;
|
|
5486
|
+
event.preventDefault();
|
|
5487
|
+
event.stopPropagation();
|
|
5488
|
+
setTarget(destination);
|
|
5489
|
+
setAnnouncement(`Drop at position ${keys.indexOf(destination) + 1} of ${keys.length}`);
|
|
5488
5490
|
}
|
|
5489
5491
|
return {
|
|
5490
|
-
|
|
5491
|
-
refresh,
|
|
5492
|
-
reconnect,
|
|
5493
|
-
activate,
|
|
5494
|
-
deactivate(current) {
|
|
5495
|
-
if (activeTarget !== current.key) return;
|
|
5496
|
-
activeTarget = void 0;
|
|
5497
|
-
activation += 1;
|
|
5498
|
-
bulkGenerations.set(current.key, (bulkGenerations.get(current.key) ?? 0) + 1);
|
|
5499
|
-
setBulkStates((values) => {
|
|
5500
|
-
const state = values[current.key];
|
|
5501
|
-
if (!state || state.status !== "running") return values;
|
|
5502
|
-
return {
|
|
5503
|
-
...values,
|
|
5504
|
-
[current.key]: {
|
|
5505
|
-
...state,
|
|
5506
|
-
status: "idle"
|
|
5507
|
-
}
|
|
5508
|
-
};
|
|
5509
|
-
});
|
|
5510
|
-
requests.abortAll();
|
|
5511
|
-
serverRequests.abortAll();
|
|
5512
|
-
refreshing.clear();
|
|
5513
|
-
},
|
|
5492
|
+
source,
|
|
5514
5493
|
target,
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
return refresh(current, true);
|
|
5522
|
-
},
|
|
5523
|
-
serverState(name, current = target()) {
|
|
5524
|
-
return serverRequests.state(serverKey(current, name));
|
|
5525
|
-
},
|
|
5526
|
-
retryServer(name, current = target()) {
|
|
5527
|
-
return mutationRetries.get(serverKey(current, name))?.();
|
|
5528
|
-
},
|
|
5529
|
-
mutating,
|
|
5530
|
-
bulkState,
|
|
5531
|
-
selectedPreset(current = target()) {
|
|
5532
|
-
return selectedPresets()[current.key];
|
|
5533
|
-
},
|
|
5534
|
-
capturePreset(current = target()) {
|
|
5535
|
-
return Object.fromEntries(list(current).map((item) => [item.name, item.status === "connected" ? "enabled" : "disabled"]));
|
|
5536
|
-
},
|
|
5537
|
-
applyPreset(name, states, current = target()) {
|
|
5538
|
-
if (mutating(current)) return;
|
|
5539
|
-
const { changes } = mcpPresetPreview(list(current), states);
|
|
5540
|
-
if (persist()) {
|
|
5541
|
-
if (preferences.setDesiredMcpStates) preferences.setDesiredMcpStates(current.scope, states);
|
|
5542
|
-
else for (const [server, state] of Object.entries(states)) preferences.setDesiredMcpState(current.scope, server, state);
|
|
5543
|
-
}
|
|
5544
|
-
setSelectedPresets((values) => ({
|
|
5545
|
-
...values,
|
|
5546
|
-
[current.key]: name
|
|
5547
|
-
}));
|
|
5548
|
-
selectedPresetStates.set(current.key, { ...states });
|
|
5549
|
-
return changeMany({
|
|
5550
|
-
action: "preset",
|
|
5551
|
-
preset: name
|
|
5552
|
-
}, changes, current);
|
|
5553
|
-
},
|
|
5554
|
-
updateSelectedPreset(name, current = target()) {
|
|
5555
|
-
invalidatePresetOperation(current, name);
|
|
5556
|
-
if (selectedPresets()[current.key] === name) resetSelectedPreset(current);
|
|
5557
|
-
},
|
|
5558
|
-
renameSelectedPreset(previous, current = target()) {
|
|
5559
|
-
invalidatePresetOperation(current, previous);
|
|
5560
|
-
if (selectedPresets()[current.key] === previous) resetSelectedPreset(current);
|
|
5561
|
-
},
|
|
5562
|
-
clearSelectedPreset(name, current = target()) {
|
|
5563
|
-
invalidatePresetOperation(current, name);
|
|
5564
|
-
if (selectedPresets()[current.key] === name) resetSelectedPreset(current);
|
|
5565
|
-
},
|
|
5566
|
-
connectAll(current = target()) {
|
|
5567
|
-
if (mutating(current)) return;
|
|
5568
|
-
resetSelectedPreset(current);
|
|
5569
|
-
return changeMany({ action: "connect" }, list(current).filter((item) => mcpToggleAction(item.status) === "connect").map((item) => ({
|
|
5570
|
-
name: item.name,
|
|
5571
|
-
action: "connect"
|
|
5572
|
-
})), current);
|
|
5573
|
-
},
|
|
5574
|
-
disconnectAll(current = target()) {
|
|
5575
|
-
if (mutating(current)) return;
|
|
5576
|
-
resetSelectedPreset(current);
|
|
5577
|
-
return changeMany({ action: "disconnect" }, list(current).filter((item) => mcpToggleAction(item.status) === "disconnect").map((item) => ({
|
|
5578
|
-
name: item.name,
|
|
5579
|
-
action: "disconnect"
|
|
5580
|
-
})), current);
|
|
5581
|
-
},
|
|
5582
|
-
toggleGroup(group, names, current = target()) {
|
|
5583
|
-
if (target().key !== current.key || mutating(current) || bulkState(current).status === "running") return;
|
|
5584
|
-
const selected = new Set(names);
|
|
5585
|
-
const items = list(current).filter((item) => selected.has(item.name));
|
|
5586
|
-
const action = mcpGroupToggleAction(items);
|
|
5587
|
-
if (!action) return;
|
|
5588
|
-
resetSelectedPreset(current);
|
|
5589
|
-
if (action === "connect") {
|
|
5590
|
-
for (const item of items) if (item.status === "connected") save(current, item.name, false);
|
|
5591
|
-
}
|
|
5592
|
-
return changeMany({
|
|
5593
|
-
action,
|
|
5594
|
-
group
|
|
5595
|
-
}, items.filter((item) => mcpToggleAction(item.status) === action).map((item) => ({
|
|
5596
|
-
name: item.name,
|
|
5597
|
-
action
|
|
5598
|
-
})), current);
|
|
5599
|
-
},
|
|
5600
|
-
retryBulk(current = target()) {
|
|
5601
|
-
const state = bulkState(current);
|
|
5602
|
-
if (state.status !== "error" || state.failed.length === 0) return;
|
|
5603
|
-
const changes = bulkRetries.get(current.key) ?? [];
|
|
5604
|
-
return changeMany({
|
|
5605
|
-
action: state.action,
|
|
5606
|
-
...state.preset && { preset: state.preset },
|
|
5607
|
-
...state.group && { group: state.group }
|
|
5608
|
-
}, changes, current);
|
|
5609
|
-
}
|
|
5494
|
+
announcement,
|
|
5495
|
+
start,
|
|
5496
|
+
hover,
|
|
5497
|
+
end,
|
|
5498
|
+
key,
|
|
5499
|
+
cancel
|
|
5610
5500
|
};
|
|
5611
5501
|
}
|
|
5612
|
-
// src/
|
|
5613
|
-
var _tmpl$$
|
|
5614
|
-
var _tmpl$2$
|
|
5615
|
-
|
|
5616
|
-
|
|
5502
|
+
// src/shared/ui/gui/sortable-list.tsx
|
|
5503
|
+
var _tmpl$$50 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=list><span role=status aria-live=polite style=position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)>Drag a handle, or press Space, use arrow keys, then Space to drop. Escape cancels. `);
|
|
5504
|
+
var _tmpl$2$35 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=listitem>`);
|
|
5505
|
+
var _tmpl$3$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<span title="Drag to reorder, or Space, arrow keys, Space. Escape cancels."style=display:inline-flex;touch-action:none;cursor:grab>`);
|
|
5506
|
+
function GuiSortableList(props) {
|
|
5507
|
+
let root;
|
|
5508
|
+
const help = (0, solid_js.createUniqueId)();
|
|
5509
|
+
const IconButton = props.ui.IconButton;
|
|
5510
|
+
const keys = () => props.items.map((item) => props.itemKey(item));
|
|
5511
|
+
const focus = createSortableFocus({
|
|
5512
|
+
root: () => root,
|
|
5513
|
+
keys,
|
|
5514
|
+
disabled: () => Boolean(props.disabled)
|
|
5515
|
+
});
|
|
5516
|
+
const interaction = createSortableInteraction({
|
|
5517
|
+
keys,
|
|
5518
|
+
scope: () => props.scope,
|
|
5519
|
+
disabled: () => Boolean(props.disabled),
|
|
5520
|
+
root: () => root,
|
|
5521
|
+
move: (from, to) => props.move(from, to)
|
|
5522
|
+
});
|
|
5617
5523
|
return (() => {
|
|
5618
|
-
var _el$ = _tmpl$2
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5524
|
+
var _el$ = _tmpl$$50(), _el$2 = _el$.firstChild;
|
|
5525
|
+
_el$2.firstChild;
|
|
5526
|
+
(0, solid_js_web.addEventListener)(_el$, "lostpointercapture", interaction.cancel);
|
|
5527
|
+
(0, solid_js_web.addEventListener)(_el$, "pointercancel", interaction.cancel);
|
|
5528
|
+
(0, solid_js_web.addEventListener)(_el$, "pointerup", interaction.end, true);
|
|
5529
|
+
(0, solid_js_web.addEventListener)(_el$, "pointermove", interaction.hover, true);
|
|
5530
|
+
(0, solid_js_web.addEventListener)(_el$, "focusout", focus.leave, true);
|
|
5531
|
+
(0, solid_js_web.addEventListener)(_el$, "focusin", focus.enter, true);
|
|
5532
|
+
(0, solid_js_web.use)((node) => {
|
|
5533
|
+
root = node;
|
|
5534
|
+
}, _el$);
|
|
5535
|
+
(0, solid_js_web.setAttribute)(_el$, "aria-describedby", help);
|
|
5536
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5537
|
+
get each() {
|
|
5538
|
+
return keys();
|
|
5625
5539
|
},
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
var
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5540
|
+
children: (key) => {
|
|
5541
|
+
const item = () => props.items.find((value) => props.itemKey(value) === key);
|
|
5542
|
+
return (() => {
|
|
5543
|
+
var _el$4 = _tmpl$2$35();
|
|
5544
|
+
(0, solid_js_web.setAttribute)(_el$4, "data-sortable-item", key);
|
|
5545
|
+
(0, solid_js_web.insert)(_el$4, () => props.children(item, (() => {
|
|
5546
|
+
var _el$5 = _tmpl$3$21();
|
|
5547
|
+
_el$5.$$keydown = (event) => interaction.key(event, key);
|
|
5548
|
+
_el$5.$$pointerdown = (event) => interaction.start(event, key);
|
|
5549
|
+
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(IconButton, {
|
|
5550
|
+
icon: "dot-grid",
|
|
5551
|
+
get label() {
|
|
5552
|
+
return `Reorder ${props.itemLabel(item())}`;
|
|
5553
|
+
},
|
|
5554
|
+
get disabled() {
|
|
5555
|
+
return props.disabled || keys().length < 2;
|
|
5556
|
+
}
|
|
5557
|
+
}));
|
|
5558
|
+
return _el$5;
|
|
5559
|
+
})()));
|
|
5560
|
+
(0, solid_js_web.effect)((_p$) => {
|
|
5561
|
+
var _v$ = keys().indexOf(key) + 1, _v$2 = keys().length, _v$3 = interaction.source() === key ? "0.65" : "1", _v$4 = interaction.target() === key && interaction.source() !== key ? "1px dashed var(--v2-border-border-focus)" : void 0;
|
|
5562
|
+
_v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$4, "aria-posinset", _p$.e = _v$);
|
|
5563
|
+
_v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$4, "aria-setsize", _p$.t = _v$2);
|
|
5564
|
+
_v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$4, "opacity", _p$.a = _v$3);
|
|
5565
|
+
_v$4 !== _p$.o && (0, solid_js_web.setStyleProperty)(_el$4, "outline", _p$.o = _v$4);
|
|
5566
|
+
return _p$;
|
|
5567
|
+
}, {
|
|
5568
|
+
e: void 0,
|
|
5569
|
+
t: void 0,
|
|
5570
|
+
a: void 0,
|
|
5571
|
+
o: void 0
|
|
5572
|
+
});
|
|
5573
|
+
return _el$4;
|
|
5574
|
+
})();
|
|
5638
5575
|
}
|
|
5639
|
-
}));
|
|
5640
|
-
(0, solid_js_web.
|
|
5576
|
+
}), _el$2);
|
|
5577
|
+
(0, solid_js_web.setAttribute)(_el$2, "id", help);
|
|
5578
|
+
(0, solid_js_web.insert)(_el$2, () => interaction.announcement(), null);
|
|
5579
|
+
(0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", props.label));
|
|
5641
5580
|
return _el$;
|
|
5642
5581
|
})();
|
|
5643
5582
|
}
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
}
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5583
|
+
(0, solid_js_web.delegateEvents)([
|
|
5584
|
+
"focusin",
|
|
5585
|
+
"focusout",
|
|
5586
|
+
"pointermove",
|
|
5587
|
+
"pointerup",
|
|
5588
|
+
"pointerdown",
|
|
5589
|
+
"keydown"
|
|
5590
|
+
]);
|
|
5591
|
+
// src/shared/ui/gui/progress.tsx
|
|
5592
|
+
var _tmpl$$49 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=progressbar aria-valuemin=0 aria-valuemax=100 style=display:grid;gap:6px;min-width:0><style>@keyframes navigator-install-pulse \{ from \{ transform: translateX(-100%); } to \{ transform: translateX(400%); } }\n@media (prefers-reduced-motion: reduce) \{ [data-navigator-install-pulse] \{ animation: none !important; } }</style><span style=display:flex;gap:6px;align-items:center></span><span style=display:block;height:3px;overflow:hidden;background:var(--v2-border-border-base)><span style=display:block;height:100%;background:var(--v2-text-text-base)>`);
|
|
5593
|
+
function GuiProgress(props) {
|
|
5594
|
+
const Loader = props.ui.Loader;
|
|
5595
|
+
return (() => {
|
|
5596
|
+
var _el$ = _tmpl$$49(), _el$3 = _el$.firstChild.nextSibling, _el$5 = _el$3.nextSibling.firstChild;
|
|
5597
|
+
(0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5598
|
+
get when() {
|
|
5599
|
+
return props.value === void 0;
|
|
5600
|
+
},
|
|
5601
|
+
get children() {
|
|
5602
|
+
return (0, solid_js_web.createComponent)(Loader, { size: "small" });
|
|
5603
|
+
}
|
|
5604
|
+
}), null);
|
|
5605
|
+
(0, solid_js_web.insert)(_el$3, () => props.label, null);
|
|
5606
|
+
(0, solid_js_web.effect)((_p$) => {
|
|
5607
|
+
var _v$ = props.label, _v$2 = props.value === void 0 ? void 0 : Math.floor(props.value * 100), _v$3 = props.label, _v$4 = props.value === void 0 ? "" : void 0, _v$5 = props.value === void 0 ? "25%" : `${Math.min(1, Math.max(0, props.value)) * 100}%`, _v$6 = props.value === void 0 ? "navigator-install-pulse 1.2s linear infinite" : void 0;
|
|
5608
|
+
_v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
|
|
5609
|
+
_v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$, "aria-valuenow", _p$.t = _v$2);
|
|
5610
|
+
_v$3 !== _p$.a && (0, solid_js_web.setAttribute)(_el$, "aria-valuetext", _p$.a = _v$3);
|
|
5611
|
+
_v$4 !== _p$.o && (0, solid_js_web.setAttribute)(_el$5, "data-navigator-install-pulse", _p$.o = _v$4);
|
|
5612
|
+
_v$5 !== _p$.i && (0, solid_js_web.setStyleProperty)(_el$5, "width", _p$.i = _v$5);
|
|
5613
|
+
_v$6 !== _p$.n && (0, solid_js_web.setStyleProperty)(_el$5, "animation", _p$.n = _v$6);
|
|
5614
|
+
return _p$;
|
|
5615
|
+
}, {
|
|
5616
|
+
e: void 0,
|
|
5617
|
+
t: void 0,
|
|
5618
|
+
a: void 0,
|
|
5619
|
+
o: void 0,
|
|
5620
|
+
i: void 0,
|
|
5621
|
+
n: void 0
|
|
5622
|
+
});
|
|
5623
|
+
return _el$;
|
|
5624
|
+
})();
|
|
5625
|
+
}
|
|
5626
|
+
// src/shared/ui/gui/icon-action.tsx
|
|
5627
|
+
function GuiIconAction(props) {
|
|
5628
|
+
const IconButton = props.ui.IconButton;
|
|
5629
|
+
const Tooltip = props.ui.Tooltip;
|
|
5630
|
+
return (0, solid_js_web.createComponent)(Tooltip, {
|
|
5631
|
+
get value() {
|
|
5632
|
+
return props.label;
|
|
5672
5633
|
},
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
return error();
|
|
5634
|
+
get children() {
|
|
5635
|
+
return (0, solid_js_web.createComponent)(IconButton, {
|
|
5636
|
+
get icon() {
|
|
5637
|
+
return props.icon;
|
|
5678
5638
|
},
|
|
5679
|
-
get
|
|
5680
|
-
return
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5639
|
+
get label() {
|
|
5640
|
+
return props.label;
|
|
5641
|
+
},
|
|
5642
|
+
size: "small",
|
|
5643
|
+
get variant() {
|
|
5644
|
+
return props.variant ?? "ghost-muted";
|
|
5645
|
+
},
|
|
5646
|
+
get disabled() {
|
|
5647
|
+
return props.disabled;
|
|
5648
|
+
},
|
|
5649
|
+
get busy() {
|
|
5650
|
+
return props.busy;
|
|
5651
|
+
},
|
|
5652
|
+
get onClick() {
|
|
5653
|
+
return props.onClick;
|
|
5689
5654
|
}
|
|
5690
5655
|
});
|
|
5691
5656
|
}
|
|
5692
5657
|
});
|
|
5693
5658
|
}
|
|
5694
|
-
// src/pages/navigator/ui/gui/
|
|
5695
|
-
var _tmpl$$
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
function GuiMcpGroup(props) {
|
|
5699
|
-
const services = useNavigatorGui();
|
|
5700
|
-
const catalogs = () => services.runtime.catalogs;
|
|
5701
|
-
const view = () => catalogs().views.mcp;
|
|
5702
|
-
const bucket = () => view().bucket(props.group);
|
|
5703
|
-
const busy = () => catalogs().mcp.bulkState().group === props.group && catalogs().mcp.bulkState().status === "running";
|
|
5704
|
-
const Button = services.ui.Button;
|
|
5659
|
+
// src/pages/navigator/ui/gui/quota-window.tsx
|
|
5660
|
+
var _tmpl$$48 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="min-width:0;margin:12px 0"><div role=meter aria-valuemin=0 aria-valuemax=100 style="height:2px;background:color-mix(in srgb, currentColor 10%, transparent)"><div style=height:100%;background:currentColor;opacity:0.5></div></div><div style=display:flex;gap:8px;font-size:12px;margin-top:5px><span style=opacity:0.6;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1></span><span style=flex-shrink:0>`);
|
|
5661
|
+
function GuiQuotaWindow(props) {
|
|
5662
|
+
const view = () => quotaPresentation(props.window);
|
|
5705
5663
|
return (() => {
|
|
5706
|
-
var _el$ = _tmpl
|
|
5707
|
-
(0, solid_js_web.insert)(_el
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
(() => {
|
|
5725
|
-
var _el$3 = _tmpl$2$35();
|
|
5726
|
-
(0, solid_js_web.insert)(_el$3, () => bucket().length);
|
|
5727
|
-
return _el$3;
|
|
5728
|
-
})()
|
|
5729
|
-
];
|
|
5730
|
-
}
|
|
5731
|
-
}), _el$4);
|
|
5732
|
-
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5733
|
-
get each() {
|
|
5734
|
-
return view().visibility.visible().filter((item) => item.bucket === props.group).map((item) => item.name);
|
|
5735
|
-
},
|
|
5736
|
-
children: (name) => (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5737
|
-
get when() {
|
|
5738
|
-
return view().visibility.visible().find((item) => item.name === name);
|
|
5739
|
-
},
|
|
5740
|
-
children: (item) => (0, solid_js_web.createComponent)(GuiMcpRow, { get item() {
|
|
5741
|
-
return item();
|
|
5742
|
-
} })
|
|
5743
|
-
})
|
|
5744
|
-
}));
|
|
5664
|
+
var _el$ = _tmpl$$48(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$2.nextSibling.firstChild, _el$6 = _el$5.nextSibling;
|
|
5665
|
+
(0, solid_js_web.insert)(_el$5, () => view().reset);
|
|
5666
|
+
(0, solid_js_web.insert)(_el$6, () => view().value);
|
|
5667
|
+
(0, solid_js_web.effect)((_p$) => {
|
|
5668
|
+
var _v$ = props.window.label, _v$2 = props.window.label, _v$3 = view().ratio === void 0 ? void 0 : Math.round(view().ratio * 100), _v$4 = view().value, _v$5 = `${(view().ratio ?? 0) * 100}%`;
|
|
5669
|
+
_v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
|
|
5670
|
+
_v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$2, "aria-label", _p$.t = _v$2);
|
|
5671
|
+
_v$3 !== _p$.a && (0, solid_js_web.setAttribute)(_el$2, "aria-valuenow", _p$.a = _v$3);
|
|
5672
|
+
_v$4 !== _p$.o && (0, solid_js_web.setAttribute)(_el$2, "aria-valuetext", _p$.o = _v$4);
|
|
5673
|
+
_v$5 !== _p$.i && (0, solid_js_web.setStyleProperty)(_el$3, "width", _p$.i = _v$5);
|
|
5674
|
+
return _p$;
|
|
5675
|
+
}, {
|
|
5676
|
+
e: void 0,
|
|
5677
|
+
t: void 0,
|
|
5678
|
+
a: void 0,
|
|
5679
|
+
o: void 0,
|
|
5680
|
+
i: void 0
|
|
5681
|
+
});
|
|
5745
5682
|
return _el$;
|
|
5746
5683
|
})();
|
|
5747
5684
|
}
|
|
5748
|
-
// src/pages/navigator/ui/gui/
|
|
5749
|
-
var _tmpl$$
|
|
5750
|
-
var _tmpl$2$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<p
|
|
5751
|
-
var _tmpl$3$
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
const
|
|
5755
|
-
const
|
|
5756
|
-
const
|
|
5757
|
-
const
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5685
|
+
// src/pages/navigator/ui/gui/limits-section.tsx
|
|
5686
|
+
var _tmpl$$47 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
|
|
5687
|
+
var _tmpl$2$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>`);
|
|
5688
|
+
var _tmpl$3$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>: `);
|
|
5689
|
+
function LimitsSection() {
|
|
5690
|
+
const props = useNavigatorGui();
|
|
5691
|
+
const limits = () => props.runtime.limits;
|
|
5692
|
+
const snapshot = () => limits()?.controller.snapshot();
|
|
5693
|
+
const state = () => limits()?.controller.state();
|
|
5694
|
+
const message = () => limits()?.selected() ? quotaStatusMessage({
|
|
5695
|
+
model: limits()?.selected(),
|
|
5696
|
+
snapshot: snapshot(),
|
|
5697
|
+
state: state() ?? { status: "idle" },
|
|
5698
|
+
hasAdapter: Boolean(limits()?.controller.current().adapter),
|
|
5699
|
+
showUpdatedAt: true
|
|
5700
|
+
}) : "Select a model in chat to view its provider limits.";
|
|
5701
|
+
const canLink = () => {
|
|
5702
|
+
const model = limits()?.selected();
|
|
5703
|
+
return model && props.onLinkAccount && limits()?.codex && model.hostConnection?.status === "ready" && canLinkCodexAccount(model) && (!model.accountID || snapshot()?.availability === "unauthenticated" && model.accountSource === "binding");
|
|
5704
|
+
};
|
|
5705
|
+
const Button = props.ui.Button;
|
|
5761
5706
|
return (0, solid_js_web.createComponent)(MonitoringSection, {
|
|
5762
|
-
id: "
|
|
5763
|
-
title: "
|
|
5764
|
-
get count() {
|
|
5765
|
-
return view().all().length;
|
|
5766
|
-
},
|
|
5707
|
+
id: "limits",
|
|
5708
|
+
title: "Limits",
|
|
5767
5709
|
get actions() {
|
|
5768
|
-
return (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5710
|
+
return [(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5769
5711
|
get when() {
|
|
5770
|
-
return
|
|
5712
|
+
return (0, solid_js_web.memo)(() => !!props.onBankedResets)() && ((snapshot()?.bankedResets?.availableCount ?? 0) > 0 || props.runtime.catalogs?.preferences.pendingResetAttempt());
|
|
5771
5713
|
},
|
|
5772
5714
|
get children() {
|
|
5773
5715
|
return (0, solid_js_web.createComponent)(Button, {
|
|
5774
5716
|
size: "small",
|
|
5775
5717
|
variant: "ghost",
|
|
5776
5718
|
get onClick() {
|
|
5777
|
-
return
|
|
5719
|
+
return props.onBankedResets;
|
|
5778
5720
|
},
|
|
5779
|
-
|
|
5780
|
-
return matched() || "Preset";
|
|
5781
|
-
}
|
|
5721
|
+
children: "Banked Resets"
|
|
5782
5722
|
});
|
|
5783
5723
|
}
|
|
5784
|
-
})
|
|
5724
|
+
}), (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
5725
|
+
get ui() {
|
|
5726
|
+
return props.ui;
|
|
5727
|
+
},
|
|
5728
|
+
icon: "refresh",
|
|
5729
|
+
label: "Refresh",
|
|
5730
|
+
onClick: () => void limits()?.controller.refresh(true)
|
|
5731
|
+
})];
|
|
5785
5732
|
},
|
|
5786
5733
|
get children() {
|
|
5787
5734
|
return [
|
|
5788
|
-
(0, solid_js_web.createComponent)(
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
get value() {
|
|
5792
|
-
return view().query();
|
|
5793
|
-
},
|
|
5794
|
-
get change() {
|
|
5795
|
-
return view().setQuery;
|
|
5796
|
-
}
|
|
5797
|
-
}),
|
|
5798
|
-
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5799
|
-
get when() {
|
|
5800
|
-
return state().error;
|
|
5735
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5736
|
+
get when() {
|
|
5737
|
+
return canLink();
|
|
5801
5738
|
},
|
|
5802
5739
|
get children() {
|
|
5803
|
-
return
|
|
5804
|
-
var _el$ = _tmpl$$51();
|
|
5805
|
-
(0, solid_js_web.insert)(_el$, () => state().error?.message);
|
|
5806
|
-
return _el$;
|
|
5807
|
-
})(), (0, solid_js_web.createComponent)(Button, {
|
|
5740
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
5808
5741
|
size: "small",
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5742
|
+
variant: "ghost",
|
|
5743
|
+
get onClick() {
|
|
5744
|
+
return props.onLinkAccount;
|
|
5745
|
+
},
|
|
5746
|
+
children: "Link Codex account"
|
|
5747
|
+
});
|
|
5812
5748
|
}
|
|
5813
5749
|
}),
|
|
5814
5750
|
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5815
5751
|
get when() {
|
|
5816
|
-
return
|
|
5752
|
+
return state()?.error;
|
|
5817
5753
|
},
|
|
5818
5754
|
get children() {
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
(0, solid_js_web.insert)(_el$2, () => bulk().completed, _el$3);
|
|
5823
|
-
(0, solid_js_web.insert)(_el$2, () => bulk().total, _el$5);
|
|
5824
|
-
return _el$2;
|
|
5825
|
-
})(), (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5826
|
-
get when() {
|
|
5827
|
-
return bulk().status === "error";
|
|
5828
|
-
},
|
|
5829
|
-
get children() {
|
|
5830
|
-
return (0, solid_js_web.createComponent)(Button, {
|
|
5831
|
-
size: "small",
|
|
5832
|
-
onClick: () => void catalogs().mcp.retryBulk()?.catch(() => {}),
|
|
5833
|
-
children: "Retry failed servers"
|
|
5834
|
-
});
|
|
5835
|
-
}
|
|
5836
|
-
})];
|
|
5755
|
+
var _el$ = _tmpl$$47();
|
|
5756
|
+
(0, solid_js_web.insert)(_el$, () => state()?.error?.message);
|
|
5757
|
+
return _el$;
|
|
5837
5758
|
}
|
|
5838
5759
|
}),
|
|
5839
|
-
(() => {
|
|
5840
|
-
var _el$6 = _tmpl$3$21();
|
|
5841
|
-
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5842
|
-
get each() {
|
|
5843
|
-
return view().groups();
|
|
5844
|
-
},
|
|
5845
|
-
get fallback() {
|
|
5846
|
-
return _tmpl$4$12();
|
|
5847
|
-
},
|
|
5848
|
-
children: (group) => (0, solid_js_web.createComponent)(GuiMcpGroup, { group })
|
|
5849
|
-
}));
|
|
5850
|
-
return _el$6;
|
|
5851
|
-
})(),
|
|
5852
5760
|
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5853
5761
|
get when() {
|
|
5854
|
-
return
|
|
5762
|
+
return message();
|
|
5855
5763
|
},
|
|
5856
5764
|
get children() {
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
onClick: () => view().visibility.expanded() ? view().visibility.showLess() : view().visibility.showAll(),
|
|
5861
|
-
get children() {
|
|
5862
|
-
return (0, solid_js_web.memo)(() => !!view().visibility.expanded())() ? "Show less" : `Show ${view().visibility.hiddenCount()} more`;
|
|
5863
|
-
}
|
|
5864
|
-
});
|
|
5865
|
-
}
|
|
5866
|
-
})
|
|
5867
|
-
];
|
|
5868
|
-
}
|
|
5869
|
-
});
|
|
5870
|
-
}
|
|
5871
|
-
// src/pages/navigator/ui/gui/skill-row.tsx
|
|
5872
|
-
function GuiSkillRow(props) {
|
|
5873
|
-
const services = useNavigatorGui();
|
|
5874
|
-
const preferences = () => services.runtime.catalogs.preferences;
|
|
5875
|
-
const Menu = services.ui.Menu;
|
|
5876
|
-
const pinned = () => preferences().toolbarPins().some((pin) => pin.kind === "skill" && pin.location === props.skill.location);
|
|
5877
|
-
return (0, solid_js_web.createComponent)(CatalogRow, {
|
|
5878
|
-
get title() {
|
|
5879
|
-
return props.skill.name;
|
|
5880
|
-
},
|
|
5881
|
-
get details() {
|
|
5882
|
-
return props.skill.description;
|
|
5883
|
-
},
|
|
5884
|
-
get favorite() {
|
|
5885
|
-
return preferences().isFavoriteSkill(props.skill);
|
|
5886
|
-
},
|
|
5887
|
-
get bookmarkDisabled() {
|
|
5888
|
-
return !preferences().ready();
|
|
5889
|
-
},
|
|
5890
|
-
bookmark: () => preferences().toggleFavoriteSkill(props.skill),
|
|
5891
|
-
activate: () => services.onSkill(props.skill),
|
|
5892
|
-
get trailing() {
|
|
5893
|
-
return (0, solid_js_web.createComponent)(Menu, {
|
|
5894
|
-
get label() {
|
|
5895
|
-
return `Options for Skill ${props.skill.name}`;
|
|
5896
|
-
},
|
|
5897
|
-
get items() {
|
|
5898
|
-
return [{
|
|
5899
|
-
label: pinned() ? "Configure toolbar button" : "Pin to toolbar",
|
|
5900
|
-
icon: "plus",
|
|
5901
|
-
disabled: !preferences().ready(),
|
|
5902
|
-
onSelect: () => services.onPin({
|
|
5903
|
-
kind: "skill",
|
|
5904
|
-
location: props.skill.location,
|
|
5905
|
-
name: props.skill.name,
|
|
5906
|
-
icon: "book"
|
|
5907
|
-
})
|
|
5908
|
-
}];
|
|
5909
|
-
}
|
|
5910
|
-
});
|
|
5911
|
-
}
|
|
5912
|
-
});
|
|
5913
|
-
}
|
|
5914
|
-
// src/pages/navigator/ui/gui/skills-section.tsx
|
|
5915
|
-
var _tmpl$$50 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
|
|
5916
|
-
var _tmpl$2$33 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
|
|
5917
|
-
var _tmpl$3$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching Skills.`);
|
|
5918
|
-
var _tmpl$4$11 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><h3 style="font-size:12px;opacity:0.65;margin:0 0 4px"></h3><ul style="margin:0;padding:0 0 0 10px;list-style:none">`);
|
|
5919
|
-
function SkillsSection() {
|
|
5920
|
-
const services = useNavigatorGui();
|
|
5921
|
-
const catalogs = () => services.runtime.catalogs;
|
|
5922
|
-
const view = () => catalogs().views.skills;
|
|
5923
|
-
const Button = services.ui.Button;
|
|
5924
|
-
return (0, solid_js_web.createComponent)(MonitoringSection, {
|
|
5925
|
-
id: "skills",
|
|
5926
|
-
title: "Skills",
|
|
5927
|
-
get count() {
|
|
5928
|
-
return view().all().length;
|
|
5929
|
-
},
|
|
5930
|
-
get children() {
|
|
5931
|
-
return [
|
|
5932
|
-
(0, solid_js_web.createComponent)(SectionFilter, {
|
|
5933
|
-
label: "Filter Skills",
|
|
5934
|
-
placeholder: "Filter skills and groups",
|
|
5935
|
-
get value() {
|
|
5936
|
-
return view().query();
|
|
5937
|
-
},
|
|
5938
|
-
get change() {
|
|
5939
|
-
return view().setQuery;
|
|
5765
|
+
var _el$2 = _tmpl$2$34();
|
|
5766
|
+
(0, solid_js_web.insert)(_el$2, message);
|
|
5767
|
+
return _el$2;
|
|
5940
5768
|
}
|
|
5941
5769
|
}),
|
|
5942
5770
|
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5943
5771
|
get when() {
|
|
5944
|
-
return
|
|
5772
|
+
return snapshot();
|
|
5945
5773
|
},
|
|
5946
|
-
|
|
5947
|
-
return [(() => {
|
|
5948
|
-
var _el$ = _tmpl$$50();
|
|
5949
|
-
(0, solid_js_web.insert)(_el$, () => catalogs().skills.error());
|
|
5950
|
-
return _el$;
|
|
5951
|
-
})(), (0, solid_js_web.createComponent)(Button, {
|
|
5952
|
-
size: "small",
|
|
5953
|
-
onClick: () => void catalogs().skills.retry().catch(() => {}),
|
|
5954
|
-
children: "Retry"
|
|
5955
|
-
})];
|
|
5956
|
-
}
|
|
5957
|
-
}),
|
|
5958
|
-
(() => {
|
|
5959
|
-
var _el$2 = _tmpl$2$33();
|
|
5960
|
-
(0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5774
|
+
children: (value) => [(0, solid_js_web.createComponent)(solid_js.For, {
|
|
5961
5775
|
get each() {
|
|
5962
|
-
return
|
|
5776
|
+
return value().windows;
|
|
5963
5777
|
},
|
|
5964
|
-
|
|
5965
|
-
|
|
5778
|
+
children: (window) => (0, solid_js_web.createComponent)(GuiQuotaWindow, { window })
|
|
5779
|
+
}), (0, solid_js_web.createComponent)(solid_js.For, {
|
|
5780
|
+
get each() {
|
|
5781
|
+
return value().balances;
|
|
5966
5782
|
},
|
|
5967
|
-
children: (
|
|
5968
|
-
var _el$
|
|
5969
|
-
(0, solid_js_web.insert)(_el$
|
|
5970
|
-
(0, solid_js_web.insert)(_el$
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
get when() {
|
|
5976
|
-
return view().visibility.visible().find((item) => item.location === location);
|
|
5977
|
-
},
|
|
5978
|
-
children: (item) => (0, solid_js_web.createComponent)(GuiSkillRow, { get skill() {
|
|
5979
|
-
return item();
|
|
5980
|
-
} })
|
|
5981
|
-
})
|
|
5982
|
-
}));
|
|
5983
|
-
return _el$4;
|
|
5783
|
+
children: (balance) => (() => {
|
|
5784
|
+
var _el$3 = _tmpl$3$20(), _el$4 = _el$3.firstChild;
|
|
5785
|
+
(0, solid_js_web.insert)(_el$3, () => balance.label, _el$4);
|
|
5786
|
+
(0, solid_js_web.insert)(_el$3, (() => {
|
|
5787
|
+
var _c$ = (0, solid_js_web.memo)(() => !!balance.unlimited);
|
|
5788
|
+
return () => _c$() ? "Unlimited" : `${balance.amount} ${balance.unit ?? ""}`;
|
|
5789
|
+
})(), null);
|
|
5790
|
+
return _el$3;
|
|
5984
5791
|
})()
|
|
5985
|
-
})
|
|
5986
|
-
return _el$2;
|
|
5987
|
-
})(),
|
|
5988
|
-
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
5989
|
-
get when() {
|
|
5990
|
-
return view().visibility.canToggle();
|
|
5991
|
-
},
|
|
5992
|
-
get children() {
|
|
5993
|
-
return (0, solid_js_web.createComponent)(Button, {
|
|
5994
|
-
size: "small",
|
|
5995
|
-
variant: "ghost",
|
|
5996
|
-
onClick: () => view().visibility.expanded() ? view().visibility.showLess() : view().visibility.showAll(),
|
|
5997
|
-
get children() {
|
|
5998
|
-
return (0, solid_js_web.memo)(() => !!view().visibility.expanded())() ? "Show less" : `Show ${view().visibility.hiddenCount()} more`;
|
|
5999
|
-
}
|
|
6000
|
-
});
|
|
6001
|
-
}
|
|
5792
|
+
})]
|
|
6002
5793
|
})
|
|
6003
5794
|
];
|
|
6004
5795
|
}
|
|
6005
5796
|
});
|
|
6006
5797
|
}
|
|
6007
|
-
// src/entities/
|
|
6008
|
-
function
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
function state(key) {
|
|
6012
|
-
let value = targets.get(key);
|
|
6013
|
-
if (!value) {
|
|
6014
|
-
value = {
|
|
6015
|
-
known: /* @__PURE__ */ new Set(),
|
|
6016
|
-
active: /* @__PURE__ */ new Map(),
|
|
6017
|
-
recent: []
|
|
6018
|
-
};
|
|
6019
|
-
targets.set(key, value);
|
|
6020
|
-
}
|
|
6021
|
-
return value;
|
|
6022
|
-
}
|
|
6023
|
-
function changed() {
|
|
6024
|
-
setRevision((value) => value + 1);
|
|
6025
|
-
}
|
|
6026
|
-
return {
|
|
6027
|
-
observeStatus(key, sessionID, status, at = now(), nativeStart) {
|
|
6028
|
-
const value = state(key);
|
|
6029
|
-
const run = value.active.get(sessionID);
|
|
6030
|
-
const isKnown = value.known.has(sessionID);
|
|
6031
|
-
value.known.add(sessionID);
|
|
6032
|
-
if (status.type === "idle") {
|
|
6033
|
-
if (!run) return;
|
|
6034
|
-
value.active.delete(sessionID);
|
|
6035
|
-
value.recent = [{
|
|
6036
|
-
...run,
|
|
6037
|
-
finishedAt: Math.max(at, run.startedAt),
|
|
6038
|
-
outcome: run.outcome ?? "finished"
|
|
6039
|
-
}, ...value.recent].sort((a, b) => b.finishedAt - a.finishedAt || a.sessionID.localeCompare(b.sessionID)).slice(0, 10);
|
|
6040
|
-
} else {
|
|
6041
|
-
const exact = typeof nativeStart === "number" && Number.isFinite(nativeStart) && nativeStart > 0 && nativeStart <= at ? nativeStart : void 0;
|
|
6042
|
-
if (run) {
|
|
6043
|
-
if (exact === void 0 || run.nativeStartedAt !== void 0 && exact <= run.nativeStartedAt) return;
|
|
6044
|
-
const next = exact > run.startedAt ? { sessionID } : run;
|
|
6045
|
-
value.active.set(sessionID, {
|
|
6046
|
-
...next,
|
|
6047
|
-
startedAt: exact,
|
|
6048
|
-
nativeStartedAt: exact,
|
|
6049
|
-
startedBeforeObservation: false
|
|
6050
|
-
});
|
|
6051
|
-
changed();
|
|
6052
|
-
return;
|
|
6053
|
-
}
|
|
6054
|
-
value.recent = value.recent.filter((item) => item.sessionID !== sessionID);
|
|
6055
|
-
value.active.set(sessionID, {
|
|
6056
|
-
sessionID,
|
|
6057
|
-
startedAt: exact ?? at,
|
|
6058
|
-
startedBeforeObservation: exact === void 0 && !isKnown,
|
|
6059
|
-
...exact !== void 0 && { nativeStartedAt: exact }
|
|
6060
|
-
});
|
|
6061
|
-
}
|
|
6062
|
-
changed();
|
|
6063
|
-
},
|
|
6064
|
-
observeError(key, sessionID, error, at = now()) {
|
|
6065
|
-
if (!sessionID) return;
|
|
6066
|
-
const value = state(key);
|
|
6067
|
-
const run = value.active.get(sessionID) ?? value.recent.find((item) => item.sessionID === sessionID);
|
|
6068
|
-
if (!run || at < run.startedAt && !run.startedBeforeObservation) return;
|
|
6069
|
-
const isCancelled = error?.name === "MessageAbortedError";
|
|
6070
|
-
const data = error && "data" in error ? error.data : void 0;
|
|
6071
|
-
const fallbackMessage = isCancelled ? "Session aborted" : "Session error";
|
|
6072
|
-
const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : fallbackMessage;
|
|
6073
|
-
const next = {
|
|
6074
|
-
...run,
|
|
6075
|
-
startedAt: Math.min(run.startedAt, at),
|
|
6076
|
-
outcome: isCancelled ? "cancelled" : "error",
|
|
6077
|
-
errorMessage: message
|
|
6078
|
-
};
|
|
6079
|
-
if (value.active.has(sessionID)) value.active.set(sessionID, next);
|
|
6080
|
-
else value.recent = value.recent.map((item) => item.sessionID === sessionID ? next : item);
|
|
6081
|
-
changed();
|
|
6082
|
-
},
|
|
6083
|
-
remove(key, sessionID) {
|
|
6084
|
-
const value = targets.get(key);
|
|
6085
|
-
if (!value) return;
|
|
6086
|
-
value.known.delete(sessionID);
|
|
6087
|
-
value.active.delete(sessionID);
|
|
6088
|
-
value.recent = value.recent.filter((item) => item.sessionID !== sessionID);
|
|
6089
|
-
changed();
|
|
6090
|
-
},
|
|
6091
|
-
active(key, sessionID) {
|
|
6092
|
-
revision();
|
|
6093
|
-
return targets.get(key)?.active.get(sessionID);
|
|
6094
|
-
},
|
|
6095
|
-
recent(key) {
|
|
6096
|
-
revision();
|
|
6097
|
-
return targets.get(key)?.recent ?? [];
|
|
6098
|
-
}
|
|
6099
|
-
};
|
|
5798
|
+
// src/entities/mcp/model/status.ts
|
|
5799
|
+
function mcpToggleAction(status) {
|
|
5800
|
+
if (status === "pending") return;
|
|
5801
|
+
return status === "connected" ? "disconnect" : "connect";
|
|
6100
5802
|
}
|
|
6101
|
-
// src/entities/
|
|
6102
|
-
var
|
|
6103
|
-
|
|
6104
|
-
|
|
5803
|
+
// src/entities/mcp/model/grouping.ts
|
|
5804
|
+
var BUCKET_RANK$1 = {
|
|
5805
|
+
Favorites: 0,
|
|
5806
|
+
Ungrouped: 2
|
|
5807
|
+
};
|
|
5808
|
+
function mcpGroupToggleAction(items) {
|
|
5809
|
+
if (items.some((item) => mcpToggleAction(item.status) === "connect")) return "connect";
|
|
5810
|
+
return items.some((item) => mcpToggleAction(item.status) === "disconnect") ? "disconnect" : void 0;
|
|
6105
5811
|
}
|
|
6106
|
-
function
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
5812
|
+
function mcpGroupStatus(items, busy = false) {
|
|
5813
|
+
if (busy) return "pending";
|
|
5814
|
+
if (items.length > 0 && items.every((item) => item.status === "connected")) return "connected";
|
|
5815
|
+
return items.find((item) => item.status !== "connected" && item.status !== "disabled")?.status ?? "disabled";
|
|
5816
|
+
}
|
|
5817
|
+
function buildMcpGroupedView(items, favorites, assignments) {
|
|
5818
|
+
return items.map((item) => ({
|
|
5819
|
+
...item,
|
|
5820
|
+
assignedGroup: assignments[item.name],
|
|
5821
|
+
bucket: favorites.has(item.name) ? "Favorites" : assignments[item.name] ?? "Ungrouped"
|
|
5822
|
+
})).sort((left, right) => {
|
|
5823
|
+
return (BUCKET_RANK$1[left.bucket] ?? 1) - (BUCKET_RANK$1[right.bucket] ?? 1) || left.bucket.localeCompare(right.bucket) || left.name.localeCompare(right.name);
|
|
5824
|
+
});
|
|
5825
|
+
}
|
|
5826
|
+
// src/entities/mcp/model/mcp-controller.ts
|
|
5827
|
+
function serverKey(current, name) {
|
|
5828
|
+
return JSON.stringify([current.key, name]);
|
|
5829
|
+
}
|
|
5830
|
+
function bulkDescription(operation, action) {
|
|
5831
|
+
if (operation.action === "preset") return `apply ${operation.preset} MCP preset`;
|
|
5832
|
+
if (operation.group) return `${action} ${operation.group} MCP group`;
|
|
5833
|
+
return `${action} all MCP servers`;
|
|
5834
|
+
}
|
|
5835
|
+
function matchingMcpPreset(items, presets) {
|
|
5836
|
+
if (items.length === 0) return;
|
|
5837
|
+
return Object.keys(presets).sort((left, right) => left.localeCompare(right)).find((name) => {
|
|
5838
|
+
const states = presets[name];
|
|
5839
|
+
return Object.keys(states).length === items.length && items.every((item) => item.status === "connected" && states[item.name] === "enabled" || item.status === "disabled" && states[item.name] === "disabled");
|
|
5840
|
+
});
|
|
5841
|
+
}
|
|
5842
|
+
function createMcpModel(options, persist, preferences) {
|
|
5843
|
+
const { source } = options;
|
|
5844
|
+
const [snapshots, setSnapshots] = (0, solid_js.createSignal)({});
|
|
5845
|
+
const [mutationCounts, setMutationCounts] = (0, solid_js.createSignal)({});
|
|
5846
|
+
const [bulkStates, setBulkStates] = (0, solid_js.createSignal)({});
|
|
5847
|
+
const [selectedPresets, setSelectedPresets] = (0, solid_js.createSignal)({});
|
|
6112
5848
|
const refreshing = /* @__PURE__ */ new Map();
|
|
6113
|
-
const
|
|
6114
|
-
const
|
|
6115
|
-
const
|
|
6116
|
-
const
|
|
6117
|
-
const
|
|
6118
|
-
const requests = createRequestState(options.
|
|
5849
|
+
const mutations = /* @__PURE__ */ new Map();
|
|
5850
|
+
const mutationRetries = /* @__PURE__ */ new Map();
|
|
5851
|
+
const bulkGenerations = /* @__PURE__ */ new Map();
|
|
5852
|
+
const bulkRetries = /* @__PURE__ */ new Map();
|
|
5853
|
+
const selectedPresetStates = /* @__PURE__ */ new Map();
|
|
5854
|
+
const requests = createRequestState(options.signal);
|
|
5855
|
+
const serverRequests = createRequestState(options.signal);
|
|
5856
|
+
let activation = 0;
|
|
6119
5857
|
let activeTarget;
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
5858
|
+
function changeMutationCount(current, offset) {
|
|
5859
|
+
setMutationCounts((values) => {
|
|
5860
|
+
const next = Math.max(0, (values[current.key] ?? 0) + offset);
|
|
5861
|
+
if (next === 0) {
|
|
5862
|
+
const copy = { ...values };
|
|
5863
|
+
delete copy[current.key];
|
|
5864
|
+
return copy;
|
|
5865
|
+
}
|
|
5866
|
+
return {
|
|
5867
|
+
...values,
|
|
5868
|
+
[current.key]: next
|
|
5869
|
+
};
|
|
5870
|
+
});
|
|
6125
5871
|
}
|
|
6126
|
-
function
|
|
6127
|
-
|
|
6128
|
-
if (
|
|
6129
|
-
|
|
5872
|
+
function setActive(current) {
|
|
5873
|
+
if (activeTarget === current.key) return;
|
|
5874
|
+
if (activeTarget) {
|
|
5875
|
+
bulkGenerations.set(activeTarget, (bulkGenerations.get(activeTarget) ?? 0) + 1);
|
|
5876
|
+
setBulkStates((values) => {
|
|
5877
|
+
const state = values[activeTarget];
|
|
5878
|
+
if (!state || state.status !== "running") return values;
|
|
5879
|
+
return {
|
|
5880
|
+
...values,
|
|
5881
|
+
[activeTarget]: {
|
|
5882
|
+
...state,
|
|
5883
|
+
status: "idle"
|
|
5884
|
+
}
|
|
5885
|
+
};
|
|
5886
|
+
});
|
|
5887
|
+
}
|
|
5888
|
+
activation += 1;
|
|
5889
|
+
requests.abortAll();
|
|
5890
|
+
serverRequests.abortAll();
|
|
5891
|
+
refreshing.clear();
|
|
5892
|
+
activeTarget = current.key;
|
|
6130
5893
|
}
|
|
6131
|
-
function
|
|
6132
|
-
return
|
|
6133
|
-
...current,
|
|
6134
|
-
[mutation.sessionID]: mutation.status
|
|
6135
|
-
};
|
|
5894
|
+
function target() {
|
|
5895
|
+
return options.target();
|
|
6136
5896
|
}
|
|
6137
|
-
function
|
|
6138
|
-
|
|
6139
|
-
for (const key of targets.keys()) {
|
|
6140
|
-
remoteFailures.delete(JSON.stringify([key, sessionID]));
|
|
6141
|
-
remoteRetryAt.delete(JSON.stringify([key, sessionID]));
|
|
6142
|
-
if (mutation.type === "remove") history.remove(key, sessionID);
|
|
6143
|
-
}
|
|
6144
|
-
for (const journal of journals) journal.sessions.push(mutation);
|
|
6145
|
-
if (options.cache === "model") setChildren((current) => Object.fromEntries(Object.entries(current).map(([key, items]) => [key, applySession(items, targets.get(key).parentID, mutation)])));
|
|
5897
|
+
function mutating(current = target()) {
|
|
5898
|
+
return (mutationCounts()[current.key] ?? 0) > 0;
|
|
6146
5899
|
}
|
|
6147
|
-
function
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
};
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
5900
|
+
function resetSelectedPreset(current) {
|
|
5901
|
+
selectedPresetStates.delete(current.key);
|
|
5902
|
+
setSelectedPresets((values) => {
|
|
5903
|
+
const next = { ...values };
|
|
5904
|
+
delete next[current.key];
|
|
5905
|
+
return next;
|
|
5906
|
+
});
|
|
5907
|
+
}
|
|
5908
|
+
function invalidatePresetOperation(current, name) {
|
|
5909
|
+
const state = bulkStates()[current.key];
|
|
5910
|
+
if (state?.action !== "preset" || state.preset !== name) return;
|
|
5911
|
+
bulkRetries.delete(current.key);
|
|
5912
|
+
setBulkStates((values) => ({
|
|
5913
|
+
...values,
|
|
5914
|
+
[current.key]: {
|
|
5915
|
+
...state,
|
|
5916
|
+
status: "idle",
|
|
5917
|
+
completed: 0,
|
|
5918
|
+
total: 0,
|
|
5919
|
+
failed: []
|
|
6160
5920
|
}
|
|
6161
|
-
|
|
5921
|
+
}));
|
|
5922
|
+
}
|
|
5923
|
+
function reconcileSelectedPreset(current, items) {
|
|
5924
|
+
const states = selectedPresetStates.get(current.key);
|
|
5925
|
+
const bulk = bulkStates()[current.key];
|
|
5926
|
+
if (!states || bulk?.action === "preset" && (bulk.status === "running" || bulk.status === "error")) return;
|
|
5927
|
+
if (items.some((item) => {
|
|
5928
|
+
const desired = states[item.name];
|
|
5929
|
+
if (!desired) return false;
|
|
5930
|
+
return (item.status === "connected" ? "enabled" : "disabled") !== desired;
|
|
5931
|
+
})) resetSelectedPreset(current);
|
|
5932
|
+
}
|
|
5933
|
+
function clearBulkFailure(current, name) {
|
|
5934
|
+
setBulkStates((values) => {
|
|
5935
|
+
const state = values[current.key];
|
|
5936
|
+
if (!state || state.status !== "error" || !state.failed.includes(name)) return values;
|
|
5937
|
+
const failed = state.failed.filter((candidate) => candidate !== name);
|
|
5938
|
+
bulkRetries.set(current.key, (bulkRetries.get(current.key) ?? []).filter((candidate) => candidate.name !== name));
|
|
5939
|
+
return {
|
|
5940
|
+
...values,
|
|
5941
|
+
[current.key]: {
|
|
5942
|
+
...state,
|
|
5943
|
+
status: failed.length > 0 ? "error" : "ready",
|
|
5944
|
+
failed
|
|
5945
|
+
}
|
|
5946
|
+
};
|
|
6162
5947
|
});
|
|
6163
5948
|
}
|
|
6164
|
-
function
|
|
6165
|
-
|
|
6166
|
-
const mutation = {
|
|
6167
|
-
sessionID: input.sessionID,
|
|
6168
|
-
error: input.error,
|
|
6169
|
-
at: now(),
|
|
6170
|
-
observed: /* @__PURE__ */ new Set()
|
|
6171
|
-
};
|
|
6172
|
-
for (const journal of journals) journal.errors.push(mutation);
|
|
6173
|
-
for (const [key, items] of Object.entries(snapshots())) {
|
|
6174
|
-
if (items.every((item) => item.id !== mutation.sessionID)) continue;
|
|
6175
|
-
history.observeError(key, mutation.sessionID, mutation.error, mutation.at);
|
|
6176
|
-
mutation.observed.add(key);
|
|
6177
|
-
}
|
|
5949
|
+
function list(current = target()) {
|
|
5950
|
+
return options.cache === "source" ? source.list(current) : snapshots()[current.key] ?? source.list(current);
|
|
6178
5951
|
}
|
|
6179
|
-
async function
|
|
5952
|
+
async function refresh(current = target(), force = false) {
|
|
6180
5953
|
const pending = refreshing.get(current.key);
|
|
6181
5954
|
if (pending && !force) return pending;
|
|
6182
|
-
const
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
if (!requestState) {
|
|
6191
|
-
journals.delete(journal);
|
|
6192
|
-
return pending;
|
|
6193
|
-
}
|
|
6194
|
-
const signal = AbortSignal.any([requestState.signal, AbortSignal.timeout(5e3)]);
|
|
6195
|
-
const request = options.snapshot(current, signal).then(async (snapshot) => {
|
|
6196
|
-
let nextChildren = snapshot.sessions;
|
|
6197
|
-
for (const mutation of journal.sessions) nextChildren = applySession(nextChildren, current.parentID, mutation);
|
|
6198
|
-
let nextStatuses = { ...snapshot.statuses };
|
|
6199
|
-
const missing = {};
|
|
6200
|
-
const remoteStatuses = options.remoteStatus ? await Promise.all(nextChildren.map(async (session) => {
|
|
6201
|
-
const key = JSON.stringify([current.key, session.id]);
|
|
6202
|
-
return (remoteRetryAt.get(key) ?? 0) <= now() ? options.remoteStatus(session, requestState.signal) : {
|
|
6203
|
-
sessionID: session.id,
|
|
6204
|
-
failed: true,
|
|
6205
|
-
cooldown: true,
|
|
6206
|
-
status: void 0
|
|
6207
|
-
};
|
|
6208
|
-
})) : [];
|
|
6209
|
-
if (!requestState.isCurrent()) return;
|
|
6210
|
-
for (const result of remoteStatuses) {
|
|
6211
|
-
if (!result) continue;
|
|
6212
|
-
const key = JSON.stringify([current.key, result.sessionID]);
|
|
6213
|
-
if (result.failed) {
|
|
6214
|
-
missing[result.sessionID] = true;
|
|
6215
|
-
if (!("cooldown" in result)) {
|
|
6216
|
-
const failures = (remoteFailures.get(key) ?? 0) + 1;
|
|
6217
|
-
remoteFailures.set(key, failures);
|
|
6218
|
-
if (failures >= 3) remoteRetryAt.set(key, now() + 3e4);
|
|
6219
|
-
}
|
|
6220
|
-
const previous = statuses()[current.key]?.[result.sessionID];
|
|
6221
|
-
if (previous) nextStatuses[result.sessionID] = previous;
|
|
6222
|
-
else delete nextStatuses[result.sessionID];
|
|
6223
|
-
continue;
|
|
6224
|
-
}
|
|
6225
|
-
remoteFailures.delete(key);
|
|
6226
|
-
remoteRetryAt.delete(key);
|
|
6227
|
-
nextStatuses[result.sessionID] = result.status ?? { type: "idle" };
|
|
6228
|
-
}
|
|
6229
|
-
for (const mutation of journal.sessions) nextChildren = applySession(nextChildren, current.parentID, mutation);
|
|
6230
|
-
for (const mutation of journal.statuses) nextStatuses = applyStatus(nextStatuses, mutation);
|
|
6231
|
-
if (requestState.isCurrent()) (0, solid_js.batch)(() => {
|
|
6232
|
-
for (const session of nextChildren) {
|
|
6233
|
-
const mutations = journal.statuses.filter((mutation) => mutation.sessionID === session.id);
|
|
6234
|
-
if (mutations.length > 0) {
|
|
6235
|
-
for (const mutation of mutations) if (!mutation.observed.has(current.key)) history.observeStatus(current.key, session.id, mutation.status, mutation.at, mutation.startedAt);
|
|
6236
|
-
} else if (!missing[session.id]) {
|
|
6237
|
-
const status = nextStatuses[session.id] ?? { type: "idle" };
|
|
6238
|
-
nextStatuses[session.id] = status;
|
|
6239
|
-
history.observeStatus(current.key, session.id, status, now(), source?.startedAt?.(session.id));
|
|
6240
|
-
}
|
|
6241
|
-
for (const mutation of journal.errors) if (mutation.sessionID === session.id && !mutation.observed.has(current.key)) history.observeError(current.key, session.id, mutation.error, mutation.at);
|
|
6242
|
-
}
|
|
6243
|
-
if (options.cache === "model") {
|
|
6244
|
-
setChildren((value) => ({
|
|
6245
|
-
...value,
|
|
6246
|
-
[current.key]: nextChildren
|
|
6247
|
-
}));
|
|
6248
|
-
setStatuses((value) => ({
|
|
6249
|
-
...value,
|
|
6250
|
-
[current.key]: nextStatuses
|
|
6251
|
-
}));
|
|
6252
|
-
}
|
|
6253
|
-
setUnavailable((value) => ({
|
|
6254
|
-
...value,
|
|
6255
|
-
[current.key]: missing
|
|
6256
|
-
}));
|
|
6257
|
-
});
|
|
5955
|
+
const requestState = requests.start(current.key, "refresh MCP servers", current.key in snapshots(), force);
|
|
5956
|
+
if (!requestState) return pending;
|
|
5957
|
+
const request = source.refresh(current, force, requestState.signal).then((items) => {
|
|
5958
|
+
if (options.cache === "model" && requestState.isCurrent()) setSnapshots((value) => ({
|
|
5959
|
+
...value,
|
|
5960
|
+
[current.key]: items
|
|
5961
|
+
}));
|
|
5962
|
+
if (requestState.isCurrent()) reconcileSelectedPreset(current, items);
|
|
6258
5963
|
requestState.succeed();
|
|
5964
|
+
return items;
|
|
6259
5965
|
}).catch((error) => {
|
|
6260
5966
|
requestState.fail(error);
|
|
6261
5967
|
throw error;
|
|
6262
5968
|
}).finally(() => {
|
|
6263
|
-
journals.delete(journal);
|
|
6264
5969
|
requestState.finish();
|
|
6265
5970
|
if (refreshing.get(current.key) === request) refreshing.delete(current.key);
|
|
6266
5971
|
});
|
|
6267
5972
|
refreshing.set(current.key, request);
|
|
6268
5973
|
return request;
|
|
6269
5974
|
}
|
|
6270
|
-
function
|
|
6271
|
-
|
|
5975
|
+
async function changeServer(current, name, action, operation = `${action} MCP server`, refreshAfter = true) {
|
|
5976
|
+
const key = serverKey(current, name);
|
|
5977
|
+
const pending = mutations.get(key);
|
|
5978
|
+
if (pending) return pending;
|
|
5979
|
+
const requestState = serverRequests.start(key, operation, false);
|
|
5980
|
+
if (!requestState) return mutations.get(key);
|
|
5981
|
+
changeMutationCount(current, 1);
|
|
5982
|
+
const request = options.change(current, name, action, requestState.signal).then(() => {
|
|
5983
|
+
requestState.succeed();
|
|
5984
|
+
mutationRetries.delete(key);
|
|
5985
|
+
clearBulkFailure(current, name);
|
|
5986
|
+
}).catch((error) => {
|
|
5987
|
+
requestState.fail(error);
|
|
5988
|
+
if (!requestState.signal.aborted && !isAbortError(error)) mutationRetries.set(key, () => changeServer(current, name, action, operation));
|
|
5989
|
+
throw error;
|
|
5990
|
+
}).finally(() => {
|
|
5991
|
+
requestState.finish();
|
|
5992
|
+
changeMutationCount(current, -1);
|
|
5993
|
+
if (mutations.get(key) === request) mutations.delete(key);
|
|
5994
|
+
});
|
|
5995
|
+
mutations.set(key, request);
|
|
5996
|
+
await request;
|
|
5997
|
+
if (refreshAfter) await refresh(current, true);
|
|
6272
5998
|
}
|
|
6273
|
-
function
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
return (snapshots()[current.key] ?? []).map((session) => ({
|
|
6277
|
-
session,
|
|
6278
|
-
status: currentStatuses[session.id] ?? (unavailable()[current.key]?.[session.id] ? void 0 : source.status(session.id))
|
|
6279
|
-
})).filter((item) => activeStatus(item.status)).map((item) => ({
|
|
6280
|
-
...item,
|
|
6281
|
-
run: history.active(current.key, item.session.id),
|
|
6282
|
-
unavailable: unavailable()[current.key]?.[item.session.id]
|
|
6283
|
-
}));
|
|
5999
|
+
function save(current, name, disabled) {
|
|
6000
|
+
if (!persist()) return;
|
|
6001
|
+
preferences.setDesiredMcpState(current.scope, name, disabled ? "disabled" : "enabled");
|
|
6284
6002
|
}
|
|
6285
|
-
function
|
|
6286
|
-
const current = target(
|
|
6287
|
-
const
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6003
|
+
async function toggle(name) {
|
|
6004
|
+
const current = target();
|
|
6005
|
+
const item = list(current).find((candidate) => candidate.name === name);
|
|
6006
|
+
const action = item && mcpToggleAction(item.status);
|
|
6007
|
+
if (!action || mutations.has(serverKey(current, name))) return;
|
|
6008
|
+
activation += 1;
|
|
6009
|
+
resetSelectedPreset(current);
|
|
6010
|
+
save(current, name, action === "disconnect");
|
|
6011
|
+
await changeServer(current, name, action);
|
|
6012
|
+
}
|
|
6013
|
+
async function activate(current = target()) {
|
|
6014
|
+
setActive(current);
|
|
6015
|
+
const generation = ++activation;
|
|
6016
|
+
const hydration = preferences.load();
|
|
6017
|
+
if (!hydration) return;
|
|
6018
|
+
await hydration;
|
|
6019
|
+
const items = await refresh(current, true);
|
|
6020
|
+
if (!persist() || generation !== activation || target().key !== current.key) return;
|
|
6021
|
+
const results = await Promise.allSettled(items.map(async (item) => {
|
|
6022
|
+
if (!persist() || generation !== activation || target().key !== current.key) return;
|
|
6023
|
+
const desired = preferences.desiredMcpState(current.scope, item.name);
|
|
6024
|
+
const action = mcpToggleAction(item.status);
|
|
6025
|
+
if (desired === "disabled" && action === "disconnect") await changeServer(current, item.name, "disconnect", "restore MCP preference", false);
|
|
6026
|
+
if (desired === "enabled" && action === "connect") await changeServer(current, item.name, "connect", "restore MCP preference", false);
|
|
6027
|
+
}));
|
|
6028
|
+
const failed = options.signal?.aborted ? [] : results.flatMap((result, index) => result.status === "rejected" && !isAbortError(result.reason) ? [items[index].name] : []);
|
|
6029
|
+
if (failed.length > 0) options.notifications.show({
|
|
6030
|
+
variant: "warning",
|
|
6031
|
+
title: "MCP preferences",
|
|
6032
|
+
message: `Could not restore: ${failed.join(", ")}`
|
|
6296
6033
|
});
|
|
6034
|
+
if (generation === activation && target().key === current.key) await refresh(current, true);
|
|
6297
6035
|
}
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6036
|
+
function reconnect(current = target()) {
|
|
6037
|
+
return retryBackgroundRefresh(() => activate(current), { signal: options.signal });
|
|
6038
|
+
}
|
|
6039
|
+
function bulkState(current = target()) {
|
|
6040
|
+
return bulkStates()[current.key] ?? {
|
|
6041
|
+
action: "connect",
|
|
6042
|
+
status: "idle",
|
|
6043
|
+
completed: 0,
|
|
6044
|
+
total: 0,
|
|
6045
|
+
failed: []
|
|
6046
|
+
};
|
|
6047
|
+
}
|
|
6048
|
+
async function changeMany(operation, changes, current = target()) {
|
|
6049
|
+
if (mutating(current)) return;
|
|
6050
|
+
setActive(current);
|
|
6051
|
+
const generation = (bulkGenerations.get(current.key) ?? 0) + 1;
|
|
6052
|
+
bulkGenerations.set(current.key, generation);
|
|
6053
|
+
setBulkStates((values) => ({
|
|
6054
|
+
...values,
|
|
6055
|
+
[current.key]: {
|
|
6056
|
+
...operation,
|
|
6057
|
+
status: "running",
|
|
6058
|
+
completed: 0,
|
|
6059
|
+
total: changes.length,
|
|
6060
|
+
failed: []
|
|
6320
6061
|
}
|
|
6062
|
+
}));
|
|
6063
|
+
if (changes.length === 0) {
|
|
6064
|
+
setBulkStates((values) => ({
|
|
6065
|
+
...values,
|
|
6066
|
+
[current.key]: {
|
|
6067
|
+
...operation,
|
|
6068
|
+
status: "ready",
|
|
6069
|
+
completed: 0,
|
|
6070
|
+
total: 0,
|
|
6071
|
+
failed: []
|
|
6072
|
+
}
|
|
6073
|
+
}));
|
|
6074
|
+
return;
|
|
6321
6075
|
}
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
}
|
|
6364
|
-
}
|
|
6365
|
-
|
|
6366
|
-
|
|
6076
|
+
const failed = [];
|
|
6077
|
+
const retry = [];
|
|
6078
|
+
await Promise.all(changes.map(async ({ name, action }) => {
|
|
6079
|
+
if (operation.action !== "preset") save(current, name, action === "disconnect");
|
|
6080
|
+
try {
|
|
6081
|
+
await changeServer(current, name, action, bulkDescription(operation, action), false);
|
|
6082
|
+
} catch (error) {
|
|
6083
|
+
if (!isAbortError(error)) {
|
|
6084
|
+
failed.push(name);
|
|
6085
|
+
retry.push({
|
|
6086
|
+
name,
|
|
6087
|
+
action
|
|
6088
|
+
});
|
|
6089
|
+
}
|
|
6090
|
+
} finally {
|
|
6091
|
+
setBulkStates((values) => {
|
|
6092
|
+
if (bulkGenerations.get(current.key) !== generation) return values;
|
|
6093
|
+
const state = values[current.key];
|
|
6094
|
+
if (!state || state.action !== operation.action) return values;
|
|
6095
|
+
return {
|
|
6096
|
+
...values,
|
|
6097
|
+
[current.key]: {
|
|
6098
|
+
...state,
|
|
6099
|
+
completed: state.completed + 1
|
|
6100
|
+
}
|
|
6101
|
+
};
|
|
6102
|
+
});
|
|
6103
|
+
}
|
|
6104
|
+
}));
|
|
6105
|
+
if (bulkGenerations.get(current.key) !== generation) return;
|
|
6106
|
+
bulkRetries.set(current.key, retry);
|
|
6107
|
+
if (activeTarget === current.key) await refresh(current, true).catch(() => {});
|
|
6108
|
+
failed.sort((left, right) => left.localeCompare(right));
|
|
6109
|
+
setBulkStates((values) => ({
|
|
6110
|
+
...values,
|
|
6111
|
+
[current.key]: {
|
|
6112
|
+
...operation,
|
|
6113
|
+
status: failed.length > 0 ? "error" : "ready",
|
|
6114
|
+
completed: changes.length,
|
|
6115
|
+
total: changes.length,
|
|
6116
|
+
failed
|
|
6117
|
+
}
|
|
6118
|
+
}));
|
|
6119
|
+
if (failed.length > 0 && activeTarget === current.key) {
|
|
6120
|
+
let action = operation.action === "preset" ? `apply ${operation.preset}` : operation.action;
|
|
6121
|
+
if (operation.group) action += ` ${operation.group}`;
|
|
6122
|
+
options.notifications.show({
|
|
6123
|
+
variant: "warning",
|
|
6124
|
+
title: "MCP servers",
|
|
6125
|
+
message: `Could not ${action}: ${failed.join(", ")}`
|
|
6126
|
+
});
|
|
6367
6127
|
}
|
|
6368
|
-
}
|
|
6369
|
-
}
|
|
6370
|
-
// src/entities/subagent/model/view.ts
|
|
6371
|
-
function filterSubagentView(rows, mode, query) {
|
|
6372
|
-
const needle = query.trim().toLocaleLowerCase();
|
|
6373
|
-
return rows.filter((row) => {
|
|
6374
|
-
if (mode === "active" && row.group !== "Active") return false;
|
|
6375
|
-
if (mode === "recent" && row.group !== "Recent") return false;
|
|
6376
|
-
if (mode === "errors" && row.run?.outcome !== "error" && !row.unavailable) return false;
|
|
6377
|
-
return !needle || [
|
|
6378
|
-
row.session.title,
|
|
6379
|
-
row.session.id,
|
|
6380
|
-
row.run?.errorMessage
|
|
6381
|
-
].some((value) => value?.toLocaleLowerCase().includes(needle));
|
|
6382
|
-
});
|
|
6383
|
-
}
|
|
6384
|
-
function countSubagentView(rows, query) {
|
|
6128
|
+
}
|
|
6385
6129
|
return {
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6130
|
+
list,
|
|
6131
|
+
refresh,
|
|
6132
|
+
reconnect,
|
|
6133
|
+
activate,
|
|
6134
|
+
deactivate(current) {
|
|
6135
|
+
if (activeTarget !== current.key) return;
|
|
6136
|
+
activeTarget = void 0;
|
|
6137
|
+
activation += 1;
|
|
6138
|
+
bulkGenerations.set(current.key, (bulkGenerations.get(current.key) ?? 0) + 1);
|
|
6139
|
+
setBulkStates((values) => {
|
|
6140
|
+
const state = values[current.key];
|
|
6141
|
+
if (!state || state.status !== "running") return values;
|
|
6142
|
+
return {
|
|
6143
|
+
...values,
|
|
6144
|
+
[current.key]: {
|
|
6145
|
+
...state,
|
|
6146
|
+
status: "idle"
|
|
6147
|
+
}
|
|
6148
|
+
};
|
|
6149
|
+
});
|
|
6150
|
+
requests.abortAll();
|
|
6151
|
+
serverRequests.abortAll();
|
|
6152
|
+
refreshing.clear();
|
|
6153
|
+
},
|
|
6154
|
+
target,
|
|
6155
|
+
toggle,
|
|
6156
|
+
persist,
|
|
6157
|
+
state(current = target()) {
|
|
6158
|
+
return requests.state(current.key);
|
|
6159
|
+
},
|
|
6160
|
+
retry(current = target()) {
|
|
6161
|
+
return refresh(current, true);
|
|
6162
|
+
},
|
|
6163
|
+
serverState(name, current = target()) {
|
|
6164
|
+
return serverRequests.state(serverKey(current, name));
|
|
6165
|
+
},
|
|
6166
|
+
retryServer(name, current = target()) {
|
|
6167
|
+
return mutationRetries.get(serverKey(current, name))?.();
|
|
6168
|
+
},
|
|
6169
|
+
mutating,
|
|
6170
|
+
bulkState,
|
|
6171
|
+
selectedPreset(current = target()) {
|
|
6172
|
+
return selectedPresets()[current.key];
|
|
6173
|
+
},
|
|
6174
|
+
capturePreset(current = target()) {
|
|
6175
|
+
return Object.fromEntries(list(current).map((item) => [item.name, item.status === "connected" ? "enabled" : "disabled"]));
|
|
6176
|
+
},
|
|
6177
|
+
applyPreset(name, states, current = target()) {
|
|
6178
|
+
if (mutating(current)) return;
|
|
6179
|
+
const { changes } = mcpPresetPreview(list(current), states);
|
|
6180
|
+
if (persist()) {
|
|
6181
|
+
if (preferences.setDesiredMcpStates) preferences.setDesiredMcpStates(current.scope, states);
|
|
6182
|
+
else for (const [server, state] of Object.entries(states)) preferences.setDesiredMcpState(current.scope, server, state);
|
|
6183
|
+
}
|
|
6184
|
+
setSelectedPresets((values) => ({
|
|
6185
|
+
...values,
|
|
6186
|
+
[current.key]: name
|
|
6187
|
+
}));
|
|
6188
|
+
selectedPresetStates.set(current.key, { ...states });
|
|
6189
|
+
return changeMany({
|
|
6190
|
+
action: "preset",
|
|
6191
|
+
preset: name
|
|
6192
|
+
}, changes, current);
|
|
6193
|
+
},
|
|
6194
|
+
updateSelectedPreset(name, current = target()) {
|
|
6195
|
+
invalidatePresetOperation(current, name);
|
|
6196
|
+
if (selectedPresets()[current.key] === name) resetSelectedPreset(current);
|
|
6197
|
+
},
|
|
6198
|
+
renameSelectedPreset(previous, current = target()) {
|
|
6199
|
+
invalidatePresetOperation(current, previous);
|
|
6200
|
+
if (selectedPresets()[current.key] === previous) resetSelectedPreset(current);
|
|
6201
|
+
},
|
|
6202
|
+
clearSelectedPreset(name, current = target()) {
|
|
6203
|
+
invalidatePresetOperation(current, name);
|
|
6204
|
+
if (selectedPresets()[current.key] === name) resetSelectedPreset(current);
|
|
6205
|
+
},
|
|
6206
|
+
connectAll(current = target()) {
|
|
6207
|
+
if (mutating(current)) return;
|
|
6208
|
+
resetSelectedPreset(current);
|
|
6209
|
+
return changeMany({ action: "connect" }, list(current).filter((item) => mcpToggleAction(item.status) === "connect").map((item) => ({
|
|
6210
|
+
name: item.name,
|
|
6211
|
+
action: "connect"
|
|
6212
|
+
})), current);
|
|
6213
|
+
},
|
|
6214
|
+
disconnectAll(current = target()) {
|
|
6215
|
+
if (mutating(current)) return;
|
|
6216
|
+
resetSelectedPreset(current);
|
|
6217
|
+
return changeMany({ action: "disconnect" }, list(current).filter((item) => mcpToggleAction(item.status) === "disconnect").map((item) => ({
|
|
6218
|
+
name: item.name,
|
|
6219
|
+
action: "disconnect"
|
|
6220
|
+
})), current);
|
|
6221
|
+
},
|
|
6222
|
+
toggleGroup(group, names, current = target()) {
|
|
6223
|
+
if (target().key !== current.key || mutating(current) || bulkState(current).status === "running") return;
|
|
6224
|
+
const selected = new Set(names);
|
|
6225
|
+
const items = list(current).filter((item) => selected.has(item.name));
|
|
6226
|
+
const action = mcpGroupToggleAction(items);
|
|
6227
|
+
if (!action) return;
|
|
6228
|
+
resetSelectedPreset(current);
|
|
6229
|
+
if (action === "connect") {
|
|
6230
|
+
for (const item of items) if (item.status === "connected") save(current, item.name, false);
|
|
6231
|
+
}
|
|
6232
|
+
return changeMany({
|
|
6233
|
+
action,
|
|
6234
|
+
group
|
|
6235
|
+
}, items.filter((item) => mcpToggleAction(item.status) === action).map((item) => ({
|
|
6236
|
+
name: item.name,
|
|
6237
|
+
action
|
|
6238
|
+
})), current);
|
|
6239
|
+
},
|
|
6240
|
+
retryBulk(current = target()) {
|
|
6241
|
+
const state = bulkState(current);
|
|
6242
|
+
if (state.status !== "error" || state.failed.length === 0) return;
|
|
6243
|
+
const changes = bulkRetries.get(current.key) ?? [];
|
|
6244
|
+
return changeMany({
|
|
6245
|
+
action: state.action,
|
|
6246
|
+
...state.preset && { preset: state.preset },
|
|
6247
|
+
...state.group && { group: state.group }
|
|
6248
|
+
}, changes, current);
|
|
6249
|
+
}
|
|
6396
6250
|
};
|
|
6397
|
-
return [...[...active].sort((a, b) => priority(a) - priority(b)).map((item) => ({
|
|
6398
|
-
...item,
|
|
6399
|
-
group: "Active"
|
|
6400
|
-
})), ...[...recent].sort((a, b) => (b.run?.finishedAt ?? 0) - (a.run?.finishedAt ?? 0) || a.session.id.localeCompare(b.session.id)).map((item) => ({
|
|
6401
|
-
...item,
|
|
6402
|
-
group: "Recent"
|
|
6403
|
-
}))];
|
|
6404
|
-
}
|
|
6405
|
-
function formatSubagentDuration(startedAt, now) {
|
|
6406
|
-
const seconds = Math.max(0, Math.floor((now - startedAt) / 1e3));
|
|
6407
|
-
let value = `${seconds}s`;
|
|
6408
|
-
if (seconds >= 3600) value = `${Math.floor(seconds / 3600)}h ${String(Math.floor(seconds / 60) % 60).padStart(2, "0")}m`;
|
|
6409
|
-
else if (seconds >= 60) value = `${Math.floor(seconds / 60)}m ${String(seconds % 60).padStart(2, "0")}s`;
|
|
6410
|
-
return value;
|
|
6411
|
-
}
|
|
6412
|
-
function createSubagentClock(key) {
|
|
6413
|
-
const [now, setNow] = (0, solid_js.createSignal)(Date.now());
|
|
6414
|
-
(0, solid_js.createEffect)(() => {
|
|
6415
|
-
if (key() === void 0) return;
|
|
6416
|
-
setNow(Date.now());
|
|
6417
|
-
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
6418
|
-
(0, solid_js.onCleanup)(() => clearInterval(timer));
|
|
6419
|
-
});
|
|
6420
|
-
return now;
|
|
6421
6251
|
}
|
|
6422
|
-
// src/
|
|
6423
|
-
var _tmpl$$
|
|
6424
|
-
var _tmpl$2$
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
const Button = props.ui.Button;
|
|
6428
|
-
function navigate(event) {
|
|
6429
|
-
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
6430
|
-
const enabled = props.options.filter((option) => !option.disabled);
|
|
6431
|
-
if (enabled.length === 0) return;
|
|
6432
|
-
event.preventDefault();
|
|
6433
|
-
event.stopPropagation();
|
|
6434
|
-
const next = (enabled.findIndex((option) => option.id === props.selected) + (event.key === "ArrowRight" ? 1 : -1) + enabled.length) % enabled.length;
|
|
6435
|
-
props.onSelect(enabled[next].id);
|
|
6436
|
-
event.currentTarget.querySelectorAll("button:not(:disabled)")[next]?.focus();
|
|
6437
|
-
}
|
|
6252
|
+
// src/pages/navigator/ui/gui/mcp-indicator.tsx
|
|
6253
|
+
var _tmpl$$46 = /*#__PURE__*/ (0, solid_js_web.template)(`<span aria-hidden=true style="display:inline-flex;width:12px;height:12px;flex-shrink:0;border-radius:50%;border:1px solid currentColor">`);
|
|
6254
|
+
var _tmpl$2$33 = /*#__PURE__*/ (0, solid_js_web.template)(`<span role=img style=display:inline-flex;width:16px;height:16px;flex-shrink:0;align-items:center;justify-content:center>`);
|
|
6255
|
+
function McpIndicator(props) {
|
|
6256
|
+
const Loader = useNavigatorGui().ui.Loader;
|
|
6438
6257
|
return (() => {
|
|
6439
|
-
var _el$ = _tmpl
|
|
6440
|
-
_el
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
return props.options.map((option) => option.id);
|
|
6258
|
+
var _el$ = _tmpl$2$33();
|
|
6259
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6260
|
+
get when() {
|
|
6261
|
+
return props.status !== "pending";
|
|
6444
6262
|
},
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6263
|
+
get fallback() {
|
|
6264
|
+
return (0, solid_js_web.createComponent)(Loader, { size: "small" });
|
|
6265
|
+
},
|
|
6266
|
+
get children() {
|
|
6267
|
+
var _el$2 = _tmpl$$46();
|
|
6268
|
+
(0, solid_js_web.effect)((_p$) => {
|
|
6269
|
+
var _v$ = props.status === "connected" ? "currentColor" : "transparent", _v$2 = props.status === "failed" ? 1 : .65;
|
|
6270
|
+
_v$ !== _p$.e && (0, solid_js_web.setStyleProperty)(_el$2, "background", _p$.e = _v$);
|
|
6271
|
+
_v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$2, "opacity", _p$.t = _v$2);
|
|
6272
|
+
return _p$;
|
|
6273
|
+
}, {
|
|
6274
|
+
e: void 0,
|
|
6275
|
+
t: void 0
|
|
6276
|
+
});
|
|
6277
|
+
return _el$2;
|
|
6278
|
+
}
|
|
6279
|
+
}));
|
|
6280
|
+
(0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", props.status));
|
|
6281
|
+
return _el$;
|
|
6282
|
+
})();
|
|
6283
|
+
}
|
|
6284
|
+
// src/pages/navigator/ui/gui/mcp-row.tsx
|
|
6285
|
+
function GuiMcpRow(props) {
|
|
6286
|
+
const services = useNavigatorGui();
|
|
6287
|
+
const catalogs = () => services.runtime.catalogs;
|
|
6288
|
+
const state = () => catalogs().mcp.serverState(props.item.name);
|
|
6289
|
+
const error = () => props.item.error || state().error?.message;
|
|
6290
|
+
return (0, solid_js_web.createComponent)(CatalogRow, {
|
|
6291
|
+
get title() {
|
|
6292
|
+
return props.item.name;
|
|
6293
|
+
},
|
|
6294
|
+
get details() {
|
|
6295
|
+
return props.item.title;
|
|
6296
|
+
},
|
|
6297
|
+
get favorite() {
|
|
6298
|
+
return catalogs().preferences.favoriteMcpServers().has(props.item.name);
|
|
6299
|
+
},
|
|
6300
|
+
get bookmarkDisabled() {
|
|
6301
|
+
return !catalogs().preferences.ready();
|
|
6302
|
+
},
|
|
6303
|
+
bookmark: () => catalogs().preferences.toggleFavoriteMcpServer(props.item.name),
|
|
6304
|
+
get leading() {
|
|
6305
|
+
return (0, solid_js_web.createComponent)(McpIndicator, { get status() {
|
|
6306
|
+
return (0, solid_js_web.memo)(() => state().status === "loading")() ? "pending" : props.item.status;
|
|
6307
|
+
} });
|
|
6308
|
+
},
|
|
6309
|
+
get disabled() {
|
|
6310
|
+
return !mcpToggleAction(props.item.status) || state().status === "loading";
|
|
6311
|
+
},
|
|
6312
|
+
activate: () => void catalogs().mcp.toggle(props.item.name).catch(() => {}),
|
|
6313
|
+
get trailing() {
|
|
6314
|
+
return (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6315
|
+
get when() {
|
|
6316
|
+
return error();
|
|
6317
|
+
},
|
|
6318
|
+
get children() {
|
|
6319
|
+
return (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
6320
|
+
get ui() {
|
|
6321
|
+
return services.ui;
|
|
6322
|
+
},
|
|
6323
|
+
icon: "info",
|
|
6324
|
+
get label() {
|
|
6325
|
+
return `Information about ${props.item.name}`;
|
|
6326
|
+
},
|
|
6327
|
+
onClick: () => services.onMcpInformation({
|
|
6328
|
+
...props.item,
|
|
6329
|
+
error: error()
|
|
6330
|
+
})
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6333
|
+
});
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
}
|
|
6337
|
+
// src/pages/navigator/ui/gui/mcp-group.tsx
|
|
6338
|
+
var _tmpl$$45 = /*#__PURE__*/ (0, solid_js_web.template)(`<strong style=overflow:hidden;text-overflow:ellipsis;white-space:nowrap>`);
|
|
6339
|
+
var _tmpl$2$32 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=opacity:0.6;font-weight:400>`);
|
|
6340
|
+
var _tmpl$3$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><ul style="margin:0;padding:0 0 0 10px;list-style:none">`);
|
|
6341
|
+
function GuiMcpGroup(props) {
|
|
6342
|
+
const services = useNavigatorGui();
|
|
6343
|
+
const catalogs = () => services.runtime.catalogs;
|
|
6344
|
+
const view = () => catalogs().views.mcp;
|
|
6345
|
+
const bucket = () => view().bucket(props.group);
|
|
6346
|
+
const busy = () => catalogs().mcp.bulkState().group === props.group && catalogs().mcp.bulkState().status === "running";
|
|
6347
|
+
const Button = services.ui.Button;
|
|
6348
|
+
return (() => {
|
|
6349
|
+
var _el$ = _tmpl$3$19(), _el$4 = _el$.firstChild;
|
|
6350
|
+
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
|
|
6351
|
+
variant: "ghost",
|
|
6352
|
+
size: "small",
|
|
6353
|
+
get disabled() {
|
|
6354
|
+
return catalogs().mcp.mutating();
|
|
6355
|
+
},
|
|
6356
|
+
onClick: () => void catalogs().mcp.toggleGroup(props.group, bucket().map((item) => item.name))?.catch(() => {}),
|
|
6357
|
+
get children() {
|
|
6358
|
+
return [
|
|
6359
|
+
(0, solid_js_web.createComponent)(McpIndicator, { get status() {
|
|
6360
|
+
return mcpGroupStatus(bucket(), busy());
|
|
6361
|
+
} }),
|
|
6362
|
+
(() => {
|
|
6363
|
+
var _el$2 = _tmpl$$45();
|
|
6364
|
+
(0, solid_js_web.insert)(_el$2, () => props.group);
|
|
6365
|
+
return _el$2;
|
|
6366
|
+
})(),
|
|
6367
|
+
(() => {
|
|
6368
|
+
var _el$3 = _tmpl$2$32();
|
|
6369
|
+
(0, solid_js_web.insert)(_el$3, () => bucket().length);
|
|
6370
|
+
return _el$3;
|
|
6371
|
+
})()
|
|
6372
|
+
];
|
|
6373
|
+
}
|
|
6374
|
+
}), _el$4);
|
|
6375
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
6376
|
+
get each() {
|
|
6377
|
+
return view().visibility.visible().filter((item) => item.bucket === props.group).map((item) => item.name);
|
|
6378
|
+
},
|
|
6379
|
+
children: (name) => (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6380
|
+
get when() {
|
|
6381
|
+
return view().visibility.visible().find((item) => item.name === name);
|
|
6382
|
+
},
|
|
6383
|
+
children: (item) => (0, solid_js_web.createComponent)(GuiMcpRow, { get item() {
|
|
6384
|
+
return item();
|
|
6385
|
+
} })
|
|
6386
|
+
})
|
|
6387
|
+
}));
|
|
6388
|
+
return _el$;
|
|
6389
|
+
})();
|
|
6390
|
+
}
|
|
6391
|
+
// src/pages/navigator/ui/gui/mcp-section.tsx
|
|
6392
|
+
var _tmpl$$44 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
|
|
6393
|
+
var _tmpl$2$31 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>/<!> servers updated`);
|
|
6394
|
+
var _tmpl$3$18 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
|
|
6395
|
+
var _tmpl$4$12 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching MCP servers.`);
|
|
6396
|
+
function McpSection() {
|
|
6397
|
+
const services = useNavigatorGui();
|
|
6398
|
+
const catalogs = () => services.runtime.catalogs;
|
|
6399
|
+
const view = () => catalogs().views.mcp;
|
|
6400
|
+
const state = () => catalogs().mcp.state();
|
|
6401
|
+
const bulk = () => catalogs().mcp.bulkState();
|
|
6402
|
+
const matched = () => matchingMcpPreset(catalogs().mcp.list(), catalogs().preferences.mcpPresets());
|
|
6403
|
+
const Button = services.ui.Button;
|
|
6404
|
+
return (0, solid_js_web.createComponent)(MonitoringSection, {
|
|
6405
|
+
id: "mcp",
|
|
6406
|
+
title: "MCP",
|
|
6407
|
+
get count() {
|
|
6408
|
+
return view().all().length;
|
|
6409
|
+
},
|
|
6410
|
+
get actions() {
|
|
6411
|
+
return (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6412
|
+
get when() {
|
|
6413
|
+
return services.onMcpPresets;
|
|
6414
|
+
},
|
|
6415
|
+
get children() {
|
|
6416
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
6417
|
+
size: "small",
|
|
6418
|
+
variant: "ghost",
|
|
6419
|
+
get onClick() {
|
|
6420
|
+
return services.onMcpPresets;
|
|
6421
|
+
},
|
|
6422
|
+
get children() {
|
|
6423
|
+
return matched() || "Preset";
|
|
6424
|
+
}
|
|
6425
|
+
});
|
|
6426
|
+
}
|
|
6427
|
+
});
|
|
6428
|
+
},
|
|
6429
|
+
get children() {
|
|
6430
|
+
return [
|
|
6431
|
+
(0, solid_js_web.createComponent)(SectionFilter, {
|
|
6432
|
+
label: "Filter MCP",
|
|
6433
|
+
placeholder: "Filter servers and groups",
|
|
6434
|
+
get value() {
|
|
6435
|
+
return view().query();
|
|
6451
6436
|
},
|
|
6452
|
-
get
|
|
6453
|
-
return
|
|
6437
|
+
get change() {
|
|
6438
|
+
return view().setQuery;
|
|
6439
|
+
}
|
|
6440
|
+
}),
|
|
6441
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6442
|
+
get when() {
|
|
6443
|
+
return state().error;
|
|
6454
6444
|
},
|
|
6455
|
-
onClick: () => props.onSelect(id),
|
|
6456
6445
|
get children() {
|
|
6457
6446
|
return [(() => {
|
|
6458
|
-
var _el$
|
|
6459
|
-
(0, solid_js_web.insert)(_el
|
|
6460
|
-
|
|
6447
|
+
var _el$ = _tmpl$$44();
|
|
6448
|
+
(0, solid_js_web.insert)(_el$, () => state().error?.message);
|
|
6449
|
+
return _el$;
|
|
6450
|
+
})(), (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
6451
|
+
get ui() {
|
|
6452
|
+
return services.ui;
|
|
6453
|
+
},
|
|
6454
|
+
icon: "refresh",
|
|
6455
|
+
label: "Retry",
|
|
6456
|
+
onClick: () => void catalogs().mcp.retry().catch(() => {})
|
|
6457
|
+
})];
|
|
6458
|
+
}
|
|
6459
|
+
}),
|
|
6460
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6461
|
+
get when() {
|
|
6462
|
+
return bulk().status === "running" || bulk().status === "error";
|
|
6463
|
+
},
|
|
6464
|
+
get children() {
|
|
6465
|
+
return [(() => {
|
|
6466
|
+
var _el$2 = _tmpl$2$31(), _el$3 = _el$2.firstChild, _el$5 = _el$3.nextSibling;
|
|
6467
|
+
_el$5.nextSibling;
|
|
6468
|
+
(0, solid_js_web.insert)(_el$2, () => bulk().completed, _el$3);
|
|
6469
|
+
(0, solid_js_web.insert)(_el$2, () => bulk().total, _el$5);
|
|
6461
6470
|
return _el$2;
|
|
6462
6471
|
})(), (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6463
6472
|
get when() {
|
|
6464
|
-
return
|
|
6473
|
+
return bulk().status === "error";
|
|
6465
6474
|
},
|
|
6466
6475
|
get children() {
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6476
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
6477
|
+
size: "small",
|
|
6478
|
+
onClick: () => void catalogs().mcp.retryBulk()?.catch(() => {}),
|
|
6479
|
+
children: "Retry failed servers"
|
|
6480
|
+
});
|
|
6470
6481
|
}
|
|
6471
6482
|
})];
|
|
6472
6483
|
}
|
|
6473
|
-
})
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6484
|
+
}),
|
|
6485
|
+
(() => {
|
|
6486
|
+
var _el$6 = _tmpl$3$18();
|
|
6487
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
6488
|
+
get each() {
|
|
6489
|
+
return view().groups();
|
|
6490
|
+
},
|
|
6491
|
+
get fallback() {
|
|
6492
|
+
return _tmpl$4$12();
|
|
6493
|
+
},
|
|
6494
|
+
children: (group) => (0, solid_js_web.createComponent)(GuiMcpGroup, { group })
|
|
6495
|
+
}));
|
|
6496
|
+
return _el$6;
|
|
6497
|
+
})(),
|
|
6498
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6499
|
+
get when() {
|
|
6500
|
+
return view().visibility.canToggle();
|
|
6501
|
+
},
|
|
6502
|
+
get children() {
|
|
6503
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
6504
|
+
size: "small",
|
|
6505
|
+
variant: "ghost",
|
|
6506
|
+
onClick: () => view().visibility.expanded() ? view().visibility.showLess() : view().visibility.showAll(),
|
|
6507
|
+
get children() {
|
|
6508
|
+
return (0, solid_js_web.memo)(() => !!view().visibility.expanded())() ? "Show less" : `Show ${view().visibility.hiddenCount()} more`;
|
|
6509
|
+
}
|
|
6510
|
+
});
|
|
6511
|
+
}
|
|
6512
|
+
})
|
|
6513
|
+
];
|
|
6514
|
+
}
|
|
6515
|
+
});
|
|
6479
6516
|
}
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
"
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
"close"
|
|
6523
|
-
];
|
|
6524
|
-
var choices = new Set(ICON_CHOICE_IDS);
|
|
6525
|
-
function isIconChoiceId(value) {
|
|
6526
|
-
return choices.has(value);
|
|
6527
|
-
}
|
|
6528
|
-
function iconChoiceLabel(id) {
|
|
6529
|
-
return id.replaceAll("-", " ");
|
|
6517
|
+
// src/pages/navigator/ui/gui/skill-row.tsx
|
|
6518
|
+
function GuiSkillRow(props) {
|
|
6519
|
+
const services = useNavigatorGui();
|
|
6520
|
+
const preferences = () => services.runtime.catalogs.preferences;
|
|
6521
|
+
const Menu = services.ui.Menu;
|
|
6522
|
+
const pinned = () => preferences().toolbarPins().some((pin) => pin.kind === "skill" && pin.location === props.skill.location);
|
|
6523
|
+
return (0, solid_js_web.createComponent)(CatalogRow, {
|
|
6524
|
+
get title() {
|
|
6525
|
+
return props.skill.name;
|
|
6526
|
+
},
|
|
6527
|
+
get details() {
|
|
6528
|
+
return props.skill.description;
|
|
6529
|
+
},
|
|
6530
|
+
get favorite() {
|
|
6531
|
+
return preferences().isFavoriteSkill(props.skill);
|
|
6532
|
+
},
|
|
6533
|
+
get bookmarkDisabled() {
|
|
6534
|
+
return !preferences().ready();
|
|
6535
|
+
},
|
|
6536
|
+
bookmark: () => preferences().toggleFavoriteSkill(props.skill),
|
|
6537
|
+
activate: () => services.onSkill(props.skill),
|
|
6538
|
+
get trailing() {
|
|
6539
|
+
return (0, solid_js_web.createComponent)(Menu, {
|
|
6540
|
+
get label() {
|
|
6541
|
+
return `Options for Skill ${props.skill.name}`;
|
|
6542
|
+
},
|
|
6543
|
+
get items() {
|
|
6544
|
+
return [{
|
|
6545
|
+
label: pinned() ? "Configure toolbar button" : "Pin to toolbar",
|
|
6546
|
+
icon: "plus",
|
|
6547
|
+
disabled: !preferences().ready(),
|
|
6548
|
+
onSelect: () => services.onPin({
|
|
6549
|
+
kind: "skill",
|
|
6550
|
+
location: props.skill.location,
|
|
6551
|
+
name: props.skill.name,
|
|
6552
|
+
icon: "book"
|
|
6553
|
+
})
|
|
6554
|
+
}];
|
|
6555
|
+
}
|
|
6556
|
+
});
|
|
6557
|
+
}
|
|
6558
|
+
});
|
|
6530
6559
|
}
|
|
6531
|
-
// src/
|
|
6532
|
-
var _tmpl$$
|
|
6533
|
-
var _tmpl$2$
|
|
6534
|
-
var _tmpl$3$
|
|
6535
|
-
var
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
"M9 16c0-8 6-13 12-13 0 6-5 12-13 12Z",
|
|
6581
|
-
"m9 8-5 1-2 6 6-1",
|
|
6582
|
-
"m16 15-1 5-6 2 1-6",
|
|
6583
|
-
"m5 17-3 5 5-3"
|
|
6584
|
-
],
|
|
6585
|
-
bug: [
|
|
6586
|
-
"M8 10h8v6a4 4 0 0 1-8 0Z",
|
|
6587
|
-
"M9 10V8a3 3 0 0 1 6 0v2",
|
|
6588
|
-
"M5 7l3 4M19 7l-3 4M3 14h5m8 0h5M5 21l4-3m6 0 4 3M12 11v9"
|
|
6589
|
-
],
|
|
6590
|
-
wand: ["m4 20 13-13 3 3L7 23Z", "M5 3v6M2 6h6M18 1v4M16 3h4"],
|
|
6591
|
-
cloud: ["M7 19a5 5 0 1 1 0-10 6 6 0 0 1 11-1 5.5 5.5 0 0 1 0 11Z"],
|
|
6592
|
-
heart: ["M12 21 3.5 12.5a5.5 5.5 0 0 1 8.5-7 5.5 5.5 0 0 1 8.5 7Z"],
|
|
6593
|
-
lightbulb: ["M9 18v-2a7 7 0 1 1 6 0v2Z", "M9 21h6M10 24h4"],
|
|
6594
|
-
"arrow-down": ["M12 3v18", "m5 14 7 7 7-7"]
|
|
6595
|
-
};
|
|
6596
|
-
function GuiIcon(props) {
|
|
6597
|
-
const Icon = props.ui.Icon;
|
|
6598
|
-
const id = () => isIconChoiceId(props.id) ? props.id : "bolt";
|
|
6599
|
-
return (() => {
|
|
6600
|
-
var _el$ = _tmpl$$48();
|
|
6601
|
-
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6602
|
-
get when() {
|
|
6603
|
-
return native[id()];
|
|
6604
|
-
},
|
|
6605
|
-
get fallback() {
|
|
6606
|
-
return (() => {
|
|
6607
|
-
var _el$2 = _tmpl$2$31();
|
|
6560
|
+
// src/pages/navigator/ui/gui/skills-section.tsx
|
|
6561
|
+
var _tmpl$$43 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
|
|
6562
|
+
var _tmpl$2$30 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
|
|
6563
|
+
var _tmpl$3$17 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching Skills.`);
|
|
6564
|
+
var _tmpl$4$11 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><h3 style="font-size:12px;opacity:0.65;margin:0 0 4px"></h3><ul style="margin:0;padding:0 0 0 10px;list-style:none">`);
|
|
6565
|
+
function SkillsSection() {
|
|
6566
|
+
const services = useNavigatorGui();
|
|
6567
|
+
const catalogs = () => services.runtime.catalogs;
|
|
6568
|
+
const view = () => catalogs().views.skills;
|
|
6569
|
+
const Button = services.ui.Button;
|
|
6570
|
+
return (0, solid_js_web.createComponent)(MonitoringSection, {
|
|
6571
|
+
id: "skills",
|
|
6572
|
+
title: "Skills",
|
|
6573
|
+
get count() {
|
|
6574
|
+
return view().all().length;
|
|
6575
|
+
},
|
|
6576
|
+
get children() {
|
|
6577
|
+
return [
|
|
6578
|
+
(0, solid_js_web.createComponent)(SectionFilter, {
|
|
6579
|
+
label: "Filter Skills",
|
|
6580
|
+
placeholder: "Filter skills and groups",
|
|
6581
|
+
get value() {
|
|
6582
|
+
return view().query();
|
|
6583
|
+
},
|
|
6584
|
+
get change() {
|
|
6585
|
+
return view().setQuery;
|
|
6586
|
+
}
|
|
6587
|
+
}),
|
|
6588
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6589
|
+
get when() {
|
|
6590
|
+
return catalogs().skills.error();
|
|
6591
|
+
},
|
|
6592
|
+
get children() {
|
|
6593
|
+
return [(() => {
|
|
6594
|
+
var _el$ = _tmpl$$43();
|
|
6595
|
+
(0, solid_js_web.insert)(_el$, () => catalogs().skills.error());
|
|
6596
|
+
return _el$;
|
|
6597
|
+
})(), (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
6598
|
+
get ui() {
|
|
6599
|
+
return services.ui;
|
|
6600
|
+
},
|
|
6601
|
+
icon: "refresh",
|
|
6602
|
+
label: "Retry",
|
|
6603
|
+
onClick: () => void catalogs().skills.retry().catch(() => {})
|
|
6604
|
+
})];
|
|
6605
|
+
}
|
|
6606
|
+
}),
|
|
6607
|
+
(() => {
|
|
6608
|
+
var _el$2 = _tmpl$2$30();
|
|
6608
6609
|
(0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
6609
6610
|
get each() {
|
|
6610
|
-
return
|
|
6611
|
+
return view().groups();
|
|
6611
6612
|
},
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6613
|
+
get fallback() {
|
|
6614
|
+
return _tmpl$3$17();
|
|
6615
|
+
},
|
|
6616
|
+
children: (group) => (() => {
|
|
6617
|
+
var _el$4 = _tmpl$4$11(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling;
|
|
6618
|
+
(0, solid_js_web.insert)(_el$5, group);
|
|
6619
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
6620
|
+
get each() {
|
|
6621
|
+
return view().visibility.visible().filter((item) => item.bucket === group).map((item) => item.location);
|
|
6622
|
+
},
|
|
6623
|
+
children: (location) => (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6624
|
+
get when() {
|
|
6625
|
+
return view().visibility.visible().find((item) => item.location === location);
|
|
6626
|
+
},
|
|
6627
|
+
children: (item) => (0, solid_js_web.createComponent)(GuiSkillRow, { get skill() {
|
|
6628
|
+
return item();
|
|
6629
|
+
} })
|
|
6630
|
+
})
|
|
6631
|
+
}));
|
|
6632
|
+
return _el$4;
|
|
6616
6633
|
})()
|
|
6617
6634
|
}));
|
|
6618
6635
|
return _el$2;
|
|
6619
|
-
})()
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6636
|
+
})(),
|
|
6637
|
+
(0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6638
|
+
get when() {
|
|
6639
|
+
return view().visibility.canToggle();
|
|
6640
|
+
},
|
|
6641
|
+
get children() {
|
|
6642
|
+
return (0, solid_js_web.createComponent)(Button, {
|
|
6643
|
+
size: "small",
|
|
6644
|
+
variant: "ghost",
|
|
6645
|
+
onClick: () => view().visibility.expanded() ? view().visibility.showLess() : view().visibility.showAll(),
|
|
6646
|
+
get children() {
|
|
6647
|
+
return (0, solid_js_web.memo)(() => !!view().visibility.expanded())() ? "Show less" : `Show ${view().visibility.hiddenCount()} more`;
|
|
6648
|
+
}
|
|
6649
|
+
});
|
|
6650
|
+
}
|
|
6651
|
+
})
|
|
6652
|
+
];
|
|
6653
|
+
}
|
|
6654
|
+
});
|
|
6630
6655
|
}
|
|
6631
|
-
// src/
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
const
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
(
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
}, ...props.groups.map((value) => ({
|
|
6685
|
-
value,
|
|
6686
|
-
label: value
|
|
6687
|
-
}))];
|
|
6688
|
-
},
|
|
6689
|
-
onChange: (value) => {
|
|
6690
|
-
setDraft(value);
|
|
6691
|
-
setCreating(false);
|
|
6692
|
-
},
|
|
6693
|
-
get disabled() {
|
|
6694
|
-
return props.disabled;
|
|
6695
|
-
}
|
|
6696
|
-
}), null);
|
|
6697
|
-
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
|
|
6698
|
-
size: "small",
|
|
6699
|
-
variant: "ghost",
|
|
6700
|
-
get disabled() {
|
|
6701
|
-
return props.disabled;
|
|
6702
|
-
},
|
|
6703
|
-
onClick: () => {
|
|
6704
|
-
setCreating(true);
|
|
6705
|
-
setDraft("");
|
|
6706
|
-
},
|
|
6707
|
-
children: "New group"
|
|
6708
|
-
}), null);
|
|
6709
|
-
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
6710
|
-
get when() {
|
|
6711
|
-
return creating();
|
|
6712
|
-
},
|
|
6713
|
-
get children() {
|
|
6714
|
-
return (0, solid_js_web.createComponent)(TextInput, {
|
|
6715
|
-
get label() {
|
|
6716
|
-
return `${props.label} new group`;
|
|
6717
|
-
},
|
|
6718
|
-
get value() {
|
|
6719
|
-
return draft();
|
|
6720
|
-
},
|
|
6721
|
-
onInput: setDraft,
|
|
6722
|
-
get disabled() {
|
|
6723
|
-
return props.disabled;
|
|
6724
|
-
},
|
|
6725
|
-
get invalid() {
|
|
6726
|
-
return draft().length > 64;
|
|
6727
|
-
}
|
|
6656
|
+
// src/entities/subagent/model/history.ts
|
|
6657
|
+
function createSubagentHistory({ now = Date.now } = {}) {
|
|
6658
|
+
const targets = /* @__PURE__ */ new Map();
|
|
6659
|
+
const [revision, setRevision] = (0, solid_js.createSignal)(0);
|
|
6660
|
+
function state(key) {
|
|
6661
|
+
let value = targets.get(key);
|
|
6662
|
+
if (!value) {
|
|
6663
|
+
value = {
|
|
6664
|
+
known: /* @__PURE__ */ new Set(),
|
|
6665
|
+
active: /* @__PURE__ */ new Map(),
|
|
6666
|
+
recent: []
|
|
6667
|
+
};
|
|
6668
|
+
targets.set(key, value);
|
|
6669
|
+
}
|
|
6670
|
+
return value;
|
|
6671
|
+
}
|
|
6672
|
+
function changed() {
|
|
6673
|
+
setRevision((value) => value + 1);
|
|
6674
|
+
}
|
|
6675
|
+
return {
|
|
6676
|
+
observeStatus(key, sessionID, status, at = now(), nativeStart) {
|
|
6677
|
+
const value = state(key);
|
|
6678
|
+
const run = value.active.get(sessionID);
|
|
6679
|
+
const isKnown = value.known.has(sessionID);
|
|
6680
|
+
value.known.add(sessionID);
|
|
6681
|
+
if (status.type === "idle") {
|
|
6682
|
+
if (!run) return;
|
|
6683
|
+
value.active.delete(sessionID);
|
|
6684
|
+
value.recent = [{
|
|
6685
|
+
...run,
|
|
6686
|
+
finishedAt: Math.max(at, run.startedAt),
|
|
6687
|
+
outcome: run.outcome ?? "finished"
|
|
6688
|
+
}, ...value.recent].sort((a, b) => b.finishedAt - a.finishedAt || a.sessionID.localeCompare(b.sessionID)).slice(0, 10);
|
|
6689
|
+
} else {
|
|
6690
|
+
const exact = typeof nativeStart === "number" && Number.isFinite(nativeStart) && nativeStart > 0 && nativeStart <= at ? nativeStart : void 0;
|
|
6691
|
+
if (run) {
|
|
6692
|
+
if (exact === void 0 || run.nativeStartedAt !== void 0 && exact <= run.nativeStartedAt) return;
|
|
6693
|
+
const next = exact > run.startedAt ? { sessionID } : run;
|
|
6694
|
+
value.active.set(sessionID, {
|
|
6695
|
+
...next,
|
|
6696
|
+
startedAt: exact,
|
|
6697
|
+
nativeStartedAt: exact,
|
|
6698
|
+
startedBeforeObservation: false
|
|
6699
|
+
});
|
|
6700
|
+
changed();
|
|
6701
|
+
return;
|
|
6702
|
+
}
|
|
6703
|
+
value.recent = value.recent.filter((item) => item.sessionID !== sessionID);
|
|
6704
|
+
value.active.set(sessionID, {
|
|
6705
|
+
sessionID,
|
|
6706
|
+
startedAt: exact ?? at,
|
|
6707
|
+
startedBeforeObservation: exact === void 0 && !isKnown,
|
|
6708
|
+
...exact !== void 0 && { nativeStartedAt: exact }
|
|
6728
6709
|
});
|
|
6729
6710
|
}
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
get
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6711
|
+
changed();
|
|
6712
|
+
},
|
|
6713
|
+
observeError(key, sessionID, error, at = now()) {
|
|
6714
|
+
if (!sessionID) return;
|
|
6715
|
+
const value = state(key);
|
|
6716
|
+
const run = value.active.get(sessionID) ?? value.recent.find((item) => item.sessionID === sessionID);
|
|
6717
|
+
if (!run || at < run.startedAt && !run.startedBeforeObservation) return;
|
|
6718
|
+
const isCancelled = error?.name === "MessageAbortedError";
|
|
6719
|
+
const data = error && "data" in error ? error.data : void 0;
|
|
6720
|
+
const fallbackMessage = isCancelled ? "Session aborted" : "Session error";
|
|
6721
|
+
const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : fallbackMessage;
|
|
6722
|
+
const next = {
|
|
6723
|
+
...run,
|
|
6724
|
+
startedAt: Math.min(run.startedAt, at),
|
|
6725
|
+
outcome: isCancelled ? "cancelled" : "error",
|
|
6726
|
+
errorMessage: message
|
|
6727
|
+
};
|
|
6728
|
+
if (value.active.has(sessionID)) value.active.set(sessionID, next);
|
|
6729
|
+
else value.recent = value.recent.map((item) => item.sessionID === sessionID ? next : item);
|
|
6730
|
+
changed();
|
|
6731
|
+
},
|
|
6732
|
+
remove(key, sessionID) {
|
|
6733
|
+
const value = targets.get(key);
|
|
6734
|
+
if (!value) return;
|
|
6735
|
+
value.known.delete(sessionID);
|
|
6736
|
+
value.active.delete(sessionID);
|
|
6737
|
+
value.recent = value.recent.filter((item) => item.sessionID !== sessionID);
|
|
6738
|
+
changed();
|
|
6739
|
+
},
|
|
6740
|
+
active(key, sessionID) {
|
|
6741
|
+
revision();
|
|
6742
|
+
return targets.get(key)?.active.get(sessionID);
|
|
6743
|
+
},
|
|
6744
|
+
recent(key) {
|
|
6745
|
+
revision();
|
|
6746
|
+
return targets.get(key)?.recent ?? [];
|
|
6747
|
+
}
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6750
|
+
// src/entities/subagent/model/subagent-controller.ts
|
|
6751
|
+
var POLL_INTERVAL_MS = 5e3;
|
|
6752
|
+
function activeStatus(status) {
|
|
6753
|
+
return status?.type === "busy" || status?.type === "retry";
|
|
6754
|
+
}
|
|
6755
|
+
function createSubagentModel(options) {
|
|
6756
|
+
const source = options.source;
|
|
6757
|
+
const now = options.now ?? Date.now;
|
|
6758
|
+
const history = createSubagentHistory({ now });
|
|
6759
|
+
const [children, setChildren] = (0, solid_js.createSignal)({});
|
|
6760
|
+
const [statuses, setStatuses] = (0, solid_js.createSignal)({});
|
|
6761
|
+
const refreshing = /* @__PURE__ */ new Map();
|
|
6762
|
+
const journals = /* @__PURE__ */ new Set();
|
|
6763
|
+
const [unavailable, setUnavailable] = (0, solid_js.createSignal)({});
|
|
6764
|
+
const targets = /* @__PURE__ */ new Map();
|
|
6765
|
+
const remoteFailures = /* @__PURE__ */ new Map();
|
|
6766
|
+
const remoteRetryAt = /* @__PURE__ */ new Map();
|
|
6767
|
+
const requests = createRequestState(options.lifecycle.signal);
|
|
6768
|
+
let activeTarget;
|
|
6769
|
+
let leases = /* @__PURE__ */ new Set();
|
|
6770
|
+
let pollTimer;
|
|
6771
|
+
const snapshots = () => options.cache === "source" ? Object.fromEntries([...targets].map(([key, current]) => [key, source.list(current.parentID)])) : children();
|
|
6772
|
+
function target(parentID) {
|
|
6773
|
+
return options.target(parentID);
|
|
6774
|
+
}
|
|
6775
|
+
function applySession(items, parentID, mutation) {
|
|
6776
|
+
const next = items.filter((item) => item.id !== (mutation.type === "upsert" ? mutation.info.id : mutation.sessionID));
|
|
6777
|
+
if (mutation.type === "upsert" && mutation.info.parentID === parentID) next.push(mutation.info);
|
|
6778
|
+
return next.sort((a, b) => a.time.created - b.time.created || a.id.localeCompare(b.id));
|
|
6779
|
+
}
|
|
6780
|
+
function applyStatus(current, mutation) {
|
|
6781
|
+
return {
|
|
6782
|
+
...current,
|
|
6783
|
+
[mutation.sessionID]: mutation.status
|
|
6784
|
+
};
|
|
6785
|
+
}
|
|
6786
|
+
function recordSession(mutation) {
|
|
6787
|
+
const sessionID = mutation.type === "upsert" ? mutation.info.id : mutation.sessionID;
|
|
6788
|
+
for (const key of targets.keys()) {
|
|
6789
|
+
remoteFailures.delete(JSON.stringify([key, sessionID]));
|
|
6790
|
+
remoteRetryAt.delete(JSON.stringify([key, sessionID]));
|
|
6791
|
+
if (mutation.type === "remove") history.remove(key, sessionID);
|
|
6792
|
+
}
|
|
6793
|
+
for (const journal of journals) journal.sessions.push(mutation);
|
|
6794
|
+
if (options.cache === "model") setChildren((current) => Object.fromEntries(Object.entries(current).map(([key, items]) => [key, applySession(items, targets.get(key).parentID, mutation)])));
|
|
6795
|
+
}
|
|
6796
|
+
function recordStatus(input) {
|
|
6797
|
+
const mutation = {
|
|
6798
|
+
...input,
|
|
6799
|
+
at: now(),
|
|
6800
|
+
startedAt: source?.startedAt?.(input.sessionID),
|
|
6801
|
+
observed: /* @__PURE__ */ new Set()
|
|
6802
|
+
};
|
|
6803
|
+
for (const journal of journals) journal.statuses.push(mutation);
|
|
6804
|
+
(0, solid_js.batch)(() => {
|
|
6805
|
+
for (const [key, items] of Object.entries(snapshots())) {
|
|
6806
|
+
if (items.every((item) => item.id !== mutation.sessionID)) continue;
|
|
6807
|
+
history.observeStatus(key, mutation.sessionID, mutation.status, mutation.at, mutation.startedAt);
|
|
6808
|
+
mutation.observed.add(key);
|
|
6809
|
+
}
|
|
6810
|
+
if (options.cache === "model") setStatuses((current) => Object.fromEntries(Object.entries(current).map(([key, value]) => [key, applyStatus(value, mutation)])));
|
|
6811
|
+
});
|
|
6812
|
+
}
|
|
6813
|
+
function recordError(input) {
|
|
6814
|
+
if (!input.sessionID) return;
|
|
6815
|
+
const mutation = {
|
|
6816
|
+
sessionID: input.sessionID,
|
|
6817
|
+
error: input.error,
|
|
6818
|
+
at: now(),
|
|
6819
|
+
observed: /* @__PURE__ */ new Set()
|
|
6820
|
+
};
|
|
6821
|
+
for (const journal of journals) journal.errors.push(mutation);
|
|
6822
|
+
for (const [key, items] of Object.entries(snapshots())) {
|
|
6823
|
+
if (items.every((item) => item.id !== mutation.sessionID)) continue;
|
|
6824
|
+
history.observeError(key, mutation.sessionID, mutation.error, mutation.at);
|
|
6825
|
+
mutation.observed.add(key);
|
|
6826
|
+
}
|
|
6827
|
+
}
|
|
6828
|
+
async function refreshTarget(current, force = false) {
|
|
6829
|
+
const pending = refreshing.get(current.key);
|
|
6830
|
+
if (pending && !force) return pending;
|
|
6831
|
+
const journal = {
|
|
6832
|
+
sessions: [],
|
|
6833
|
+
statuses: [],
|
|
6834
|
+
errors: []
|
|
6835
|
+
};
|
|
6836
|
+
journals.add(journal);
|
|
6837
|
+
targets.set(current.key, current);
|
|
6838
|
+
const requestState = requests.start(current.key, "refresh subagents", current.key in children(), force);
|
|
6839
|
+
if (!requestState) {
|
|
6840
|
+
journals.delete(journal);
|
|
6841
|
+
return pending;
|
|
6842
|
+
}
|
|
6843
|
+
const signal = AbortSignal.any([requestState.signal, AbortSignal.timeout(5e3)]);
|
|
6844
|
+
const request = options.snapshot(current, signal).then(async (snapshot) => {
|
|
6845
|
+
let nextChildren = snapshot.sessions;
|
|
6846
|
+
for (const mutation of journal.sessions) nextChildren = applySession(nextChildren, current.parentID, mutation);
|
|
6847
|
+
let nextStatuses = { ...snapshot.statuses };
|
|
6848
|
+
const missing = {};
|
|
6849
|
+
const remoteStatuses = options.remoteStatus ? await Promise.all(nextChildren.map(async (session) => {
|
|
6850
|
+
const key = JSON.stringify([current.key, session.id]);
|
|
6851
|
+
return (remoteRetryAt.get(key) ?? 0) <= now() ? options.remoteStatus(session, requestState.signal) : {
|
|
6852
|
+
sessionID: session.id,
|
|
6853
|
+
failed: true,
|
|
6854
|
+
cooldown: true,
|
|
6855
|
+
status: void 0
|
|
6856
|
+
};
|
|
6857
|
+
})) : [];
|
|
6858
|
+
if (!requestState.isCurrent()) return;
|
|
6859
|
+
for (const result of remoteStatuses) {
|
|
6860
|
+
if (!result) continue;
|
|
6861
|
+
const key = JSON.stringify([current.key, result.sessionID]);
|
|
6862
|
+
if (result.failed) {
|
|
6863
|
+
missing[result.sessionID] = true;
|
|
6864
|
+
if (!("cooldown" in result)) {
|
|
6865
|
+
const failures = (remoteFailures.get(key) ?? 0) + 1;
|
|
6866
|
+
remoteFailures.set(key, failures);
|
|
6867
|
+
if (failures >= 3) remoteRetryAt.set(key, now() + 3e4);
|
|
6868
|
+
}
|
|
6869
|
+
const previous = statuses()[current.key]?.[result.sessionID];
|
|
6870
|
+
if (previous) nextStatuses[result.sessionID] = previous;
|
|
6871
|
+
else delete nextStatuses[result.sessionID];
|
|
6872
|
+
continue;
|
|
6873
|
+
}
|
|
6874
|
+
remoteFailures.delete(key);
|
|
6875
|
+
remoteRetryAt.delete(key);
|
|
6876
|
+
nextStatuses[result.sessionID] = result.status ?? { type: "idle" };
|
|
6755
6877
|
}
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6878
|
+
for (const mutation of journal.sessions) nextChildren = applySession(nextChildren, current.parentID, mutation);
|
|
6879
|
+
for (const mutation of journal.statuses) nextStatuses = applyStatus(nextStatuses, mutation);
|
|
6880
|
+
if (requestState.isCurrent()) (0, solid_js.batch)(() => {
|
|
6881
|
+
for (const session of nextChildren) {
|
|
6882
|
+
const mutations = journal.statuses.filter((mutation) => mutation.sessionID === session.id);
|
|
6883
|
+
if (mutations.length > 0) {
|
|
6884
|
+
for (const mutation of mutations) if (!mutation.observed.has(current.key)) history.observeStatus(current.key, session.id, mutation.status, mutation.at, mutation.startedAt);
|
|
6885
|
+
} else if (!missing[session.id]) {
|
|
6886
|
+
const status = nextStatuses[session.id] ?? { type: "idle" };
|
|
6887
|
+
nextStatuses[session.id] = status;
|
|
6888
|
+
history.observeStatus(current.key, session.id, status, now(), source?.startedAt?.(session.id));
|
|
6889
|
+
}
|
|
6890
|
+
for (const mutation of journal.errors) if (mutation.sessionID === session.id && !mutation.observed.has(current.key)) history.observeError(current.key, session.id, mutation.error, mutation.at);
|
|
6891
|
+
}
|
|
6892
|
+
if (options.cache === "model") {
|
|
6893
|
+
setChildren((value) => ({
|
|
6894
|
+
...value,
|
|
6895
|
+
[current.key]: nextChildren
|
|
6896
|
+
}));
|
|
6897
|
+
setStatuses((value) => ({
|
|
6898
|
+
...value,
|
|
6899
|
+
[current.key]: nextStatuses
|
|
6900
|
+
}));
|
|
6901
|
+
}
|
|
6902
|
+
setUnavailable((value) => ({
|
|
6903
|
+
...value,
|
|
6904
|
+
[current.key]: missing
|
|
6905
|
+
}));
|
|
6906
|
+
});
|
|
6907
|
+
requestState.succeed();
|
|
6908
|
+
}).catch((error) => {
|
|
6909
|
+
requestState.fail(error);
|
|
6910
|
+
throw error;
|
|
6911
|
+
}).finally(() => {
|
|
6912
|
+
journals.delete(journal);
|
|
6913
|
+
requestState.finish();
|
|
6914
|
+
if (refreshing.get(current.key) === request) refreshing.delete(current.key);
|
|
6782
6915
|
});
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
enter(event) {
|
|
6786
|
-
const target = event.target;
|
|
6787
|
-
focused = target.getAttribute("aria-label")?.startsWith("Reorder ") ? target.closest("[data-sortable-item]")?.dataset.sortableItem : void 0;
|
|
6788
|
-
},
|
|
6789
|
-
leave(event) {
|
|
6790
|
-
if (event.relatedTarget && !props.root().contains(event.relatedTarget)) focused = void 0;
|
|
6791
|
-
}
|
|
6792
|
-
};
|
|
6793
|
-
}
|
|
6794
|
-
// src/shared/ui/gui/sortable-interaction.ts
|
|
6795
|
-
function createSortableInteraction(props) {
|
|
6796
|
-
const [source, setSource] = (0, solid_js.createSignal)();
|
|
6797
|
-
const [target, setTarget] = (0, solid_js.createSignal)();
|
|
6798
|
-
const [announcement, setAnnouncement] = (0, solid_js.createSignal)("");
|
|
6799
|
-
let drag;
|
|
6800
|
-
const signature = () => JSON.stringify(props.keys());
|
|
6801
|
-
function cancel() {
|
|
6802
|
-
const previous = drag;
|
|
6803
|
-
drag = void 0;
|
|
6804
|
-
setSource(void 0);
|
|
6805
|
-
setTarget(void 0);
|
|
6806
|
-
if (previous && previous.pointer >= 0 && props.root().hasPointerCapture(previous.pointer)) props.root().releasePointerCapture(previous.pointer);
|
|
6807
|
-
}
|
|
6808
|
-
(0, solid_js.createEffect)(() => {
|
|
6809
|
-
source();
|
|
6810
|
-
if (drag && (props.disabled() || props.scope() !== drag.scope || signature() !== drag.keys)) cancel();
|
|
6811
|
-
});
|
|
6812
|
-
function escape(event) {
|
|
6813
|
-
if (event.key !== "Escape") return;
|
|
6814
|
-
event.preventDefault();
|
|
6815
|
-
event.stopPropagation();
|
|
6816
|
-
cancel();
|
|
6916
|
+
refreshing.set(current.key, request);
|
|
6917
|
+
return request;
|
|
6817
6918
|
}
|
|
6818
|
-
(
|
|
6819
|
-
|
|
6820
|
-
globalThis.window.addEventListener("keydown", escape, { capture: true });
|
|
6821
|
-
(0, solid_js.onCleanup)(() => globalThis.window.removeEventListener("keydown", escape, true));
|
|
6822
|
-
});
|
|
6823
|
-
(0, solid_js.onCleanup)(cancel);
|
|
6824
|
-
function hover(event) {
|
|
6825
|
-
if (!drag || event.pointerId !== drag.pointer) return;
|
|
6826
|
-
const node = document.elementFromPoint(event.clientX, event.clientY)?.closest("[data-sortable-item]");
|
|
6827
|
-
setTarget(node && props.root().contains(node) ? node.dataset.sortableItem : void 0);
|
|
6919
|
+
function refresh(parentID, force = false) {
|
|
6920
|
+
return refreshTarget(target(parentID), force);
|
|
6828
6921
|
}
|
|
6829
|
-
function
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
id
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
setSource(id);
|
|
6841
|
-
setTarget(id);
|
|
6922
|
+
function list(parentID) {
|
|
6923
|
+
const current = target(parentID);
|
|
6924
|
+
const currentStatuses = options.cache === "source" ? Object.fromEntries(source.list(parentID).map((item) => [item.id, source.status(item.id)])) : statuses()[current.key] ?? {};
|
|
6925
|
+
return (snapshots()[current.key] ?? []).map((session) => ({
|
|
6926
|
+
session,
|
|
6927
|
+
status: currentStatuses[session.id] ?? (unavailable()[current.key]?.[session.id] ? void 0 : source.status(session.id))
|
|
6928
|
+
})).filter((item) => activeStatus(item.status)).map((item) => ({
|
|
6929
|
+
...item,
|
|
6930
|
+
run: history.active(current.key, item.session.id),
|
|
6931
|
+
unavailable: unavailable()[current.key]?.[item.session.id]
|
|
6932
|
+
}));
|
|
6842
6933
|
}
|
|
6843
|
-
function
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6934
|
+
function recent(parentID) {
|
|
6935
|
+
const current = target(parentID);
|
|
6936
|
+
const sessions = new Map((snapshots()[current.key] ?? []).map((session) => [session.id, session]));
|
|
6937
|
+
return history.recent(current.key).flatMap((run) => {
|
|
6938
|
+
const session = sessions.get(run.sessionID);
|
|
6939
|
+
return session ? [{
|
|
6940
|
+
session,
|
|
6941
|
+
status: { type: "idle" },
|
|
6942
|
+
run,
|
|
6943
|
+
unavailable: false
|
|
6944
|
+
}] : [];
|
|
6945
|
+
});
|
|
6851
6946
|
}
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
event
|
|
6856
|
-
|
|
6857
|
-
|
|
6947
|
+
const unsubscribe = options.subscribe((event) => {
|
|
6948
|
+
switch (event.type) {
|
|
6949
|
+
case "upsert":
|
|
6950
|
+
recordSession(event);
|
|
6951
|
+
break;
|
|
6952
|
+
case "remove":
|
|
6953
|
+
recordSession(event);
|
|
6954
|
+
recordStatus({
|
|
6955
|
+
sessionID: event.sessionID,
|
|
6956
|
+
status: { type: "idle" }
|
|
6957
|
+
});
|
|
6958
|
+
break;
|
|
6959
|
+
case "status":
|
|
6960
|
+
recordStatus(event);
|
|
6961
|
+
break;
|
|
6962
|
+
case "error":
|
|
6963
|
+
recordError(event);
|
|
6964
|
+
break;
|
|
6965
|
+
case "reconnect": {
|
|
6966
|
+
const current = activeTarget ? targets.get(activeTarget) : void 0;
|
|
6967
|
+
if (current) retryBackgroundRefresh(() => refreshTarget(current), { signal: options.lifecycle.signal }).catch(() => {});
|
|
6968
|
+
break;
|
|
6858
6969
|
}
|
|
6859
|
-
return;
|
|
6860
6970
|
}
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6971
|
+
});
|
|
6972
|
+
options.lifecycle.onDispose(() => {
|
|
6973
|
+
unsubscribe();
|
|
6974
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
6975
|
+
});
|
|
6976
|
+
return {
|
|
6977
|
+
target,
|
|
6978
|
+
list,
|
|
6979
|
+
recent,
|
|
6980
|
+
refresh,
|
|
6981
|
+
state(parentID) {
|
|
6982
|
+
return requests.state(target(parentID).key);
|
|
6983
|
+
},
|
|
6984
|
+
retry(parentID) {
|
|
6985
|
+
return refresh(parentID, true);
|
|
6986
|
+
},
|
|
6987
|
+
activate(parentID) {
|
|
6988
|
+
const current = target(parentID);
|
|
6989
|
+
targets.set(current.key, current);
|
|
6990
|
+
if (activeTarget !== current.key) {
|
|
6991
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
6992
|
+
requests.abortAll();
|
|
6993
|
+
refreshing.clear();
|
|
6994
|
+
activeTarget = current.key;
|
|
6995
|
+
leases = /* @__PURE__ */ new Set();
|
|
6996
|
+
const poll = () => {
|
|
6997
|
+
if (activeTarget !== current.key || options.lifecycle.signal.aborted) return;
|
|
6998
|
+
refreshTarget(current).catch(() => {});
|
|
6999
|
+
pollTimer = setTimeout(poll, POLL_INTERVAL_MS);
|
|
6871
7000
|
};
|
|
6872
|
-
|
|
6873
|
-
setTarget(id);
|
|
6874
|
-
setAnnouncement("Picked up. Use arrow keys, Space to drop, or Escape to cancel.");
|
|
6875
|
-
} else if (drag.pointer === -1 && drag.id === id) {
|
|
6876
|
-
const destination = target();
|
|
6877
|
-
const valid = props.scope() === drag.scope && signature() === drag.keys;
|
|
6878
|
-
cancel();
|
|
6879
|
-
if (valid && destination && destination !== id) props.move(id, destination);
|
|
7001
|
+
if (options.cache === "model") pollTimer = setTimeout(poll, POLL_INTERVAL_MS);
|
|
6880
7002
|
}
|
|
6881
|
-
|
|
7003
|
+
const lease = Symbol(current.key);
|
|
7004
|
+
leases.add(lease);
|
|
7005
|
+
return () => {
|
|
7006
|
+
if (activeTarget !== current.key || !leases.delete(lease) || leases.size > 0) return;
|
|
7007
|
+
activeTarget = void 0;
|
|
7008
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
7009
|
+
pollTimer = void 0;
|
|
7010
|
+
requests.abortAll();
|
|
7011
|
+
refreshing.clear();
|
|
7012
|
+
};
|
|
7013
|
+
},
|
|
7014
|
+
open(sessionID) {
|
|
7015
|
+
options.open(sessionID);
|
|
6882
7016
|
}
|
|
6883
|
-
if (drag?.pointer !== -1 || drag.id !== id || !["ArrowUp", "ArrowDown"].includes(event.key)) return;
|
|
6884
|
-
const keys = props.keys();
|
|
6885
|
-
const index = keys.indexOf(target() ?? id);
|
|
6886
|
-
const destination = keys[index + (event.key === "ArrowUp" ? -1 : 1)];
|
|
6887
|
-
if (!destination || index === -1) return;
|
|
6888
|
-
event.preventDefault();
|
|
6889
|
-
event.stopPropagation();
|
|
6890
|
-
setTarget(destination);
|
|
6891
|
-
setAnnouncement(`Drop at position ${keys.indexOf(destination) + 1} of ${keys.length}`);
|
|
6892
|
-
}
|
|
6893
|
-
return {
|
|
6894
|
-
source,
|
|
6895
|
-
target,
|
|
6896
|
-
announcement,
|
|
6897
|
-
start,
|
|
6898
|
-
hover,
|
|
6899
|
-
end,
|
|
6900
|
-
key,
|
|
6901
|
-
cancel
|
|
6902
7017
|
};
|
|
6903
7018
|
}
|
|
6904
|
-
// src/
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
disabled: () => Boolean(props.disabled)
|
|
6917
|
-
});
|
|
6918
|
-
const interaction = createSortableInteraction({
|
|
6919
|
-
keys,
|
|
6920
|
-
scope: () => props.scope,
|
|
6921
|
-
disabled: () => Boolean(props.disabled),
|
|
6922
|
-
root: () => root,
|
|
6923
|
-
move: (from, to) => props.move(from, to)
|
|
7019
|
+
// src/entities/subagent/model/view.ts
|
|
7020
|
+
function filterSubagentView(rows, mode, query) {
|
|
7021
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
7022
|
+
return rows.filter((row) => {
|
|
7023
|
+
if (mode === "active" && row.group !== "Active") return false;
|
|
7024
|
+
if (mode === "recent" && row.group !== "Recent") return false;
|
|
7025
|
+
if (mode === "errors" && row.run?.outcome !== "error" && !row.unavailable) return false;
|
|
7026
|
+
return !needle || [
|
|
7027
|
+
row.session.title,
|
|
7028
|
+
row.session.id,
|
|
7029
|
+
row.run?.errorMessage
|
|
7030
|
+
].some((value) => value?.toLocaleLowerCase().includes(needle));
|
|
6924
7031
|
});
|
|
6925
|
-
return (() => {
|
|
6926
|
-
var _el$ = _tmpl$$44(), _el$2 = _el$.firstChild;
|
|
6927
|
-
_el$2.firstChild;
|
|
6928
|
-
(0, solid_js_web.addEventListener)(_el$, "lostpointercapture", interaction.cancel);
|
|
6929
|
-
(0, solid_js_web.addEventListener)(_el$, "pointercancel", interaction.cancel);
|
|
6930
|
-
(0, solid_js_web.addEventListener)(_el$, "pointerup", interaction.end, true);
|
|
6931
|
-
(0, solid_js_web.addEventListener)(_el$, "pointermove", interaction.hover, true);
|
|
6932
|
-
(0, solid_js_web.addEventListener)(_el$, "focusout", focus.leave, true);
|
|
6933
|
-
(0, solid_js_web.addEventListener)(_el$, "focusin", focus.enter, true);
|
|
6934
|
-
(0, solid_js_web.use)((node) => {
|
|
6935
|
-
root = node;
|
|
6936
|
-
}, _el$);
|
|
6937
|
-
(0, solid_js_web.setAttribute)(_el$, "aria-describedby", help);
|
|
6938
|
-
(0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
|
|
6939
|
-
get each() {
|
|
6940
|
-
return keys();
|
|
6941
|
-
},
|
|
6942
|
-
children: (key) => {
|
|
6943
|
-
const item = () => props.items.find((value) => props.itemKey(value) === key);
|
|
6944
|
-
return (() => {
|
|
6945
|
-
var _el$4 = _tmpl$2$30();
|
|
6946
|
-
(0, solid_js_web.setAttribute)(_el$4, "data-sortable-item", key);
|
|
6947
|
-
(0, solid_js_web.insert)(_el$4, () => props.children(item, (() => {
|
|
6948
|
-
var _el$5 = _tmpl$3$17();
|
|
6949
|
-
_el$5.$$keydown = (event) => interaction.key(event, key);
|
|
6950
|
-
_el$5.$$pointerdown = (event) => interaction.start(event, key);
|
|
6951
|
-
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(IconButton, {
|
|
6952
|
-
icon: "dot-grid",
|
|
6953
|
-
get label() {
|
|
6954
|
-
return `Reorder ${props.itemLabel(item())}`;
|
|
6955
|
-
},
|
|
6956
|
-
get disabled() {
|
|
6957
|
-
return props.disabled || keys().length < 2;
|
|
6958
|
-
}
|
|
6959
|
-
}));
|
|
6960
|
-
return _el$5;
|
|
6961
|
-
})()));
|
|
6962
|
-
(0, solid_js_web.effect)((_p$) => {
|
|
6963
|
-
var _v$ = keys().indexOf(key) + 1, _v$2 = keys().length, _v$3 = interaction.source() === key ? "0.65" : "1", _v$4 = interaction.target() === key && interaction.source() !== key ? "1px dashed var(--v2-border-border-focus)" : void 0;
|
|
6964
|
-
_v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$4, "aria-posinset", _p$.e = _v$);
|
|
6965
|
-
_v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$4, "aria-setsize", _p$.t = _v$2);
|
|
6966
|
-
_v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$4, "opacity", _p$.a = _v$3);
|
|
6967
|
-
_v$4 !== _p$.o && (0, solid_js_web.setStyleProperty)(_el$4, "outline", _p$.o = _v$4);
|
|
6968
|
-
return _p$;
|
|
6969
|
-
}, {
|
|
6970
|
-
e: void 0,
|
|
6971
|
-
t: void 0,
|
|
6972
|
-
a: void 0,
|
|
6973
|
-
o: void 0
|
|
6974
|
-
});
|
|
6975
|
-
return _el$4;
|
|
6976
|
-
})();
|
|
6977
|
-
}
|
|
6978
|
-
}), _el$2);
|
|
6979
|
-
(0, solid_js_web.setAttribute)(_el$2, "id", help);
|
|
6980
|
-
(0, solid_js_web.insert)(_el$2, () => interaction.announcement(), null);
|
|
6981
|
-
(0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", props.label));
|
|
6982
|
-
return _el$;
|
|
6983
|
-
})();
|
|
6984
7032
|
}
|
|
6985
|
-
(
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
i: void 0,
|
|
7023
|
-
n: void 0
|
|
7024
|
-
});
|
|
7025
|
-
return _el$;
|
|
7026
|
-
})();
|
|
7033
|
+
function countSubagentView(rows, query) {
|
|
7034
|
+
return {
|
|
7035
|
+
all: filterSubagentView(rows, "all", query).length,
|
|
7036
|
+
active: filterSubagentView(rows, "active", query).length,
|
|
7037
|
+
recent: filterSubagentView(rows, "recent", query).length,
|
|
7038
|
+
errors: filterSubagentView(rows, "errors", query).length
|
|
7039
|
+
};
|
|
7040
|
+
}
|
|
7041
|
+
function buildSubagentView(active, recent) {
|
|
7042
|
+
const priority = (item) => {
|
|
7043
|
+
if (item.run?.errorMessage || item.unavailable) return 0;
|
|
7044
|
+
return item.status.type === "retry" ? 1 : 2;
|
|
7045
|
+
};
|
|
7046
|
+
return [...[...active].sort((a, b) => priority(a) - priority(b)).map((item) => ({
|
|
7047
|
+
...item,
|
|
7048
|
+
group: "Active"
|
|
7049
|
+
})), ...[...recent].sort((a, b) => (b.run?.finishedAt ?? 0) - (a.run?.finishedAt ?? 0) || a.session.id.localeCompare(b.session.id)).map((item) => ({
|
|
7050
|
+
...item,
|
|
7051
|
+
group: "Recent"
|
|
7052
|
+
}))];
|
|
7053
|
+
}
|
|
7054
|
+
function formatSubagentDuration(startedAt, now) {
|
|
7055
|
+
const seconds = Math.max(0, Math.floor((now - startedAt) / 1e3));
|
|
7056
|
+
let value = `${seconds}s`;
|
|
7057
|
+
if (seconds >= 3600) value = `${Math.floor(seconds / 3600)}h ${String(Math.floor(seconds / 60) % 60).padStart(2, "0")}m`;
|
|
7058
|
+
else if (seconds >= 60) value = `${Math.floor(seconds / 60)}m ${String(seconds % 60).padStart(2, "0")}s`;
|
|
7059
|
+
return value;
|
|
7060
|
+
}
|
|
7061
|
+
function createSubagentClock(key) {
|
|
7062
|
+
const [now, setNow] = (0, solid_js.createSignal)(Date.now());
|
|
7063
|
+
(0, solid_js.createEffect)(() => {
|
|
7064
|
+
if (key() === void 0) return;
|
|
7065
|
+
setNow(Date.now());
|
|
7066
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
7067
|
+
(0, solid_js.onCleanup)(() => clearInterval(timer));
|
|
7068
|
+
});
|
|
7069
|
+
return now;
|
|
7027
7070
|
}
|
|
7028
7071
|
// src/pages/navigator/ui/gui/subagent-row.tsx
|
|
7029
7072
|
var _tmpl$$42 = /*#__PURE__*/ (0, solid_js_web.template)(`<li><p style="font-size:12px;opacity:0.65;margin:0 0 8px;overflow-wrap:anywhere">`);
|
|
@@ -7452,11 +7495,13 @@ function TodoSection() {
|
|
|
7452
7495
|
},
|
|
7453
7496
|
children: "Enable Todo"
|
|
7454
7497
|
}), null);
|
|
7455
|
-
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7498
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
7499
|
+
get ui() {
|
|
7500
|
+
return props.ui;
|
|
7501
|
+
},
|
|
7502
|
+
icon: "refresh",
|
|
7503
|
+
label: "Retry",
|
|
7504
|
+
onClick: () => void props.runtime.refresh(true)
|
|
7460
7505
|
}), null);
|
|
7461
7506
|
return _el$6;
|
|
7462
7507
|
})();
|
|
@@ -9094,10 +9139,8 @@ function createMiniWindowInteraction(props) {
|
|
|
9094
9139
|
};
|
|
9095
9140
|
}
|
|
9096
9141
|
// src/pages/navigator/ui/gui/mini-window.tsx
|
|
9097
|
-
var _tmpl$$29 = /*#__PURE__*/ (0, solid_js_web.template)(`<aside data-navigator-floating style="position:fixed;display:flex;flex-direction:column;z-index:40;background:var(--v2-background-bg-layer-01);color:var(--v2-text-text-base);border:1px solid var(--v2-border-border-base, color-mix(in srgb, currentColor 20%, transparent));border-radius:12px;box-shadow:var(--v2-elevation-overlay, 0 8px 32px #0003);overflow:hidden;font-size:13px"><header style=display:
|
|
9142
|
+
var _tmpl$$29 = /*#__PURE__*/ (0, solid_js_web.template)(`<aside data-navigator-floating style="position:fixed;display:flex;flex-direction:column;z-index:40;background:var(--v2-background-bg-layer-01);color:var(--v2-text-text-base);border:1px solid var(--v2-border-border-base, color-mix(in srgb, currentColor 20%, transparent));border-radius:12px;box-shadow:var(--v2-elevation-overlay, 0 8px 32px #0003);overflow:hidden;font-size:13px"><header style=display:grid;gap:6px;padding:8px;cursor:move;touch-action:none;user-select:none><strong data-navigator-session-title style=min-width:0;overflow:hidden;overflow-wrap:anywhere;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:20px></strong><div role=group aria-label="Mini-window actions"style=display:flex;gap:4px;align-items:center><span data-navigator-move title="Drag or use arrow keys; Shift moves ten pixels"></span></div></header><footer style=display:flex;gap:4px;padding:6px;align-items:center><span title="Drag or use arrow keys; Shift resizes ten pixels"style=margin-left:auto;cursor:nwse-resize;touch-action:none>`);
|
|
9098
9143
|
function NavigatorMiniWindow(props) {
|
|
9099
|
-
const Button = props.ui.Button;
|
|
9100
|
-
const IconButton = props.ui.IconButton;
|
|
9101
9144
|
const interaction = createMiniWindowInteraction(props);
|
|
9102
9145
|
function dragHeader(event) {
|
|
9103
9146
|
const target = event.target;
|
|
@@ -9105,63 +9148,77 @@ function NavigatorMiniWindow(props) {
|
|
|
9105
9148
|
interaction.start(event, "move");
|
|
9106
9149
|
}
|
|
9107
9150
|
return (() => {
|
|
9108
|
-
var _el$ = _tmpl$$29(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$2.nextSibling, _el$
|
|
9151
|
+
var _el$ = _tmpl$$29(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$2.nextSibling, _el$7 = _el$6.firstChild;
|
|
9109
9152
|
(0, solid_js_web.addEventListener)(_el$2, "lostpointercapture", interaction.end);
|
|
9110
9153
|
(0, solid_js_web.addEventListener)(_el$2, "pointercancel", interaction.end);
|
|
9111
9154
|
(0, solid_js_web.addEventListener)(_el$2, "pointerup", interaction.end, true);
|
|
9112
9155
|
(0, solid_js_web.addEventListener)(_el$2, "pointermove", interaction.move, true);
|
|
9113
9156
|
_el$2.$$pointerdown = dragHeader;
|
|
9114
|
-
_el$3
|
|
9115
|
-
|
|
9157
|
+
(0, solid_js_web.insert)(_el$3, () => props.title);
|
|
9158
|
+
_el$5.$$keydown = (event) => interaction.key(event, "move");
|
|
9159
|
+
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9160
|
+
get ui() {
|
|
9161
|
+
return props.ui;
|
|
9162
|
+
},
|
|
9116
9163
|
icon: "dot-grid",
|
|
9117
9164
|
label: "Move Navigator mini-window"
|
|
9118
9165
|
}));
|
|
9119
|
-
(0, solid_js_web.insert)(_el$4, (
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9166
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9167
|
+
get ui() {
|
|
9168
|
+
return props.ui;
|
|
9169
|
+
},
|
|
9170
|
+
icon: "layout-right",
|
|
9171
|
+
label: "Dock",
|
|
9123
9172
|
get onClick() {
|
|
9124
9173
|
return props.redock;
|
|
9125
|
-
}
|
|
9126
|
-
children: "Dock"
|
|
9174
|
+
}
|
|
9127
9175
|
}), null);
|
|
9128
|
-
(0, solid_js_web.insert)(_el$, () => props.children, _el$
|
|
9129
|
-
(0, solid_js_web.insert)(_el$
|
|
9130
|
-
|
|
9131
|
-
|
|
9176
|
+
(0, solid_js_web.insert)(_el$, () => props.children, _el$6);
|
|
9177
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9178
|
+
get ui() {
|
|
9179
|
+
return props.ui;
|
|
9180
|
+
},
|
|
9181
|
+
icon: "magnifying-glass",
|
|
9182
|
+
label: "Search",
|
|
9132
9183
|
get onClick() {
|
|
9133
9184
|
return props.search;
|
|
9185
|
+
}
|
|
9186
|
+
}), _el$7);
|
|
9187
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9188
|
+
get ui() {
|
|
9189
|
+
return props.ui;
|
|
9134
9190
|
},
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(Button, {
|
|
9138
|
-
size: "small",
|
|
9139
|
-
variant: "ghost-muted",
|
|
9191
|
+
icon: "refresh",
|
|
9192
|
+
label: "Refresh",
|
|
9140
9193
|
get onClick() {
|
|
9141
9194
|
return props.refresh;
|
|
9195
|
+
}
|
|
9196
|
+
}), _el$7);
|
|
9197
|
+
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9198
|
+
get ui() {
|
|
9199
|
+
return props.ui;
|
|
9142
9200
|
},
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(Button, {
|
|
9146
|
-
size: "small",
|
|
9147
|
-
variant: "ghost-muted",
|
|
9201
|
+
icon: "outline-reset",
|
|
9202
|
+
label: "Reset position",
|
|
9148
9203
|
get onClick() {
|
|
9149
9204
|
return interaction.reset;
|
|
9205
|
+
}
|
|
9206
|
+
}), _el$7);
|
|
9207
|
+
_el$7.$$keydown = (event) => interaction.key(event, "resize");
|
|
9208
|
+
(0, solid_js_web.addEventListener)(_el$7, "lostpointercapture", interaction.end);
|
|
9209
|
+
(0, solid_js_web.addEventListener)(_el$7, "pointercancel", interaction.end);
|
|
9210
|
+
(0, solid_js_web.addEventListener)(_el$7, "pointerup", interaction.end, true);
|
|
9211
|
+
(0, solid_js_web.addEventListener)(_el$7, "pointermove", interaction.move, true);
|
|
9212
|
+
_el$7.$$pointerdown = (event) => interaction.start(event, "resize");
|
|
9213
|
+
(0, solid_js_web.insert)(_el$7, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9214
|
+
get ui() {
|
|
9215
|
+
return props.ui;
|
|
9150
9216
|
},
|
|
9151
|
-
children: "Reset position"
|
|
9152
|
-
}), _el$6);
|
|
9153
|
-
_el$6.$$keydown = (event) => interaction.key(event, "resize");
|
|
9154
|
-
(0, solid_js_web.addEventListener)(_el$6, "lostpointercapture", interaction.end);
|
|
9155
|
-
(0, solid_js_web.addEventListener)(_el$6, "pointercancel", interaction.end);
|
|
9156
|
-
(0, solid_js_web.addEventListener)(_el$6, "pointerup", interaction.end, true);
|
|
9157
|
-
(0, solid_js_web.addEventListener)(_el$6, "pointermove", interaction.move, true);
|
|
9158
|
-
_el$6.$$pointerdown = (event) => interaction.start(event, "resize");
|
|
9159
|
-
(0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(IconButton, {
|
|
9160
9217
|
icon: "outline-expand",
|
|
9161
9218
|
label: "Resize Navigator mini-window"
|
|
9162
9219
|
}));
|
|
9163
9220
|
(0, solid_js_web.effect)((_p$) => {
|
|
9164
|
-
var _v$ = `Navigator mini-window: ${props.title}`, _v$2 = props.modal, _v$3 = props.modal, _v$4 = `${props.rect.x}px`, _v$5 = `${props.rect.y}px`, _v$6 = `${props.rect.width}px`, _v$7 = `${props.rect.height}px`, _v$8 = props.modal ? "hidden" : "visible", _v$9 = props.mode;
|
|
9221
|
+
var _v$ = `Navigator mini-window: ${props.title}`, _v$2 = props.modal, _v$3 = props.modal, _v$4 = `${props.rect.x}px`, _v$5 = `${props.rect.y}px`, _v$6 = `${props.rect.width}px`, _v$7 = `${props.rect.height}px`, _v$8 = props.modal ? "hidden" : "visible", _v$9 = props.mode, _v$0 = props.title;
|
|
9165
9222
|
_v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
|
|
9166
9223
|
_v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$, "aria-hidden", _p$.t = _v$2);
|
|
9167
9224
|
_v$3 !== _p$.a && (_el$.inert = _p$.a = _v$3);
|
|
@@ -9171,6 +9228,7 @@ function NavigatorMiniWindow(props) {
|
|
|
9171
9228
|
_v$7 !== _p$.s && (0, solid_js_web.setStyleProperty)(_el$, "height", _p$.s = _v$7);
|
|
9172
9229
|
_v$8 !== _p$.h && (0, solid_js_web.setStyleProperty)(_el$, "visibility", _p$.h = _v$8);
|
|
9173
9230
|
_v$9 !== _p$.r && (0, solid_js_web.setStyleProperty)(_el$, "color-scheme", _p$.r = _v$9);
|
|
9231
|
+
_v$0 !== _p$.d && (0, solid_js_web.setAttribute)(_el$3, "title", _p$.d = _v$0);
|
|
9174
9232
|
return _p$;
|
|
9175
9233
|
}, {
|
|
9176
9234
|
e: void 0,
|
|
@@ -9181,7 +9239,8 @@ function NavigatorMiniWindow(props) {
|
|
|
9181
9239
|
n: void 0,
|
|
9182
9240
|
s: void 0,
|
|
9183
9241
|
h: void 0,
|
|
9184
|
-
r: void 0
|
|
9242
|
+
r: void 0,
|
|
9243
|
+
d: void 0
|
|
9185
9244
|
});
|
|
9186
9245
|
return _el$;
|
|
9187
9246
|
})();
|
|
@@ -9193,48 +9252,56 @@ function NavigatorMiniWindow(props) {
|
|
|
9193
9252
|
"keydown"
|
|
9194
9253
|
]);
|
|
9195
9254
|
// src/pages/navigator/ui/gui/monitoring-panel.tsx
|
|
9196
|
-
var _tmpl$$28 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-panel style=display:flex;flex-direction:column;height:100%;min-height:0><header style="padding:8px 12px;display:
|
|
9255
|
+
var _tmpl$$28 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-panel style=display:flex;flex-direction:column;height:100%;min-height:0><header data-navigator-panel-header style="padding:8px 12px;display:grid;gap:6px;min-width:0"><strong data-navigator-session-title style=min-width:0;overflow:hidden;overflow-wrap:anywhere;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:20px></strong><div role=group aria-label="Navigator actions"style=display:flex;gap:4px;align-items:center;flex-wrap:wrap>`);
|
|
9197
9256
|
var _tmpl$2$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=padding:12px><p>Navigator is in its mini-window.`);
|
|
9198
|
-
var _tmpl$3$10 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>Loading Navigator…`);
|
|
9257
|
+
var _tmpl$3$10 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status> Loading Navigator…`);
|
|
9199
9258
|
function MonitoringPanel(props) {
|
|
9200
|
-
const
|
|
9259
|
+
const Loader = props.ui.Loader;
|
|
9201
9260
|
return (() => {
|
|
9202
|
-
var _el$ = _tmpl$$28(), _el$
|
|
9261
|
+
var _el$ = _tmpl$$28(), _el$3 = _el$.firstChild.firstChild, _el$4 = _el$3.nextSibling;
|
|
9203
9262
|
(0, solid_js_web.insert)(_el$3, () => props.title);
|
|
9204
|
-
(0, solid_js_web.insert)(_el$
|
|
9205
|
-
|
|
9206
|
-
|
|
9263
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9264
|
+
get ui() {
|
|
9265
|
+
return props.ui;
|
|
9266
|
+
},
|
|
9267
|
+
icon: "magnifying-glass",
|
|
9268
|
+
label: "Search",
|
|
9207
9269
|
get onClick() {
|
|
9208
9270
|
return props.search;
|
|
9209
|
-
}
|
|
9210
|
-
children: "Search"
|
|
9271
|
+
}
|
|
9211
9272
|
}), null);
|
|
9212
|
-
(0, solid_js_web.insert)(_el$
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9273
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9274
|
+
get ui() {
|
|
9275
|
+
return props.ui;
|
|
9276
|
+
},
|
|
9277
|
+
icon: "refresh",
|
|
9278
|
+
label: "Refresh",
|
|
9279
|
+
onClick: () => void props.runtime?.refresh(true)
|
|
9217
9280
|
}), null);
|
|
9218
|
-
(0, solid_js_web.insert)(_el$
|
|
9219
|
-
|
|
9220
|
-
|
|
9281
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9282
|
+
get ui() {
|
|
9283
|
+
return props.ui;
|
|
9284
|
+
},
|
|
9285
|
+
icon: "expand",
|
|
9286
|
+
label: "Float",
|
|
9221
9287
|
get onClick() {
|
|
9222
9288
|
return props.float;
|
|
9223
|
-
}
|
|
9224
|
-
children: "Float"
|
|
9289
|
+
}
|
|
9225
9290
|
}), null);
|
|
9226
|
-
(0, solid_js_web.insert)(_el$
|
|
9291
|
+
(0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(solid_js.Show, {
|
|
9227
9292
|
get when() {
|
|
9228
9293
|
return props.onSettings;
|
|
9229
9294
|
},
|
|
9230
9295
|
get children() {
|
|
9231
|
-
return (0, solid_js_web.createComponent)(
|
|
9232
|
-
|
|
9233
|
-
|
|
9296
|
+
return (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9297
|
+
get ui() {
|
|
9298
|
+
return props.ui;
|
|
9299
|
+
},
|
|
9300
|
+
icon: "settings-gear",
|
|
9301
|
+
label: "Settings",
|
|
9234
9302
|
get onClick() {
|
|
9235
9303
|
return props.onSettings;
|
|
9236
|
-
}
|
|
9237
|
-
children: "Settings"
|
|
9304
|
+
}
|
|
9238
9305
|
});
|
|
9239
9306
|
}
|
|
9240
9307
|
}), null);
|
|
@@ -9244,16 +9311,19 @@ function MonitoringPanel(props) {
|
|
|
9244
9311
|
},
|
|
9245
9312
|
get fallback() {
|
|
9246
9313
|
return (() => {
|
|
9247
|
-
var _el$
|
|
9248
|
-
_el$
|
|
9249
|
-
(0, solid_js_web.insert)(_el$
|
|
9250
|
-
|
|
9314
|
+
var _el$5 = _tmpl$2$21();
|
|
9315
|
+
_el$5.firstChild;
|
|
9316
|
+
(0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(GuiIconAction, {
|
|
9317
|
+
get ui() {
|
|
9318
|
+
return props.ui;
|
|
9319
|
+
},
|
|
9320
|
+
icon: "layout-right",
|
|
9321
|
+
label: "Dock Navigator",
|
|
9251
9322
|
get onClick() {
|
|
9252
9323
|
return props.dock;
|
|
9253
|
-
}
|
|
9254
|
-
children: "Dock Navigator"
|
|
9324
|
+
}
|
|
9255
9325
|
}), null);
|
|
9256
|
-
return _el$
|
|
9326
|
+
return _el$5;
|
|
9257
9327
|
})();
|
|
9258
9328
|
},
|
|
9259
9329
|
get children() {
|
|
@@ -9262,7 +9332,11 @@ function MonitoringPanel(props) {
|
|
|
9262
9332
|
return props.runtime;
|
|
9263
9333
|
},
|
|
9264
9334
|
get fallback() {
|
|
9265
|
-
return
|
|
9335
|
+
return (() => {
|
|
9336
|
+
var _el$7 = _tmpl$3$10(), _el$8 = _el$7.firstChild;
|
|
9337
|
+
(0, solid_js_web.insert)(_el$7, (0, solid_js_web.createComponent)(Loader, { size: "small" }), _el$8);
|
|
9338
|
+
return _el$7;
|
|
9339
|
+
})();
|
|
9266
9340
|
},
|
|
9267
9341
|
children: (runtime) => (0, solid_js_web.createComponent)(MonitoringContent, (0, solid_js_web.mergeProps)(props, { get runtime() {
|
|
9268
9342
|
return runtime();
|
|
@@ -11067,7 +11141,7 @@ function createGuiBugReport(context) {
|
|
|
11067
11141
|
let token = "";
|
|
11068
11142
|
(0, solid_js.onCleanup)(() => abort.abort());
|
|
11069
11143
|
const model = createBugReportModel({
|
|
11070
|
-
navigatorVersion: "0.27.
|
|
11144
|
+
navigatorVersion: "0.27.3",
|
|
11071
11145
|
openCodeVersion: context.app.version,
|
|
11072
11146
|
platform: context.app.platform,
|
|
11073
11147
|
runtime: "OpenCode Desktop GUI"
|
|
@@ -11119,8 +11193,8 @@ function createGuiBugReport(context) {
|
|
|
11119
11193
|
}
|
|
11120
11194
|
// src/app/gui/release.ts
|
|
11121
11195
|
var guiRelease = {
|
|
11122
|
-
version: "0.27.
|
|
11123
|
-
changelog: "# Changelog\n\n## [0.27.2] - 2026-11-11\n\n- Keep Desktop Settings fields and actions inside their rows at narrow widths, with readable labels and compact group creation.\n- Reorder Desktop sections, Quick Actions, toolbar pins and button icons by dragging their handles, or use Space and arrow keys to move them with the keyboard. Escape cancels an unfinished move.\n- Show download and installation progress in place of the running version in TUI and inline in Desktop About. Show real percentages only when byte totals are available; otherwise show the active stage.\n- Bring Desktop section arrows, loading indicators and Todo rows closer to native OpenCode. Completed and cancelled tasks use muted, struck-through text with distinct status icons.\n- Remove duplicate model and reasoning-effort selectors from the Desktop sidebar. Select them below chat instead; Limits continue to follow the active model.\n\n## [0.27.1] - 2026-11-11\n\n- Drag the Desktop mini-window by its header as well as its move handle, while keeping Dock a separate action. Match its surface and controls to OpenCode's light and dark themes.\n- Use native Desktop switches and selectors for Skill trust and Todo configuration, and align multiline fields with the host theme and focus styles.\n- Show a remaining-lifetime scale and time until expiry for banked reset credits with provider-supplied dates. Keep missing expiry explicit and prevent selecting expired credits for review.\n\n## [0.27.0] - 2026-11-11\n\n- Add an experimental OpenCode Desktop interface with a native panel, narrow-screen drawer, and opt-in in-app mini-window. Move, resize, reset and redock it with the mouse or keyboard while keeping the selected session and filters.\n- Bring Search Everything, Skills, MCP groups and presets, Quick Actions, and customizable toolbar pins to Desktop. Share private favorites, trust decisions and preferences with local TUI instances without duplicating monitoring.\n- Add native Desktop settings with scoped section controls, groups, reviewed presets and project profiles, portable import/export, a seven-slide setup guide, About, browsable release history and editable GitHub Bug reports.\n- Keep superseded Desktop configuration reads from showing a false error after a newer refresh, while preserving genuine failures and retry guidance.\n- Show verified provider/account quotas in Desktop with explicit account linking and separately confirmed banked resets. Keep remote sessions isolated from local accounts and preserve unresolved reset attempts across retries.\n- Support OpenCode 1.19.5 and 2.2.6 while preserving both TUI adapters, existing settings, pinned-source updates and read-only legacy Todo archives.\n\n## [0.26.0] - 2026-11-06\n\n- Prevent background retries from accumulating cancellation listeners and preferences loading from waiting indefinitely on recovery markers.\n- Show exact active Subagent durations from OpenCode 2's native execution start time, preserving the observation fallback when timing is unavailable. Keep interrupted executions marked as cancelled in recent history.\n\n## [0.25.0] - 2026-10-31\n\n- Offer Enable Todo when OpenCode 2's native tool is disabled, with an existing server-config picker, exact change preview and separate confirmation. Preserve unrelated JSONC content and refuse stale targets; distinguish disabled Todo from an enabled empty list.\n- Update the seven-slide setup wizard for native Todo enablement, provider/account limits, multi-icon or text-only toolbar pins, About/changelog and Bug reports. Describe each host's real permissions/LSP capabilities and keep navigation visible while short-terminal content scrolls.\n\n## [0.24.0] - 2026-10-31\n\n- Support the latest stable OpenCode 1.19.5 and 2.2.5 releases, preserving both host adapters and existing sidebar behavior.\n- Preserve Limits scales and reset-credit controls across equivalent quota snapshots and unrelated workspace events, while retaining current-account and credential-change guards.\n- Keep rounded selection backgrounds consistent in nested dialogs and highlighted rows.\n- Configure each toolbar button with zero to three icons and optional custom text, including text-only buttons. Keep legacy/state choices, unsaved drafts, rounded clipping, and width-aware More/wrapping.\n- Keep Quick Action rows and their hover/focus state stable while typing in the main prompt on both supported OpenCode hosts.\n- Show toolbar hover/focus hints without moving Limits or other sections, preserving centered, uniformly sized icon controls and empty-toolbar collapse.\n- Add Settings → About with the running versions, explicit update status/checking, confirmed updates, and a versioned changelog that can be reopened independently of first-launch upgrade notes.\n- Prepare editable Bug reports with confirmed sending through authenticated GitHub CLI and an independent Open in browser action. Retain drafts through errors and cancellation, and require manual review before retrying an uncertain submission.\n\n## [0.23.0] - 2026-10-28\n\n- Support only the latest stable OpenCode 1.x and 2.x releases, currently 1.19.5 and 2.2.0, including the newer terminal renderer.\n- Keep Skills, MCP servers, and Subagents current as OpenCode 2 updates, and launch the intended Skill when multiple sources have the same name.\n- Show OpenCode Console workspace budgets and Go allowance through the public host usage API without a Navigator server plugin. Preserve workspace scope, native units, reset times, and explicit failure/retry states.\n- Preserve Navigator shortcuts and nested-dialog navigation with OpenCode 2.2's keyboard handling.\n- Verify a supported runtime before changing a pinned Navigator snapshot, preserving the installed version when no compatible verifier is available.\n\n## [0.22.0] - 2026-10-23\n\n- Pin Quick Actions and Skills to a compact sidebar toolbar independently of bookmarks. Choose icons in a searchable picker, customize supported state icons, reorder buttons, and select a More menu or wrapping rows. Preserve Skill confirmations, unavailable reasons, keyboard navigation, and Text fallback; hide the toolbar entirely when empty.\n- Use OpenCode 2's built-in Todo history for the sidebar, with native completed-write and revert semantics, existing filters/progress, and manual Refresh. Keep edits in ordinary chat, preserve previous Navigator tasks as a read-only archive, and retain the independent provider-quota server integration.\n- Support OpenCode 2.1's plugin and rendering APIs while retaining the OpenCode 1.x adapter; restore custom dialogs and rounded selections on the newer native renderer.\n- Replace the shortcut toast with an icon-led hint featuring highlighted keys, navigation/update groups, a distinct Escape action, and responsive Text/no-corner-font layouts. Keep prompt focus and share its action list with scrollable keyboard help.\n- Update Subagent status immediately from OpenCode 2's execution lifecycle and keep unresolved external credentials separate from verified provider accounts.\n- Keep OpenCode updates on the current major line and preserve pinned-source Navigator updates when a target release needs newer runtime dependencies.\n\n## [0.21.8] - 2026-10-09\n\n- Make the unfilled part of Limits scales substantially quieter, matching the theme-derived sidebar-divider tone. Keep the filled segment, reset text, and remaining values readable in both icon modes and after theme changes.\n\n## [0.21.7] - 2026-10-09\n\n- Remove the vertical guide and its reserved gutter from Limits in both icon modes. Keep full-width quota scales, reset-left/remaining-right details, and one blank row between quota windows.\n\n## [0.21.6] - 2026-10-09\n\n- Refine Limits with a continuous muted guide, full-width thin-line quota scales, and reset-left/remaining-right details. Keep long reset text from overlapping the remaining value and preserve Text fallback, resize clipping, and existing controls.\n\n## [0.21.5] - 2026-10-07\n\n- Make automatic Limits refresh configurable in scoped Behavior settings and portable configuration, with a five-minute default and one-minute minimum. Keep manual Refresh and supported model/account switches immediate.\n- Avoid extra quota polling from unrelated preference changes and unchanged provider-account metadata observations.\n\n## [0.21.4] - 2026-10-07\n\n- Add `c` to Navigator shortcuts for a manual update check and `u` to check then confirm a Navigator update. Report available, current, or unavailable results, preserve the installation method and scope, and require a restart after updating.\n- Ignore cancelled, outdated, and repeated update confirmations, and recover from stalled update checks without blocking later checks.\n\n## [0.21.3] - 2026-10-06\n\n- Replace block quota meters with full-width adaptive thin-line scales and keep quota rows inside the sidebar's padding after resize. Show only reset time below each meter, removing technical account and window-duration suffixes.\n\n## [0.21.2] - 2026-10-06\n\n- Make Limits compact with clickable provider/model and variant controls, remaining-headroom progress rows, and muted reset times. Move Refresh and Banked Resets into the section header, remove the section counter and Provider sources action, and keep reset consumption behind a separate confirmation.\n\n## [0.21.1] - 2026-10-06\n\n- Fix Codex account quota windows being hidden when the provider omits model metadata. Show ordinary usage as shared account quota, retain banked-reset counts, and keep separate model buckets explicitly associated.\n\n## [0.21.0] - 2026-10-06\n\n- Automatically verify Codex account identity from OpenCode 2's ChatGPT connection. When host identity is unavailable, confirm a private binding once per connection or provider and reuse it across models, projects, and sessions; preserve compatible older confirmations and isolate conflicting ones until relinked.\n- Expand OpenCode 2 Limits with documented native subscription allowances, API rate-limit observations, configured capacities, account balances, and key budgets. Keep provider-native units, currencies, model associations, and active-account boundaries explicit.\n- Add Provider sources to explain each provider's supported measurements, required permissions, and unavailable APIs without guessing remaining quota.\n- Keep available account balances visible when a separate subscription read fails, and show exhausted NanoGPT subscription windows instead of hiding them.\n- Keep stale quota guidance visible after failed refreshes, reject late results after credential changes, and recover from stalled provider reads without blocking model response streams.\n\n## [0.20.0] - 2026-10-05\n\n- Add a default-visible Limits section for the selected model's provider-native quota windows, reset times, account identity, and freshness. Codex CLI support requires an explicit private account binding; unsupported providers show calm guidance.\n- Review Codex banked reset credits and use them only after a separate confirmation and fresh eligibility checks. Preserve the same attempt key when reconciling an uncertain result, including after a restart.\n- Save named, commit-safe project layout and MCP profiles to `.opencode/navigator.json` with the `opencode-navigator-profile` command, an explicit preview, and `--apply`; profile application remains manual.\n\n## [0.19.3] - 2026-10-03\n\n- Indent grouped Todo, Subagent, Skill, and MCP rows and align MCP server status indicators with their group headings.\n- Place Skill, MCP, and Quick Action bookmarks before item names. Reveal unselected bookmarks on hover or keyboard focus, keep favorites visible, and keep labels steady.\n\n## [0.19.2] - 2026-10-02\n\n- Show MCP group connection states with the same radio-style indicators as individual servers, without Connect/Disconnect labels on group headings.\n\n## [0.19.1] - 2026-10-02\n\n- Remember the OpenCode 1.x auto-approve mode as a user-wide default for new sessions, including changes made through the host's permission toggle.\n\n## [0.19.0] - 2026-10-02\n\n- Connect or disconnect all eligible MCP servers in a group from its heading, including filtered-out items, with keyboard access and failed-only retry.\n- Organize Skills into user-wide groups by source location, with Favorites first and group names searchable across the full catalog.\n- Reload saved Navigator settings from disk in another running OpenCode session without restarting it.\n\n## [0.18.2] - 2026-10-02\n\n- Open the host Settings dialog from the OpenCode 2.x Permissions Quick Action, where the user can change between `prompt` and `auto accept`; keep the direct auto-approve toggle on OpenCode 1.x.\n\n## [0.18.1] - 2026-10-01\n\n- Show calm Todo setup guidance in OpenCode 2.x when Navigator's server plugin is absent, without a request error or Retry control. Actual server failures still offer Retry.\n- Keep Quick Action names readable in narrow sidebars by placing unavailable reasons below them and showing shortcuts only when they fit.\n\n## [0.18.0] - 2026-10-01\n\n- Add durable per-session Todo lists to OpenCode 2.x through a separately configured Navigator server plugin and an agent Todo tool.\n- Update Todo in the sidebar as tasks change, and offer an off-by-default per-session switch for model-context Todo instructions.\n- Keep Todo visible with setup guidance when the OpenCode 2.x server plugin is missing.\n\n## [0.17.3] - 2026-09-30\n\n## [0.17.2] - 2026-09-30\n\n- Update a pinned local Navigator installation from its version label while keeping its file or directory source unchanged.\n- Hide the session title and creation date independently with Global/Worktree settings in OpenCode 1.x.\n\n## [0.17.1] - 2026-09-29\n\n- Fix the local Navigator installation changing unexpectedly when rebuilding the repository; it now stays on its pinned version.\n\n## [0.17.0] - 2026-09-29\n\n- Add an opt-in Behavior setting to start a new session directly in chat with the sidebar from Home or New session.\n- Remember the previously installed Navigator version and show the intervening release notes once after an update.\n\n## [0.16.1] - 2026-09-25\n\n- Make the entire OpenCode or Navigator version label open its own update confirmation when an update is available. The separator and the other version remain inactive.\n- Replace the small update arrow with a more prominent filled-circle Nerd Font indicator, retaining an ASCII fallback.\n\n## [0.16.0] - 2026-09-25\n\n- Show both OpenCode and Navigator versions in the OpenCode 2.x footer.\n- Confirm updates from the footer or command palette, preserve the original installation method and scope, and report the outcome with a restart reminder.\n\nEarlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).\n\n[0.22.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.8...v0.22.0\n[0.21.8]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.7...v0.21.8\n[0.21.7]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.6...v0.21.7\n[0.21.6]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.5...v0.21.6\n[0.21.5]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.4...v0.21.5\n[0.21.4]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.3...v0.21.4\n[0.21.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.2...v0.21.3\n[0.21.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.1...v0.21.2\n[0.21.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.0...v0.21.1\n[0.21.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.20.0...v0.21.0\n[0.20.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.3...v0.20.0\n[0.19.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.2...v0.19.3\n[0.19.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.1...v0.19.2\n[0.19.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.0...v0.19.1\n[0.19.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.2...v0.19.0\n[0.18.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.1...v0.18.2\n[0.18.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.0...v0.18.1\n[0.18.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.3...v0.18.0\n[0.17.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.2...v0.17.3\n[0.17.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.1...v0.17.2\n[0.17.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.0...v0.17.1\n[0.17.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.16.1...v0.17.0\n[0.16.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.16.0...v0.16.1\n[0.16.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.15.0...v0.16.0\n"
|
|
11196
|
+
version: "0.27.3",
|
|
11197
|
+
changelog: "# Changelog\n\n## [0.27.3] - 2026-11-12\n\n- Keep the Desktop session title on its own full-width row in both the panel and floating mini-window, with readable wrapping instead of squeezing it between action labels.\n- Use native icon buttons with tooltips for familiar sidebar actions such as Search, Refresh, Settings, Float, Dock and information. Keep descriptive labels for account linking, Banked Resets, presets and other less obvious operations.\n- Remove the persistent account/model scope explanation from successful Desktop Limits. Keep the short update time, quota data and actionable warnings without changing account scope or reset-credit safeguards.\n\n## [0.27.2] - 2026-11-11\n\n- Keep Desktop Settings fields and actions inside their rows at narrow widths, with readable labels and compact group creation.\n- Reorder Desktop sections, Quick Actions, toolbar pins and button icons by dragging their handles, or use Space and arrow keys to move them with the keyboard. Escape cancels an unfinished move.\n- Show download and installation progress in place of the running version in TUI and inline in Desktop About. Show real percentages only when byte totals are available; otherwise show the active stage.\n- Bring Desktop section arrows, loading indicators and Todo rows closer to native OpenCode. Completed and cancelled tasks use muted, struck-through text with distinct status icons.\n- Remove duplicate model and reasoning-effort selectors from the Desktop sidebar. Select them below chat instead; Limits continue to follow the active model.\n\n## [0.27.1] - 2026-11-11\n\n- Drag the Desktop mini-window by its header as well as its move handle, while keeping Dock a separate action. Match its surface and controls to OpenCode's light and dark themes.\n- Use native Desktop switches and selectors for Skill trust and Todo configuration, and align multiline fields with the host theme and focus styles.\n- Show a remaining-lifetime scale and time until expiry for banked reset credits with provider-supplied dates. Keep missing expiry explicit and prevent selecting expired credits for review.\n\n## [0.27.0] - 2026-11-11\n\n- Add an experimental OpenCode Desktop interface with a native panel, narrow-screen drawer, and opt-in in-app mini-window. Move, resize, reset and redock it with the mouse or keyboard while keeping the selected session and filters.\n- Bring Search Everything, Skills, MCP groups and presets, Quick Actions, and customizable toolbar pins to Desktop. Share private favorites, trust decisions and preferences with local TUI instances without duplicating monitoring.\n- Add native Desktop settings with scoped section controls, groups, reviewed presets and project profiles, portable import/export, a seven-slide setup guide, About, browsable release history and editable GitHub Bug reports.\n- Keep superseded Desktop configuration reads from showing a false error after a newer refresh, while preserving genuine failures and retry guidance.\n- Show verified provider/account quotas in Desktop with explicit account linking and separately confirmed banked resets. Keep remote sessions isolated from local accounts and preserve unresolved reset attempts across retries.\n- Support OpenCode 1.19.5 and 2.2.6 while preserving both TUI adapters, existing settings, pinned-source updates and read-only legacy Todo archives.\n\n## [0.26.0] - 2026-11-06\n\n- Prevent background retries from accumulating cancellation listeners and preferences loading from waiting indefinitely on recovery markers.\n- Show exact active Subagent durations from OpenCode 2's native execution start time, preserving the observation fallback when timing is unavailable. Keep interrupted executions marked as cancelled in recent history.\n\n## [0.25.0] - 2026-10-31\n\n- Offer Enable Todo when OpenCode 2's native tool is disabled, with an existing server-config picker, exact change preview and separate confirmation. Preserve unrelated JSONC content and refuse stale targets; distinguish disabled Todo from an enabled empty list.\n- Update the seven-slide setup wizard for native Todo enablement, provider/account limits, multi-icon or text-only toolbar pins, About/changelog and Bug reports. Describe each host's real permissions/LSP capabilities and keep navigation visible while short-terminal content scrolls.\n\n## [0.24.0] - 2026-10-31\n\n- Support the latest stable OpenCode 1.19.5 and 2.2.5 releases, preserving both host adapters and existing sidebar behavior.\n- Preserve Limits scales and reset-credit controls across equivalent quota snapshots and unrelated workspace events, while retaining current-account and credential-change guards.\n- Keep rounded selection backgrounds consistent in nested dialogs and highlighted rows.\n- Configure each toolbar button with zero to three icons and optional custom text, including text-only buttons. Keep legacy/state choices, unsaved drafts, rounded clipping, and width-aware More/wrapping.\n- Keep Quick Action rows and their hover/focus state stable while typing in the main prompt on both supported OpenCode hosts.\n- Show toolbar hover/focus hints without moving Limits or other sections, preserving centered, uniformly sized icon controls and empty-toolbar collapse.\n- Add Settings → About with the running versions, explicit update status/checking, confirmed updates, and a versioned changelog that can be reopened independently of first-launch upgrade notes.\n- Prepare editable Bug reports with confirmed sending through authenticated GitHub CLI and an independent Open in browser action. Retain drafts through errors and cancellation, and require manual review before retrying an uncertain submission.\n\n## [0.23.0] - 2026-10-28\n\n- Support only the latest stable OpenCode 1.x and 2.x releases, currently 1.19.5 and 2.2.0, including the newer terminal renderer.\n- Keep Skills, MCP servers, and Subagents current as OpenCode 2 updates, and launch the intended Skill when multiple sources have the same name.\n- Show OpenCode Console workspace budgets and Go allowance through the public host usage API without a Navigator server plugin. Preserve workspace scope, native units, reset times, and explicit failure/retry states.\n- Preserve Navigator shortcuts and nested-dialog navigation with OpenCode 2.2's keyboard handling.\n- Verify a supported runtime before changing a pinned Navigator snapshot, preserving the installed version when no compatible verifier is available.\n\n## [0.22.0] - 2026-10-23\n\n- Pin Quick Actions and Skills to a compact sidebar toolbar independently of bookmarks. Choose icons in a searchable picker, customize supported state icons, reorder buttons, and select a More menu or wrapping rows. Preserve Skill confirmations, unavailable reasons, keyboard navigation, and Text fallback; hide the toolbar entirely when empty.\n- Use OpenCode 2's built-in Todo history for the sidebar, with native completed-write and revert semantics, existing filters/progress, and manual Refresh. Keep edits in ordinary chat, preserve previous Navigator tasks as a read-only archive, and retain the independent provider-quota server integration.\n- Support OpenCode 2.1's plugin and rendering APIs while retaining the OpenCode 1.x adapter; restore custom dialogs and rounded selections on the newer native renderer.\n- Replace the shortcut toast with an icon-led hint featuring highlighted keys, navigation/update groups, a distinct Escape action, and responsive Text/no-corner-font layouts. Keep prompt focus and share its action list with scrollable keyboard help.\n- Update Subagent status immediately from OpenCode 2's execution lifecycle and keep unresolved external credentials separate from verified provider accounts.\n- Keep OpenCode updates on the current major line and preserve pinned-source Navigator updates when a target release needs newer runtime dependencies.\n\n## [0.21.8] - 2026-10-09\n\n- Make the unfilled part of Limits scales substantially quieter, matching the theme-derived sidebar-divider tone. Keep the filled segment, reset text, and remaining values readable in both icon modes and after theme changes.\n\n## [0.21.7] - 2026-10-09\n\n- Remove the vertical guide and its reserved gutter from Limits in both icon modes. Keep full-width quota scales, reset-left/remaining-right details, and one blank row between quota windows.\n\n## [0.21.6] - 2026-10-09\n\n- Refine Limits with a continuous muted guide, full-width thin-line quota scales, and reset-left/remaining-right details. Keep long reset text from overlapping the remaining value and preserve Text fallback, resize clipping, and existing controls.\n\n## [0.21.5] - 2026-10-07\n\n- Make automatic Limits refresh configurable in scoped Behavior settings and portable configuration, with a five-minute default and one-minute minimum. Keep manual Refresh and supported model/account switches immediate.\n- Avoid extra quota polling from unrelated preference changes and unchanged provider-account metadata observations.\n\n## [0.21.4] - 2026-10-07\n\n- Add `c` to Navigator shortcuts for a manual update check and `u` to check then confirm a Navigator update. Report available, current, or unavailable results, preserve the installation method and scope, and require a restart after updating.\n- Ignore cancelled, outdated, and repeated update confirmations, and recover from stalled update checks without blocking later checks.\n\n## [0.21.3] - 2026-10-06\n\n- Replace block quota meters with full-width adaptive thin-line scales and keep quota rows inside the sidebar's padding after resize. Show only reset time below each meter, removing technical account and window-duration suffixes.\n\n## [0.21.2] - 2026-10-06\n\n- Make Limits compact with clickable provider/model and variant controls, remaining-headroom progress rows, and muted reset times. Move Refresh and Banked Resets into the section header, remove the section counter and Provider sources action, and keep reset consumption behind a separate confirmation.\n\n## [0.21.1] - 2026-10-06\n\n- Fix Codex account quota windows being hidden when the provider omits model metadata. Show ordinary usage as shared account quota, retain banked-reset counts, and keep separate model buckets explicitly associated.\n\n## [0.21.0] - 2026-10-06\n\n- Automatically verify Codex account identity from OpenCode 2's ChatGPT connection. When host identity is unavailable, confirm a private binding once per connection or provider and reuse it across models, projects, and sessions; preserve compatible older confirmations and isolate conflicting ones until relinked.\n- Expand OpenCode 2 Limits with documented native subscription allowances, API rate-limit observations, configured capacities, account balances, and key budgets. Keep provider-native units, currencies, model associations, and active-account boundaries explicit.\n- Add Provider sources to explain each provider's supported measurements, required permissions, and unavailable APIs without guessing remaining quota.\n- Keep available account balances visible when a separate subscription read fails, and show exhausted NanoGPT subscription windows instead of hiding them.\n- Keep stale quota guidance visible after failed refreshes, reject late results after credential changes, and recover from stalled provider reads without blocking model response streams.\n\n## [0.20.0] - 2026-10-05\n\n- Add a default-visible Limits section for the selected model's provider-native quota windows, reset times, account identity, and freshness. Codex CLI support requires an explicit private account binding; unsupported providers show calm guidance.\n- Review Codex banked reset credits and use them only after a separate confirmation and fresh eligibility checks. Preserve the same attempt key when reconciling an uncertain result, including after a restart.\n- Save named, commit-safe project layout and MCP profiles to `.opencode/navigator.json` with the `opencode-navigator-profile` command, an explicit preview, and `--apply`; profile application remains manual.\n\n## [0.19.3] - 2026-10-03\n\n- Indent grouped Todo, Subagent, Skill, and MCP rows and align MCP server status indicators with their group headings.\n- Place Skill, MCP, and Quick Action bookmarks before item names. Reveal unselected bookmarks on hover or keyboard focus, keep favorites visible, and keep labels steady.\n\n## [0.19.2] - 2026-10-02\n\n- Show MCP group connection states with the same radio-style indicators as individual servers, without Connect/Disconnect labels on group headings.\n\n## [0.19.1] - 2026-10-02\n\n- Remember the OpenCode 1.x auto-approve mode as a user-wide default for new sessions, including changes made through the host's permission toggle.\n\n## [0.19.0] - 2026-10-02\n\n- Connect or disconnect all eligible MCP servers in a group from its heading, including filtered-out items, with keyboard access and failed-only retry.\n- Organize Skills into user-wide groups by source location, with Favorites first and group names searchable across the full catalog.\n- Reload saved Navigator settings from disk in another running OpenCode session without restarting it.\n\n## [0.18.2] - 2026-10-02\n\n- Open the host Settings dialog from the OpenCode 2.x Permissions Quick Action, where the user can change between `prompt` and `auto accept`; keep the direct auto-approve toggle on OpenCode 1.x.\n\n## [0.18.1] - 2026-10-01\n\n- Show calm Todo setup guidance in OpenCode 2.x when Navigator's server plugin is absent, without a request error or Retry control. Actual server failures still offer Retry.\n- Keep Quick Action names readable in narrow sidebars by placing unavailable reasons below them and showing shortcuts only when they fit.\n\n## [0.18.0] - 2026-10-01\n\n- Add durable per-session Todo lists to OpenCode 2.x through a separately configured Navigator server plugin and an agent Todo tool.\n- Update Todo in the sidebar as tasks change, and offer an off-by-default per-session switch for model-context Todo instructions.\n- Keep Todo visible with setup guidance when the OpenCode 2.x server plugin is missing.\n\n## [0.17.3] - 2026-09-30\n\n## [0.17.2] - 2026-09-30\n\n- Update a pinned local Navigator installation from its version label while keeping its file or directory source unchanged.\n- Hide the session title and creation date independently with Global/Worktree settings in OpenCode 1.x.\n\n## [0.17.1] - 2026-09-29\n\n- Fix the local Navigator installation changing unexpectedly when rebuilding the repository; it now stays on its pinned version.\n\n## [0.17.0] - 2026-09-29\n\n- Add an opt-in Behavior setting to start a new session directly in chat with the sidebar from Home or New session.\n- Remember the previously installed Navigator version and show the intervening release notes once after an update.\n\n## [0.16.1] - 2026-09-25\n\n- Make the entire OpenCode or Navigator version label open its own update confirmation when an update is available. The separator and the other version remain inactive.\n- Replace the small update arrow with a more prominent filled-circle Nerd Font indicator, retaining an ASCII fallback.\n\n## [0.16.0] - 2026-09-25\n\n- Show both OpenCode and Navigator versions in the OpenCode 2.x footer.\n- Confirm updates from the footer or command palette, preserve the original installation method and scope, and report the outcome with a restart reminder.\n\nEarlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).\n\n[0.22.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.8...v0.22.0\n[0.21.8]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.7...v0.21.8\n[0.21.7]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.6...v0.21.7\n[0.21.6]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.5...v0.21.6\n[0.21.5]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.4...v0.21.5\n[0.21.4]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.3...v0.21.4\n[0.21.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.2...v0.21.3\n[0.21.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.1...v0.21.2\n[0.21.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.0...v0.21.1\n[0.21.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.20.0...v0.21.0\n[0.20.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.3...v0.20.0\n[0.19.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.2...v0.19.3\n[0.19.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.1...v0.19.2\n[0.19.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.0...v0.19.1\n[0.19.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.2...v0.19.0\n[0.18.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.1...v0.18.2\n[0.18.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.0...v0.18.1\n[0.18.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.3...v0.18.0\n[0.17.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.2...v0.17.3\n[0.17.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.1...v0.17.2\n[0.17.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.0...v0.17.1\n[0.17.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.16.1...v0.17.0\n[0.16.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.16.0...v0.16.1\n[0.16.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.15.0...v0.16.0\n"
|
|
11124
11198
|
};
|
|
11125
11199
|
// src/app/gui/about.ts
|
|
11126
11200
|
function createGuiAbout(context) {
|
|
@@ -16104,7 +16178,7 @@ var setup = (context) => {
|
|
|
16104
16178
|
try {
|
|
16105
16179
|
await preferences.flush();
|
|
16106
16180
|
context.toast.show({
|
|
16107
|
-
title: `Navigator 0.27.
|
|
16181
|
+
title: `Navigator 0.27.3`,
|
|
16108
16182
|
variant: "default"
|
|
16109
16183
|
});
|
|
16110
16184
|
} catch {
|